串口DMA接收数据使用双BUFF,接收不定长数据

本文介绍了如何在硬件DMA支持存储切换功能的背景下,针对串口接收不定长数据的场景,正确配置双BUFF并避免使用存储切换。详细讲解了计数器管理、DMA通道操作和数据搬运过程,强调了在处理非定长数据时的特殊处理方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用双BUFF的首先注意事项:
有的硬件DMA带有存储切换功能,这个功能主要是在一个BUFF满了之后自动切换成另一个BUFF,主要实现了两个功能:一是自动切换buff和自动设置传输的长度;
这里不建议使用,因为我需要串口DMA接收不定长数据,既然是不定长,那么每一次从DMA Buff中搬运出数据时,需要计算出DMA传输的长度并设置,还要设置要传输的DMA Buff;如果是定长数据的接收那么可以使用存储切换功能;
DMA接收数据的实现过程:
1.获取DMA CNT的值,并和上次获取的值做比较得出这次需要从DMA BUFF中搬运的数量。此寄存器记录了能够通过DMA传输的数据个数,每传输一个数据该值变减一,直到该值为0,会自动加载,该初始值在初始化的时候设置好;
无论使用哪一个BUFF接收数据,DMA的CNT都会变化。
2.失能DMA,因为在失能的情况下才能修改寄存器的值;
3.获取上一次使用的BUFF,切换buff,使得DMA搬运的数据到正确的DMA BUFF;使用的哪个BUFF自己可以设置一个标志;
4.使能DMA
5.开启传输即把DMA BUFF中的数据搬运到外设,注意这就不是DMA自动搬运的过程了。

DMA双BUFF配置寄存器和从DMA BUFF中取数的过程如下:

   if (pUartSioChan->SIOCHAN_iMethod == UART_DMA_MODE) {
        dma_channel_disable(uiDmaX, iDmaRxChan);                        /*  通道失能                    */
        _G_uiDmaRxCnt = dma_transfer_number_get(uiDmaX, iDmaRxChan);        /*  获取DMA的CNT剩余数据长度    */
        if (_G_uiDmaRxCnt != _G_uiLastLength) {                                                    /*  和上一次CNT的值作比较     */

            _G_uiLastLength = _G_uiDmaRxCnt;
            uiReceivedCount = DMA_RXBUFF_SIZE - _G_uiDmaRxCnt;                  /*  获取接收数据量              */

//            uiBuffUsed = dma_using_memory_get(uiDmaX, iDmaRxChan);             /*  双BUFF时判断                */

            /*
             * 设置传输长度
             */
            DMA_CHCNT(uiDmaX, iDmaRxChan) = DMA_RXBUFF_SIZE;
            /*
            * 设置传输BUFF
            */
            dmaSwitchBuffer(uiDmaX, iDmaRxChan, _G_iRxNextBuff);
            _G_iRxNextBuff = !(_G_iRxNextBuff);
            _G_iBuffToTransfer = !(_G_iRxNextBuff);

            dma_channel_enable(uiDmaX, iDmaRxChan);

            /*
             * 开始从内存中搬运到TTY设备
             */
            while(uiCount < uiReceivedCount) {
                if (_G_iBuffToTransfer == DMA_MEMORY_0) {
                   PUTRXCHAR(_G_ucRxbuffer1[uiCount]);
                } else if (_G_iBuffToTransfer == DMA_MEMORY_1) {
                   PUTRXCHAR(_G_ucRxbuffer2[uiCount]);
                }
                ++uiCount;

            }
        }
    }

判断是否从DMA BUFF中取数的机制是获取DMA CNT的值,与上一次CNT值进行比较,两个值不同,则开始处理DMA BUFF中的数据。将CNT值存储为全局变量,每个通道存储在自己的全局变量里。

使用STM32 HAL库实现DMA接收数据的步骤如下: 1. 首先,在代码中定义一个接收数组,比如`uint8_t receive_buff[18]`,用于存储接收到的数据。 2. 然后,在USART的中断处理函数(比如`USART1_IRQHandler`)中,使用以下代码片段来处理DMA接收数据: ```c if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) { __HAL_UART_CLEAR_IDLEFLAG(&huart1); HAL_UART_DMAStop(&huart1); DMA2_Stream2->NDTR = (uint16_t)(RC_FRAME_LENGTH); HAL_UART_Receive_DMA(&huart1, (uint8_t*)receive_buff, 18); HAL_Delay(25); if (__HAL_DMA_GET_COUNTER(&hdma_usart1_rx) == 0 && receive_buff == 4) { memcpy(data_Handle, receive_buff, 18); } } ``` 上述代码中,首先判断是否发生了空闲中断,如果发生了则进行以下操作: - 清除空闲中断标志 - 停止DMA接收 - 重置DMA存储指针到起始位置 - 再次开启DMA接收 - 延时一段时间(例如25ms) - 判断DMA剩余数据单元数量是否为0,并且接收数组中的某个特定位置的值是否等于4,以确定数据的正确性 - 如果数据正确,则将接收数组中的数据复制到其他数组中进行进一步处理。 这样,就使用STM32 HAL库实现了DMA接收数据的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [STM32 HAL库串口+DMA空闲中断接收不定长数据](https://download.youkuaiyun.com/download/chenyongfeng123/13087603)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [STM32 hal库解决串口+DMA接收数据](https://blog.youkuaiyun.com/m0_49933527/article/details/114187881)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值