前言: 上一内容ADC多路采集数据之前用的是DR数据寄存器,CPU需要不停访问轮询,一路采集完成才能采集另一路,非常消耗资源。DMA是通过DR数据寄存器,采集完后发一个DMA数据请求,然后会把数据放到内存中去,实现一个搬运工的角色,释放了CPU。
目录
1、实验要求:利用ADC采集电位器以及芯片内部温度传感器的数据,在main函数中启动ADC转换以及DMA传输,最后在DMA完成中断中打印采集到的数据。
一、DMA基本概念
(1)DMA简介
DMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。
二、STM32DMA功能框图分析
中午参考手册9.3
1、外设通道
STM32F4xx 系列资源丰富,具有两个 DMA 控制器,同时外设繁多,为实现正常传输,DMA需要通道选择控制。每个 DMA控制器具有 8个数据流,每个数据流对应 8个外设请求。 外设通道选择要解决的主要问题是决定哪一个外设作为该数据流的源地址或者目标地址。
注: DMA控制器会通过 DMA数据流 x 配置寄存器 DMA_SxCR的 CHSEL[2:0]位选择对应的通道作为该数据流的目标外设。
2、数据量仲裁
一个 DMA控制器对应 8个数据流,数据流包含要传输数据的源地址、目标地址、数据长度等等信息。如果我们需要同时使用同一个 DMA 控制器(DMA1 或 DMA2)多个外设请求时,那必然需要同时使用多个数据流,那究竟哪一个数据流具有优先传输的权利呢?这就需要仲裁器来管理判断了
数据流传输优先级配置配置
- 1DMA_SxCR寄存器 PL[1:0]位,可以设置为非常高、高、中和低四个级别
- 2如果两个或以上数据流软件设置优先级一样,则他们优先级取决于数据流编号,编号越低越具有优先权
3、数据FIFO
每个数据流都有一个独立的 “4 字 ”FIFO(先进先出存储器缓冲区)。 DMA传输具有 FIFO模式和直接模式。
a.直接模式
每个 DMA 请求会立即启动对存储器的传输。当在直接模式(禁止 FIFO)下将 DMA请求配置为以存储器到外设模式传输数据时,DMA 仅会将一个数据从存储器预加载到内部 FIFO,从而确保一旦外设触发 DMA 请求时则立即传输数据。
b.FIFO模式
可通过控制寄存器 DMA_SxFCR 的 FTH[1:0]位来设置FIFO 阈值级别为 FIFO 大小的 1/4、1/2 或 3/4。如果数据存储量达到阈值级别时,FIFO 内容将传输到目标中。
4、存储器端 同下
5、外设端口口
DMA 控制器提供两个 AHB 主端口:AHB 存储器端口 (用于连接存储器)和 AHB 外设端口(用于连接外设)。
但是,要执行存储器到存储器的传输,AHB 外设端口 必须也能访问存储器。所以 DMA1 不能实现存储器到存储器传输。
三、STM32DMSA传输
1、DMA传输模式
模式选择可以通过 DMA_SxCR 寄存器的 DIR[1:0]位控制
- DMA1 只有外设到存储器和存储器到外设两种模式
- DMA2 除前面两种外还支持存储器到存储器的传输模式。
2、DMA传输的源、目的、长度
- DMA_SxPAR寄存器: 设置外设寄存器地址
- DMA_SxM0AR寄存器:设置存储器地址
- DMA_SxCR 寄存器 : DIR[1:0]位配置数据的传输方向
- DMA_CNDTRx 寄存器: 写入需要传输的数据量, (0 到 65535)
- DMA_SxCR 寄存器中的 PSIZE 和 MSIZE 位:设置源和目的的数据宽度,两边的位宽尽量保持一致
3、DMA增量设置
- 根据设置 DMA_SxCR 寄存器中 PINC 和 MINC 位的状态,外设和存储器指针在每次传输后可以自动向后递增或保持常量。
- 当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值,增量值取决与所选的数据宽度为 1 、 2 或 4 。
4、DMA循环模式
- 循环模式用于处理循环缓冲区和连续的数据传输 ( 如 ADC 的扫描模式 ) 。可以使用 DMA_SxCR寄存器中的 CIRC 位使能此特性。
- 当启动了循环模式,一组的数据传输完成时,计数寄存器将会自动地被恢复成配置该通道时设置的初值, DMA 操作将会继续进行。
5、DMA单次传输和突发传输
- DMA传输类型有单次(Single)传输和突发(Burst)传输。DMA 控制器可以产生单次传输或 4 个、8 个和 16 个节拍的增量突发传输。
- 突发大小通过软件针对两个 AHB 端口独立配置,配置时使用 DMA_SxCR 寄存器中的MBURST[1:0] 和 PBURST[1:0] 位。
- 为确保数据一致性,形成突发的每一组传输都不可分割:在突发传输序列期间,AHB 传输会锁定,并且 AHB 总线矩阵的仲裁器不解除对 DMA 主总线的授权。
四、STM32DMA中断
对于每个 DMA 数据流,可在发生以下事件时产生中断:
- 达到半传输
- 传输完成
- 传输错误
- FIFO 错误(上溢、下溢或 FIFO 级别错误)
- 直接模式错误
注:这些标志位都在中断状态寄存器DMA_xISR中设置
五、DMA多路采集实例
1、实验要求:利用ADC采集电位器以及芯片内部温度传感器的数据,在main函数中启动ADC转换以及DMA传输,最后在DMA完成中断中打印采集到的数据。
利用DMA的好处:
- 多路采集数据之前用的是DR数据寄存器,CPU需要不停访问轮询,一路采集完成才能采集另一路,非常消耗资源
- DMA是通过DR数据寄存器,采集完后发一个DMA数据请求,然后会把数据放到内存中去,可以用buf[]接收,一般设置为递增方式存储4
2、cubmx配置
和上一内容一样,开启168Mhz时钟,串口打印,pa5 adc1in,温度adc采集
使能DMA
配置DMA
3、编程思路
1实现一个printf重定义方便调试打印
2主函数中循环开启adcDMA方式采集,延时1s
3回调函数中打印采集信息
我们先追一下源码:
我们改写这个函数
//放在adc.c文件下,因为属于adc的回调函数
extern uint16_t adc_value[2] ;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance == ADC1)
{
printf("adc_value[0]=%d, adc_value[1]=%d\n",adc_value[0],adc_value[1]);
}
}
main函数
int fputc(int ch,FILE *p) //printf函数重定向
{
while(!(USART1->SR & (1<<7)));
USART1->DR = (uint8_t)ch;
return ch;
}
uint16_t adc_value[2] = {0};
/* USER CODE END 0 */
/**
* @brief The application entry point.
*
* @retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
printf("this is DMA_test\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)adc_value,2); //开启DMA
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
4、实验效果