stm32f407 6个串口dma_STM32实例DMA 实验

    在前面我们提到过 DMA,这一章我们就来学习 STM32F1 的DMA 使

用。要实现的功能是:通过 K_UP 按键控制 DMA 串口 1 数据的传送,在传送过程中让 D2 指示灯不断闪烁,直到数据传送完成。D1 指示灯闪烁提示系统正常运行。学习时可以参考《STM32F10x 中文参考手册》-10 DMA 控制器(DMA)章节。

DMA 简介

    DMA,全称是 Direct Memory Access,中文意思为直接存储器访问。DMA 可用于实现外设与存储器之间或者存储器与存储器之间数据传输的高效性。之所以称为高效, 是因为 DMA 传输数据移动过程无需 CPU 直接操作, 这样节省的 CPU 资源就可供其它操作使用。从硬件层面来理解,DMA 就好像是 RAM 与 I/O 设备间数据传输的通路, 外设与存储器之间或者存储器与存储器之间可以直接在这条通路上进行数据传输。这里说的外设一般指外设的数据寄存器, 比如 ADC、SPI、I2C、DCMI等外设的数据寄存器, 存储器一般是指片内 SRAM、 外部存储器、 片内 Flash等。

    STM32F1 最多有 2 个 DMA 控制器 ( DMA2 仅存在大容量产品中) ,DMA1 有7 个通道。DMA2 有 5 个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个 DMA 请求的优先权。

STM32F1 的 DMA 有以下主要特性:

● 12 个独立的可配置的通道(请求):DMA1 有 7 个通道, DMA2 有 5 个通

● 每个通道都直接连接专用的硬件 DMA 请求,每个通道都同样支持软件触

发。这些功能通过软件来配置。

● 在同一个 DMA 模块上, 多个请求间的优先权可以通过软件编程设置(共有

四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求 0 优先于请求1,依此类推) 。

● 独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。

● 支持循环的缓冲器管理

● 每个通道都有 3 个事件标志(DMA 半传输、 DMA 传输完成和 DMA 传输出错),这3 个事件标志逻辑或成为一个单独的中断请求。

● 存储器和存储器间的传输

● 外设和存储器、存储器和外设之间的传输

● 闪存、 SRAM、外设的 SRAM、 APB1、 APB2 和 AHB 外设均可作为访问的源和目标。

● 可编程的数据传输数目:最大为 65535

DMA 结构框图

    DMA 控制器独立于内核,属于一个单独的外设,结构比较简单,从编程的角度来看,我们只需掌握结构框图中的三部分内容即可。如图所示(大家也可以查看《STM32F10x中文参考手册》-10 DMA 控制器(DMA)章节内容)。

feab303d5a5c3766c22ae4b3d6d187ea.png

    我们把 DMA 结构框图分成3个子模块,按照顺序依次进行简单介绍。

(1)标号 1:DMA 请求

    如果外设要想通过 DMA 来传输数据, 必须先给 DMA 控制器发送 DMA 请求,DMA 收到请求信号之后, 控制器会给外设一个应答信号, 当外设应答后且 DMA 控制器收到应答信号之后,就会启动 DMA 的传输,直到传输完毕。

    根据前面介绍我们知道,DMA 含有 DMA1 和 DMA2 两个控制器,其中 DMA1 含有 7个通道,DMA2 含有 5 个通道,不同的 DMA 控制器的通道对应着不同的外设请求。

    从DMA 请求映射图中可以知道各通道所对应的外设请求,如图分别是DMA1和DMA2请求映射图:

51b760f1afcb8336991d578e4fe4101f.png

075451d6e1c4bf18572fcc480eac3369.png

    DMA2 请求通道中 ADC3、 SDIO 和 TIM8 的 DMA 请求只在大容量产品中存在,这个在具体项目时要注意。

(2)标号 2:DAM 通道

    DMA 具有 12 个独立可编程的通道,其中 DMA1 有 7 个通道, DMA2 有 5个通道,每个通道对应不同的外设的 DMA 请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

(3)标号 3:仲裁器

    当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器也管理。仲裁器管理 DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在 DMA_CCRx 寄存器中设置,有 4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的 DMA 通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高,比如通道 0高于通道 1。在大容量产品和互联型产品中,DMA1 控制器拥有高于 DMA2 控制器的优先级。

DMA 数据配置

    使用 DMA, 最核心就是配置要传输的数据, 包括数据从哪里来, 要到哪里去,传输的数据的单位是什么,要传多少数据,是一次传输还是循环传输等。

(1)从哪里来到哪里去

    我们知道 DMA 传输数据的方向有三个:从外设到存储器,从存储器到外设,从存储器到存储器。具体的方向 DMA_CCR 位 4 DIR 配置:0 表示从外设到存储器, 1 表示从存储器到外设。这里面涉及到的外设地址由

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于STM32F407芯片的串口DMA接收数据的实例代码: ```c #include "stm32f4xx.h" #include <stdio.h> #include <string.h> #define USART1_DR_Address ((uint32_t)0x40011004) char RxBuffer[64]; uint8_t RxCounter = 0; uint8_t RxFlag = 0; void USART_Config(void); void DMA_Config(void); int main(void) { USART_Config(); DMA_Config(); while(1) { if(RxFlag) { printf("Received data: %s\r\n", RxBuffer); RxFlag = 0; memset(RxBuffer, 0, sizeof(RxBuffer)); RxCounter = 0; } } } void USART_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); } void DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); DMA_DeInit(DMA2_Stream2); DMA_InitStructure.DMA_Channel = DMA_Channel_4; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)USART1_DR_Address; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)RxBuffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = sizeof(RxBuffer); DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream2, &DMA_InitStructure); DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); DMA_Cmd(DMA2_Stream2, ENABLE); } void DMA2_Stream2_IRQHandler(void) { if(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TCIF2)) { DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2); RxCounter = sizeof(RxBuffer) - DMA_GetCurrDataCounter(DMA2_Stream2); RxBuffer[RxCounter] = '\0'; RxFlag = 1; } } ``` 在这个例子中,我们使用USART1和DMA2_Stream2来接收串口数据。首先,在USART_Config函数中,我们进行了USART的配置,将USART1的TX和RX引脚分别配置为PA9和PA10,并设置波特率为115200。 接下来,在DMA_Config函数中,我们对DMA进行了配置。我们将DMA的通道设置为4,将DMA的方向设置为从外设到内存,并将DMA的模式设置为循环模式。我们还启用了DMA的中断,并将DMA2_Stream2_IRQHandler函数作为中断处理函数。 最后,在DMA2_Stream2_IRQHandler函数中,我们检查DMA传输完成中断标志位,并清除该标志位。然后,我们通过DMA_GetCurrDataCounter函数计算已经接收到的数据量,并将RxFlag设置为1,表示已经接收到了一条完整的数据。 在主函数中,我们不断地检查RxFlag标志位,如果该标志位为1,则表示已经接收到了一条完整的数据,我们将其打印出来,并将RxFlag和RxBuffer数组清零。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值