你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

物联网之STM32开发七(数据搬运工DMA)

[复制链接]
STMCU-管管 发布时间:2020-9-28 10:54
STM32数据搬运工-DMA内容概要:
4 |( A+ C6 _3 Q) d0 X% s$ i  B

STM32-DMA工作原理

ADC_DMA多路采集实例

: x7 s6 R1 {& {0 K


9 H1 p4 @; M$ M- D9 C% v0 D& a7 X, e

STM32-DMA工作原理) O6 f* O+ C2 R8 B
8 C  S' C0 N% Q4 g6 x& E0 d

内容概要:

DMA简介

STM32F0-DMA通道

STM32F0-DMA传输

STM32F0-DMA中断

DMA简介:

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


. {9 Q- Q8 }" ?$ q  o( ]

1_meitu_7.jpg

0 G( A1 x5 G! f% H8 Q7 A$ H
" w* f3 K0 n# {& b

注:正常情况下,数据之间的传输先将数据传输到微处理器的寄存器中,然后再从寄存器中将数据传输到目标

        DMA模式下:ADC传输数据到内存储器中,首先由ADC向DMA发出请求,DMA申请使用总线,然后控制ADC和存储器之间的数据传输。无需CPU的干扰。

STM32F0-DMA简介:

DMA功能框图和特性:

2_meitu_8.jpg

● 5 个独立的可配置通道 ( 请求 ) (因为只有一条总线,所以同一时刻只能使用一个通道传输,可通过仲裁器Arbiter设置优先级,确定哪个通道先传输)

● 每个通道都直接连接专用的硬件 DMA 请求 (DMA可以直接与外设等进行数据传送)

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

● 独立数据源和目标数据区的传输宽度 ( 字节、半字、全字 ) 源 和目标地址必须按数据传输宽度对齐

● 支持循环的缓冲器管理

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

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

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

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

● 可编程的数据传输数目:最大为 65536(16位)

. i" ^) ?1 a0 [8 p% p

/ [; b! Y6 A+ q# h* p: |9 i

STM32F0-DMA通道:

3_meitu_9.jpg

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

STM32F0-DMA通道的优先级:

仲裁器根据优先级管理着通道的请求和启动外设 / 存储器的访问(同一时刻只能有一个通道传输数据)

优先级管理分两个方面:

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

- 最高优先级

- 高优先级

- 中等优先级

- 低优先级

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


/ e) }7 {3 y# w. b1 C


; z+ M0 E9 {& }8 K8 b% G* \0 R6 P

STM32F0-DMA传输:

4_meitu_10.jpg

' ]( r- Y) O; P+ b

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

DMA传输的源、目的、长度:

    DMA_CPARx 寄存器:  设置外设寄存器地址  

    DMA_CMARx 寄存器:设置存储器地址  

    DMA_CCRx 寄存器   : 配置数据的传输方向(外设传输数据传输到存储器,或者存储器数据传输到外设), 如果是存储器到存储器模式,需配置DMA_CCRx的MEM2MEM位  

    注:如果是两个外设之间的数据传输,则将其中一个外设寄存器地址填写到DMA_CMARx 寄存器,如果是两个内存之间的数据传输,则将其中一个内存的地址写入DMA_CPARx 寄存器。

    DMA_CNDTRx 寄存器: 写入需要传输的数据量, (0 到 65535)  

    DMA_CCRx 寄存器中的 PSIZE 和 MSIZE 位:设置源和目的的数据宽度(比如都设置成16位),两边的位宽尽量保持一致

DMA增量设置:

    通过设置 DMA_CCRx 寄存器中的 PINC 和 MINC 标志位,外设和存储器的指针在每次传输后可以有选择地完成自动增量

    当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值,增量值取决与所选的数据宽度为 1 、 2 或 4 。

DMA循环模式:

    循环模式用于处理循环缓冲区和连续的数据传输 ( 如 ADC 的扫描模式 ) 。在 DMA_CCRx 寄存器中的 CIRC 位用于开启这一功能。(如摄像头的覆盖存储)

    当启动了循环模式,一组的数据传输完成时,计数寄存器将会自动地被恢复成配置该通道时设置的初值, DMA 操作将会继续进行。

STM32F0-DMA中断:

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

5_meitu_11.jpg

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


7 H: J4 O; d" c


) D* ]: v4 \: @9 C, a

ADC_DMA多路采集实例
' Z$ k8 c+ _2 \* k8 w+ Z7 k8 |- I, \  l5 V: }

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

电路连接:

6_meitu_12.jpg

实验过程:

7_meitu_13.jpg

8_meitu_14.jpg

9_meitu_15.jpg

10_meitu_16.jpg

11_meitu_17.jpg

12_meitu_18.jpg

重写fputc函数:

13_meitu_1.jpg

+ @$ v5 c, I7 R6 r0 U" j+ y9 g  a8 \
  1. int fputc(int ch,FILE *f){        
    , Q- \5 `- H: E4 Y# d
  2.     while((USART1->ISR&(1<<7)) == 0);        + \3 n5 J3 m  I6 j' \5 i  H
  3.     USART1->TDR=(uint8_t)ch;$ S9 a! R- \& f* I# F% F/ s
  4.     return ch;
    1 c$ a. o+ g0 o4 `
  5. }
复制代码

2 t. c  y/ ?; n" q

追加到GPIO中断的回调函数并重写回调函数:

4 ^1 G# c0 Q  O7 G+ I+ T' r


9 P! `: B5 G. y0 a% ?( m( j% @

                                                                   14_meitu_2.jpg

15_meitu_3.jpg


( D) X0 H4 }, P, f/ U4 c* A
; F  o5 D) O3 V8 M% V
  1. ​uint16_t adc_value[2] = {0};
      I# I0 O9 C! z: h  Y* M

  2. . _+ r2 h: P: |  V, H
  3. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)+ n0 _3 `, p0 c4 L, q% w
  4. {
    8 Y2 K$ ~/ ]5 V; L5 _' {9 |
  5.         if(GPIO_PIN_8 == GPIO_Pin)
    ; c  E; R2 ~7 G
  6.         {" s' H, S4 A5 w: g6 W
  7.                 HAL_ADC_Start_DMA(&hadc, (uint32_t*)adc_value, 2); /*启动ADC 和 DMA,使能DMA中断$ T: D6 |4 a  w
  8. (如果搬运完成(两次数据搬运到adc_value)则产生DMA中断);其中第二个参数为DMA搬运过来的数据存放位2 r, J) m5 N: m/ w4 x8 r6 `$ o0 g7 c
  9. 置的地址(内存地址),第三个参数为需要传输的次数(这里需要采集连个ADC通道的数据,所以填2),达到这个
    4 Q$ p: T3 j; {% y1 R& t" o5 z7 K
  10. 次数之后就会产生一次DMA中断*/
      @% \: j" h/ o
  11.         }
    & T8 G) x  z! P% X/ V: O. r) y, ]" w
  12. }
复制代码
9 l- A* j# X7 M

在main.c文件中找到相关头文件,并添加到gpio.c中


& _% _  f- G. m) {& V8 n


% E9 \- m) Y" e4 M, }9 E

17_meitu_5.jpg

追加到DMA通道1的回调函数:

18_meitu_6.jpg

19_meitu_7.jpg

20_meitu_8.jpg

21_meitu_9.jpg

22_meitu_10.jpg

23_meitu_11.jpg

重新编写DMA的回调函数:


6 t& b; |% B3 u

  1. ​​​extern uint16_t adc_value[2];
    6 D6 j. l: Q1 X1 t
  2. ; u2 J. m' }, W$ w& e
  3. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) /*DMA的中断回调函数,如果调用了这个函
    ' f9 \. ?( e* d/ x0 ]; z5 w' t
  4. 数则表明DMA搬运数据已经完成*/
    ) {- E0 z7 i; A% r8 ^
  5. {
    ; L2 _# M( ~# D
  6.         printf("key adc value = %d\n", adc_value[0]);/ n! I* Q. O2 J  n; h0 I+ ~
  7.         printf("light adc value = %d\n", adc_value[1]);, q1 _% s- p4 F6 `( a/ I
  8.         memset(adc_value,0,sizeof(adc_value));9 ]1 t- _1 y' L+ b6 C$ L# ]5 @2 p# J6 N
  9.         //HAL_ADC_Stop_DMA(hadc); /*如果ADC设置为连续采集(DMA设置为循环模式),则需要关闭ADC和
    1 ^0 C$ |+ Q5 ^/ G2 K5 z
  10. DMA,否则会不断地去采集搬运*/  
    1 }1 \9 O  Q- ?" V& T8 O
  11. }
复制代码
: I- ?8 _" q/ k' Z# @0 o* R7 A

实验结果:

屏幕截图 2020-09-28 105320.png

. l4 A1 v/ T5 i0 H; y
; z- |. v3 ]1 {6 {& s: {3 w* C
16_meitu_4.jpg
24_meitu_12.jpg
收藏 2 评论0 发布时间:2020-9-28 10:54

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版