如何做自己的网站表白,网站建设源代码文件,亿创电力建设集团有限公司网站,品牌推广语什么是DMA#xff1f; DMA(Direct Memory Access#xff0c;直接存储器访问) 提供在外设与内存、存储器和存储器、外设与外设之间的高速数据传输使用。它允许不同速度的硬件装置来沟通#xff0c;而不需要依赖于CPU#xff0c;在这个时间中#xff0c;CPU对于内存的工作来…什么是DMA DMA(Direct Memory Access直接存储器访问) 提供在外设与内存、存储器和存储器、外设与外设之间的高速数据传输使用。它允许不同速度的硬件装置来沟通而不需要依赖于CPU在这个时间中CPU对于内存的工作来说就无法使用。 简单描述就是一个数据搬运工 DMA的意义 代替 CPU 搬运数据为 CPU 减负。
数据搬运的工作比较耗时间数据搬运工作时效要求高有数据来就要搬走没啥技术含量CPU 节约出来的时间可以处理更重要的事。
搬运什么数据 这里的外设指的是spi、usart、iic、adc 等基于APB1 、APB2或AHB时钟的外设而这里的存储器包括自身的闪存(flash)或者内存(SRAM)以及外设的存储设备都可以作为访问地源或者目的。 三种搬运方式
存储器→存储器例如复制某特别大的数据buf存储器→外设 例如将某数据buf写入串口TDR寄存器外设→存储器 例如将串口RDR寄存器写入某数据buf 存储器→存储器 存储器→外设 外设→存储器
DMA 控制器
STM32F103有2个 DMA 控制器DMA1有7个通道DMA2有5个通道。 一个通道每次只能搬运一个外设的数据 如果同时有多个外设的 DMA 请求则按照优先级进行响应。 DMA1有7个通道每个通道都有其能够搬运的外设 DMA2有5个通道
DMA及通道的优先级
优先级管理采用软件硬件 软件 每个通道的优先级可以在DMA_CCRx寄存器中设置有4个等级 最高级高级中级低级 硬件 如果2个请求它们的软件优先级相同则较低编号的通道比较高编号的通道有较高的优先权。 比如如果软件优先级相同通道2优先于通道4
DMA传输方式
DMA_Mode_Normal正常模式 一次DMA数据传输完后停止DMA传送 也就是只传输一次DMA_Mode_Circular循环传输模式 当传输结束时硬件自动会将传输数据量寄存器进行重装进行下一轮的数据传输。 也就是多次传输模式
指针递增模式
外设和存储器指针在每次传输后可以自动向后递增或保持常量。当设置为增量模式时下一个要传输的地址将是前一个地址加上增量值。
实验一、内存到内存搬运
实验要求 使用DMA的方式将数组A的内容复制到数组B中搬运完之后将数组B的内容打印到屏幕。 CubeMX配置 重定向 printf 的话记得将下面这个勾打开 用到的库函数
HAL_DMA_Start HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
参数一DMA_HandleTypeDef *hdmaDMA通道句柄
参数二uint32_t SrcAddress源内存地址
参数三uint32_t DstAddress目标内存地址
参数四uint32_t DataLength传输数据长度。注意需要乘以sizeof(uint32_t)返回值HAL_StatusTypeDefHAL状态OKbusyERRORTIMEOUT__HAL_DMA_GET_FLAG
#define __HAL_DMA_GET_FLAG(__HANDLE__, __FLAG__) (DMA1-ISR (__FLAG__))
参数一HANDLEDMA通道句柄
参数二FLAG数据传输标志。DMA_FLAG_TCx表示数据传输完成标志
返回值FLAG的值SET/RESET代码实现
开启数据传输等待数据传输完成打印数组内容
#define BUF_SIZE 16// 源数组uint32_t srcBuf[BUF_SIZE] {0x00000000,0x11111111,0x22222222,0x33333333,0x44444444,0x55555555,0x66666666,0x77777777,0x88888888,0x99999999,0xAAAAAAAA,0xBBBBBBBB,0xCCCCCCCC,0xDDDDDDDD,0xEEEEEEEE,0xFFFFFFFF};// 目标数组uint32_t desBuf[BUF_SIZE];int fputc(int ch, FILE *f)
{ unsigned char temp[1]{ch};HAL_UART_Transmit(huart1,temp,1,0xffff); return ch;
}main函数里// 开启数据传输HAL_DMA_Start(hdma_memtomem_dma1_channel1, (uint32_t)srcBuf, (uint32_t)desBuf, sizeof(uint32_t) * BUF_SIZE);// 等待数据传输完成while(__HAL_DMA_GET_FLAG(hdma_memtomem_dma1_channel1, DMA_FLAG_TC1) RESET);// 打印数组内容for (i 0; i BUF_SIZE; i)printf(Buf[%d] %X\r\n, i, desBuf[i]);实验二、内存到外设搬运
实验要求 使用DMA的方式将内存数据搬运到串口1发送寄存器同时闪烁LED1。 CubeMX配置 DMA配置 用到的库函数 HAL_UART_Transmit_DMA
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
参数一UART_HandleTypeDef *huart串口句柄
参数二uint8_t *pData待发送数据首地址
参数三uint16_t Size待发送数据长度
返回值HAL_StatusTypeDefHAL状态OKbusyERRORTIMEOUT代码实现
准备数据将数据通过串口DMA发送
#define BUF_SIZE 1000// 待发送的数据unsigned char sendBuf[BUF_SIZE];main函数里// 准备数据for (i 0; i BUF_SIZE; i)sendBuf[i] A;// 将数据通过串口DMA发送HAL_UART_Transmit_DMA(huart1, sendBuf, BUF_SIZE);while (1)
{HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);HAL_Delay(100);
}实验三、外设到内存搬运
实验要求 使用DMA的方式将串口接收缓存寄存器的值搬运到内存中同时闪烁LED1。 CubeMX配置 DMA配置 串口中断配置 用到的库函数
__HAL_UART_ENABLE
#define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((((__INTERRUPT__) 28U) UART_CR1_REG_INDEX)? ((__HANDLE__)-Instance-CR1 | ((__INTERRUPT__)
UART_IT_MASK)): \
(((__INTERRUPT__) 28U) UART_CR2_REG_INDEX)? ((__HANDLE__)-Instance-CR2 | ((__INTERRUPT__)
UART_IT_MASK)): \
((__HANDLE__)-Instance-CR3 |((__INTERRUPT__) UART_IT_MASK)))
参数一HANDLE串口句柄
参数二INTERRUPT需要使能的中断
返回值无HAL_UART_Receive_DMA
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
参数一UART_HandleTypeDef *huart串口句柄
参数二uint8_t *pData接收缓存首地址
参数三uint16_t Size接收缓存长度
返回值HAL_StatusTypeDefHAL状态OKbusyERRORTIMEOUT__HAL_UART_GET_FLAG
#define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)-Instance-SR
(__FLAG__)) (__FLAG__))
参数一HANDLE串口句柄
参数二FLAG需要查看的FLAG返回值FLAG的值__HAL_UART_CLEAR_IDLEFLAG
#define __HAL_UART_CLEAR_IDLEFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__)
参数一HANDLE串口句柄
返回值无HAL_UART_DMAStop
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)
参数一UART_HandleTypeDef *huart串口句柄
返回值HAL_StatusTypeDefHAL状态OKbusyERRORTIMEOUT__HAL_DMA_GET_COUNTER
#define __HAL_DMA_GET_COUNTER(__HANDLE__) ((__HANDLE__)-Instance-CNDTR)
参数一HANDLE串口句柄
返回值未传输数据大小代码实现 如何判断串口接收是否完成如何知道串口收到数据的长度 使用串口空闲中断IDLE
串口空闲时触发空闲中断空闲中断标志位由硬件置1软件清零
利用串口空闲中断可以用如下流程实现DMA控制的任意长数据接收 使能IDLE空闲中断 使能DMA接收中断 收到串口接收中断DMA不断传输数据到缓冲区 一帧数据接收完毕串口暂时空闲触发串口空闲中断 在中断服务函数中清除中断标志位关闭DMA传输防止干扰 计算刚才收到了多少个字节的数据。 处理缓冲区数据开启DMA传输开始下一帧接收。 有三个文件需要修改 main.c
uint8_t rcvBuf[BUF_SIZE]; // 接收数据缓存数组uint8_t rcvLen 0; // 接收一帧数据的长度__HAL_UART_ENABLE_IT(huart1, UART_IT_IDLE); // 使能IDLE空闲中断HAL_UART_Receive_DMA(huart1,rcvBuf,100); // 使能DMA接收中断while (1)
{HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);HAL_Delay(300);
}main.h
#define BUF_SIZE 100stm32f1xx_it.c
extern uint8_t rcvBuf[BUF_SIZE];extern uint8_t rcvLen;void USART1_IRQHandler(void)
{/* USER CODE BEGIN USART1_IRQn 0 *//* USER CODE END USART1_IRQn 0 */HAL_UART_IRQHandler(huart1);/* USER CODE BEGIN USART1_IRQn 1 */if((__HAL_UART_GET_FLAG(huart1,UART_FLAG_IDLE) SET)) // 判断IDLE标志位是否被置位{ __HAL_UART_CLEAR_IDLEFLAG(huart1);// 清除标志位HAL_UART_DMAStop(huart1); // 停止DMA传输防止干扰uint8_t temp__HAL_DMA_GET_COUNTER(hdma_usart1_rx); rcvLen BUF_SIZE - temp; //计算数据长度HAL_UART_Transmit_DMA(huart1, rcvBuf, rcvLen);//发送数据HAL_UART_Receive_DMA(huart1, rcvBuf, BUF_SIZE);//开启DMA}/* USER CODE END USART1_IRQn 1 */}