/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaSlaveIRQHandler
 * Description   : Interrupt handler for SPI master mode.
 * This handler is used when the hasExtraByte flag is set to retrieve the received last byte.
 *
 *END**************************************************************************/
void SPI_DRV_DmaSlaveIRQHandler(uint32_t instance)
{
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
    /* instantiate local variable of type spi_master_state_t and point to global state */
    spi_dma_slave_state_t * spiDmaState = (spi_dma_slave_state_t *)g_spiStatePtr[instance];

    SPI_Type *base = g_spiBase[instance];

    /* If the SPI module contains a FIFO (and if it is enabled), check the FIFO empty flag */
    if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base)))
    {
        if (SPI_HAL_GetFifoStatusFlag(base, kSpiRxFifoEmpty) == 0)
        {
            /* If there is a receive buffer, copy the final byte from the SPI data register
             *  to the receive buffer
             */
            if (spiDmaState->receiveBuffer)
            {
                spiDmaState->receiveBuffer[spiDmaState->remainingReceiveByteCount] =
                                                              SPI_HAL_ReadDataLow(base);
            }
            /* Else, read out the data register and throw away the bytes read */
            else
            {
                /* Read and throw away the lower data buffer to clear it out */
                s_rxBuffIfNull = SPI_HAL_ReadDataLow(base);
            }
            /* Read and throw away the upper data buffer to clear it out */
            s_rxBuffIfNull = SPI_HAL_ReadDataHigh(base);

            SPI_DRV_DmaSlaveCompleteTransfer(instance);
        }
    }
    else /* Check the read pending flag */
    {
        if (SPI_HAL_IsReadBuffFullPending(base) == 1)
        {
            /* If there is a receive buffer, copy the final byte from the SPI data register
             *  to the receive buffer
             */
            if (spiDmaState->receiveBuffer)
            {
                spiDmaState->receiveBuffer[spiDmaState->remainingReceiveByteCount] =
                                                              SPI_HAL_ReadDataLow(base);
            }
            /* Else, read out the data register and throw away the bytes read */
            else
            {
                /* Read and throw away the lower data buffer to clear it out */
                s_rxBuffIfNull = SPI_HAL_ReadDataLow(base);
            }
            /* Read and throw away the upper data buffer to clear it out */
            s_rxBuffIfNull = SPI_HAL_ReadDataHigh(base);
            SPI_DRV_DmaSlaveCompleteTransfer(instance);
        }
    }
#endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */
}
/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaMasterCallback
 * Description   : This function is called when the DMA generates an interrupt.
 * The DMA generates an interrupt when the channel is "done", meaning that the
 * expected number of bytes have been transferred.  When the interrupt occurs,
 * the DMA will jump to this callback as it was registered in the DMA register
 * callback service function.  The user will defined their own callback function
 * to take whatever action they deem necessary for handling the end of a transfer.
 * For example, the user may simply want their callback function to set a global
 * flag to indicate that the transfer is complete.  The user defined callback
 * is passed in through the "param" parameter.
 * The parameter chanStatus is currently not used.
 *
 *END**************************************************************************/
void SPI_DRV_DmaMasterCallback(void *param, dma_channel_status_t chanStatus)
{
    uint32_t instance = (uint32_t)(param);

    /* instantiate local variable of type spi_master_state_t and point to global state */
    spi_dma_master_state_t * spiDmaState = (spi_dma_master_state_t *)g_spiStatePtr[instance];

    SPI_Type *base = g_spiBase[instance];

    /* If the extraByte flag was set, need to enable the TX empty interrupt to get the last byte */
    if (spiDmaState->extraByte)
    {
        SPI_HAL_SetTxDmaCmd(base, false);

        /* If the TX buffer is already empty then it may not generate an interrupt so soon
         * after the TX DMA is disabled, therefore read the RX data and put into RX buffer.
         */
        if (SPI_HAL_GetIntStatusFlag(base, kSpiTxBufferEmptyFlag))
        {
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
            /* If the SPI module contains a FIFO (and if it is enabled), check the FIFO empty flag */
            if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base)))
            {
                /* Wait till the rx buffer has data */
                while (SPI_HAL_GetFifoStatusFlag(base, kSpiRxFifoEmpty) == 1) {}

            }
            else /* Check the read pending flag */
            {
                /* Wait till the rx buffer has data */
                while (SPI_HAL_IsReadBuffFullPending(base) == 0) {}
            }

            /* If there is a receive buffer, copy the final byte from the SPI data register
             *  to the receive buffer
             */
            if (spiDmaState->receiveBuffer)
            {
                spiDmaState->receiveBuffer[spiDmaState->transferByteCnt-2] =
                                                              SPI_HAL_ReadDataLow(base);
            }
            /* Else, read out the data register and throw away the bytes read */
            else
            {
                /* Read and throw away the lower data buffer to clear it out */
                s_rxBuffIfNull = SPI_HAL_ReadDataLow(base);
            }
            /* Read and throw away the upper data buffer to clear it out */
            s_rxBuffIfNull = SPI_HAL_ReadDataHigh(base);
            SPI_DRV_DmaMasterCompleteTransfer(instance);
#endif
        }
        else
        {
            /* Else, if the TX buffer is not empty, enable the interrupt and handle the
             * receive in the ISR
             */
            SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, true);
        }
    }
    else /* If no extra byte is needing to be receive, complete the transfer */
    {
        SPI_DRV_DmaMasterCompleteTransfer(instance);
    }
}
Exemplo n.º 3
0
/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_MasterIRQHandler
 * Description   : Interrupt handler for SPI master mode.
 * This handler uses the buffers stored in the spi_master_state_t structs to transfer data.
 *
 *END**************************************************************************/
void SPI_DRV_MasterIRQHandler(uint32_t instance)
{
    /* instantiate local variable of type spi_master_state_t and point to global state */
    spi_master_state_t * spiState = (spi_master_state_t *)g_spiStatePtr[instance];

    SPI_Type *base = g_spiBase[instance];

    /* Exit the ISR if no transfer is happening for this instance.*/
    if (!spiState->isTransferInProgress)
    {
        return;
    }

    /* RECEIVE IRQ handler: Check read buffer only if there are remaining bytes to read. */
    if (spiState->remainingReceiveByteCount)
    {
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
        uint8_t byteReceivedLow, byteReceivedHigh;

        spi_data_bitcount_mode_t bitCntRx = SPI_HAL_Get8or16BitMode(base);

        /* If the SPI module contains a FIFO (and if it's enabled), drain the FIFO until it is empty
         * or until the remainingSendByteCount reaches 0.
         */
        if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base)))
        {
            /* Clear the RX near full interrupt */
            SPI_HAL_ClearFifoIntUsingBitWrite(base, kSpiRxNearFullClearInt);

            /* Architectural note: When developing the RX FIFO drain code, 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 drain process with continual checks of the bits/frame setting.
             */

            /* Optimized for bit count = 16 with FIFO support */
            if (bitCntRx == kSpi16BitMode)
            {
                /* Do this while the RX FIFO is not empty */
                while (SPI_HAL_GetFifoStatusFlag(base, kSpiRxFifoEmpty) == 0)
                {
                    /* Read the bytes from the RX FIFO */
                    byteReceivedLow = SPI_HAL_ReadDataLow(base);
                    byteReceivedHigh = SPI_HAL_ReadDataHigh(base);

                    /* Store read bytes into rx buffer only if a buffer pointer was provided */
                    if (spiState->receiveBuffer)
                    {
                        *spiState->receiveBuffer = byteReceivedLow;
                        ++spiState->receiveBuffer;

                        /* If the extraByte flag is set and these are the last 2 bytes, then skip.
                         * This will avoid over-writing the rx buffer with another un-needed byte.
                         */
                        if (!((spiState->extraByte) && (spiState->remainingReceiveByteCount == 2)))
                        {
                            *spiState->receiveBuffer = byteReceivedHigh;
                            ++spiState->receiveBuffer;
                        }
                    }

                    spiState->remainingReceiveByteCount -= 2; /* decrement the rx byte count by 2 */

                    /* If there is no more data to receive, break */
                    if (spiState->remainingReceiveByteCount == 0)
                    {
                        break;
                    }
                }
            }

            /* Optimized for bit count = 8 with FIFO support */
            else
            {
                while (SPI_HAL_GetFifoStatusFlag(base, kSpiRxFifoEmpty) == 0)
                {
                    /* Read the bytes from the RX FIFO */
                    byteReceivedLow = SPI_HAL_ReadDataLow(base);

                    /* Store read bytes into rx buffer only if a buffer pointer was provided */
                    if (spiState->receiveBuffer)
                    {
                        *spiState->receiveBuffer = byteReceivedLow;
                        ++spiState->receiveBuffer;
                    }

                    --spiState->remainingReceiveByteCount; /* decrement the rx byte count by 1 */

                    /* If there is no more data to receive, break */
                    if (spiState->remainingReceiveByteCount == 0)
                    {
                        break;
                    }
                }
            }

            /* If the remaining RX byte count is less than the RX FIFO watermark, enable
             * the TX FIFO empty interrupt. Once the TX FIFO is empty, we are ensured
             * that the transmission is complete and can then drain the RX FIFO.
             */
            if (spiState->remainingReceiveByteCount < g_spiFifoSize[instance])
            {
                SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, true); /* TX FIFO empty interrupt */
            }
        }

        /* For SPI modules that do not have a FIFO (or if disabled), but have 16-bit transfer
         * capability */
        else
        {
            if (SPI_HAL_IsReadBuffFullPending(base))
            {

                /* For 16-bit transfers w/o FIFO support */
                if (bitCntRx == kSpi16BitMode)
                {
                    /* Read the bytes from the RX FIFO */
                    byteReceivedLow = SPI_HAL_ReadDataLow(base);
                    byteReceivedHigh = SPI_HAL_ReadDataHigh(base);

                    /* Store read bytes into rx buffer only if a buffer pointer was provided */
                    if (spiState->receiveBuffer)
                    {
                        *spiState->receiveBuffer = byteReceivedLow;
                        ++spiState->receiveBuffer;

                        /* If the extraByte flag is set and these are the last 2 bytes, then skip.
                         * This will avoid over-writing the rx buffer with another un-needed byte.
                         */
                        if (!((spiState->extraByte) && (spiState->remainingReceiveByteCount == 2)))
                        {
                            *spiState->receiveBuffer = byteReceivedHigh;
                            ++spiState->receiveBuffer;
                        }
                    }

                    spiState->remainingReceiveByteCount -= 2; /* decrement the rx byte count by 2 */

                }

                /* For 8-bit transfers w/o FIFO support */
                else
                {
                    /* Read the bytes from the RX FIFO */
                    byteReceivedLow = SPI_HAL_ReadDataLow(base);

                    /* Store read bytes into rx buffer only if a buffer pointer was provided */
                    if (spiState->receiveBuffer)
                    {
                        *spiState->receiveBuffer = byteReceivedLow;
                        ++spiState->receiveBuffer;
                    }

                    --spiState->remainingReceiveByteCount; /* decrement the rx byte count by 1 */
                }
            }
        }

#else /* For SPI modules that do not support 16-bit transfers and don't have FIFO */

        uint8_t byteReceived;
        /* For SPI modules without 16-bit transfer capability or FIFO support */
        if (SPI_HAL_IsReadBuffFullPending(base))
        {
            /* Read the bytes from the RX FIFO */
            byteReceived = SPI_HAL_ReadData(base);

            /* Store read bytes into rx buffer only if a buffer pointer was provided */
            if (spiState->receiveBuffer)
            {
                *spiState->receiveBuffer = byteReceived;
                ++spiState->receiveBuffer;
            }

            --spiState->remainingReceiveByteCount; /* decrement the rx byte count by 1 */
        }
#endif  /* FSL_FEATURE_SPI_16BIT_TRANSFERS */
    }

    /* TRANSMIT IRQ handler
     * Check write buffer. We always have to send a byte in order to keep the transfer
     * moving. So if the caller didn't provide a send buffer, we just send a zero byte.
     */
    uint8_t byteToSend = 0;
    if (spiState->remainingSendByteCount)
    {
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
        uint8_t byteToSendLow = 0;
        uint8_t byteToSendHigh = 0;

        spi_data_bitcount_mode_t bitCntTx = SPI_HAL_Get8or16BitMode(base);

        /* If SPI module has a FIFO and if it is enabled */
        if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base)))
        {
            if (SPI_HAL_GetFifoStatusFlag(base, kSpiTxNearEmpty))
            {
                /* Fill of the TX FIFO with ongoing data */
                SPI_DRV_MasterFillupTxFifo(instance);
             }
        }
        else
        {
            if (SPI_HAL_IsTxBuffEmptyPending(base))
            {
                if (bitCntTx == kSpi16BitMode)
                {
                    if (spiState->sendBuffer)
                    {
                        byteToSendLow = *(spiState->sendBuffer);
                        ++spiState->sendBuffer;

                        byteToSendHigh = *(spiState->sendBuffer);
                        ++spiState->sendBuffer;
                    }
                    SPI_HAL_WriteDataLow(base, byteToSendLow);
                    SPI_HAL_WriteDataHigh(base, byteToSendHigh);

                    spiState->remainingSendByteCount -= 2;  /* decrement by 2 */
                    spiState->transferredByteCount += 2;  /* increment by 2 */
                }
                else /* SPI configured for 8-bit transfers */
                {
                    if (spiState->sendBuffer)
                    {
                        byteToSend = *(spiState->sendBuffer);
                        ++spiState->sendBuffer;
                    }
                    SPI_HAL_WriteDataLow(base, byteToSend);

                    --spiState->remainingSendByteCount;
                    ++spiState->transferredByteCount;
                }
            }
        }
#else /* For SPI modules that do not support 16-bit transfers */
        if (SPI_HAL_IsTxBuffEmptyPending(base))
        {
            if (spiState->sendBuffer)
            {
                byteToSend = *(spiState->sendBuffer);
                ++spiState->sendBuffer;
            }
            SPI_HAL_WriteData(base, byteToSend);

            --spiState->remainingSendByteCount;
            ++spiState->transferredByteCount;
        }
#endif  /* FSL_FEATURE_SPI_16BIT_TRANSFERS */
    }

    /* Check if we're done with this transfer.  The transfer is complete when all of the
     * expected data is received.
     */
    if ((spiState->remainingSendByteCount == 0) && (spiState->remainingReceiveByteCount == 0))
    {
        /* Complete the transfer. This disables the interrupts, so we don't wind up in
         * the ISR again.
         */
        SPI_DRV_MasterCompleteTransfer(instance);
    }
}