STM32 DMA 传输类型调试记录

外设到内存

模式:单次、外设地址不自增,内存地址自增

c 复制代码
hdma_usart1_rx.Instance = DMA1_Channel5;				// 使用通道 5
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; 	// 方向:外设 to 内存
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;		// 外设地址是否自增:不自增
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;			// 内存地址是否自增:自增
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;	// 外设数据位宽:字节
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;		// 内存数据位宽:字节
hdma_usart1_rx.Init.Mode = DMA_NORMAL;							// DMA 模式:普通,即单次传输
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;				// 优先级:低优先级
c 复制代码
函数原型:
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);
函数使用:
HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);

源地址:(uint32_t)&huart->Instance->DR,即串口的数据寄存器,虽然占 32 位地址空间,但高 24 位为保留位,所以该寄存器保存一个字节。

目的地址:用户自定义的一个 buf

数据长度:传送的数据长度

c 复制代码
HAL_UART_Receive_DMA(&huart1, recv_buf, sizeof(recv_buf));
	/* Enable the DMA transfer for the receiver request by setting the DMAR bit 
       in the UART CR3 register */
    SET_BIT(huart->Instance->CR3, USART_CR3_DMAR); // UART 控制寄存器3,bit6 使能/禁止 DMA 接收

CPU 使能 DMA 传输后,活由 DMA 来干,CPU 就去忙其它事情了。

演示:

模式:循环、外设地址不自增,内存地址自增

c 复制代码
hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; // // DMA 模式:循环

演示:

内存到外设

模式:单次

c 复制代码
    hdma_usart1_tx.Instance = DMA1_Channel4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;	// 内存到外设
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;		// 外设地址不自增
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;			// 内存地址自增
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;	// 外设数据位宽:字节
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;		// 内存数据位宽:字节
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;					// 单次
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
c 复制代码
uint8_t buf[10] = "hello";
HAL_UART_Transmit_DMA(&huart1, buf, sizeof(buf));

DMA 将内存数据 buf10 一个字节一个字节地搬运到串口的数据寄存器,搬运时,内存地址按字节递增,外设地址保持不变。

模式:循环

c 复制代码
hdma_usart1_tx.Init.Mode = DMA_CIRCULAR; // 循环

即 DMA 一遍又一遍地将 buf10 的数据按字节方式依次拷贝到串口的数据寄存器 DR 中。

由于 DMA 搬运效率太高,串口输出太快,可以看到串口助手接收计数增长很猛,但显示的数据不多,串口助手的bug?

将波特率提高到 1500000 再跑下效果

可以看到 DMA 的效率是非常高的。

内存到内存

模式:单次,源地址自增,内存地址自增

c 复制代码
  /* Configure DMA request hdma_memtomem_dma1_channel1 on DMA1_Channel1 */
  hdma_memtomem_dma1_channel1.Instance = DMA1_Channel1;
  hdma_memtomem_dma1_channel1.Init.Direction = DMA_MEMORY_TO_MEMORY;
  hdma_memtomem_dma1_channel1.Init.PeriphInc = DMA_PINC_ENABLE;	// 源地址自增
  hdma_memtomem_dma1_channel1.Init.MemInc = DMA_MINC_ENABLE;	// 目的地址自增
  hdma_memtomem_dma1_channel1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_memtomem_dma1_channel1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  hdma_memtomem_dma1_channel1.Init.Mode = DMA_NORMAL;
  hdma_memtomem_dma1_channel1.Init.Priority = DMA_PRIORITY_LOW;

演示:

模式:单次,源地址自增,内存地址不自增

c 复制代码
  hdma_memtomem_dma1_channel1.Init.PeriphInc = DMA_PINC_ENABLE;	// 源地址自增
  hdma_memtomem_dma1_channel1.Init.MemInc = DMA_MINC_ENABLE;	// 目的地址自增

模式:单次,源地址不自增,内存地址自增

相关推荐
国产化创客1 小时前
创客开发入门(三)Arduino IDE 开发环境
ide·单片机·嵌入式硬件·课程设计·智能硬件
CedarQR1 小时前
LubanCat-2 (RK3568) Debian 下让 H3C Magic USB 无线网卡(AIC8800)联网全记录
linux·网络·单片机·嵌入式硬件·debian·3568·h3c
LongRunning11 小时前
【BLE】STM32WB55_低功耗(十一)
stm32
芯片人00711 小时前
纯硬件一键开关机ASIC芯片,为什么比 MCU 方案更适合更可靠
人工智能·单片机·嵌入式硬件·物联网·芯片
染予12 小时前
Ka 阵面星历下发与执行逻辑说明
stm32·嵌入式硬件
芯片人00713 小时前
武汉广昇科技的GMUX1308A模拟开关芯片成功导入中国台湾上市企业联昌电子,助力汽车电子供应链自主可控
科技·嵌入式硬件·物联网·汽车·芯片
恒锐丰科技林技术员16 小时前
EG2181D 半桥栅极驱动芯片详解:高压 MOS/IGBT 驱动实用器件
经验分享·嵌入式硬件·硬件工程
国科安芯16 小时前
面向卫星测控应答机的抗辐射MCU信号采集与定时控制研究
单片机·嵌入式硬件·mcu·架构·卫星·商业航天·抗辐射
CC城子16 小时前
EtherNet/IP I/O 丢包排查(linux系统)
linux·单片机·tcp/ip·ethernetip
新晨单片机设计17 小时前
S010A-基于STM32单片机水温控制系统(数码管显示)【Proteus仿真+Keil程序+原理图】
stm32·单片机·嵌入式硬件