stm32之DMA

   1.DMA直接存储器访问,用来提供外设寄存器(GPIO口,TIMx,USART等)<->存储器(SRAM(程序运行在这个空间),Flash(程序存储在这里面),u8 data[]--都是运行在SRAM空间里的),存储器<->存储器(这种模式不可以和循环模式同时使用)之间数据传送,节省了MCU的资源。

 外设:片上外设:芯片上的,GPIO口,USART等。

        片外外设:连接的外部设备,例如dht11,MQ2等。

  内核:是芯片架构,里面有各种逻辑电路,类似于人脑。

  2.DMA1通道选择:ADC1的DMA通道就是DMA1,不管是ADC1的哪个通道,使用DMA对应的都是DMA1的通道1;同样ADC2对应DMA2的通道2;

    3.DMA的作用:DMA传输方式无需CPU直接控制传输, 也没有中断处理方式那样保留现场和恢复现场过程, 通过硬件为RAM和IO设备开辟一条直接传输数据的通道, 使得CPU的效率大大提高。 

    4.DMA的工作原理
    当用户将参数设置好, 主要涉及源地址、 目标地址、传输数据量这三个, DMA控制器就会启动数据传输, 传输的终点就是剩余传输数据量为0( 循环传输不是这样的) 。换句话说只要剩余传输数据量不是0, 而且DMA是启动状态, 那么就会发生数据传输。 

  5.DMA主要特性

12个独立的可配置的通道(请求)DMA17个通道, DMA25个通道

● 每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。

● 在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推)

● 独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。

● 支持循环的缓冲器管理

● 每个通道都有3个事件标志(DMA半传输、 DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。

● 存储器和存储器间的传输
● 外设和存储器、存储器和外设之间的传输
● 闪存、 SRAM、外设的SRAMAPB1APB2AHB外设均可作为访问的源和目标。
● 可编程的数据传输数目:最大为65535

  6.仲裁器
仲裁器根据通道请求的优先级来启动外设/存储器的访问。
优先权管理分2个阶段:
● 软件:每个通道的优先权可以在DMA_CCRx寄存器中设置,有4个等级:
最高优先级
高优先级
中等优先级
低优先级
● 硬件:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优
先权。举个例子,通道2优先于通道4
注意: 在大容量产品和互联型产品中, DMA1控制器拥有高于DMA2控制器的优先级
  7.DMA的处理过程

  在发生一个事件后, 外设向DMA控制器发送一个请求信号。 DMA控制器根据通道的优先权处理请求。 当DMA控制器开始访问发出请求的外设时, DMA控制器立
即发送给它一个应答信号。 当从DMA控制器得到应答信号时, 外设立即释放它的请求。 一旦外设释放了这个请求, DMA控制器同时撤销应答信号。 如果有更多的
请求时, 外设可以启动下一个周期。

    8.DMA的请求映像

 

 

 

    9.DMA的配置过程(通道1-DMA1为例)

  1.使能DMAx的时钟:RCC->AHBENR |=(1<<0);

    2.是否使用DMA模式:ADCx->CR2的第8位DMA决定--ADC1->CR2 |= (1<<8);

  3.设置模式:存储器到存储器模式、外设<->存储器模式:DMAx的通道几的CCR寄存器的第14位MEM2MEM决定:DMA1_Channel1->CCR &=~(1<<14);//非存储器到存储器模式

  4.设置外设寄存器地址:外设寄存器储存在ADCx->DR中:DMA1_Channel1->CPAR = (u32)&(ADC1->DR);

  5.设置数据寄存的地址:DMA1_Channel1->CMAR = (u32)dmabuff;//dmabuff自己定义的数组的数组名,在进行强转

  6.设置要传输的数据量:DMAx的CNDTR寄存器:DMA1_Channel1->CNDTR = sizeof(dmabuff)/sizeof(dmabuff[0]);

  7.设置通道优先级:DMA1_Channel1->CCR |=(2<<12);

    

   8.设置数据传输方向:DMA1_Channel1->CCR &=~(1<<4);

        

   9.设置循环或非循环模式:DMA1_Channel1->CCR |=(1<<5);

  循环模式用于处理循环缓冲区和连续的数据传输(如ADC的扫描模式)。 在DMA_CCRx寄存器中的CIRC位用于开启这一功能。当启动了循环模式, 数据传输的数目变为0时, 最后一次传输结束时, DMA_CNDTRx寄存器的内容会自动地被重新加载为其初始数值, 内部的当前外设/存储器地址寄存器也被重新加载为DMA_CPARx/DMA_CMARx寄存器 设定的初始基地址, DMA操作将会继续进行。

  当通道配置为非循环模式时, 传输结束后(即传输计数变为0)将不再产生DMA操作。 要开始新的DMA传输, 需要在关闭DMA通道的情况下, 在DMA_CNDTRx寄存器中重新写入传输数目。 

  10.外设增量不增量模式:DMA1_Channel1->CCR &=~(1<<6);

       

   11.存储器增量不增量模式:DMA1_Channel1->CCR |=(1<<7);

  

   12.外设数据宽度:DMA1_Channel1->CCR |=(1<<8);

  

   13.存储器数据宽度:DMA1_Channel1->CCR |=(1<<10);

       

   14.启动DMA通道:

       

   15.启动规则通道转换:ADC1->CR2 |=(1<<22);

/************************库函数类型****************************/

 

 1 void LDR_DMAConfig(void)
 2 {
 3 #if reg_progream
 4     
 5         //使能DMA1时钟
 6     RCC->AHBENR |=(1<<0);
 7     ADC1->CR2 |= (1<<8);//使能ADC  DMA传输
 8     //设置外设寄存器地址
 9     DMA1_Channel1->CPAR = (u32)&(ADC1->DR);
10     //设置数据存储器的地址
11     DMA1_Channel1->CMAR = (u32)dmabuff;
12     //设置要传输的数据量
13     DMA1_Channel1->CNDTR = sizeof(dmabuff)/sizeof(dmabuff[0]);
14     //设置通道的优先级:高
15     DMA1_Channel1->CCR |=(2<<12); 
16     //设置数据传输的方向:从外设读
17     DMA1_Channel1->CCR &=~(1<<4);
18     //非存储器到存储器模式
19     DMA1_Channel1->CCR &=~(1<<14);
20     //循环模式
21     DMA1_Channel1->CCR |=(1<<5);
22     //外设不增量模式
23     DMA1_Channel1->CCR &=~(1<<6);
24     //存储器增量模式
25     DMA1_Channel1->CCR |=(1<<7);
26     //外设数据宽度:16位
27     DMA1_Channel1->CCR |=(1<<8);
28     //存储器数据宽度:16位
29     DMA1_Channel1->CCR |=(1<<10);
30     //启动DMA通道
31     DMA1_Channel1->CCR |=(1<<0);
32     //启动规则通道转换
33     ADC1->CR2 |=(1<<22);
34 #else
35  DMA_InitTypeDef DMA_InitStruct;
36     //使能DMA1时钟
37     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
38     ADC_DMACmd(ADC1,ENABLE);//使能DMA传输
39     //外设基地址
40     DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)&(ADC1->DR);
41     //存储器基地址
42     DMA_InitStruct.DMA_MemoryBaseAddr = (u32)dmabuff;
43     //传输的数据量
44     DMA_InitStruct.DMA_BufferSize = sizeof(dmabuff)/sizeof(dmabuff[0]);
45     //优先级:高
46     DMA_InitStruct.DMA_Priority = DMA_Priority_High;
47     //数据传输的方向:外设为数据源
48     DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
49     //非存储器到存储器模式
50     DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
51     //循环模式
52     DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
53     //外设不增量
54     DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
55     //存储器增量
56     DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
57     //外设数据宽度:16位
58     DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
59     //存储器数据宽度:16位
60     DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
61     DMA_Init(DMA1_Channel1,&DMA_InitStruct);
62     //使能DMA1通道1
63     DMA_Cmd(DMA1_Channel1,ENABLE);
64     
65     //使能指定ADC软件转换功能
66     ADC_SoftwareStartConvCmd(ADC1,ENABLE);
67 #endif
68 }
DMA_Config---配置

 

    10.获取存储值--lenth的数组大小一般是外设数目也可以直接将lenth换成外设数目的具体数值。

 1 void DMA_Value(void)
 2 {
 3 u8 i=0;
 4 //取出转换的数目右移20位是因为前20还是存在的,
 5 //右移20位只不过是把他移到前面了,+1是因为0000表示1
 6 u8 lenth=((ADC1->SQR1 &(0xf<<20))>>20)+1;
 7 for(i=0;i<lenth;i++)
 8 {
 9 printf("dmabuff[%d]=%d ",i,dmabuff[i]);
10 }
11 if(i>=lenth)
12 {
13 printf("\r\n");
14 }
15 }
void DMA_Value(void)

 







 

posted @ 2020-04-16 22:39  听雨书  阅读(1232)  评论(0编辑  收藏  举报