找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 11927|回复: 1
收起左侧

关于STM32 DMA重新使能的话题

[复制链接]
ID:98618 发表于 2016-11-1 00:05 | 显示全部楼层 |阅读模式
有人发现当DMA配置为normal模式,一轮传输完成后再使能同一DMA数据流时,即使有DMA请求产生,DMA根本不进行数据传输。这里不妨以STM32F4为例聊聊该话题。


其实,在非循环模式下配置的DMA数据流传输结束后(即要传输的数据数目达到零),除非软件重新对数据流编程并使能该数据流(通过将 DMA_SxCR 寄存器中的 EN 位置 1),否则DMA 会停止传输(硬件会将 DMA_SxCR 寄存器中的EN 位清零)并不再响应任何 DMA 请求。也就是说,当一轮DMA传输完成后,简单来一句 __HAL_DMA_ENABLE(hdma)并不能再次重启DMA传输,必须先行对数据流重新进行初始化配置,然后使能该DMA数据流。


不过,要对STM32F4系列内部各DMA数据流进行配置,首先要保证 DMA_SxCR 寄存器中的 EN 位已被清零。一般来讲,在进行DMA数据流配置前,先对该EN位进行写0去禁用该DMA流,然后读取此位以确认没有正在进行的数据流传输操作。将此位写 0 可能不会立即生效,因为只有当前所有传输都已完成时才会将其写为 0。当读取到 EN 位为 0 时,才可以配置DMA数据流。配置完成后,如果是再次配置的话,记得将先前的DMA 传输中在状态寄存器(DMA_LISR 和 DMA_HISR)中置 1 的所有数据流专用位置0, 然后重新使能数据流,即将 DMA_SxCR 寄存器中的 EN位置 1 激活数据流。


OK,这里拿个实际案例看看以加深下印象。


有人用STM32F4芯片做产品,他是基于STM32CUBE库做应用开发。用DMA做USART通信的数据传输,DMA配置为循环模式

他发现HAL_UART_Transmit_DMA()这个函数在做了一次DMA配置后,第二次使用它更新配置时无法生效。比如按下面步骤操作:


1HAL_UART_Transmit_DMA(&huart1,DataBuff, 10);

2HAL_UART_DMAPause(&huart1);                           

3 HAL_UART_Transmit_DMA(&huart1,&DataBuff[5],5); 

4HAL_UART_DMAResume(&huart1);                           

             

开发者的目的是希望先将DataBuff[0]至DataBuff[9]10个数据传到串口上去。中途调整DMA配置[即第【3】句],然后发送DataBuff[5]至DataBuff[9]的5个数据到串口助手上去。


结果发现经过2次配置后的结果没变,发送的都是DataBuff[0]至DataBuff[9]的10个数据。为什么呢?不妨一起看看。

上面第【1】句做usart TX的DMA传输配置。循环从DataBuf处开始取10个数据送往串口;

接着第【2】句是在DMA完成中断里进行。暂停USART TX传输的DMA请求,并延时2S;

然后第【3】句再做USART TX的DMA配置,循环从&DataBuf【5】处开始取5个数据送往串口;

最后第【4】句重新开启USART TX的DMA传输;


按照上面几步也貌似条理清晰,有根有据。可结果为什么发现第【3】句的二次配置没法生效呢?


从前面的描述我们得知,如果需要对某STREAM进行DMA配置的话,首先须DISABLE该STREAM,即先对DMA_SxCR寄存器的EN位清零。而且这个清零并不一定立即生效,必须保证该STREAM当前没有在进行DMA传输。所以,做清零操作后,还要去读该EN位,直至读到该位为0后方能对该DMA STREAM 进行再次配置

HAL_UART_Transmit_DMA()函数里有对DMA_SxCR的EN位清零的动作,不过没有读取确认的动作。复位后DMA_SxCR寄存器的EN位默认是0毫无疑问,所以复位后第【1】句用HAL_UART_Transmit_DMA()函数配置后生效自然没问题。


上面的第2】句在DMA完成中断里进行,暂停UART TX的DMA请求,还延时了2S。本意是想让DMA停下来,为后面二次配置做准备。但他这里只是暂停了DMA请求,加上这里配置DMA为循环模式,也就是说在进入DMA完成中断时,DMA又做了下一轮传输的准备,其中包括传输数据项数目寄存器DMA_SxNDTR的重装。此时尽管暂停了DMA请求,但该DMA流是处于传输未完成状态。


那么紧跟着的第【3】句对USART TX的DMA二次配置,HAL_UART_Transmit_DMA()函数里虽然有对DMA_SxCR的EN位清零,但由于此时该STREAM处于传输未完成状态,所以无法实现最终清零。


既然无法对EN位清零,相关配置就无法写入生效。加上该函数没有对EN位是否为0的未做进一步确认判断,自然而然地下行到第【4】句重新开启USART TX的DMA传输。最后的结果当然还是按照老配置运行了。【有心的话,可以去STM32F4参考手册看看数据流 x 配置寄存器 DMA_SxCR,里面多个参数只有在EN位为0时方可进行写操作

 

好了,就此打住。MCU开发中不少问题往往可能就卡在技术手册看得不到位。在开发过程中遇到难解问题时,有时细心看看手册的相关部分,或许会有踏破铁鞋无觅处,得来全不费工夫的感觉。

回复

使用道具 举报

ID:303001 发表于 2018-8-23 13:17 | 显示全部楼层
朋友,多谢你这篇帖子,我今天找了一上午DMA使能无效的问题,看过你这篇文章后,醍醐灌顶啊!问题终于解决,多谢!这次问题提醒我,以后得多看看手册,即便是用库编程。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表