当前位置:首页 > 嵌入式 > 嵌入式大杂烩
[导读]之前有个同事因为用串口查询方式发送数据,被我说了一顿,明明有DMA资源,竟然放着不用,对于鱼鹰这种性能强迫症来说,肯定无法忍受,所以当时就和他说,有时间你把它改一下。谁知道过了好几个月他才有时间弄这个,然后还是出了问题,没法子,只能找我解决了。现象是这样的,使用查询方式,一点问题...

之前有个同事因为用串口查询方式发送数据,被我说了一顿,明明有 DMA 资源,竟然放着不用,对于鱼鹰这种性能强迫症来说,肯定无法忍受,所以当时就和他说,有时间你把它改一下。


谁知道过了好几个月他才有时间弄这个,然后还是出了问题,没法子,只能找我解决了。



现象是这样的,使用查询方式,一点问题没有,从机可以正常接收数据,一旦换成 DMA,从机就无法正常解析数据了,从机缓存的数据也不正确。



因为当时我也一脸懵逼,也不知道他做了什么操作导致的,毕竟他调用的 DMA 发送函数都是鱼鹰很久以前写的,也是久经考验的代码,不可能出现问题才对。



所以在没有头绪的情况下,直接同时调试两颗单片机了。



对,你没有看错,就是使用两个调试器同时调试两个单片机。



很简单,就在下面的图中选择即可,估计有很多老司机都不知道这个吧。(不同工程)





这样一台电脑就可以同时调试主机和从机了。



当时首先查看了 DMA 外设和 UART 寄存器情况,发现并没有问题(毕竟如果这个错了,再怎么查应用代码也是没用的,排查问题要讲究先后顺序)。



又在线查了一会发现,如果我在 DMA 发送函数后打上断点,从机是可以正常解析的,这一点又让我疑惑了,所以为了防止从机代码可能有问题,直接让同事用一个串口模块接收数据。



串口助手显示,发送的字节数是正确的,但是只有帧头几个字节对的,其它字节全是错的。



一看到这里,鱼鹰大概就知道了,大概率是 DMA 发送缓冲区被篡改了,一查函数调用,瞬间就明白了是怎么回事,函数调用大概如下(细节没有展示):


void dma_send(DMA_Channel_TypeDef *DMAx, void *buff, uint8_t size)

{

DMAx->CNDTR = size;

DMAx->CMAR = buff;

}


void send_data()

{

uint8_t buff[8];

buff[0] = 1;

buff[1] = 2;

……

dma_send(dma1, buff, 8);

}竟然用局部数组变量作为 DMA 发送的缓冲区,鱼鹰也是醉了。


那么为什么查询方式下,这样的代码不会出错,DMA 方式就错了?



要解答这样的问题,基础必须扎实:


1、DMA 传输原理


2、局部变量存放位置与特性。



只要知道这两点,这个问题就很容易避免。


但事实上,很多人只会大概用,根本没有真正理解。



DMA  串口传输凭什么说效率高?是因为它让串口速率传输更快了吗?一个字节传输本来要 1 ms,用 DMA 只要 0.5 ms?估计很多人都是这么理解的吧。



事实上,DMA 并没有加快传输速率,只不过是把传输的任务转交给专业的而言《数据传输还用 CPU?不如交给 DMA 吧!》,而 CPU 就可以专心干剩下的事情。



注意这里的转交一词,CPU 把必要的传输信息(比如传输地址、大小等)告诉 DMA 后,一般会启动 DMA,之后立刻运行后面的代码,但此时 DMA 缓存地址里面的数据并没全部发送出去,如果这个缓存用的是局部变量,离开这个函数后,局部变量被回收,并会继续给其他函数使用,此时这个缓存的数据就被篡改了,这样 DMA 发送出去的数据当然不正确。



所以,从这个角度来说,DMA 并没有加快串口本身的传输速度,只是解放了 CPU 资源而已。但是 CPU 被解放了, DMA 所使用的 缓存 资源可不能也随之解放呀,只能等发送完毕后才能释放。所以最简单的方法是在 缓存 前面加一个 static 。



那么为什么查询不会出问题呢?查询是把所有缓存中的数据发送出去后,才会离开当前函数,这样局部变量始终存在,也就不会有问题了,不像 DMA 一样扔到缓存里面就溜之大吉,局部变量也随之溜了。



但是,还有一种特殊的局部变量,也能达到全局的效果。这就是操作系统中的主函数的局部变量。


void task()

{

uint32_t buff[32]; // 局部变量,但效果和全局变量差不多。

while(1)

{

}

}因为任务一般会被死循环包含,永不退出(前提条件),所以这里的局部变量也就不会被释放掉,所以有些情况下,为了更好的使用资源,会采用这种方式。


好了,今天的分享到此结束,有收获的话,记得三连支持一波呦!



往期推荐:


解析内核的Makefile、Kconfig和.config之间的关联!


极客感十足的电子胸牌 ART-Badge V2.0开发记录!




本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭