예제 #1
0
/*FUNCTION**********************************************************************
 *
 * Function Name : DSPI_DRV_DmaTxCallback
 * Description   : Callback function, this called when DMA transmitting data
 * completed
 *
 *END**************************************************************************/
static void DSPI_DRV_DmaTxCallback(void *param, dma_channel_status_t status)
{
    uint32_t instance = (uint32_t)param;
    SPI_Type *base = g_dspiBase[instance];
    dspi_dma_master_state_t * dspiDmaState = (dspi_dma_master_state_t *)g_dspiStatePtr[instance];
    uint32_t dmaChannel;
    DMAMUX_Type *dmamuxbase;

    dmaChannel = dspiDmaState->dmaTxDataChannel.channel;
    dmamuxbase = g_dmamuxBase[dmaChannel/FSL_FEATURE_DMAMUX_MODULE_CHANNEL];
    // DMA_DRV_ClearStatus(&dspiDmaState->dmaTxDataChannel);
    DMAMUX_HAL_SetChannelCmd(dmamuxbase, dmaChannel, false);
    DMAMUX_HAL_SetChannelCmd(dmamuxbase, dmaChannel, true);

    /* Stop DMA Tx channel */
    DMA_DRV_StopChannel(&dspiDmaState->dmaTxDataChannel);

    /* Setup DMA to transmit the last frame */
    /* Have one more byte, config DMA Rx channel to receive this byte */
    DMA_DRV_ConfigTransfer(&dspiDmaState->dmaTxDataChannel,
                           kDmaPeripheralToPeripheral,
                           4u, (uint32_t)(&s_lastCmdData), /* src is data register */
                           DSPI_HAL_GetMasterPushrRegAddr(base), /* dest is temporary location */
                           4u);

    /* Register callback */
    DMA_DRV_RegisterCallback(&dspiDmaState->dmaTxDataChannel, DSPI_DRV_DmaTxLastCallback, (void *)instance);

    /* Enable the DMA peripheral request */
    DMA_DRV_StartChannel(&dspiDmaState->dmaTxDataChannel);
}
예제 #2
0
/*FUNCTION**********************************************************************
 *
 * Function Name : DSPI_DRV_DmaRxCallback
 * Description   : Callback function, this called when DMA receiving data
 * completed
 *
 *END**************************************************************************/
static void DSPI_DRV_DmaRxCallback(void *param, dma_channel_status_t status)
{
    uint32_t instance = (uint32_t)param;
    SPI_Type *base = g_dspiBase[instance];
    dspi_dma_master_state_t * dspiDmaState = (dspi_dma_master_state_t *)g_dspiStatePtr[instance];

    /* Stop DMA Rx channel */
    DMA_DRV_StopChannel(&dspiDmaState->dmaRxChannel);

    if (dspiDmaState->extraByte != 0)
    {
        /* Have one more byte, config DMA Rx channel to receive this byte */
        DMA_DRV_ConfigTransfer(&dspiDmaState->dmaRxChannel,
                               kDmaPeripheralToPeripheral,
                               1u, DSPI_HAL_GetPoprRegAddr(base), /* src is data register */
                               (uint32_t)(&s_rxBuffIfNull), /* dest is temporary location */
                               (uint32_t)(1u));

        /* Register callback */
        DMA_DRV_RegisterCallback(&dspiDmaState->dmaRxChannel, DSPI_DRV_DmaRxCallback, (void *)instance);

        /* Enable the DMA peripheral request */
        DMA_DRV_StartChannel(&dspiDmaState->dmaRxChannel);

        if (dspiDmaState->rxBuffer)
        {
            /* Update the receive pointer to extra byte */
            dspiDmaState->rxBuffer = dspiDmaState->rxBuffer + dspiDmaState->rxTransferByteCnt;
        }
        dspiDmaState->rxTransferByteCnt = 0;
        dspiDmaState->extraByte = false;

        return;
    }

    /* If transmission completed, stop the transferring */
    if ((dspiDmaState->isTransferInProgress) &&
            (dspiDmaState->rxTransferByteCnt == 0))
    {
        /* Extra byte completed */
        if (dspiDmaState->rxBuffer)
        {
            /* Store the extra byte */
            *dspiDmaState->rxBuffer = (uint8_t)s_rxBuffIfNull;
        }
        /* Stop DMA Rx channel */
        DMA_DRV_StopChannel(&dspiDmaState->dmaRxChannel);

        DSPI_DRV_DmaMasterCompleteTransfer(instance);
    }
    else
    {
        /* Stop DMA Rx channel */
        DMA_DRV_StopChannel(&dspiDmaState->dmaRxChannel);

        DSPI_DRV_DmaMasterCompleteTransfer(instance);
    }
}
예제 #3
0
/*FUNCTION**********************************************************************
 *
 * Function Name : LPSCI_DRV_DmaInit
 * Description   : This function initializes a LPSCI instance for operation.
 * This function will initialize the run-time state structure to keep track of
 * the on-going transfers, ungate the clock to the LPSCI module, initialize the
 * module to user defined settings and default settings, configure LPSCI DMA
 * and enable the LPSCI module transmitter and receiver.
 * The following is an example of how to set up the lpsci_dma_state_t and the
 * lpsci_user_config_t parameters and how to call the LPSCI_DRV_DmaInit function
 * by passing in these parameters:
 *    lpsci_user_config_t lpsciConfig;
 *    lpsciConfig.baudRate = 9600;
 *    lpsciConfig.bitCountPerChar = kLpsci8BitsPerChar;
 *    lpsciConfig.parityMode = kLpsciParityDisabled;
 *    lpsciConfig.stopBitCount = kLpsciOneStopBit;
 *    lpsci_dma_state_t lpsciDmaState;
 *    LPSCI_DRV_DmaInit(instance, &lpsciDmaState, &lpsciConfig);
 *
 *END**************************************************************************/
lpsci_status_t LPSCI_DRV_DmaInit(uint32_t instance,
                               lpsci_dma_state_t * lpsciDmaStatePtr,
                               const lpsci_dma_user_config_t * lpsciUserConfig)
{
    assert(lpsciDmaStatePtr && lpsciUserConfig);
    assert(instance < UART0_INSTANCE_COUNT);

    UART0_Type * base = g_lpsciBase[instance];
    uint32_t lpsciSourceClock = 0;
    dma_request_source_t lpsciTxDmaRequest = kDmaRequestMux0Disable;
    dma_request_source_t lpsciRxDmaRequest = kDmaRequestMux0Disable;
    dma_channel_t *chn;
    DMA_Type * dmaBase;
    dma_channel_link_config_t config;

    config.channel1 = 0;
    config.channel2 = 0;
    config.linkType = kDmaChannelLinkDisable;

    /* Exit if current instance is already initialized. */
    if (g_lpsciStatePtr[instance])
    {
        return kStatus_LPSCI_Initialized;
    }

    /* Clear the state structure for this instance. */
    memset(lpsciDmaStatePtr, 0, sizeof(lpsci_dma_state_t));

    /* Save runtime structure pointer.*/
    g_lpsciStatePtr[instance] = lpsciDmaStatePtr;

    /* Un-gate LPSCI module clock */
    CLOCK_SYS_EnableLpsciClock(instance);

    /* Set LPSCI clock source */
    CLOCK_SYS_SetLpsciSrc(instance, lpsciUserConfig->clockSource);

    /* Initialize LPSCI to a known state. */
    LPSCI_HAL_Init(base);

    /* Create Semaphore for txIrq and rxIrq. */
    OSA_SemaCreate(&lpsciDmaStatePtr->txIrqSync, 0);
    OSA_SemaCreate(&lpsciDmaStatePtr->rxIrqSync, 0);

    /* LPSCI clock source is either system or bus clock depending on instance */
    lpsciSourceClock = CLOCK_SYS_GetLpsciFreq(instance);

    /* Initialize LPSCI baud rate, bit count, parity and stop bit. */
    LPSCI_HAL_SetBaudRate(base, lpsciSourceClock, lpsciUserConfig->baudRate);
    LPSCI_HAL_SetBitCountPerChar(base, lpsciUserConfig->bitCountPerChar);
    LPSCI_HAL_SetParityMode(base, lpsciUserConfig->parityMode);
#if FSL_FEATURE_LPSCI_HAS_STOP_BIT_CONFIG_SUPPORT
    LPSCI_HAL_SetStopBitCount(base, lpsciUserConfig->stopBitCount);
#endif

    /* Enable DMA trigger when transmit data register empty,
     * and receive data register full. */
    LPSCI_HAL_SetTxDmaCmd(base, true);
    LPSCI_HAL_SetRxDmaCmd(base, true);

    switch (instance)
    {
        case 0:
            lpsciRxDmaRequest = kDmaRequestMux0LPSCI0Rx;
            lpsciTxDmaRequest = kDmaRequestMux0LPSCI0Tx;
            break;
        default :
            break;
    }

    /* Request DMA channels for RX FIFO. */
    DMA_DRV_RequestChannel(kDmaAnyChannel, lpsciRxDmaRequest,
                            &lpsciDmaStatePtr->dmaLpsciRx);
    DMA_DRV_RegisterCallback(&lpsciDmaStatePtr->dmaLpsciRx,
                    LPSCI_DRV_DmaRxCallback, (void *)instance);

    chn = &lpsciDmaStatePtr->dmaLpsciRx;
    dmaBase = g_dmaBase[chn->channel/FSL_FEATURE_DMA_DMAMUX_CHANNELS];

    DMA_HAL_SetAutoAlignCmd(dmaBase, chn->channel, false);
    DMA_HAL_SetCycleStealCmd(dmaBase, chn->channel, true);
    DMA_HAL_SetAsyncDmaRequestCmd(dmaBase, chn->channel, false);
    DMA_HAL_SetDisableRequestAfterDoneCmd(dmaBase, chn->channel, true);
    DMA_HAL_SetChanLink(dmaBase, chn->channel, &config);

    DMA_HAL_SetSourceAddr(dmaBase, chn->channel, LPSCI_HAL_GetDataRegAddr(base));
    DMA_HAL_SetSourceModulo(dmaBase, chn->channel, kDmaModuloDisable);
    DMA_HAL_SetSourceTransferSize(dmaBase, chn->channel, kDmaTransfersize8bits);
    DMA_HAL_SetSourceIncrementCmd(dmaBase, chn->channel, false);

    DMA_HAL_SetDestModulo(dmaBase, chn->channel, kDmaModuloDisable);
    DMA_HAL_SetDestTransferSize(dmaBase, chn->channel, kDmaTransfersize8bits);
    DMA_HAL_SetDestIncrementCmd(dmaBase, chn->channel, true);

    DMA_HAL_SetIntCmd(dmaBase, chn->channel, true);

    /* Request DMA channels for TX FIFO. */
    DMA_DRV_RequestChannel(kDmaAnyChannel, lpsciTxDmaRequest,
                            &lpsciDmaStatePtr->dmaLpsciTx);
    DMA_DRV_RegisterCallback(&lpsciDmaStatePtr->dmaLpsciTx,
                    LPSCI_DRV_DmaTxCallback, (void *)instance);

    chn = &lpsciDmaStatePtr->dmaLpsciTx;
    dmaBase = g_dmaBase[chn->channel/FSL_FEATURE_DMA_DMAMUX_CHANNELS];

    DMA_HAL_SetAutoAlignCmd(dmaBase, chn->channel, false);
    DMA_HAL_SetCycleStealCmd(dmaBase, chn->channel, true);
    DMA_HAL_SetAsyncDmaRequestCmd(dmaBase, chn->channel, false);
    DMA_HAL_SetDisableRequestAfterDoneCmd(dmaBase, chn->channel, true);
    DMA_HAL_SetChanLink(dmaBase, chn->channel, &config);

    DMA_HAL_SetSourceModulo(dmaBase, chn->channel, kDmaModuloDisable);
    DMA_HAL_SetSourceTransferSize(dmaBase, chn->channel, kDmaTransfersize8bits);
    DMA_HAL_SetSourceIncrementCmd(dmaBase, chn->channel, true);

    DMA_HAL_SetDestAddr(dmaBase, chn->channel, LPSCI_HAL_GetDataRegAddr(base));
    DMA_HAL_SetDestModulo(dmaBase, chn->channel, kDmaModuloDisable);
    DMA_HAL_SetDestTransferSize(dmaBase, chn->channel, kDmaTransfersize8bits);
    DMA_HAL_SetDestIncrementCmd(dmaBase, chn->channel, false);

    DMA_HAL_SetIntCmd(dmaBase, chn->channel, true);

    /* Finally, enable the LPSCI transmitter and receiver*/
    LPSCI_HAL_EnableTransmitter(base);
    LPSCI_HAL_EnableReceiver(base);

    return kStatus_LPSCI_Success;
}
예제 #4
0
/*!
 * @brief Initiate (start) a transfer using DMA. This is not a public API as it is called from
 *  other driver functions
 */
static dspi_status_t DSPI_DRV_DmaMasterStartTransfer(uint32_t instance,
        const dspi_dma_device_t * device,
        const uint8_t * sendBuffer,
        uint8_t * receiveBuffer,
        size_t transferByteCount)
{
    /* instantiate local variable of type dspi_dma_master_state_t and point to global state */
    dspi_dma_master_state_t * dspiDmaState = (dspi_dma_master_state_t *)g_dspiStatePtr[instance];
    /* For temporarily storing DMA instance and channel */
    uint8_t transferSizeInBytes = 1U;

    uint32_t calculatedBaudRate;
    dspi_command_config_t command;  /* create an instance of the data command struct*/
    SPI_Type *base = g_dspiBase[instance];
    uint32_t txTransferByteCnt = 0;
    uint32_t rxTransferByteCnt = 0;

    /* Initialize s_wordToSend */
    s_wordToSend = 0;

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

    /* Calculate the transfer size on bits/frame */
    if (dspiDmaState->bitsPerFrame <= 8)
    {
        transferSizeInBytes = 1U;
    }
    else if (dspiDmaState->bitsPerFrame <= 16)
    {
        transferSizeInBytes = 2U;
    }
    else
    {
        transferSizeInBytes = 4U;
    }

    /* Configure bus for this device. If NULL is passed, we assume the caller has
     * preconfigured the bus using DSPI_DRV_DmaMasterConfigureBus().
     * Do nothing for calculatedBaudRate. If the user wants to know the calculatedBaudRate
     * then they can call this function separately.
     */
    if (device)
    {
        DSPI_DRV_DmaMasterConfigureBus(instance, device, &calculatedBaudRate);
        dspiDmaState->bitsPerFrame = device->dataBusConfig.bitsPerFrame; /*update 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 TX transfer byte count
     * by one and assert a flag to indicate to the send functions that it will
     * need to handle an extra byte.
     * For receive, we actually round down the transfer count to the next lowest even number.
     * Then in the interrupt handler, we take care of geting this last byte.
     */
    if ((dspiDmaState->bitsPerFrame > 8) && (transferByteCount & 1UL))
    {
        dspiDmaState->extraByte = true;
        txTransferByteCnt = transferByteCount + 1U;  /* Increment to next even byte count */
        rxTransferByteCnt = transferByteCount & ~1U;  /* Decrement to next even byte count */
    }
    else
    {
        dspiDmaState->extraByte = false;
        txTransferByteCnt = transferByteCount;
        rxTransferByteCnt = transferByteCount;
    }
    /* Store the receiveBuffer pointer and receive byte count to the run-time state struct
     * for later use in the interrupt handler.
     */
    dspiDmaState->rxBuffer = (uint8_t *)receiveBuffer;
    dspiDmaState->rxTransferByteCnt = rxTransferByteCnt;

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

    /* Reset the transfer counter to 0. Normally this is done via the PUSHR[CTCNT], but as we
     * are under DMA controller, we won't be able to change this bit dynamically after the
     * first word is transferred.
     */
    DSPI_HAL_PresetTransferCount(base, 0);

    /* 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);

    /************************************************************************************
     * Set up the RX DMA channel Transfer Control Descriptor (TCD)
     * Do this before filling the TX FIFO.
     * Note, if there is no remaining receive count, then bypass RX DMA set up.
     * This means we only have one byte to read of a 16-bit data word and will read this
     * in the complete transfer function.
     ***********************************************************************************/
    /* If a receive buffer is used and if rxTransferByteCnt > 0 */
    if (rxTransferByteCnt)
    {
        if (!receiveBuffer)
        {
            /* Set up this channel's control which includes enabling the DMA interrupt */
            DMA_DRV_ConfigTransfer(&dspiDmaState->dmaRxChannel,
                                   kDmaPeripheralToPeripheral,
                                   transferSizeInBytes,
                                   DSPI_HAL_GetPoprRegAddr(base), /* src is data register */
                                   (uint32_t)(&s_rxBuffIfNull), /* dest is temporary location */
                                   (uint32_t)(rxTransferByteCnt));
        }
        else
        {
            /* Set up this channel's control which includes enabling the DMA interrupt */
            DMA_DRV_ConfigTransfer(&dspiDmaState->dmaRxChannel,
                                   kDmaPeripheralToMemory,
                                   transferSizeInBytes,
                                   DSPI_HAL_GetPoprRegAddr(base), /* src is data register */
                                   (uint32_t)(receiveBuffer), /* dest is rx buffer */
                                   (uint32_t)(rxTransferByteCnt));

            /* Destination size is only 1 byte */
            DMA_DRV_SetDestTransferSize(&dspiDmaState->dmaRxChannel, 1U);
        }

        /* Enable the DMA peripheral request */
        DMA_DRV_StartChannel(&dspiDmaState->dmaRxChannel);
    }
    else if (dspiDmaState->extraByte)
    {
        /* Need to receive only one frame - extra byte by calling Rx callback function*/
        DSPI_DRV_DmaRxCallback((void *)instance, kDmaIdle);
    }

    /************************************************************************************
     * Set up the Last Command/data Word Intermediate Buffer and fill up the TX FIFO.
     ***********************************************************************************/
    /* 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 = dspiDmaState->whichPcs;
    command.whichCtar = dspiDmaState->whichCtar;
    command.clearTransferCount = false; /* don't clear the transfer count */

    /************************************************************************
     * Next, set up the Last Command/data Word Intermediate Buffer before
     * filling up the TX FIFO
     * Create a 32-bit word with the final 16-bit command settings. This means
     * that EOQ = 1 and CONT = 0.
     * This 32-bit word will also be initialized with the final data byte/word
     * from the send source buffer and then the entire 32-bit word will be
     * transferred to the DSPI PUSHR.
     ************************************************************************/
    /* Declare a variable for storing the last send data (either 8- or 16-bit) */
    uint32_t lastWord = 0;

    /* If a send buffer was provided, the word comes from there. Otherwise we just send
     * a zero (initialized above).
     */
    if (sendBuffer)
    {
        /* Store the last byte from the send buffer */
        if (dspiDmaState->bitsPerFrame <= 8)
        {
            lastWord = sendBuffer[txTransferByteCnt-1]; /* Last byte */
        }
        /* Store the last two bytes the send buffer */
        else
        {
            /* If 16-bit transfers and odd transfer byte count then an extra byte was added
             * to the transfer byte count, but we cannot access more of the send buffer
             */
            if(!dspiDmaState->extraByte)
            {
                lastWord = sendBuffer[txTransferByteCnt-1] ; /* Save off the last byte */
                lastWord = lastWord << 8U; /* Shift to MSB (separate step due to MISHA) */
            }
            lastWord |= sendBuffer[txTransferByteCnt-2]; /* OR with next to last byte */
        }
    }

    /* Now, build the last command/data word intermediate buffer */
    command.isChipSelectContinuous = false; /* Always clear CONT for last data word */
    command.isEndOfQueue = true; /* Set EOQ for last data word */
    s_lastCmdData = DSPI_HAL_GetFormattedCommand(base, &command) | lastWord;
    /************************************************************************
     * Begin TX DMA channels transfer control descriptor set up.
     * 1. First, set up intermediate buffers which contain 16-bit commands.
     * 2. Set up the DMA Software Transfer Control Descriptors (STCD) for various
     *    scenarios:
     *    - Channel for intermediate buffer to TX FIFO
     *    - Channel for source buffer to intermediate buffer
     *    - STCD for scatter/gather for end of previous channel to replace
     *      intermediate buffer with last-command buffer.
     ************************************************************************/

    /************************************************************************
     * Intermediate Buffer
     * Create a 32-bit word with the 16-bit command settings. Data from
     * the send source buffer will be transferred here and then the entire
     * 32-bit word will be transferred to the DSPI PUSHR.
     * This buffer will be preloaded with the next data word in the send buffer
     ************************************************************************/
    /* restore the isChipSelectContinuous setting to the original value as it was cleared above */
    command.isChipSelectContinuous = dspiDmaState->isChipSelectContinuous;
    command.isEndOfQueue = false; /* Clear End of Queue (previously set for last cmd/data word)*/
    s_cmdData = DSPI_HAL_GetFormattedCommand(base, &command);

    /* Place the next data from the send buffer into the intermediate buffer (preload it)
     * based on whether it is one byte or two.
     */
    if (dspiDmaState->bitsPerFrame <= 8)
    {
        /* If a send buffer was provided, the word comes from there. Otherwise we just send
         * a zero (initialized above).
         */
        if (sendBuffer)
        {
            s_wordToSend = *sendBuffer;  /* queue up the next data */
            ++sendBuffer; /* increment to next data word*/
        }
        --txTransferByteCnt; /* decrement txTransferByteCnt*/
    }
    else
    {
        /* If a send buffer was provided, the word comes from there. Otherwise we just send
         * a zero (initialized above).
         */
        if (sendBuffer)
        {
            s_wordToSend = *sendBuffer;
            ++sendBuffer; /* increment to next data byte */

            /* Note, if the extraByte flag is set and we're down to the last two bytes we can still
             * do this even though we're going past the sendBuffer size. We're just reading data we
             * don't care about anyways since it is dummy data to make up for the last byte.
             */
            s_wordToSend |= (unsigned)(*sendBuffer) << 8U;
            ++sendBuffer; /* increment to next data byte */

        }
        txTransferByteCnt -= 2;  /* decrement txTransferByteCnt by 2 bytes */
    }

    s_cmdData |= s_wordToSend; /* write s_wordToSend to intermediate buffer */

    /* For Tx, DSPI need two DMA channel, one for calculate the command and data into one value
     * (dmaTxCmdChannel), and another for push the value into DSPI PUSHR register (dmaTxDataChannel).
     * The dmaTxCmdChannel DMA channel will be triggered by DSPI Tx FIFO, and the dmaTxDataChannel
     * DMA channel will be linked to calculate DMA channel and triggered by this channel also.
     */

    /* If the transfer size is less than size of one frame, only transmit the last byte that calculated */
    if (!txTransferByteCnt)
    {
        DMA_DRV_ConfigTransfer(&dspiDmaState->dmaTxDataChannel, kDmaMemoryToPeripheral,
                               4u, (uint32_t)(&s_lastCmdData),
                               DSPI_HAL_GetMasterPushrRegAddr(base), 4u);
        /* Register callback for last byte transmitting */
        DMA_DRV_RegisterCallback(&dspiDmaState->dmaTxDataChannel, DSPI_DRV_DmaTxLastCallback, (void *)instance);
    }
    else
    {
        /* Config DMA to copy data from generated cmd data to FIFO */
        if (dspiDmaState->bitsPerFrame <= 8)
        {
            DMA_DRV_ConfigTransfer(&dspiDmaState->dmaTxDataChannel, kDmaPeripheralToPeripheral,
                                   4u, (uint32_t)(&s_cmdData),
                                   DSPI_HAL_GetMasterPushrRegAddr(base),
                                   (uint32_t)((txTransferByteCnt) * 4));
        }
        else
        {
            DMA_DRV_ConfigTransfer(&dspiDmaState->dmaTxDataChannel, kDmaPeripheralToPeripheral,
                                   4u, (uint32_t)(&s_cmdData),
                                   DSPI_HAL_GetMasterPushrRegAddr(base),
                                   (uint32_t)((txTransferByteCnt) * 2));
        }
        /* Register Tx callback function */
        DMA_DRV_RegisterCallback(&dspiDmaState->dmaTxDataChannel, DSPI_DRV_DmaTxCallback, (void *)instance);

        /* Config dmaTxCmdChannel channel if send buffer is provided */
        if (sendBuffer)
        {
            dma_channel_link_config_t config;
            DMA_DRV_ConfigTransfer(&dspiDmaState->dmaTxCmdChannel, kDmaMemoryToPeripheral,
                                   1u, (uint32_t)(sendBuffer),
                                   (uint32_t)(&s_cmdData),
                                   (uint32_t)(txTransferByteCnt - transferSizeInBytes));
            if (dspiDmaState->bitsPerFrame > 8)
            {
                DMA_DRV_SetDestTransferSize(&dspiDmaState->dmaTxCmdChannel, 2U);
            }

            /* Link dmaTxCmdChannel after dmaTxDataChannel */
            config.channel1 = dspiDmaState->dmaTxCmdChannel.channel;
            config.channel2 = 0;
            config.linkType = kDmaChannelLinkChan1;
            DMA_DRV_ConfigChanLink(&dspiDmaState->dmaTxDataChannel, &config);
            /* start channel */
            DMA_DRV_StartChannel(&dspiDmaState->dmaTxCmdChannel);
        }
    }

    /* Register callback */
    DMA_DRV_RegisterCallback(&dspiDmaState->dmaRxChannel, DSPI_DRV_DmaRxCallback, (void *)instance);

    /* Enable the Receive FIFO Drain DMA Request */
    DSPI_HAL_SetRxFifoDrainDmaIntMode(base, kDspiGenerateDmaReq, true);

    /* Enable TFFF DMA request */
    DSPI_HAL_SetTxFifoFillDmaIntMode(base, kDspiGenerateDmaReq, true);

    /* Enable the DMA peripheral request */
    DMA_DRV_StartChannel(&dspiDmaState->dmaTxDataChannel);

    return kStatus_DSPI_Success;
}
예제 #5
0
/*FUNCTION**********************************************************************
 *
 * Function Name : UART_DRV_DmaInit
 * Description   : This function initializes a UART instance for operation.
 * This function will initialize the run-time state structure to keep track of
 * the on-going transfers, ungate the clock to the UART module, initialize the
 * module to user defined settings and default settings, configure UART DMA
 * and enable the UART module transmitter and receiver.
 * The following is an example of how to set up the uart_dma_state_t and the
 * uart_user_config_t parameters and how to call the UART_DRV_DmaInit function
 * by passing in these parameters:
 *    uart_user_config_t uartConfig;
 *    uartConfig.baudRate = 9600;
 *    uartConfig.bitCountPerChar = kUart8BitsPerChar;
 *    uartConfig.parityMode = kUartParityDisabled;
 *    uartConfig.stopBitCount = kUartOneStopBit;
 *    uart_dma_state_t uartDmaState;
 *    UART_DRV_DmaInit(instance, &uartDmaState, &uartConfig);
 *
 *END**************************************************************************/
uart_status_t UART_DRV_DmaInit(uint32_t instance,
                               uart_dma_state_t * uartDmaStatePtr,
                               const uart_dma_user_config_t * uartUserConfig)
{
    assert(uartDmaStatePtr && uartUserConfig);
    assert(g_uartBase[instance]);
    assert(instance < UART_INSTANCE_COUNT);
    /* This driver only support UART instances with separate DMA channels for
     * both Tx and Rx.*/
    assert(FSL_FEATURE_UART_HAS_SEPARATE_DMA_RX_TX_REQn(instance) == 1);

    UART_Type * base = g_uartBase[instance];
    uint32_t uartSourceClock = 0;
    dma_request_source_t uartTxDmaRequest = kDmaRequestMux0Disable;
    dma_request_source_t uartRxDmaRequest = kDmaRequestMux0Disable;

    /* Exit if current instance is already initialized. */
    if (g_uartStatePtr[instance])
    {
        return kStatus_UART_Initialized;
    }

    /* Clear the state structure for this instance. */
    memset(uartDmaStatePtr, 0, sizeof(uart_dma_state_t));

    /* Save runtime structure pointer.*/
    g_uartStatePtr[instance] = uartDmaStatePtr;

    /* Un-gate UART module clock */
    CLOCK_SYS_EnableUartClock(instance);

    /* Initialize UART to a known state. */
    UART_HAL_Init(base);

    /* Create Semaphore for txIrq and rxIrq. */
    OSA_SemaCreate(&uartDmaStatePtr->txIrqSync, 0);
    OSA_SemaCreate(&uartDmaStatePtr->rxIrqSync, 0);

    /* UART clock source is either system or bus clock depending on instance */
    uartSourceClock = CLOCK_SYS_GetUartFreq(instance);

    /* Initialize UART baud rate, bit count, parity and stop bit. */
    UART_HAL_SetBaudRate(base, uartSourceClock, uartUserConfig->baudRate);
    UART_HAL_SetBitCountPerChar(base, uartUserConfig->bitCountPerChar);
    UART_HAL_SetParityMode(base, uartUserConfig->parityMode);
#if FSL_FEATURE_UART_HAS_STOP_BIT_CONFIG_SUPPORT
    UART_HAL_SetStopBitCount(base, uartUserConfig->stopBitCount);
#endif

    /* Enable DMA trigger when transmit data register empty,
     * and receive data register full. */
    UART_HAL_SetTxDmaCmd(base, true);
    UART_HAL_SetRxDmaCmd(base, true);

    switch (instance)
    {
#if (FSL_FEATURE_UART_HAS_SEPARATE_DMA_RX_TX_REQn(0) == 1)
        case 0:
            uartRxDmaRequest = kDmaRequestMux0UART0Rx;
            uartTxDmaRequest = kDmaRequestMux0UART0Tx;
            break;
#endif
#if (FSL_FEATURE_UART_HAS_SEPARATE_DMA_RX_TX_REQn(1) == 1)
        case 1:
            uartRxDmaRequest = kDmaRequestMux0UART1Rx;
            uartTxDmaRequest = kDmaRequestMux0UART1Tx;
            break;
#endif
#if (FSL_FEATURE_UART_HAS_SEPARATE_DMA_RX_TX_REQn(2) == 1)
        case 2:
            uartRxDmaRequest = kDmaRequestMux0UART2Rx;
            uartTxDmaRequest = kDmaRequestMux0UART2Tx;
            break;
#endif
        default :
            break;
    }

    /* Request DMA channels for RX FIFO. */
    DMA_DRV_RequestChannel(kDmaAnyChannel, uartRxDmaRequest,
                            &uartDmaStatePtr->dmaUartRx);
    DMA_DRV_RegisterCallback(&uartDmaStatePtr->dmaUartRx,
                    UART_DRV_DmaRxCallback, (void *)instance);

    /* Request DMA channels for TX FIFO. */
    DMA_DRV_RequestChannel(kDmaAnyChannel, uartTxDmaRequest,
                            &uartDmaStatePtr->dmaUartTx);
    DMA_DRV_RegisterCallback(&uartDmaStatePtr->dmaUartTx,
                    UART_DRV_DmaTxCallback, (void *)instance);

    /* Finally, enable the UART transmitter and receiver*/
    UART_HAL_EnableTransmitter(base);
    UART_HAL_EnableReceiver(base);

    return kStatus_UART_Success;
}
/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaSlaveStartTransfer
 * Description   : Starts the transfer with information passed.
 *
 *END**************************************************************************/
static spi_status_t SPI_DRV_DmaSlaveStartTransfer(uint32_t instance)
{
    spi_dma_slave_state_t * spiState = (spi_dma_slave_state_t *)g_spiStatePtr[instance];

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

    /* Initialize s_byteToSend */
    s_byteToSend = spiState->dummyPattern;

    /* If the transfer count is zero, then return immediately. */
    if (spiState->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 (spiState->isSync)
        {
            /* Signal the synchronous completion object */
            OSA_EventSet(&spiState->event, kSpiDmaTransferDone);
        }
        return kStatus_SPI_Success;
    }

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

    /* First, set the DMA transfer size in bytes */
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
    if (SPI_HAL_Get8or16BitMode(base) == kSpi16BitMode)
    {
        transferSizeInBytes = 2;
        /* If bits/frame > 8, meaning 2 bytes, then the transfer byte count must not be an odd
         * count. If so, drop the last odd byte. This odd byte will be transferred in when dma
         * completed
         */
        if (spiState->remainingSendByteCount % 2 != 0)
        {
            spiState->remainingSendByteCount ++;
            spiState->remainingReceiveByteCount --;
            spiState->hasExtraByte = true;
        }
        else
        {
            spiState->hasExtraByte = false;
        }
    }
    else
    {
        transferSizeInBytes = 1;
    }
#else
    transferSizeInBytes = 1;
#endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */

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

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

    /************************************************************************************
     * Set up the RX DMA channel Transfer Control Descriptor (TCD)
     * Note, if there is no receive buffer (if user passes in NULL), then bypass RX DMA
     * set up.
     ************************************************************************************/
    /* If no receive buffer then disable incrementing the destination and set the destination
     * to a temporary location
     */
    if ((spiState->remainingReceiveByteCount > 0) || (spiState->hasExtraByte))
    {
        uint32_t receiveSize = spiState->remainingReceiveByteCount;
        if ((!spiState->receiveBuffer) || (!spiState->remainingReceiveByteCount))
        {
            if (!spiState->remainingReceiveByteCount)
            {
                /* If receive count is 0, always receive 1 frame (2 bytes) */
                receiveSize = 2;
            }
            /* Set up this channel's control which includes enabling the DMA interrupt */
            DMA_DRV_ConfigTransfer(&spiState->dmaReceive,
                                   kDmaPeripheralToPeripheral,
                                   transferSizeInBytes,
                                   SPI_HAL_GetDataRegAddr(base), /* src is data register */
                                   (uint32_t)(&s_rxBuffIfNull), /* dest is temporary location */
                                   (uint32_t)(receiveSize));
        }
        else
        {
            /* Set up this channel's control which includes enabling the DMA interrupt */
            DMA_DRV_ConfigTransfer(&spiState->dmaReceive,
                                   kDmaPeripheralToMemory,
                                   transferSizeInBytes,
                                   SPI_HAL_GetDataRegAddr(base), /* src is data register */
                                   (uint32_t)(spiState->receiveBuffer), /* dest is rx buffer */
                                   (uint32_t)(receiveSize));
        }
        /* Destination size is only one byte */
        DMA_DRV_SetDestTransferSize(&spiState->dmaReceive, 1U);

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

        /* Register callback for DMA interrupt */
        DMA_DRV_RegisterCallback(&spiState->dmaReceive, SPI_DRV_DmaSlaveCallback, 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.
     */
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
    if (transferSizeInBytes == 2) /* 16-bit transfers for SPI16 module */
    {
        if (spiState->sendBuffer)
        {
            s_byteToSend = *(spiState->sendBuffer);
            SPI_HAL_WriteDataLow(base, s_byteToSend);
            ++spiState->sendBuffer;

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

    /* If there are no more bytes to send then return without setting up the TX DMA channel.
     * Else, set up the TX DMA channel and enable the TX DMA request.
     */
    if (!spiState->remainingSendByteCount) /* No more bytes to send */
    {
        if ((spiState->remainingReceiveByteCount) || (spiState->hasExtraByte))
        {
            /* 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, set up the TX DMA channel */
    {
        /* If there is a send buffer, data comes from there, else send 0 */
        if (spiState->sendBuffer)
        {
            /* Set up this channel's control which includes enabling the DMA interrupt */
            DMA_DRV_ConfigTransfer(&spiState->dmaTransmit, kDmaMemoryToPeripheral,
                                   transferSizeInBytes,
                                   (uint32_t)(spiState->sendBuffer),
                                   SPI_HAL_GetDataRegAddr(base),
                                   (uint32_t)(spiState->remainingSendByteCount));
        }
        else /* Configure TX DMA channel to send zeros */
        {
            /* Set up this channel's control which includes enabling the DMA interrupt */
            DMA_DRV_ConfigTransfer(&spiState->dmaTransmit, kDmaPeripheralToPeripheral,
                                   transferSizeInBytes,
                                   (uint32_t)(&s_byteToSend),
                                   SPI_HAL_GetDataRegAddr(base),
                                   (uint32_t)(spiState->remainingSendByteCount));
        }
        /* Source size is only one byte */
        DMA_DRV_SetSourceTransferSize(&spiState->dmaTransmit, 1U);

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

        /* Enable the SPI RX DMA request also. */
        SPI_HAL_SetRxDmaCmd(base, true);

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

    return kStatus_SPI_Success;
}
/*!
 * @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;
}
/*FUNCTION**********************************************************************
 *
 * Function Name : LPUART_DRV_DmaInit
 * Description   : This function initializes a LPUART instance for operation.
 * This function will initialize the run-time state structure to keep track of
 * the on-going transfers, ungate the clock to the LPUART module, initialize the
 * module to user defined settings and default settings, configure LPUART DMA
 * and enable the LPUART module transmitter and receiver.
 * The following is an example of how to set up the lpuart_dma_state_t and the
 * lpuart_user_config_t parameters and how to call the LPUART_DRV_DmaInit function
 * by passing in these parameters:
 *    lpuart_user_config_t lpuartConfig;
 *    lpuartConfig.baudRate = 9600;
 *    lpuartConfig.bitCountPerChar = kLpuart8BitsPerChar;
 *    lpuartConfig.parityMode = kLpuartParityDisabled;
 *    lpuartConfig.stopBitCount = kLpuartOneStopBit;
 *    lpuart_dma_state_t lpuartDmaState;
 *    LPUART_DRV_DmaInit(instance, &lpuartDmaState, &lpuartConfig);
 *
 *END**************************************************************************/
lpuart_status_t LPUART_DRV_DmaInit(uint32_t instance,
                               lpuart_dma_state_t * lpuartDmaStatePtr,
                               const lpuart_dma_user_config_t * lpuartUserConfig)
{
    assert(lpuartDmaStatePtr && lpuartUserConfig);
    assert(instance < LPUART_INSTANCE_COUNT);

    LPUART_Type * base = g_lpuartBase[instance];
    uint32_t lpuartSourceClock = 0;
    dma_request_source_t lpuartTxDmaRequest = kDmaRequestMux0Disable;
    dma_request_source_t lpuartRxDmaRequest = kDmaRequestMux0Disable;

    /* Exit if current instance is already initialized. */
    if (g_lpuartStatePtr[instance])
    {
        return kStatus_LPUART_Initialized;
    }

    /* Clear the state structure for this instance. */
    memset(lpuartDmaStatePtr, 0, sizeof(lpuart_dma_state_t));

    /* Save runtime structure pointer.*/
    g_lpuartStatePtr[instance] = lpuartDmaStatePtr;

    /* Un-gate LPUART module clock */
    CLOCK_SYS_EnableLpuartClock(instance);

    /* Set LPUART clock source */
    CLOCK_SYS_SetLpuartSrc(instance, lpuartUserConfig->clockSource);

    /* Initialize LPUART to a known state. */
    LPUART_HAL_Init(base);

    /* Create Semaphore for txIrq and rxIrq. */
    OSA_SemaCreate(&lpuartDmaStatePtr->txIrqSync, 0);
    OSA_SemaCreate(&lpuartDmaStatePtr->rxIrqSync, 0);

    /* LPUART clock source is either system or bus clock depending on instance */
    lpuartSourceClock = CLOCK_SYS_GetLpuartFreq(instance);

    /* Initialize LPUART baud rate, bit count, parity and stop bit. */
    LPUART_HAL_SetBaudRate(base, lpuartSourceClock, lpuartUserConfig->baudRate);
    LPUART_HAL_SetBitCountPerChar(base, lpuartUserConfig->bitCountPerChar);
    LPUART_HAL_SetParityMode(base, lpuartUserConfig->parityMode);
#if FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
    LPUART_HAL_SetStopBitCount(base, lpuartUserConfig->stopBitCount);
#endif

    /* Enable DMA trigger when transmit data register empty,
     * and receive data register full. */
    LPUART_HAL_SetTxDmaCmd(base, true);
    LPUART_HAL_SetRxDmaCmd(base, true);

    switch (instance)
    {
        case 0:
            lpuartRxDmaRequest = kDmaRequestMux0LPUART0Rx;
            lpuartTxDmaRequest = kDmaRequestMux0LPUART0Tx;
            break;
        default :
            break;
    }

    /* Request DMA channels for RX FIFO. */
    DMA_DRV_RequestChannel(kDmaAnyChannel, lpuartRxDmaRequest,
                            &lpuartDmaStatePtr->dmaLpuartRx);
    DMA_DRV_RegisterCallback(&lpuartDmaStatePtr->dmaLpuartRx,
                    LPUART_DRV_DmaRxCallback, (void *)instance);

    /* Request DMA channels for TX FIFO. */
    DMA_DRV_RequestChannel(kDmaAnyChannel, lpuartTxDmaRequest,
                            &lpuartDmaStatePtr->dmaLpuartTx);
    DMA_DRV_RegisterCallback(&lpuartDmaStatePtr->dmaLpuartTx,
                    LPUART_DRV_DmaTxCallback, (void *)instance);

    /* Finally, enable the LPUART transmitter and receiver*/
    LPUART_HAL_SetTransmitterCmd(base, true);
    LPUART_HAL_SetReceiverCmd(base, true);

    return kStatus_LPUART_Success;
}
예제 #9
0
파일: main.c 프로젝트: TheDukeZip/ahabadge
/*!
 * @brief Main function
 */
int main (void)
{
    /* enable clock for PORTs */
    CLOCK_SYS_EnablePortClock(PORTA_IDX);
    //CLOCK_SYS_EnablePortClock(PORTB_IDX);
    CLOCK_SYS_EnablePortClock(PORTC_IDX);
    CLOCK_SYS_EnablePortClock(PORTD_IDX);
    CLOCK_SYS_EnablePortClock(PORTE_IDX);

    /* Set allowed power mode, allow all. */
    SMC_HAL_SetProtection(SMC, kAllowPowerModeAll);

    /* Set system clock configuration. */
    CLOCK_SYS_SetConfiguration(&g_defaultClockConfigVlpr);

    /* Initialize LPTMR */
    lptmr_state_t lptmrState;
    LPTMR_DRV_Init(LPTMR0_IDX, &lptmrState, &g_lptmrConfig);
    LPTMR_DRV_SetTimerPeriodUs(LPTMR0_IDX, 100000);
    LPTMR_DRV_InstallCallback(LPTMR0_IDX, lptmr_call_back);

    /* Initialize DMA */
    dma_state_t dma_state;
    DMA_DRV_Init(&dma_state);

    /* Initialize PIT */
    PIT_DRV_Init(0, false);
    PIT_DRV_InitChannel(0, 0, &g_pitChan0);

    /* Initialize CMP */
    CMP_DRV_Init(0, &g_cmpState, &g_cmpConf);
    CMP_DRV_ConfigDacChn(0, &g_cmpDacConf);
    PORT_HAL_SetMuxMode(g_portBase[GPIOC_IDX], 0, kPortMuxAlt5);
    CMP_DRV_Start(0);

    /* Buttons */
    GPIO_DRV_InputPinInit(&g_switch1);
    GPIO_DRV_InputPinInit(&g_switch2);
    GPIO_DRV_InputPinInit(&g_switchUp);
    GPIO_DRV_InputPinInit(&g_switchDown);
    GPIO_DRV_InputPinInit(&g_switchLeft);
    GPIO_DRV_InputPinInit(&g_switchRight);
    GPIO_DRV_InputPinInit(&g_switchSelect);

    /* Start LPTMR */
    LPTMR_DRV_Start(LPTMR0_IDX);

    /* Setup LPUART1 */
    LPUART_DRV_Init(1, &g_lpuartState, &g_lpuartConfig);
    LPUART_DRV_InstallRxCallback(1, lpuartRxCallback, rxBuff, NULL, true);
    LPUART_DRV_InstallTxCallback(1, lpuartTxCallback, NULL, NULL);
    LPUART_BWR_CTRL_TXINV(g_lpuartBase[1], 1);
    PORT_HAL_SetMuxMode(g_portBase[GPIOE_IDX], 0, kPortMuxAlt3);
    PORT_HAL_SetMuxMode(g_portBase[GPIOE_IDX], 1, kPortMuxAlt3);

    /* Setup FlexIO for the WS2812B */
    FLEXIO_Type *fiobase = g_flexioBase[0];
    CLOCK_SYS_SetFlexioSrc(0, kClockFlexioSrcMcgIrClk);
    FLEXIO_DRV_Init(0, &g_flexioConfig);
    FLEXIO_HAL_ConfigureTimer(fiobase, 0, &g_timerConfig);
    FLEXIO_HAL_ConfigureShifter(fiobase, 0, &g_shifterConfig);
    PORT_HAL_SetMuxMode(g_portBase[GPIOE_IDX], 20, kPortMuxAlt6);
    FLEXIO_DRV_Start(0);

    FLEXIO_HAL_SetShifterStatusDmaCmd(fiobase, 1, true);
    DMA_DRV_RequestChannel(kDmaAnyChannel, kDmaRequestMux0FlexIOChannel0,
            &g_fioChan);
    DMA_DRV_RegisterCallback(&g_fioChan, fioDmaCallback, NULL);

    /* Connect buzzer to TPM0_CH3 */
    PORT_HAL_SetMuxMode(g_portBase[GPIOE_IDX], 30, kPortMuxAlt3);
    tpm_general_config_t tmpConfig = {
        .isDBGMode = false,
        .isGlobalTimeBase = false,
        .isTriggerMode = false,
        .isStopCountOnOveflow = false,
        .isCountReloadOnTrig = false,
        .triggerSource = kTpmTrigSel0,
    };
    TPM_DRV_Init(0, &tmpConfig);
    TPM_DRV_SetClock(0, kTpmClockSourceModuleMCGIRCLK, kTpmDividedBy1);

    /* Blank LED just in case, saves power */
    led(0x00, 0x00, 0x00);

    /* Init e-paper display */
    EPD_Init();

    /* Throw up first image */
    int ret = EPD_Draw(NULL, images[current_image]);
    if (-1 == ret) {
        led(0xff, 0x00, 0x00);
    } else if (-2 == ret) {
        led(0xff, 0xff, 0x00);
    } else if (-3 == ret) {
        led(0x00, 0x00, 0xff);
    } else {
        led(0x00, 0xff, 0x00);
    }
    blank_led = 30;

    /* Deinit so we can mess around on the bus pirate */
    //EPD_Deinit();

    /* We're done, everything else is triggered through interrupts */
    for(;;) {
        if (cue_next_image) {
            int old_image = current_image;
            current_image = (current_image + 1) % image_count;
            EPD_Draw(images[old_image], images[current_image]);
            cue_next_image = 0;
        }
#ifndef DEBUG
        SMC_HAL_SetMode(SMC, &g_idlePowerMode);
#endif
    }
}