Beispiel #1
0
/*!
 * @brief Fill up the TX FIFO with data.
 * This function fills up the TX FIFO with initial data for start of transfers where it will
 * first clear the transfer count.  Otherwise, if the TX FIFO fill is part of an ongoing transfer
 * then do not clear the transfer count.  The param "isInitialData" is used to determine if this
 * is an initial data fill.
 * This is not a public API as it is called from other driver functions.
 */
static void DSPI_DRV_MasterFillupTxFifo(uint32_t instance)
{
    /* instantiate local variable of type dspi_master_state_t and point to global state */
    dspi_master_state_t * dspiState = (dspi_master_state_t *)g_dspiStatePtr[instance];
    SPI_Type *base = g_dspiBase[instance];
    dspi_command_config_t command;  /* create an instance of the data command struct*/
    uint32_t cmd; /* Command word to be OR'd with data word */
    uint16_t wordToSend = 0;
    /* Declare variables for storing volatile data later in the code */
    uint32_t remainingReceiveByteCount, remainingSendByteCount;

    /* Before sending the data, we first need to initialize the data command struct
     * Configure the data command attributes for the desired PCS, CTAR, and continuous PCS
     * which are derived from the run-time state struct
     */
    command.whichPcs = dspiState->whichPcs;
    command.whichCtar = dspiState->whichCtar;
    command.isChipSelectContinuous = dspiState->isChipSelectContinuous;
    command.isEndOfQueue = 0;
    command.clearTransferCount = 0;

    /* "Build" the command word. Only do this once since the commad word members don't
     * change until the last word sent (which is when the end of queue flag gets set).
     */
    cmd = DSPI_HAL_GetFormattedCommand(base, &command);

    /* Store the DSPI state struct volatile member variables into temporary
     * non-volatile variables to allow for MISRA compliant calculations
     */
    remainingSendByteCount = dspiState->remainingSendByteCount;
    remainingReceiveByteCount = dspiState->remainingReceiveByteCount;

    /* Architectural note: When developing the TX FIFO fill functionality, it was found that to
     * achieve more efficient run-time performance, it was better to first check the bits/frame
     * setting and then proceed with the FIFO fill management process, rather than to clutter the
     * FIFO fill process with continual checks of the bits/frame setting.
     */

    /* If bits/frame is greater than one byte */
    if (dspiState->bitsPerFrame > 8)
    {
        /* Fill the fifo until it is full or until the send word count is 0 or until the difference
         * between the remainingReceiveByteCount and remainingSendByteCount equals the FIFO depth.
         * The reason for checking the difference is to ensure we only send as much as the
         * RX FIFO can receive.
         * For this case where bitsPerFrame > 8, each entry in the FIFO contains 2 bytes of the
         * send data, hence the difference between the remainingReceiveByteCount and
         * remainingSendByteCount must be divided by 2 to convert this difference into a
         * 16-bit (2 byte) value.
         */
        while((DSPI_HAL_GetStatusFlag(base, kDspiTxFifoFillRequest) == 1) &&
              ((remainingReceiveByteCount - remainingSendByteCount)/2 <
                g_dspiFifoSize[instance]))
        {
            /* On the last word to be sent, set the end of queue flag in the data command struct
             * and ensure that the CONT bit in the PUSHR is also cleared even if it was cleared to
             * begin with. If CONT is set it means continuous chip select operation and to ensure
             * the chip select is de-asserted, this bit must be cleared on the last data word.
             */
            if (dspiState->remainingSendByteCount == 2)
            {
                command.isEndOfQueue = 1;
                command.isChipSelectContinuous = 0;
                cmd = DSPI_HAL_GetFormattedCommand(base, &command);

                /* If there is an extra byte to send due to an odd byte count, prepare the final
                 * wordToSend here
                 */
                if (dspiState->sendBuffer)
                {
                    if (dspiState->extraByte)
                    {
                        wordToSend = *(dspiState->sendBuffer);
                    }
                    else
                    {
                        wordToSend = *(dspiState->sendBuffer);
                        ++dspiState->sendBuffer; /* increment to next data byte */
                        wordToSend |= (unsigned)(*(dspiState->sendBuffer)) << 8U;
                    }
                }
            }
            /* For all words except the last word */
            else
            {
                /* If a send buffer was provided, the word comes from there. Otherwise we just send
                 * a zero (initialized above).
                 */
                if (dspiState->sendBuffer)
                {
                    wordToSend = *(dspiState->sendBuffer);
                    ++dspiState->sendBuffer; /* increment to next data byte */
                    wordToSend |= (unsigned)(*(dspiState->sendBuffer)) << 8U;
                    ++dspiState->sendBuffer; /* increment to next data byte */
                }
            }
            DSPI_HAL_WriteCmdDataMastermode(base, cmd|wordToSend);

            /* Try to clear the TFFF; if the TX FIFO is full this will clear */
            DSPI_HAL_ClearStatusFlag(base, kDspiTxFifoFillRequest);

            dspiState->remainingSendByteCount -= 2; /* decrement remainingSendByteCount by 2 */

            /* exit loop if send count is zero, else update local variables for next loop */
            if (dspiState->remainingSendByteCount == 0)
            {
                break;
            }
            else
            {
                /* Store the DSPI state struct volatile member variables into temporary
                 * non-volatile variables to allow for MISRA compliant calculations
                 */
                remainingSendByteCount = dspiState->remainingSendByteCount;
            }
        } /* End of TX FIFO fill while loop */
    }
    /* Optimized for bits/frame less than or equal to one byte. */
    else
    {
        /* Fill the fifo until it is full or until the send word count is 0 or until the difference
         * between the remainingReceiveByteCount and remainingSendByteCount equals the FIFO depth.
         * The reason for checking the difference is to ensure we only send as much as the
         * RX FIFO can receive.
         */
        while((DSPI_HAL_GetStatusFlag(base, kDspiTxFifoFillRequest) == 1) &&
              ((remainingReceiveByteCount - remainingSendByteCount) <
                g_dspiFifoSize[instance]))
        {
            /* On the last word to be sent, set the end of queue flag in the data command struct
             * and ensure that the CONT bit in the PUSHR is also cleared even if it was cleared to
             * begin with. If CONT is set it means continuous chip select operation and to ensure
             * the chip select is de-asserted, this bit must be cleared on the last data word.
             */
            if (dspiState->remainingSendByteCount == 1)
            {
                command.isEndOfQueue = 1;
                command.isChipSelectContinuous = 0;
                cmd = DSPI_HAL_GetFormattedCommand(base, &command);
            }

            /* If a send buffer was provided, the word comes from there. Otherwise we just send
             * a zero (initialized above).
             */
            if (dspiState->sendBuffer)
            {
                wordToSend = *(dspiState->sendBuffer);
                ++dspiState->sendBuffer; /* increment to next data word*/
            }
            DSPI_HAL_WriteCmdDataMastermode(base, cmd|wordToSend);

            /* Try to clear the TFFF; if the TX FIFO is full this will clear */
            DSPI_HAL_ClearStatusFlag(base, kDspiTxFifoFillRequest);

            --dspiState->remainingSendByteCount; /* decrement remainingSendByteCount*/

            /* exit loop if send count is zero, else update local variables for next loop */
            if (dspiState->remainingSendByteCount == 0)
            {
                break;
            }
            else
            {
                /* Store the DSPI state struct volatile member variables into temporary
                 * non-volatile variables to allow for MISRA compliant calculations
                 */
                remainingSendByteCount = dspiState->remainingSendByteCount;
            }
        } /* End of TX FIFO fill while loop */
    }
}
uint16_t SpiInOut(Spi_t *obj, uint16_t outData)
{
    uint16_t data = 0x00;

    if ((obj == NULL) || (obj->Spi) == NULL) {
        while (1)
            ;
    }

    if (obj->isSlave) {

    } else {
        dspi_command_config_t
        commandConfig =
        {
            .isChipSelectContinuous = false,
            .whichCtar = kDspiCtar0,
            .whichPcs = kDspiPcs0,
            .clearTransferCount = true,
            .isEndOfQueue = false
        };
        if (outData != 0x00) {
            // Restart the transfer by stop then start again, this will clear out the shift register
            DSPI_HAL_StopTransfer(obj->Spi);
            // Flush the FIFOs
            DSPI_HAL_SetFlushFifoCmd(obj->Spi, true, true);
            // Clear status flags that may have been set from previous transfers.
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxComplete);
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiEndOfQueue);
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxFifoUnderflow);
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxFifoFillRequest);
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiRxFifoOverflow);
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiRxFifoDrainRequest);
            // Clear the transfer count.
            DSPI_HAL_PresetTransferCount(obj->Spi, 0);
            // Start the transfer process in the hardware
            DSPI_HAL_StartTransfer(obj->Spi);
            // Send the data to slave.
            // Write data to PUSHR
            DSPI_HAL_WriteDataMastermode(obj->Spi, &commandConfig, outData);
        } else {
            // Restart the transfer by stop then start again, this will clear out the shift register
            DSPI_HAL_StopTransfer(obj->Spi);
            // Flush the FIFOs
            DSPI_HAL_SetFlushFifoCmd(obj->Spi, true, true);
            //Clear status flags that may have been set from previous transfers.
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxComplete);
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiEndOfQueue);
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxFifoUnderflow);
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiTxFifoFillRequest);
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiRxFifoOverflow);
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiRxFifoDrainRequest);
            // Clear the transfer count.
            DSPI_HAL_PresetTransferCount(obj->Spi, 0);
            // Start the transfer process in the hardware
            DSPI_HAL_StartTransfer(obj->Spi);
            // Write command to PUSHR.
            DSPI_HAL_WriteDataMastermode(obj->Spi, &commandConfig, 0);
            // Check RFDR flag
            while (DSPI_HAL_GetStatusFlag(obj->Spi, kDspiRxFifoDrainRequest) == false) {
            }
            // Read data from POPR
            data = DSPI_HAL_ReadData(obj->Spi);
            // Clear RFDR flag
            DSPI_HAL_ClearStatusFlag(obj->Spi, kDspiRxFifoDrainRequest);
        }
    }
    return data;
}
Beispiel #3
0
/*!
 * @brief Initiate (start) a transfer. This is not a public API as it is called from other
 *  driver functions
 */
static dspi_status_t DSPI_DRV_MasterStartTransfer(uint32_t instance,
                                                  const dspi_device_t * device)
{
    /* instantiate local variable of type dspi_master_state_t and point to global state */
    dspi_master_state_t * dspiState = (dspi_master_state_t *)g_dspiStatePtr[instance];
    SPI_Type *base = g_dspiBase[instance];
    uint32_t calculatedBaudRate;

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

    /* Configure bus for this device. If NULL is passed, we assume the caller has
     * preconfigured the bus using DSPI_DRV_MasterConfigureBus().
     * Do nothing for calculatedBaudRate. If the user wants to know the calculatedBaudRate
     * then they can call this function separately.
     */
    if (device)
    {
        DSPI_DRV_MasterConfigureBus(instance, device, &calculatedBaudRate);
        dspiState->bitsPerFrame = device->dataBusConfig.bitsPerFrame;/*update dspiState bits/frame*/
    }

    /* 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 increase the transfer byte count
     * by one and assert a flag to indicate to the send and receive functions that it will
     * need to handle an extra byte.
     */
    if ((dspiState->bitsPerFrame > 8) && (dspiState->remainingSendByteCount & 1UL))
    {
        dspiState->remainingSendByteCount += 1;
        dspiState->remainingReceiveByteCount += 1;
        dspiState->extraByte = true;
    }
    else
    {
        dspiState->extraByte = false;
    }


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

    /* Restart the transfer by stop then start again, this will clear out the shift register */
    DSPI_HAL_StopTransfer(base);

    /* flush the fifos*/
    DSPI_HAL_SetFlushFifoCmd(base, true, true);

    /* Clear status flags that may have been set from previous transfers */
    DSPI_HAL_ClearStatusFlag(base, kDspiTxComplete);
    DSPI_HAL_ClearStatusFlag(base, kDspiEndOfQueue);
    DSPI_HAL_ClearStatusFlag(base, kDspiTxFifoUnderflow);
    DSPI_HAL_ClearStatusFlag(base, kDspiTxFifoFillRequest);
    DSPI_HAL_ClearStatusFlag(base, kDspiRxFifoOverflow);
    DSPI_HAL_ClearStatusFlag(base, kDspiRxFifoDrainRequest);

    /* Clear the transfer count */
    DSPI_HAL_PresetTransferCount(base, 0);

    /* Start the transfer, make sure to do this before filling the FIFO */
    DSPI_HAL_StartTransfer(base);

    /* Fill up the DSPI FIFO (even if one word deep, data still written to data buffer) */
    DSPI_DRV_MasterFillupTxFifo(instance);

    /* RX FIFO Drain request: RFDF_RE to enable RFDF interrupt
     * Since SPI is a synchronous interface, we only need to enable the RX interrupt.
     * The IRQ handler will get the status of RX and TX interrupt flags.
     */
    DSPI_HAL_SetRxFifoDrainDmaIntMode(base, kDspiGenerateIntReq, true);

    return kStatus_DSPI_Success;
}
Beispiel #4
0
/*FUNCTION**********************************************************************
 *
 * Function Name : DSPI_DRV_SlaveIRQHandler
 * Description   : DSPI Slave Generic IRQ handler.
 *
 * This handler check errors of driver and it puts data into Tx FIFO, gets data
 * from Rx FIFO whenever data transmitting/received.
 *
 *END**************************************************************************/
void DSPI_DRV_SlaveIRQHandler(uint32_t instance)
{
    SPI_Type *base = g_dspiBase[instance];
    dspi_slave_state_t *dspiState = (dspi_slave_state_t *)g_dspiStatePtr[instance];
    uint8_t nBytes;

    /* Calculate number of bytes in a frame */
    nBytes = dspiState->bitsPerFrame >> 3;      /* Number of bytes is bits/frame divide 8 */
    if ((dspiState->bitsPerFrame & 0x07) != 0)  /* Bits/frame module 8 is not zero */
    {
        nBytes += 1;
    }

    /* Because SPI protocol is synchronous, the number of bytes that that slave received from the
     * master is the actual number of bytes that the slave transmitted to the master. So we only
     * monitor the received size to know when the transfer is complete.
     */
    if (dspiState->remainingReceiveByteCount > 0)
    {
        /* Read data if remaining receive byte > 0 */
        uint32_t dataReceived;
        uint32_t dataSend = 0;

        while (DSPI_HAL_GetStatusFlag(base, kDspiRxFifoDrainRequest))
        {
            /* Have received data in the buffer. */
            dataReceived = DSPI_HAL_ReadData(base);
            /* clear the rx fifo drain request, needed for non-DMA applications as this flag
             * will remain set even if the rx fifo is empty. By manually clearing this flag, it
             * either remain clear if no more data is in the fifo, or it will set if there is
             * more data in the fifo.
             */
            DSPI_HAL_ClearStatusFlag(base, kDspiRxFifoDrainRequest);

            /* If bits/frame is one byte */
            if (nBytes == 1)
            {
                if (dspiState->receiveBuffer)
                {
                    /* Receive buffer is not null, store data into it */
                    *dspiState->receiveBuffer = dataReceived;
                    ++dspiState->receiveBuffer;
                }
                if (dspiState->sendBuffer)
                {
                    dataSend = *dspiState->sendBuffer;
                    ++dspiState->sendBuffer;
                }

                /* Descrease remaining receive byte count */
                --dspiState->remainingReceiveByteCount;
                --dspiState->remainingSendByteCount;
            }
            /* If bits/frame is 2 bytes */
            else
            {
                /* With multibytes frame receiving, we only receive till the received size
                 * matches user request. Other bytes will be ignored.
                 */
                if (dspiState->receiveBuffer)
                {
                    /* Receive buffer is not null, store first byte into it */
                    *dspiState->receiveBuffer = dataReceived;
                    ++dspiState->receiveBuffer;

                    if (--dspiState->remainingReceiveByteCount > 0)
                    {
                        /* Receive buffer is not null, store second byte into it */
                        *dspiState->receiveBuffer = dataReceived >> 8;
                        ++dspiState->receiveBuffer;
                    }

                    /* Decrease remaining receive byte count */
                    --dspiState->remainingReceiveByteCount;
                }
                else
                {