예제 #1
0
파일: main.c 프로젝트: cjc1029nice/ksdk
/*!
 * @brief SPI master DMA non-blocking.
 *
 * Thid function uses SPI master to send an array to slave
 * and receive the array back from slave,
 * then compare whether the two buffers are the same.
 */
int main (void)
{
    uint8_t loopCount = 0;
    uint32_t j;
    uint32_t failCount = 0;
    uint32_t calculatedBaudRate;
    spi_dma_master_state_t spiDmaMasterState;
    dma_state_t state;
    spi_dma_master_user_config_t userDmaConfig =
    {
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
        .bitCount       = kSpi8BitMode,
#endif
        .polarity       = kSpiClockPolarity_ActiveHigh,
        .phase          = kSpiClockPhase_FirstEdge,
        .direction      = kSpiMsbFirst,
        .bitsPerSec     = TRANSFER_BAUDRATE
    };

    // init the hardware, this also sets up up the SPI pins for each specific SoC
    hardware_init();
    // Init OSA layer.
    OSA_Init();

    PRINTF("\r\nSPI board to board dma-non-blocking example");
    PRINTF("\r\nThis example run on instance %d", (uint32_t)SPI_MASTER_INSTANCE);
    PRINTF("\r\nBe sure master's SPI%d and slave's SPI%d are connected\r\n",
                    (uint32_t)SPI_MASTER_INSTANCE, (uint32_t)SPI_MASTER_INSTANCE);

    // Set up and init the master
    DMA_DRV_Init(&state);
    // Init the dspi module for eDMA operation
    SPI_DRV_DmaMasterInit(SPI_MASTER_INSTANCE, &spiDmaMasterState);
    SPI_DRV_DmaMasterConfigureBus(SPI_MASTER_INSTANCE,
                                    &userDmaConfig,
                                    &calculatedBaudRate);

    if (calculatedBaudRate > userDmaConfig.bitsPerSec)
    {
        PRINTF("\r\n**Something failed in the master bus config \r\n");
        return -1;
    }
    else
    {
        PRINTF("\r\nBaud rate in Hz is: %d\r\n", calculatedBaudRate);
    }

    while(1)
    {
        // Initialize the source buffer
        for (j = 0; j < TRANSFER_SIZE; j++)
        {
            s_spiSourceBuffer[j] = j + loopCount;
        }

        // Reset the sink buffer
        for (j = 0; j < TRANSFER_SIZE; j++)
        {
            s_spiSinkBuffer[j] = 0;
        }

        // Start the transfer
        SPI_DRV_DmaMasterTransferBlocking(SPI_MASTER_INSTANCE, NULL, s_spiSourceBuffer,
                                        NULL, TRANSFER_SIZE, MASTER_TRANSFER_TIMEOUT);
        while (SPI_DRV_DmaMasterGetTransferStatus(SPI_MASTER_INSTANCE, NULL) == kStatus_SPI_Busy)
        {
        }

        // Delay sometime to wait slave receive and send back data
        OSA_TimeDelay(500U);

        //Receive data from slave
        SPI_DRV_DmaMasterTransfer(SPI_MASTER_INSTANCE, NULL, NULL,
                            s_spiSinkBuffer, TRANSFER_SIZE);
        while (SPI_DRV_DmaMasterGetTransferStatus(SPI_MASTER_INSTANCE, NULL) == kStatus_SPI_Busy)
        {
        }

        // Verify the contents of the master sink buffer
        // refer to the slave driver for the expected data pattern
        failCount = 0; // reset failCount variable

        for (j = 0; j < TRANSFER_SIZE; j++)
        {
            if (s_spiSinkBuffer[j] != s_spiSourceBuffer[j])
            {
                 failCount++;
            }
        }

        // Print out transmit buffer.
        PRINTF("\r\nMaster transmit:");
        for (j = 0; j < TRANSFER_SIZE; j++)
        {
            // Print 16 numbers in a line.
            if ((j & 0x0F) == 0)
            {
                PRINTF("\r\n    ");
            }
            PRINTF(" %02X", s_spiSourceBuffer[j]);
        }
        // Print out receive buffer.
        PRINTF("\r\nMaster receive:");
        for (j = 0; j < TRANSFER_SIZE; j++)
        {
            // Print 16 numbers in a line.
            if ((j & 0x0F) == 0)
            {
                PRINTF("\r\n    ");
            }
            PRINTF(" %02X", s_spiSinkBuffer[j]);
        }

        if (failCount == 0)
        {
            PRINTF("\r\n Spi master transfer succeed! \r\n");
        }
        else
        {
            PRINTF("\r\n **failures detected in Spi master transfer! \r\n");
        }

        // Wait for press any key.
        PRINTF("\r\nPress any key to run again\r\n");
        GETCHAR();
        loopCount++;
    }
}
/*!
 * @brief Initiate (start) a transfer using DMA. This is not a public API as it is called from
 *  other driver functions
 */
spi_status_t SPI_DRV_DmaMasterStartTransfer(uint32_t instance,
                                            const spi_dma_master_user_config_t * device)
{
    /* instantiate local variable of type spi_dma_master_state_t and point to global state */
    spi_dma_master_state_t * spiDmaState = (spi_dma_master_state_t *)g_spiStatePtr[instance];

    /* For temporarily storing DMA register channel */
    void * param;
    uint32_t calculatedBaudRate;
    SPI_Type *base = g_spiBase[instance];
    uint32_t transferSizeInBytes;  /* DMA transfer size in bytes */

    /* Initialize s_byteToSend */
    s_byteToSend = 0;

    /* If the transfer count is zero, then return immediately.*/
    if (spiDmaState->remainingSendByteCount == 0)
    {
        /* Signal the synchronous completion object if the transfer wasn't async.
         * Otherwise, when we return the the sync function we'll get stuck in the sync wait loop.
         */
        if (spiDmaState->isTransferBlocking)
        {
            OSA_SemaPost(&spiDmaState->irqSync);
        }

        return kStatus_SPI_Success;
    }

    /* Configure bus for this device. If NULL is passed, we assume the caller has
     * preconfigured the bus using SPI_DRV_DmaMasterConfigureBus().
     * Do nothing for calculatedBaudRate. If the user wants to know the calculatedBaudRate
     * then they can call this function separately.
     */
    if (device)
    {
        SPI_DRV_DmaMasterConfigureBus(instance, device, &calculatedBaudRate);
    }

    /* In order to flush any remaining data in the shift register, disable then enable the SPI */
    SPI_HAL_Disable(base);
    SPI_HAL_Enable(base);

#if FSL_FEATURE_SPI_16BIT_TRANSFERS
    /* Check the transfer byte count. If bits/frame > 8, meaning 2 bytes, and if
     * the transfer byte count is an odd count we'll have to round down the RX transfer byte count
     * to the next lowest even number by one and assert a flag to indicate in the interrupt handler
     * that we take care of sending and receiving this last byte.  We'll round up TX byte count.
     */
    if (SPI_HAL_Get8or16BitMode(base) == kSpi16BitMode) /* Applies to 16-bit transfers */
    {
        /* Odd byte count for 16-bit transfers, set the extraByte flag */
        if (spiDmaState->remainingSendByteCount & 1UL) /* If odd byte count */
        {
            transferSizeInBytes = 2; /* Set transfer size to two bytes for the DMA operation */
            spiDmaState->extraByte = true; /* Set the extraByte flag */

            /* Round up TX byte count so when DMA completes, all data would've been sent */
            spiDmaState->remainingSendByteCount += 1U;

            /* Round down RX byte count which means at the end of the RX DMA transfer, we'll need
             * to set up an interrupt to get the last byte.
             */
            spiDmaState->remainingReceiveByteCount &= ~1U;

            /* Store the transfer byte count to the run-time state struct
             * for later use in the interrupt handler.
             */
            spiDmaState->transferByteCnt = spiDmaState->remainingSendByteCount;
        }
        /* Even byte count for 16-bit transfers, clear the extraByte flag */
        else
        {
            transferSizeInBytes = 2; /* Set transfer size to two bytes for the DMA operation */
            spiDmaState->extraByte = false; /* Clear the extraByte flag */
        }
    }
    else /* For 8-bit transfers */
    {
        transferSizeInBytes = 1;
        spiDmaState->extraByte = false;
    }
#else
    transferSizeInBytes = 1;
#endif

    param = (void *)(instance); /* For DMA callback, set "param" as the SPI instance number */

    /* Check that we're not busy.*/
    if (spiDmaState->isTransferInProgress)
    {
        return kStatus_SPI_Busy;
    }

    /* Save information about the transfer for use by the ISR.*/
    spiDmaState->isTransferInProgress = true;

    /************************************************************************************
     * Set up the RX DMA channel Transfer Control Descriptor (TCD)
     * Note, if there is no receive byte count, then bypass RX DMA set up.
     ***********************************************************************************/
    if (spiDmaState->remainingReceiveByteCount)
    {
        /* If no receive buffer then disable incrementing the destination and set the destination
         * to a temporary location
         */
        if (!spiDmaState->receiveBuffer)
        {
            /* Set up this channel's control which includes enabling the DMA interrupt */
            DMA_DRV_ConfigTransfer(&spiDmaState->dmaReceive,
                                   kDmaPeripheralToPeripheral,
                                   transferSizeInBytes,
                                   SPI_HAL_GetDataRegAddr(base), /* src is data register */
                                   (uint32_t)(&s_rxBuffIfNull), /* dest is temporary location */
                                   (uint32_t)(spiDmaState->remainingReceiveByteCount));
        }
        else
        {
            /* Set up this channel's control which includes enabling the DMA interrupt */
            DMA_DRV_ConfigTransfer(&spiDmaState->dmaReceive,
                                   kDmaPeripheralToMemory,
                                   transferSizeInBytes,
                                   SPI_HAL_GetDataRegAddr(base), /* src is data register */
                                   (uint32_t)(spiDmaState->receiveBuffer),/* dest is rx buffer */
                                   (uint32_t)(spiDmaState->remainingReceiveByteCount));
        }

        /* Dest size is always 1 byte on each transfer */
        DMA_DRV_SetDestTransferSize(&spiDmaState->dmaReceive, 1U);

        /* Enable the DMA peripheral request */
        DMA_DRV_StartChannel(&spiDmaState->dmaReceive);

        /* Register callback for DMA interrupt */
        DMA_DRV_RegisterCallback(&spiDmaState->dmaReceive, SPI_DRV_DmaMasterCallback, param);
    }

    /************************************************************************************
     * Set up the TX DMA channel Transfer Control Descriptor (TCD)
     * Note, if there is no source buffer (if user passes in NULL), then send zeros
     ***********************************************************************************/
    /* Per the reference manual, before enabling the SPI transmit DMA request, we first need
     * to read the status register and then write to the SPI data register.  Afterwards, we need
     * to decrement the sendByteCount and perform other driver maintenance functions.
     */

    /* Read the SPI Status register */
    SPI_HAL_IsTxBuffEmptyPending(base);

    /* Start the transfer by writing the first byte/word to the SPI data register.
     * If a send buffer was provided, the byte/word comes from there. Otherwise we just send zeros.
     * This will cause an immeidate transfer which in some cases may cause the RX DMA channel to
     * complete before having the chance to completely set up the TX DMA channel. As such, we'll
     * enable the RX DMA channel last.
     */
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
    if (transferSizeInBytes == 2) /* 16-bit transfers for SPI16 module */
    {
        if (spiDmaState->sendBuffer)
        {
            s_byteToSend = *(spiDmaState->sendBuffer);
            SPI_HAL_WriteDataLow(base, s_byteToSend);
            ++spiDmaState->sendBuffer;

            s_byteToSend = *(spiDmaState->sendBuffer);
            SPI_HAL_WriteDataHigh(base, s_byteToSend);
            ++spiDmaState->sendBuffer;
        }
        else  /* Else, if no send buffer, write zeros */
        {
            SPI_HAL_WriteDataLow(base, s_byteToSend);
            SPI_HAL_WriteDataHigh(base, s_byteToSend);
        }
        spiDmaState->remainingSendByteCount -= 2;  /* Decrement the send byte count by 2 */
    }
    else /* 8-bit transfers for SPI16 module */
    {
        if (spiDmaState->sendBuffer)
        {
            s_byteToSend = *(spiDmaState->sendBuffer);
            ++spiDmaState->sendBuffer;
        }
        SPI_HAL_WriteDataLow(base, s_byteToSend); /* If no send buffer, s_byteToSend=0 */
        --spiDmaState->remainingSendByteCount; /* Decrement the send byte count */
    }
#else
    /* For SPI modules that do not support 16-bit transfers */
    if (spiDmaState->sendBuffer)
    {
        s_byteToSend = *(spiDmaState->sendBuffer);
        ++spiDmaState->sendBuffer;
    }
    SPI_HAL_WriteData(base, s_byteToSend); /* If no send buffer, s_byteToSend=0 */
    --spiDmaState->remainingSendByteCount; /* Decrement the send byte count */
#endif

    /* If there are no more bytes to send then return without setting up the TX DMA channel
     * and let the receive DMA channel complete the transfer if the RX DMA channel was setup.
     * If the RX DMA channel was not set up (due to odd byte count of 1 in 16-bit mode), enable
     * the interrupt to get the received byte.
     */
    if (!spiDmaState->remainingSendByteCount) /* No more bytes to send */
    {
        if (spiDmaState->remainingReceiveByteCount)
        {
            /* Enable the RX DMA channel request now  */
            SPI_HAL_SetRxDmaCmd(base, true);
            return kStatus_SPI_Success;
        }
        else /* If RX DMA chan not setup then enable the interrupt to get the received byte */
        {
            SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, true);
            return kStatus_SPI_Success;
        }
    }
    /* Else, since there are more bytes to send, go ahead and set up the TX DMA channel */
    else
    {
        /* If there is a send buffer, data comes from there, else send 0 */
        if (spiDmaState->sendBuffer)
        {
            /* Set up this channel's control which includes enabling the DMA interrupt */
            DMA_DRV_ConfigTransfer(&spiDmaState->dmaTransmit, kDmaMemoryToPeripheral,
                                   transferSizeInBytes,
                                   (uint32_t)(spiDmaState->sendBuffer),
                                   SPI_HAL_GetDataRegAddr(base),
                                   (uint32_t)(spiDmaState->remainingSendByteCount));
        }
        else /* Configure TX DMA channel to send zeros */
        {
            /* Set up this channel's control which includes enabling the DMA interrupt */
            DMA_DRV_ConfigTransfer(&spiDmaState->dmaTransmit, kDmaPeripheralToPeripheral,
                                   transferSizeInBytes,
                                   (uint32_t)(&s_byteToSend),
                                   SPI_HAL_GetDataRegAddr(base),
                                   (uint32_t)(spiDmaState->remainingSendByteCount));
        }

        /* Source size is only one byte on each transfer */
        DMA_DRV_SetSourceTransferSize(&spiDmaState->dmaTransmit, 1U);

        /* Enable the SPI TX DMA Request */
        SPI_HAL_SetTxDmaCmd(base, true);

        /* Enable the SPI RX DMA Request after the TX DMA request is enabled.  This is done to
         * make sure that the RX DMA channel does not end prematurely before we've completely set
         * up the TX DMA channel since part of the TX DMA set up involves placing 1 or 2 bytes of
         * data into the send data register which causes an immediate transfer.
         */
        SPI_HAL_SetRxDmaCmd(base, true);

        /* Enable the DMA peripheral request */
        DMA_DRV_StartChannel(&spiDmaState->dmaTransmit);
    }

    return kStatus_SPI_Success;
}
예제 #3
0
// Setup the board as a spi master
int main (void)
{
    uint8_t loopCount = 0;
    uint32_t j;
    uint32_t failCount = 0;
    uint8_t * pRxBuff;
    uint32_t calculatedBaudRate;
    spi_master_state_t spiMasterState;
    spi_dma_master_state_t spiDmaMasterState;
    dma_state_t state;
    spi_dma_master_user_config_t userDmaConfig =
    {
    #if FSL_FEATURE_SPI_16BIT_TRANSFERS
        .bitCount       = kSpi8BitMode,
    #endif
        .polarity       = kSpiClockPolarity_ActiveHigh,
        .phase          = kSpiClockPhase_FirstEdge,
        .direction      = kSpiMsbFirst,
        .bitsPerSec     = TRANSFER_BAUDRATE
    };

    // init the hardware, this also sets up up the SPI pins for each specific SoC
    hardware_init();

    dbg_uart_init();

    OSA_Init();

    printf("\r\n SPI board to board dma-blocking example");
    printf("\r\n This example run on instance 0 ");
    printf("\r\n Be sure master's SPI0 and slave's SPI0 are connected ");

    //USER CONFIGURABLE OPTION FOR SPI INSTANCE

    // Configure SPI pin
    configure_spi_pins(SPI_MASTER_INSTANCE);

    printf("\rIMPORTANT, MAKE SURE TO FIRST SET UP THE SPI SLAVE BOARD!\r\n");

    //USER CONFIGURABLE OPTION FOR RXBUFF
    pRxBuff = s_spiSinkBuffer;
    // Set up and init the master
    DMA_DRV_Init(&state);
    // Init the dspi module for eDMA operation
    SPI_DRV_DmaMasterInit(SPI_MASTER_INSTANCE, &spiDmaMasterState);

    SPI_DRV_DmaMasterConfigureBus(SPI_MASTER_INSTANCE,
                                    &userDmaConfig,
                                    &calculatedBaudRate);


    if (calculatedBaudRate > userDmaConfig.bitsPerSec)
    {
        printf("\r**Something failed in the master bus config \r\n");
        return -1;
    }


    printf("\r\nSpi master SYNC test with various baud rates  \r\n");

    printf("\r\nBaudRate set to %dHz\r\n", calculatedBaudRate);
    while(1)
    {
        // Initialize the source buffer
        for (j = 0; j < TRANSFER_SIZE; j++)
        {
            s_spiSourceBuffer[j] = j + loopCount;
        }

        // Reset the sink buffer
        for (j = 0; j < TRANSFER_SIZE; j++)
        {
            s_spiSinkBuffer[j] = 0;
        }
        /* Start the transfer */
        if (SPI_DRV_DmaMasterTransferBlocking(SPI_MASTER_INSTANCE, NULL, s_spiSourceBuffer,
                            NULL, TRANSFER_SIZE, MASTER_TRANSFER_TIMEOUT) == kStatus_SPI_Timeout)
        {
            printf("\r**Sync transfer timed-out \r\n");
        }

        // Delay sometime to wait slave receive and send back data
        OSA_TimeDelay(500U);

        if (SPI_DRV_DmaMasterTransferBlocking(SPI_MASTER_INSTANCE, NULL, NULL,
                            s_spiSinkBuffer, TRANSFER_SIZE, MASTER_TRANSFER_TIMEOUT) == kStatus_SPI_Timeout)
        {
            printf("\r**Sync transfer timed-out \r\n");
        }
        // Verify the contents of the master sink buffer
        // refer to the slave driver for the expected data pattern
        failCount = 0; // reset failCount variable

        for (j = 0; j < TRANSFER_SIZE; j++)
        {
            if (s_spiSinkBuffer[j] != s_spiSourceBuffer[j])
            {
                 failCount++;
            }
        }

        if (failCount == 0)
        {
            printf("\r\nMaster transmit:");
            for (j = 0; j < TRANSFER_SIZE; j++)
            {
                if (j%16 == 0)
                {
                    printf("\r\n    ");
                }
                printf(" %02X", s_spiSourceBuffer[j]);
            }
            printf("\r\nMaster receive:");
            for (j = 0; j < TRANSFER_SIZE; j++)
            {
                if (j%16 == 0)
                {
                    printf("\r\n    ");
                }
                printf(" %02X", s_spiSinkBuffer[j]);
            }
            printf("\r\n");
            printf("\r Spi master blocking transfer succeed! \r\n");
        }
        else
        {
            printf("\r\nSource buffer:");
            for (j = 0; j < TRANSFER_SIZE; j++)
            {
                if (j%16 == 0)
                {
                    printf("\r\n    ");
                }
                printf(" %02X", s_spiSourceBuffer[j]);
            }
            printf("\r\nSink buffer:");
            for (j = 0; j < TRANSFER_SIZE; j++)
            {
                if (j%16 == 0)
                {
                    printf("\r\n    ");
                }
                printf(" %02X", s_spiSinkBuffer[j]);
            }
            printf("\r\n");
            printf("\r **failures detected in Spi master blocking transfer! \r\n");
        }

        // Wait for press any key.
        printf("\r\nPress any key to run again\r\n");
        getchar();
        loopCount++;
    }
}