当前位置: 首页 > article >正文

STM32数据搬运工DMA

   DMA的概念

        DMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。

● 5 个独立的可配置通道 ( 请求 )

● 每个通道都直接连接专用的硬件 DMA 请求

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

中等和低 )

● 独立数据源和目标数据区的传输宽度 ( 字节、半字、全字 ) 源

和目标地址必须按数据传输宽度对齐

● 支持循环的缓冲器管理

● 每个通道都有 3 个事件标志 (DMA 半传输、 DMA 传输完成和 DMA 传输出错 )

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

● 外设到存储器和存储器到外设,外设到外设间的传输

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

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

注:可修改SYSCFG_CFGR1来配置通道的映射关系

DMA通道优先级

仲裁器根据优先级管理着通道的请求和启动外设 / 存储器的访问

优先级管理分两个方面:

● 软件:可通过 DMA_CCRx 寄存器配置每个通道的优先级,优先级分4个等级:

- 最高优先级

- 高优先级

- 中等优先级

- 低优先级

● 硬件:如果 2 个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高

的优先权。举个例子,通道 2 优先于通道 4 

传输模式

1个DMA控制器,5个可独立配置的通道。所有通道都支持memory to memory的传输、外设到外设的传输、以及外设和memory之间的传输

源、目的、长度 

l  DMA_CPARx 寄存器:  设置外设寄存器地址
l  DMA_CMARx 寄存器:设置存储器地址
l  DMA_CCRx 寄存器   : 配置数据的传输方向

    如果是存储器到存储器模式,需配置DMA_CCRx的MEM2MEM位

l DMA_CNDTRx 寄存器: 写入需要传输的数据量, (0 到 65535)
l DMA_CCRx 寄存器中的 PSIZE 和 MSIZE 位:

   设置源和目的的数据宽度,两边的位宽尽量保持一致

 增量设置

l  通过设置 DMA_CCRx 寄存器中的 PINC 和 MINC 标志位,外设和存储器的指针在每次传输后可以有选择地完成自动增量
l  当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值,增量值取决与所选的数据宽度为 1 、 2 或 4 。

循环模式

l 循环模式用于处理循环缓冲区和连续的数据传输 ( 如 ADC 的扫描模式 ) 。在 DMA_CCRx 寄存器中的 CIRC 位用于开启这一功能。
l 当启动了循环模式,一组的数据传输完成时,计数寄存器将会自动地被恢复成配置该通道时设置的初值, DMA 操作将会继续进行

中断

每个 DMA 通道都可以在 DMA 传输过半、传输完成和传输错误时产生中断。为应用的灵活性考虑,通过设置寄存器的不同位来打开这些中断 

注:这些标志位都在中断状态寄存器DMA_ISR中设置 

实验要求:

 

  利用ADC采集按键以及光照传感器的数据,在按键中断处理程序中启动DMA传输,

最后在DMA完成中断中打印采集到的数据

 

 

 

 F0没有FIFO,高端一些的单片机有,可以解决源和目的位数不一致问题

extern uint16_t adc_value[2];
 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
 {
	printf("key adc value = %d\n",adc_value[0]);
	printf("light adc value = %d\n",adc_value[1]);
	
	memset(adc_value,0,sizeof(adc_value));
	 
	HAL_ADC_Stop_DMA(hadc);
 }
uint16_t adc_value[2] = {0};

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == GPIO_PIN_8)
	{
		 HAL_ADC_Start_DMA(&hadc, (uint32_t *)adc_value, 2);
	}
}
int fputc(int ch, FILE *f)
{
	while(!(USART1->ISR & (1<<7)));
	
	USART1->TDR = ch;
	
	return  ch;
}

---------------------------------------------------------------------------------------------------------------------------------

解决一下我的timer2定时器问题

用cubemx生成的RCC时钟配置自动选择了两个源

HSI和HSE,正常应该只是用HSE的不知道是不是cubemx的bug


http://www.kler.cn/a/3400.html

相关文章:

  • Class1(2020):Shell基础(一)——Shell概念
  • 计算机视觉算法实战——无人机检测
  • OpenCV:高通滤波之索贝尔、沙尔和拉普拉斯
  • 困境如雾路难寻,心若清明步自轻---2024年创作回顾
  • 在 C++ 中实现调试日志输出
  • 华为OD机试真题---战场索敌
  • 【贪心算法】一文让你学会“贪心”(贪心算法详解及经典案例)
  • 2023-第十四届蓝桥杯冲刺计划!
  • 蓝桥杯冲刺 - week2
  • HFish蜜罐的介绍和简单测试(三)
  • 【蓝桥杯集训·每日一题】AcWing 3662. 最大上升子序列和
  • 【Vue3】用Element Plus实现列表界面
  • Unity | 发布Android的那些事儿
  • Spring - Spring 注解相关面试题总结
  • 新人使用Git获取远程仓库项目
  • Html5版飞机大战游戏中(Boss战)制作
  • 你的应用太慢了,给我司带来了巨额损失,该怎么办
  • 【Python入门第三十六天】Python丨文件写入
  • 【蓝桥杯嵌入式】第十三届蓝桥杯嵌入式国赛客观题以及详细题解
  • 使用C++编写一个AVL的增删改查代码并附上代码解释
  • Java_Spring:3. IoC 的概念和作用-程序的耦合和解耦
  • c#文案语音配图片一键生成视频
  • 【设计模式-工厂方法】想象力和创造力:你考虑过自动化实现工厂吗?
  • 建堆、堆排序、TopK问题大合集
  • 一文让你吃透 Vue3中的组件间通讯 【一篇通】
  • 【Docker】Compose容器编排LNMP上云