STM32 串口DMA收发数据

一、STM32 DMA简介与功能说明

1、STM32F4 DMA简介

DMA(Direct memory access),即直接存储器访问。用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输的一种方式。它无需CPU参与,也没有中断处理等过程,通过硬件方式为RAM与I/O设备提供一条直接传送数据的通道。 STM32F4有2个DMA控制器,每个DMA控制器有8个数据流,每个数据流有8个通道(或请求)。其中2个DMA的请求映射如下:

2、DMA主要特性

  1. 每个DMA控制器有8个数据流(stream),每个数据流有8个通道
  2. 每个数据有单独的四级32bit先进先出存储器缓冲区(FIFO),可用FIFO模式或直接模式:
    FIFO模式:可通过软件将阈值级别选取为FIFO大小的1/4、1/2或3/4
    直接模式:每个DMA请求会立即启动对存储器的传输。当在直接模式下降DMA请求配置为以存储器到外设模式传输数据时,DMA仅会将一个数据从存储器预加载到内部FIFO,从而保证一旦外设触发DMA请求时则立即传输数据
  3. DMA数据流请求之间的优先级可通过软件编程的方式决定(4个级别:非常高、高、中、低),在软件优先级相同的情况下可以通过硬件决定优先级(例如:请求0的优先级高于请求1)
  4. 要传输的数据的数目可以由DMA控制器或外设管理:
    DMA流控制器:要传输的数据数量范围1~65535,可用软件编程
    外设流控制器:要传输的数据数量未知,由源或目标外设控制
  5. 每个数据流都支持循环缓冲区管理
  6. 有5个事件标志(DMA半传输、DMA传输完成、DMA传输错误、DMA FIFO错误、直接模式错误),进行逻辑或运算,从而产生每个数据流的单个中断请求。

3、DMA传输方向

  1. 外设到存储器的传输
  2. 存储器到外设的传输
  3. 存储器到存储器的传输(仅DMA2可用)

4、DMA事务

DMA事务有给定数目的数据传输序列组成。其数据传输宽度(8bit、16bit、32bit)可用软件编程。
每个DMA传输包含三项操作:

  • 通过DMA_SxPAR(外设)或DMA_SxM0AR(存储器)寄存器寻址,从外设数据寄存器或存储器单元中加载数据。
  • 通过DMA_SxPAR或DMA_SxM0AR寄存器寻址,将加载的数据存储到外设数据寄存器或存储器单元中。
  • DMA_SxNDTR计数器在数据存储结束后递减,该计数器中包含仍需执行的事务数。

5、DMA数据流

8个数据流都可以提供源和目标之间的单向传输链路。
每个数据流配置后都可以执行:

  • 常规类型事务:存储器到外设、外设到存储器或存储器到存储器的传输。
  • 双缓冲区类型事务:使用存储器的两个存储器指针的双缓冲区传输(当DMA正在进行自/至缓冲区的读/写操作时,应用程序可以进行至/自其它缓冲区的写/读操作)

6、源、目标和传输模式

传输方向使用DAM_SxCR寄存器中的DIR[1:0]bit进行配置,有三种传输方向:存储器到外设、外设到存储器或存储器到存储器。相应的源和目标地址如下图:

当传输数据宽度(在DMA_SxCR寄存器的PSIZE或MSIZE位中编程)分别是半字或字时,写入DMA_SxPAR或DMA_SxM0AR/M1AR寄存器的外设或存储器地址必须分别在字或半字地址的边界对齐。

7、指针递增与循环模式

根据DMA_SxCR寄存器中PINC和MINC位的状态,外设和存储器指针在每次传输后可以自动向后递增或保持常量。通过单个寄存器访问外设源或目标数据时,禁止递增模式十分有用,一般使用的是禁止模式。
如果使能了递增模式,则根据在DMA_SxCR寄存器PSIZE或MSIZE位中编程的数据宽度,下一次传输的地址将是前一次传输的地址递增1(对应一个字节)、2(对应半字)或 4(对应字)。
如果将PINCOS位置 1,则不论PSIZE值是多少,下一次传输的地址总是前一次传输的地址递增 4(自动与 32 位地址对齐)。
循环模式可用于处理循环缓冲区和连续数据流(例如ADC扫描模式)。可以使用DMA_SxCR寄存器中的CIRC位使能此特性。当激活循环模式时,要传输的数据项的数目在数据流配置阶段自动用设置的初始值进行加载,并继续响应 DMA 请求。

8、双缓冲模式

通过将DMA_SxCR寄存器中的DBM位置1,即可使能双缓冲区模式。此模式在处理数据量较大的情况下,十分有用,比如开启双缓冲采集摄像头数据。双缓冲模式除了有两个存储器指针之外,数据流的工作方式与常规(单缓冲区)数据流的一样。使能双缓冲区模式时,将自动使能循环模式(DMA_SxCR中的CIRC位的状态是“无关”),并在每次事务结束时交换存储器指针。在此模式下,每次事务结束时,DMA控制器都从一个存储器目标交换为另一个存储器目标。 这样,软件在处理一个存储器区域的同时,DMA传输还可以填充/使用第二个存储器区域。其库函数代码如下:

  /** @param  Memory1BaseAddr: the base address of the second buffer (Memory 1)  * @param  DMA_CurrentMemory: specifies which memory will be first buffer for*         the transactions when the Stream will be enabled. *          This parameter can be one of the following values:*            @arg DMA_Memory_0: Memory 0 is the current buffer.*            @arg DMA_Memory_1: Memory 1 is the current buffer. */
void DMA_DoubleBufferModeConfig(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t Memory1BaseAddr,uint32_t DMA_CurrentMemory)
{  /* Check the parameters */assert_param(IS_DMA_ALL_PERIPH(DMAy_Streamx));assert_param(IS_DMA_CURRENT_MEM(DMA_CurrentMemory));if (DMA_CurrentMemory != DMA_Memory_0){/* Set Memory 1 as current memory address */DMAy_Streamx->CR |= (uint32_t)(DMA_SxCR_CT);    }else{/* Set Memory 0 as current memory address */DMAy_Streamx->CR &= ~(uint32_t)(DMA_SxCR_CT);    }/* Write to DMAy Streamx M1AR */DMAy_Streamx->M1AR = Memory1BaseAddr;
}

注意:在双缓冲区模式下使能数据流时,可遵循下列条件,实时更新 AHB 存储器的基址(DMA_SxM0AR或 DMA_SxM1AR):
● 当DMA_SxCR 寄存器中的CT位为“0”时,可以写入DMA_SxM1AR寄存器。当CT=“1”时,试图写入此寄存器会将错误标志位 (TEIF) 置 1,并自动禁止数据流。
● 当DMA_SxCR 寄存器中的CT位为“1”时,可以写入DMA_SxM0AR寄存器。当CT=“0”时,试图写入此寄存器会将错误标志位 (TEIF) 置 1,并自动禁止数据流。
因此目标存储器依据DMA_SxCR 寄存器中CT值的情况,决定是从存储器 0 更改为 存储器 1(或从存储器 1 更改为存储器 0)。对于所有其它模式(双缓冲区模式除外),一旦使能数据流,存储器地址寄存器即被写保护。

二、发送代码分析

void DMA_UART_RX(void *data, int len)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);    //开启DMA  DMA_DeInit(DMA2_Stream5);while(DMA_GetCmdStatus(DMA2_Stream5) != DISABLE){}   //等待stream可配置,即DMAy_SxCR.EN变为0//配置StreamDMA_InitStructure.DMA_Channel = DMA_Channel_4;          //从8个channel中选择一个DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;            //外设地址DMA_InitStructure.DMA_Memory0BaseAddr = (u32)data;      //存储器0地址,双缓存模式还要使用M1ARDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;            //外设到存储器模式DMA_InitStructure.DMA_BufferSize = len;                //数据传输量,以外设数据项为单位 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //外设地址保持不变DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //存储器地址递增DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据位宽:8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         //存储器数据位宽:8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                         //普通模式(与循环模式对应)DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                   //中等优先级DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                  //禁止FIFO模式         DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;             //单次传输DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;     //单次传输DMA_Init(DMA2_Stream5, &DMA_InitStructure);DMA_Cmd(DMA2_Stream5, ENABLE);
}

由最前面的DMA请求映射图可知,串口1接收对应DMA2数据流5通道4,即相应的配置DMA2_Stream5,DMA_Channel_4。因为是配置的DMA串口接收,所以外设地址对应(u32)&USART1->DR或(0x40011004,查存储器映射表即可);串口接收模式对应的是外设到存储器,故设置为DMA_DIR_PeripheralToMemory。

void USART1_IRQHandler(void)
{ if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  {  USART1->SR;  USART1->DR;//清除SR寄存器IDLE位(读USART_SR,再读USART_DR)DMA_Cmd(DMA2_Stream5, DISABLE);              //关闭DMA        DMA_ClearFlag(DMA2_Stream5, DMA_FLAG_TCIF5); //清除标志位//remian_num = DMA_GetCurrDataCounter(DMA2_Stream5);  //获取当前接收区的剩余长度//设置再次接收//DMA_SetCurrDataCounter(DMA2_Stream2,RX_BUF_LEN);  //设置传输数据长度//DMA_Cmd(DMA2_Stream2,ENABLE);  //打开DMA}
}

此处配置的是利用空闲中断来实现,即当串口数据流停止后,就会产生IDLE中断。利用空闲中断可以很好地判断DMA接收不定长度的数据是否完成,接收数据因此变得十分灵活但要注意的是,在中断里面要清除清除SR寄存器IDLE位(先读USART_SR,再读USART_DR),关闭DMA,清除空闲标志位。

STM32 串口DMA收发(二)相关推荐

  1. 【32单片机学习】(6)STM32串口+DMA收发不定长数据

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1.DMA介绍 2.串口接收数据 3.实验现象 1.实验电路图 2.串口收发不定长数据视频演示 3.OLED 显示接收数据 ...

  2. STM32 串口DMA接收 Openmv / K210 整数、小数字符串数据 (基于HAL库)

    目录 前言 一.工程配置 二.串口DMA部分代码 1.源文件UART_DMA.c 2.头文件UART_DMA.h 3.stm32f1xx_it.c的修改 4.串口收发DMA测试 三.字符串数字提取代码 ...

  3. openmv和stm32串口通信完成二维码识别

    openmv和stm32串口通信完成二维码识别 文章目录 前言 一.所用的硬件: 二.openmv端 2.stm32端 总结 前言 注:我只是个大一的小白,本文只完成基本功能,希望能帮助有困惑的人(我 ...

  4. STM32串口DMA接收双缓冲

    STM32高端MCU(F4.F7等)才支持DMA双缓冲,低端MCU(F1)不支持DMA双缓冲,不过有替代方案可实现类型效果. 一.MCU支持DMA双缓冲的情形 不再赘述,参见博客 STM32 串口DM ...

  5. STM32串口+DMA使用1

    STM32串口+DMA使用 STM32有5个串口资源(USART1,USART2,USART3及UART4,UART5).其中3个USART(通用同步/异步收/发器universalsynchrono ...

  6. 【华大测评】+串口DMA收发数据

    串口传输用中断实现的话,要频繁的进入中断函数,这样无疑增加MCU的负担,干扰正常程序的运行,对于一些实时性强的应用,如数字显示应用中,液晶屏显示可能受影响而不能正常显示.用DMA实现串口收发数据,进行 ...

  7. STM32F0系列串口DMA收发数据

    关于STM32F0系列串口DMA收发数据详解 这里用的库函数版本,芯片型号为stm32f030c8t6.在用到串口DMA时,要按以下几个步骤进行. 1.确定使用的串口号,这里,我用的是usart2,对 ...

  8. STM32 进阶教程 15 - 串口DMA收发

    前言 串口操作相信大家一定很熟悉,如果你已经会串口的收发数据,并可以灵活使用轮询及中断方式对串口进行数据收发,那么恭喜你,学完本节内容后,也将可以学会串口的更高级操作方式,DMA方式,DMA操作串口可 ...

  9. 一个严谨的STM32串口DMA发送接收(1.5Mbps波特率)机制

    文章目录 1 前言 2 串口有必要使用DMA吗 3 实现方式 4 STM32串口使用DMA 5 串口DMA接收 5.1 基本流程 5.2 相关配置 5.3 接收处理 5.3 .1 接收数据大小 5.3 ...

最新文章

  1. C#开发学习——web服务器端控件
  2. Java虚拟机JVM常用的几种回收算法和垃圾回收器
  3. cisco stp技术应用
  4. 爬虫 spider08——爬取腾讯娱乐新闻【使用redis去重】
  5. go语言中go+select的理解
  6. [转载] python——连接Oracle数据库
  7. C#基于两种需求向图片添加水印
  8. 【现代编译器】语法分析——正则表达式,上下文无关文法,递归下降分析,分析树...
  9. python webqq机器人_使用Python的Tornado框架实现一个简单的WebQQ机器人
  10. 喝酒娱乐小游戏微信小程序源码
  11. socks5 转换为 http 代理(使用privoxy)
  12. MATLAB经纬度转化
  13. Docker:镜像加速器
  14. javascript有效的anagram挑战
  15. 网贷逾期会有什么后果,又如何解决呢?
  16. 浪潮ps9.0 oracle,浪潮ERP-PS V9.1安装手册.doc
  17. MapGIS应用操作题
  18. Android APP开发框架选择——JSBridge既个人心得和技巧
  19. kafka监控获取logSize, offset, lag等信息
  20. 我想咨询一下Python,请问在哪儿找资源比较好呀?

热门文章

  1. bj bku hvh vh
  2. 精简指令集-RISC
  3. 示波器万用表源表电源信号发生器频谱仪程控软件,ATECLOUD智能测试平台
  4. 【福利】微信小程序130个精选Demo合集+123套源码视频
  5. 翻新机是这样造出来的
  6. MATLAB R2022b Update4安装包下载及安装教程
  7. Python-Django毕业设计餐厅订餐系统(程序+Lw)
  8. java response 远程 乱码_java-response-乱码解决
  9. 机器学习西瓜书(周志华)第七章 贝叶斯分类器
  10. error C2664: “strcmp”: 不能将参数 1 从“WCHAR [260]”转换为“const char *”