| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 嵌入式 -> YIE002开发探索07-串口(DMA) -> 正文阅读 |
|
[嵌入式]YIE002开发探索07-串口(DMA) |
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365) YIE002开发探索之串口(DMA)在实际应用中,单片机的CPU是最“忙”的,需要完成的任务非常多。因此,CPU资源是非常宝贵的,能够少用就尽量少用,这也能很大程度上提高系统的稳定性。 DMA(直接存储器访问)就是用来解决类似问题的。它用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输,无须CPU干预,就可以实现数据的快速移动。 我曾和朋友开发过一款DTU的产品,是使用STM32单片机和FreeRTOS构建的系统。系统中有三个串口都需要发挥作用,如果只用中断的话,CPU频繁被中断跳转,效率是很低的,根本无法满足现场的数据需求。因此,我们根据应用需求,使用DMA构建了环状的串口数据接收和发送架构,产品最终表现很好。 本篇准备尝试在新的开发方式下,实现串口的DMA数据传输。 1 STM32的DMADMA全称为Direct Memory Access,也即直接存储器访问。CPU完成初始化动作,传输的动作则是由DMA控制器来实现完成的。 典型的例子是移动外设的数据到内存区,这样的操作不需要处理器干预,因此可以让处理器去排程做其他工作。 DMA传输对于高效能嵌入式系统算法和网络很重要,它没有中断处理的现场保留和恢复的过程,通过硬件为内存和外部I/O设备构建直接传输数据的通道,大大提高了CPU的效率。 1.1 STM32的DMA功能STM32 最多有 2 个 DMA 控制器(DMA2 仅存在大容量产品中), DMA1 有 7 个通道。 DMA2 有 5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁起来协调各个 DMA 请求的优先权。 STM32的DMA主要特性如下: 从外设(TIMx、 ADC、 SPIx、 I2Cx 和 USARTx)产生的 DMA 请求,通过逻辑或输入到DMA 控制器,这就意味着同时只能有一个请求有效。外设的 DMA 请求,可以通过设置相应的外设寄存器中的控制位,被独立地开启或关闭。 如图1,给出各外设的DMA对应通道。 当然,DM2也有对应的通道览表。本篇使用的例子中,用的是串口1,其DMA通道是在DMA1下的。想查看更多的信息,请查阅《STM32参考手册》。 对于DMA的寄存器,整理的思维导图如图2所示。 阅读DMA相关的代码时,对寄存器的理解是必不可少的。上一篇中对串口中断的Cube Library的代码进行了跟踪,DMA的处理过程也差不多,就不再细致地跟踪阅读了。 1.2 STM32串口的DMAYIE002开发探索05中,曾经列出了与串口相关的Cube Library的API函数。其中就包含了与DMA相关的两个函数,HAL_UART_Transmit_DMA()(串口DMA模式发送)和HAL_UART_Receive_DMA()(串口DMA模式接收)。 这两个函数的使用方法,与上一篇介绍的HAL_UART_Tramsit_IT()和HAL_UART_Receive_IT()类似。在1.1节中,我们知道,USART1_Tx使用DMA1的通道4,USART1_Rx使用DMA1的通道5。使用过程中,有以下问题需要先搞清楚: 1) USART采用DMA接收时,如何读取当前接收到的字节数? 先回答第2个问题。 以USART1为例,在startup_stm32f103xb.s中,给出了DMA相关的中断函数:
其中,DMA1_Channel4_IRQHandler()为数据发送中断函数(数据从内存发往串口设备);DMA1_Channel5_IRQHandler()为数据接收中断函数(从串口设备接收数据,发往内存)。 而除了USART1的串口中断函数为USART1_IRQHandler()。包括DMA的中断函数在内,这三个函数均定义在stm32f1xx_it.c源文件中。 每个DMA通道都可以在DMA传输过半、传输完成和传输错误时产生中断,可通过设置寄存器的不同位来打开这些中断。 在本篇的示例中,使用的是传输完成时产生中断。而字符串传输完成,是通过串口的IDLE中断来判断的。 也就是说,基本的程序设计为: 在这种情况下,上述三个中断被调用的顺序依次为: USART1_IRQHandler()(实际上是IDLE中断被触发了)-> 下面回答本节的第1个问题。 USART采用DMA接收时,并没有全局变量来表示接收到数据的长度。可以通过DMA通道x传输数量寄存器(DMA_CNDTRx)中包含的数据传输数量,来进行判断。此寄存器中包含了剩余待传输字节数目,在每次DMA传输后递减。 可通过宏__HAL_DMA_GET_COUNTER来实现,其定义如下:
将预先定义的接收总字节数,减去剩余待传输字节数目,就得到了目前接收到的数据字节数了。 对DMA进行了上述了解后,我们进入编程环节。 2 YIE002-STM32的串口编程(DMA)本篇的示例,在上一篇串口(中断)的示例代码基础上进行修改。对于字符串结束的判断(也即数据帧的结束),仍旧通过IDLE中断函数来处理。而串口数据的接收和发送,则改用DMA来实现了。 2.1 串口(DMA)的Cube MX图形配置在Pinout&Configuration栏的Connectivity中,选择USART1的配置界面。之前设置的参数不用修改,主要是添加DMA的处理。USART1的配置界面中,DMA Setting对话框提供了“Add”和“Delete”按钮,可以使用“Add”按钮添加串口的DMA接收和发送,如图3所示。 添加了USART1_RX和USART1_TX两个DMA请求,两者的模式都设置为Normal,数据宽度为字节,其相关的内存地址选择了自动增加。 在添加的过程中,主要它们所用的DMA通道,以及方向就可以了。 对于DMA中断优先级,仍旧可以在System Core的NVIC配置界面上修改。我修改的内容如图4所示。 完成上述配置后,选择GENERATE CODE按钮,生成代码。 2.2 添加应用代码代码的架构,沿用的上一篇的代码。由于采用的DMA传输,串口回调函数HAL_UART_RxCpltCallback()不必编写。主要修改的地方如下: 1) 全局变量
2) 修改主函数main()中的代码
3) 修改IDLE中断处理函数
本篇代码的功能,实际上与上一篇是一样的,测试方法和前两篇完全一样。如本篇开始所说,我曾经使用串口DMA构建了ringbuff的串口环形缓冲区。构建环形缓冲区的基本知识,在本篇中都已经描述过了,有兴趣的话试试吧。 |
|
嵌入式 最新文章 |
基于高精度单片机开发红外测温仪方案 |
89C51单片机与DAC0832 |
基于51单片机宠物自动投料喂食器控制系统仿 |
《痞子衡嵌入式半月刊》 第 68 期 |
多思计组实验实验七 简单模型机实验 |
CSC7720 |
启明智显分享| ESP32学习笔记参考--PWM(脉冲 |
STM32初探 |
STM32 总结 |
【STM32】CubeMX例程四---定时器中断(附工 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 | -2024/12/28 1:39:13- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |
数据统计 |