DMA简述与使用实例

DMA简述与使用实例

之后要学:SPI / IIC+DMA

学习的这位up主的视频:全网最清楚的DMA讲解,三种搬运模式三个例子讲清楚(STM32教程基于HAL库和CUBEIDE)_哔哩哔哩_bilibili

目录

01-基本信息

1-概述

2-方向

3-模式

正常模式

轮询模式

4-地址自增

02-实例一:串口读取陀螺仪

01-基本信息

1-概述

DMA能将外设/内存与外设/内存间建立直接的通道进行数据传输,而无需CPU进行数据的传输,可以将资源用在更合适的地方

2-方向

外设-》内存、内存-》外设,内存-》内存

3-模式

正常模式

只执行一次DMA数据传输,在接收到制定的数据大小之后,结束DMA

轮询模式

可以一直进行数据的传输,不过要注意防止数据的覆盖等,需要特殊的算法进行数据的结算(以后学)

4-地址自增

有这四种自增方式

02-实例一:串口读取陀螺仪

认为适用于接收连续的数据包,协议

1-cubemx配置

配置为正常模式,外设地址不变,内存地址自增

正常模式需要每次调用完成,重新开启DMA,但算法相对简单

当前外设为串口接收寄存器,只有一个地址无需自增

内存需要存放多个数据,所以需要自增,不能覆盖

数据宽度也很重要,但是了解不深,以后再说

串口中断也要打开

在后续处理中,需要用串口中断来进行DMA接收数据完成的判断

2-代码编写

1-初始化

__HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_IDLE); //使能IDLE

//开启DMA接收,

HAL_UART_Receive_DMA(&hlpuart1,uart1_rx_buf, UART1_PACK_SIZE);

DMA接收,只需要设定好初始位置,定义好数组大小、接收数据数目比接收的一帧数据大就行,后续会进行处理

使能IDLE,即空闲中断,之后在中断处理函数中进行处理

2-中断处理函数

在stm32g4xx_it.c中

void LPUART1_IRQHandler(void)

{

/* USER CODE BEGIN LPUART1_IRQn 0 */

extern uint8_t uart1_rx_buf[UART1_PACK_SIZE];//16Byte

extern uint16_t uart1_rx_size;

extern uint8_t uart1_rx_cplt_flag;

uint32_t tmp_flag = 0;

uint32_t temp;

tmp_flag =__HAL_UART_GET_FLAG(&hlpuart1,UART_FLAG_IDLE); //获取IDLE标志位

if((tmp_flag != RESET))//idle标志被置位

{

__HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);//清除标志位

HAL_UART_DMAStop(&hlpuart1);

temp = __HAL_DMA_GET_COUNTER(&hdma_lpuart1_rx);// 获取DMA中未传输的数据个数

uart1_rx_size = sizeof(uart1_rx_buf) - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数

uart1_rx_cplt_flag = 1; // 接受完成标志位置1

}

/* USER CODE END LPUART1_IRQn 0 */

HAL_UART_IRQHandler(&hlpuart1);

/* USER CODE BEGIN LPUART1_IRQn 1 */

/* USER CODE END LPUART1_IRQn 1 */

}

使能IDLE中断后,在串口空闲下便会进入此中断(其他中断会进吗)然后判断串口当前是否空闲,若空闲,代表一帧数据接收完毕,然后结束DMA(之前接收函数比具体数据数量大也没关系就是这个原因,之后会重新开启),使能标志位,之后进行到串口数据处理函数中,便可以进行处理。

ps:一帧数据代表一次发送所有信息,如55 51 aa aa aa 55 52 aa aa aa,此时接受了两个帧头,但因为是一遍发过来的,所以为一帧。

ps:空闲中断只有在接收完成数据后才会打开,发送不会。

ps:所以单片机,openmv的printf,print发送的是什么呢,是一帧还是一个个发送的呢,或许之后可以用打包函数,直接打包数据发送出去就是一帧

3-串口数据处理函数

uint8_t uart1_receiveData_parse(void)

{

uint8_t ret = 1;

//如果接收到数据包

if(uart1_rx_cplt_flag)

{

//数据处理

for(uint8_t i=0;i<99;i++)

{

jy901_read_data(uart1_rx_buf[i]);

}

//清空数据包与标志位

memset(uart1_rx_buf, 0, UART1_PACK_SIZE);

uart1_rx_cplt_flag = 0;

uart1_rx_size = 0;

//重新打开DMA接收

HAL_UART_Receive_DMA(&hlpuart1,uart1_rx_buf, UART1_PACK_SIZE);

}

return ret;

}

注意,这并不是什么接收完成中断之类的,而是一个简单的函数的,需要外界的调用,我将其放在定时器中断函数中,每1ms调用一次函数,则1ms读取一次数据。

03-实例二:另一种DMA收发数据的方案

发送数据:关闭DMA在buffer与串口寄存器的通道,然后将数据写入缓冲区(buffer),全部写入写入后开启通道,则会将所有的数据发出去

接收数据:

若是发送指令后立即读取其反馈,则可以默认关闭DMA通道,然后发送完成指令后立即打开。在空闲中断服务函数中判断,若有,则将缓冲区数组的数据取出并进行计算

相关推荐

dnf真野猪打法装备攻略(真野猪boss怎么打?这几招教你!)
毒霸药膏的功效与作用 毒霸药膏主要有什么功效
365下载手机版

毒霸药膏的功效与作用 毒霸药膏主要有什么功效

📅 07-04 👁️ 9271
《西游记·荆棘岭》
365wm完美体育

《西游记·荆棘岭》

📅 07-13 👁️ 7952