IMXRT学习记录 – DMA粗略

这几天看了下DMA,还真是只能给个粗略的认识,尝试配置DMA+PTC+ADC+ATC_ETC无果,就开始有点放弃,然后查看一下DMA例子,想到DMA还有个典型的应用就是串口,串口辣么慢,一个一个字符打又老中断CPU(或者堵塞),实在不环保.

才发现原来DMA+UART是不用自己写的LPUART_ReceiveEDMA和LPUART_SendEDMA都做好了,而且只需要LPUART_TransferCreateHandleEDMA初始化一下,是不是很贴心,然后查看其他代码,I2C,SPI也有同样的函数,唯独ADC_ETC没有?看来是我一开始选择了困难模式.

一般的DMA+外设初始化步骤大概如下(前提是官方做了函数):

  1. 初始化板子上的IO等配置.
  2. 初始化本身的外设(比如说串口,就可以先LPUART_GetDefaultConfig,填充参数,然后LPUART_Init就可以了.)
  3. 初始化DMAMUX,绑定通道.(比如官方例子绑定DMA CH0到kDmaRequestMuxLPUART1Tx,这里需要DMAMUX_Init初始化一下DMAMUX,DMAMUX_SetSource并DMAMUX_EnableChannel就可以了.)
  4. 初始化EDMA,绑定回调.(比如官方例子EDMA_Init初始化DMA0,然后EDMA_CreateHandle根据通道分别绑定g_lpuartTxEdmaHandle和g_lpuartRxEdmaHandle)
  5. 把EDMA和对应硬件外设连接起来.(比如官方例子中的LPUART_TransferCreateHandleEDMA,连接后得到了加料Handle g_lpuartEdmaHandle,以及绑定用户空间的处理回调LPUART_UserCallback)
  6. 完成

在官方的UART例子中,最终目的是得到g_lpuartEdmaHandle,可以用其他通道来进行,似乎没有什么限制.

在实际使用,就是收发,回调三个关键点,回调一般不携带数据,但是会回传状态等信息.

下面是官方给出的I2C,SPI,UART回调例子,可见回调是可复用(只要判断进来的Handle就能区分谁回调),并且主要携带status的一个函数.

static void lpi2c_master_callback(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, status_t status, void *userData)
{
    /* Signal transfer success when received success status. */
    if (status == kStatus_Success)
    {
        g_MasterCompletionFlag = true;
    }
}


void LPSPI_MasterUserCallback(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, status_t status, void *userData)
{
    if (status == kStatus_Success)
    {
        PRINTF("This is LPSPI master edma transfer completed callback. \r\n\r\n");
    }


    isTransferCompleted = true;
}


void LPUART_UserCallback(LPUART_Type *base, lpuart_edma_handle_t *handle, status_t status, void *userData)
{
    userData = userData;


    if (kStatus_LPUART_TxIdle == status)
    {
        txBufferFull = false;
        txOnGoing    = false;
    }


    if (kStatus_LPUART_RxIdle == status)
    {
        rxBufferEmpty = false;
        rxOnGoing     = false;
    }
}
在函数方面,其实就是普通的收发函数,添加EDMA后缀,比如LPUART_Receive => LPUART_ReceiveEDMA,当然容错是没实现的,像这个函数,如果收不到特定字节数,是会停在那里的.
—————————–
用上面的知识,基本能把一些外设DMA化,但是如果要任意外设DMA化,暂时我没看懂,但是先往下分析代码.既然说到了LPUART_ReceiveEDMA,那么就看LPUART_ReceiveEDMA,在看的过程中,我还对比了其他类似的DMA化的函数,发现基本如下:
  1. (传输发起)EDMA_PrepareTransfer->EDMA_SubmitTransfer->EDMA_StartTransfer->LPUART_EnableRxDMA
    • 交给EDMA后,EMA会传输,根据LPUART初始化设定的CallBack,会在传输完成后回调.
    • 数据交到这个函数后,立马就返回了.
  2. (传输完成)LPUART_SendEDMACallback / LPUART_ReceiveEDMACallback
  3. (回调发生)LPUART_TransferAbortReceiveEDMA / LPUART_TransferAbortSendEDMA->用户回调函数()
而M2M(内存到内存)传输也是这样的,但是不知道为什么应用到ADC_ETC就不会了呢,是没触发哪个REQ吗?后续再看吧.

发表评论

电子邮件地址不会被公开。 必填项已用*标注