从未遗忘 发表于 2023-11-30 17:24:03

DMA与回调函数

本帖最后由 从未遗忘 于 2023-11-30 17:32 编辑

今天写DMA的时候发现,串口在开启DMA时,    DMA中断函数和   串口回调函数都可以完成同样的回调处理,那DMA模式和回调函数方式谁更好呢?DMA中断函数比如DMA1_Channel1_IRQHandler频繁进中断,在使用时会影响CPU工作吗?因为是中断,但是我不确定DMA的中断也是CPU处理吗?


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        uint8_t tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
        if((tmp_flag != RESET))//通过标志位判断接收是否结束
        {
                __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
                HAL_UART_DMAStop(&huart1);
                uint8_t temp=__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);               
                UART3_LEN =UART3_RX_BUF_SIZE-temp; //计算出数据长度
                HAL_UART_Transmit_DMA(&huart1,g_RxBuf3,UART3_LEN);
                HAL_UART_Receive_DMA(&huart1,g_RxBuf3,UART3_RX_BUF_SIZE);//开启DMA接收,方便下一次接收数据       
        }
}


void DMA1_Channel1_IRQHandler(void)
{       
        uint8_t tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
        if((tmp_flag != RESET))//通过标志位判断接收是否结束
        {
                __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
                HAL_UART_DMAStop(&huart1);
                uint8_t temp=__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);               
                UART3_LEN =UART3_RX_BUF_SIZE-temp; //计算出数据长度
                HAL_UART_Transmit_DMA(&huart1,g_RxBuf3,UART3_LEN);
                HAL_UART_Receive_DMA(&huart1,g_RxBuf3,UART3_RX_BUF_SIZE);//开启DMA接收,方便下一次接收数据       
        }
}



在实际测试如果收发同时进行,如果发的快了,回调函数会有一直传0的现象。感觉DMA1_Channel1_IRQHandler处理更稳定呢?

庄永 发表于 2023-11-30 19:38:08

DMA中断会占用CPU,看你的应用建议不开DMA中断,使用空闲中断就好了

从未遗忘 发表于 2023-11-30 19:55:11

庄永 发表于 2023-11-30 19:38
DMA中断会占用CPU,看你的应用建议不开DMA中断,使用空闲中断就好了

好嘞,谢谢您

caicaptain2 发表于 2023-12-1 08:14:07


中断里面的代码都需要cpu参与的。
但是,还是有区别。 串口中断打开的话,每收到一个字节都会进中断的,比较费时。 dma中断打开的话,比如dma一次有100个数据,那么只会在第50个数据(传输一半),和第100个数据(传输完成)时候产生中断。

eric2013 发表于 2023-12-1 08:58:43

使用串口DMA中断,特别注意这个问题

等待DMA传输完成后,还有等待TC发送完成标志才是真正的结束。

https://img.anfulai.cn/dz/attachment/forum/202111/06/115811qamtx905z6kzds9x.png

从未遗忘 发表于 2023-12-1 09:10:22

caicaptain2 发表于 2023-12-1 08:14
中断里面的代码都需要cpu参与的。
但是,还是有区别。 串口中断打开的话,每收到一个字节都会进中断的, ...

明白,网上说DMA的数据传送分为预处理、数据传送和后处理3个阶段。

(1)预处理

由CPU完成一些必要的准备工作。首先,CPU执行几条I/O指令,用以测试I/O设备状态,向DMA控制器的有关寄存器置初值,设置传送方向、启动该设备等。然后,CPU继续执行原来的程序,直到I/O设备准备好发送的数据(输入情况)或接受的数据(输出情况)时,I/O设备向DMA控制器发送DMA请求,再由DMA控制器向CPU发送总线请求(统称为DMA请求),用以传输数据。

(2)数据传送

DMA的数据传输可以以单字节(或字)为基本单位,对于以数据块为单位的传送(如银盘),DMA占用总线后的数据输入和输出操作都是通过循环来实现。需要特别之处的是,这一循环也是由DMA控制器(而不是通过CPU执行程序)实现的,即数据传送阶段是完全由DMA(硬件)来控制的。

(3)后处理

DMA控制器向CPU发送中断请求,CPU执行中断服务程序做DMA结束处理,包括检验送入主存的数据是否正确,测试传送过程中是否出错(错误则转入诊断程序)和决定是否继续使用DMA传送其他数据块等。

感觉使用DMA传输怎么都会进入中断的话,会比串口中断好些

从未遗忘 发表于 2023-12-1 09:15:31

eric2013 发表于 2023-12-1 08:58
使用串口DMA中断,特别注意这个问题

等待DMA传输完成后,还有等待TC发送完成标志才是真正的结束。

/**
* @briefClear the DMA Channel pending flags.
* @param__HANDLE__ DMA handle
* @param__FLAG__ specifies the flag to clear.
*          This parameter can be any combination of the following values:
*            @arg DMA_FLAG_TCxTransfer complete flag
*            @arg DMA_FLAG_HTxHalf transfer complete flag
*            @arg DMA_FLAG_TExTransfer error flag
*            @arg DMA_FLAG_GLxGlobal interrupt flag
*         Where x can be from 1 to 8 to select the DMA Channel x flag.
* @retval None
*/
确实,写的时候发现HAL_UART_Transmit_DMA()如果不在发送中断里清标志位只能发送一次然后卡死

yzvip7 发表于 2023-12-1 09:20:22

串口使用DMA,发送和接收都需要打开串口dma中断,其中发送可以直接使用,关心串口最后的回调函数即可,至于接收利用空闲在串口中断里,判断标志位,即可,把接收的缓存设置大点是正常接收量的2-3倍,而可以不关心DMA接收中断,直接调用空闲即可。

skyshine 发表于 2023-12-1 10:39:15

eric2013 发表于 2023-12-1 08:58
使用串口DMA中断,特别注意这个问题

等待DMA传输完成后,还有等待TC发送完成标志才是真正的结束。

如果是usart发送使用DMA,这个TC发送完成标志是dma的TC还是USART的TC,个人感觉应该是后者的,我现在RS485就是等UART的TC标志然后关dma通道,之后转换为接收模式

eric2013 发表于 2023-12-1 16:03:39

skyshine 发表于 2023-12-1 10:39
如果是usart发送使用DMA,这个TC发送完成标志是dma的TC还是USART的TC,个人感觉应该是后者的,我现在RS48 ...

是的,USART的TC

STM32的485串口DMA切换收发的正确姿势
https://www.armbbs.cn/forum.php?mod=viewthread&tid=109441&fromuid=58
(出处: 硬汉嵌入式论坛)

页: [1]
查看完整版本: DMA与回调函数