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

【经验分享】STM32 DMA程序示例

[复制链接]
STMCU小助手 发布时间:2022-6-16 17:00
01. DMA简介( s- u8 s! _0 D' n$ s/ W# [2 D1 h
DMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。0 b9 P5 @- K( X8 T" m+ x

& @1 `- N4 {( K1 @1 FSTM32F4 最多有 2 个 DMA 控制器(DMA1 和 DMA2),共 16 个数据流(每个控制器 8 个),每一个 DMA 控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共可以有多达 8个通道(或称请求)。每个数据流通道都有一个仲裁器,用于处理 DMA 请求间的优先级。
, ^1 A/ B5 f5 @0 U+ m$ y
9 L. Y7 i6 w0 R  H02. 功能描述1 G3 W, Y/ `% w! ?# e
利用 STM32F4 的 DMA 来实现串口数据传送,并在 TFTLCD 模块上显示当前的传送进度。
% I% l) i( x& b" _; N+ V; N1 i, r6 s, f  X+ k7 L
03. 硬件设计9 m2 v( O  U) F
硬件资源有:) B4 [8 D! Z3 t

, J2 I0 o8 h, b( Z, M" l1) 指示灯 DS0
+ L' E, ^$ I) ?- G" d
$ F* G5 Y- X( Q2) KEY0 按键
2 V; _% }) S0 Z2 Q, r3 C9 G9 w5 ?4 |8 B0 j* Z
3) 串口% ~) w+ W3 a) h3 B, Y- m
4 V3 C) o  [& K  D/ Q
4) TFTLCD 模块2 i9 K+ l0 d) j
& m( ?: {" U* k* f
5) DMA
, Q( Y) Z0 c- O) {) a6 U' N* D, [9 G/ X
04. 程序设计
2 a: w- b6 m/ G! V! t5 w% ?, @- pdma.h7 O: E  l: D7 C% }: s& w

5 ^" F, }+ r9 {5 F
  1. #ifndef __DMA_H__; E2 A$ F7 J$ ^6 g
  2. #define __DMA_H__
    3 e' G" s( X: p

  3. " F8 i1 I+ l) y& F
  4. #include "sys.h"% e# X6 r) `( F5 Y0 Y: X; e

  5. . h- W& O4 Y4 e$ o; l
  6. //DMA初始化
    ! `% N' @, ^  a8 G: h. s# j1 ^
  7. void MYDMA_Init(DMA_Stream_TypeDef* DMA_Streamx, u32 chx, u32 par, u32 mar, u16 ndtr);. \$ x. K# o$ d/ S* l/ B
  8.   u# ], c& l' `1 m' Z" S; N1 V$ y$ w
  9. //DMA使能
    5 {) ?* s; c: ]* I  J& |
  10. void MYDMA_Enable(DMA_Stream_TypeDef* DMA_Streamx, u16 ndtr);
    - j! I( z) p( _, g8 N

  11. ; c1 ]& V" i; ]" a3 e6 P6 y
  12. 5 t2 [* N' m1 n
  13. #endif /*__DMA_H__*/8 f3 `3 S& K8 |5 Y# j* w
复制代码

. c5 z' X4 b" Fdma.c- e5 D* o8 Z% T# F) X" P$ j

4 {2 e; N$ `4 C) O  k- [; N
  1. #include "dma.h"
    4 F, Y& B; H- B+ i/ D& k) G( z
  2. % T0 D+ ?$ f7 }( j7 T

  3. / i( \3 o9 h. {
  4. //DMA初始化
    3 @. W) f+ n  e
  5. void MYDMA_Init(DMA_Stream_TypeDef* DMA_Streamx, u32 chx, u32 par, u32 mar, u16 ndtr)
    5 _- J$ O3 C$ l2 ~; @% \
  6. {
    ) u! c7 `" A: M: u/ B
  7.         DMA_InitTypeDef DMA_InitStructure;
    6 ]+ w8 O' \: v. U
  8.         % m, r$ D, J) k* c3 k* `
  9.         //判断是否为DMA1或者DMA2
    0 [$ x( E3 v7 @3 s4 |  k
  10.         if ((u32)DMA_Streamx > (u32)DMA2)3 n, c) i0 _: ~5 m2 m$ f  n
  11.         {$ a: I+ P9 I: o& v/ E
  12.                 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);+ o* m7 ]# R* w% ]  ^$ f
  13.         }: k/ T1 N" e0 m7 U
  14.         else3 |; M' L/ w2 {. A% b9 k
  15.         {7 \- @. @# v& k1 v
  16.                 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
    2 r& L" v* A9 r6 s1 h
  17.         }
    * E- a7 o& W! m' K
  18.         + |  T9 m+ i$ O- Y( \
  19.         //反初始化% d. o' O% u' r6 p7 P
  20.         DMA_DeInit(DMA_Streamx);
    . K3 z# m1 u0 v2 `; ?! t3 Z
  21.         
    % `0 I  D: }0 T! p; z# Z7 r4 @
  22.         //等待DMA可以配置
    7 q3 t0 d+ t  e0 u
  23.         while(DMA_GetCmdStatus(DMA_Streamx) != DISABLE)
    ; E9 n' W7 z3 Q& k" K' P1 J
  24.         {
    / s* i, ]) ^8 _) j
  25.         }' Z" U1 R% _$ ^' J; j1 o/ N
  26.         / g8 m; L' _3 }/ z/ A
  27.         //配置DMA Stream% M) g1 f- J9 p& U! D6 I
  28.         ; |! H( k1 i  N8 _' }8 m
  29.         ' u6 ]! }, U. j$ _  T" _# ^
  30.         //通道选择
    " P! ~  S+ `+ p& _2 v4 x+ a
  31.         DMA_InitStructure.DMA_Channel = chx;
    + _& `. q4 S7 k5 n( H
  32.         //DMA外设地址
    1 G; H; H" p0 l$ g6 w; b' C7 p! {
  33.         DMA_InitStructure.DMA_PeripheralBaseAddr = par;& g) j% ~  s! I2 w- _, P: Q
  34.         //DMA存储器0地址, C/ n$ p# M4 V" d- V
  35.         DMA_InitStructure.DMA_Memory0BaseAddr = mar;  l* Y- p+ z# d3 f
  36.         //存储器到外设模式4 }4 D- j3 D/ r4 p* E6 K
  37.         DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    ; _8 M6 L7 D5 p$ g, c5 }
  38.         //数据传输量. p% b% e$ p+ S" y& ^
  39.         DMA_InitStructure.DMA_BufferSize = ndtr;
    6 Z+ B5 v. M; _" o2 h" J+ t, R
  40.         //外设非增量模式
    9 i- F* n+ Y  U# B5 V
  41.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    # D8 g! l; T1 R
  42.         //存储器增量模式% ?( `1 g6 V' |" G: O- s4 j: u
  43.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;2 g( x) t) D" U; G4 |$ p6 |( I2 t
  44.         //外设数据长度8位
    ( W$ X: \/ [6 T; h6 I, H" |
  45.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;( D5 E9 i) d+ Q2 V6 B; M; X
  46.         //存储器数据长度8位  l2 W- a( m. d1 q' j
  47.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;; N1 U% D3 v6 q6 X) a
  48.         //使用普通模式5 s- t+ [/ n# ~. I% b5 B  T
  49.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    7 }" M) G3 z8 ~
  50.         //中等优先级
    - @% k3 n  D- f: V
  51.         DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;3 o$ r) |* A" s6 P
  52.         //关闭FIFO模式+ `& o% J/ O) b6 Z# E5 f$ `% _
  53.         DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;5 @" k: M1 A/ |' K/ z% i
  54.         //选择FIFO阈值 没有启动FIFO 随便选择
    ) P8 B8 J# D% d- q- g. c
  55.         DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    5 f6 N7 X; L  w! ^# i! u+ x
  56.         //存储器突发单次传输
    " S$ q/ ?: F: o
  57.         DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;! R# _# L" w* v3 g0 x
  58.         //外设突发单次传输# B3 z" k  A; r( h- z" L+ }1 ~
  59.         DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;8 X, }9 _7 Z) b) `. {0 T
  60.         //初始化4 k& g8 r: K/ B, D
  61.         DMA_Init(DMA_Streamx, &DMA_InitStructure);2 X: x# n5 S; _
  62. }" V( {& B/ X) D4 T; r; O5 j+ Q

  63. 6 q/ ~/ h+ ?1 g9 c( k! M
  64. //DMA使能# N! k, x# I2 o3 r" d2 k# W
  65. void MYDMA_Enable(DMA_Stream_TypeDef* DMA_Streamx, u16 ndtr)
    & T8 {( B% z4 O; I
  66. {
    . X& R" }% P5 f4 n. N) k( X3 |
  67.         //关闭DMA传输
    3 {& _% `% U' _
  68.         DMA_Cmd(DMA_Streamx, DISABLE);
    8 r; m. W2 X0 v' T- ]7 h
  69.         ( c" [$ g8 h  C; g- @
  70.         //保证DMA可以被设置
    ! E3 A; `2 h) y: y# g. p2 h) f
  71.         while(DMA_GetCmdStatus(DMA_Streamx) != DISABLE)
    , f7 \* q7 ^  r- n& J6 V
  72.         {- E+ z0 Z9 x5 i
  73.         }
    ) S) B5 n- I1 D+ O

  74. ) \) ?8 S  f7 H  U! A
  75.         //设置数据传输量
    & d0 j3 Z6 m$ f: i% d7 U  j4 y, i
  76.         DMA_SetCurrDataCounter(DMA_Streamx, ndtr);, Z( Z* p& G$ R: k* B- }) z
  77.         
    ( ]1 |6 j' A& Y6 H" L6 A
  78.         //开启DMA传输
    & ^& |  V' C. W6 `7 _: ?. j% Z
  79.         DMA_Cmd(DMA_Streamx, ENABLE);7 V7 F5 q5 m& D1 G  o
  80. }
复制代码
/ ^% a% P- S9 ]8 Y. j) o  k
main.c; [$ T% X. I2 L

5 w: W) J" Q6 P
  1. #include "sys.h"
    9 X: I# [! S/ d) y
  2. #include "delay.h"7 @0 L/ `$ Z+ y3 G) s8 z; ^
  3. #include "usart.h"5 N+ j9 Z9 U- B8 x( Y8 H
  4. #include "led.h"" Z9 Y5 l' p# E  w. \' w- ^, V6 [3 Q$ Y
  5. #include "beep.h"
    % K; {3 Y8 Y' e4 @1 \0 h- J% F3 W
  6. #include "key.h"
    1 X& u$ p7 r) Q) p/ ]/ |+ v4 R* Y* @
  7. #include "usmart.h". a* v& i* S# Q! i2 Z/ c
  8. #include "lcd.h"
    ) S- g  }- x- {
  9. #include "rtc.h", s6 S5 E4 f' o
  10. #include "rng.h"
    7 g, D- s! s. s. F8 e. c# j
  11. #include "key.h"5 \) h  E6 ?5 R1 Z
  12. #include "wkup.h"
    # U6 i  E6 F4 `3 f$ u
  13. #include "adc.h"
    2 T' Z2 ~. R# g# f; ~5 B8 T& s
  14. #include "dma.h"5 k! u3 {+ v) E9 ~% n5 e
  15. 1 x- s5 ^8 y, j7 K# ~; E/ E" }+ E
  16. & U2 o7 k+ W( [1 |: n3 o4 y
  17. #define SEND_BUF_SIZE 8200        //发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.* ^" u8 F3 m% U- {' }( ]: @6 E- M2 b
  18. 2 ~  h( u# {7 K$ a) \
  19. u8 SendBuff[SEND_BUF_SIZE];        //发送数据缓冲区7 Z! I2 n4 y! O
  20. const u8 TEXT_TO_SEND[]={"ALIENTEK Explorer STM32F4 DMA 串口实验"};         
    & O9 ^4 S+ f: D
  21. 2 y  P& f. L9 H: n6 l# b

  22. # |5 E& X+ ?5 N2 N1 i5 l. d/ r+ S) l7 t
  23. 8 h+ G$ C$ \/ [4 z/ M2 ^' p1 r" U
  24. int main(void)
    7 f! r# |+ `! a. n* r
  25. {   c5 ?- {/ }  f
  26.         u16 i = 0;
    1 N' U# M; @+ _) I: `
  27.         u8 t = 0;' F$ E# |! o' Q# X) i! h4 u
  28.         u8 j, mask = 0;
    8 N- E; p1 z- k, a1 G4 n# n1 B! a
  29.         //进度6 x) S/ G# l! l) H9 |
  30.         float pro = 0;; _! D# q/ b, l) e- w6 q
  31. & c7 x4 {. I5 l" `

  32. 9 ^) t6 l: J0 a  R! ~1 P( a
  33.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组21 O! @" r# y0 q2 q& Y& K! _
  34.         
    ; v) t' w% N5 h3 [  R
  35.         delay_init(168);* A" L3 ?, g0 X, o# F2 w5 c
  36.         
    1 A/ Q. l6 J& X; H* |, A
  37.         uart_init(115200);
    ; I- f7 C' P3 G% g
  38.         ' @: f! V1 K1 s: {5 e
  39.         LED_Init();
    ; _  V  q4 U' G; r  t8 M* s
  40.         KEY_Init();
    0 T$ N' p% E2 l9 Q
  41.         LCD_Init();& J1 ]/ a+ m- \2 _
  42.   Q* U2 X/ N/ `9 U
  43.         MYDMA_Init(DMA2_Stream7, DMA_Channel_4,(u32)&USART1->DR, (u32)SendBuff, SEND_BUF_SIZE);
    0 B) \3 o) \0 O
  44. % ?& l3 _8 l5 k: p: y2 B* c, j
  45.                
    : q& U3 S+ I" p1 P
  46.         POINT_COLOR = RED;2 D2 Q0 B4 `( ~, g1 e4 v
  47.         
    # d% [$ O+ c! \: h( o
  48.         LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");        " K8 ~+ l( \7 Y! m8 H" T
  49.         LCD_ShowString(30,70,200,16,16,"DMA TEST");        
      U$ d8 g  H$ p: r% x1 j4 m  m
  50.         LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");9 v4 f; M1 x) D8 e. K
  51.         LCD_ShowString(30,110,200,16,16,"2014/5/6");         
    ; g1 z0 o: h$ ^
  52.         LCD_ShowString(30,130,200,16,16,"KEY0:Start");         
    % R2 g4 q2 h/ B& e$ n6 n: K4 _( U
  53.         POINT_COLOR=BLUE;//设置字体为蓝色 ; A/ w& \% e; Z2 C
  54. 4 i: g+ U9 l% Y' N' \! ?
  55.         
    6 K6 ^  R9 q$ ?6 m+ X/ V+ m1 N3 v) q
  56.          //显示提示信息        4 s5 E+ U  }5 B
  57.         j = sizeof(TEXT_TO_SEND);           
    5 Y: c" {* G0 V5 D5 F
  58.         for(i = 0;i < SEND_BUF_SIZE; i++)//填充ASCII字符集数据
    3 w/ k2 i+ |/ c7 r
  59.     {
    ' k$ X1 D  U& R% }( C3 w4 A. }4 ~
  60.                 if(t >= j)//加入换行符
    1 w/ R6 O% Z' l9 G# o
  61.                 {
    5 i5 v1 G  e0 H) [
  62.                         if(mask)  {: y% J- l3 `" c# a1 g
  63.                         {/ T( w( ?, k* ]9 c+ u
  64.                                 SendBuff<i> = 0x0a;' O& z3 w( B$ k& {. ?
  65.                                 t = 0;8 f1 n  g8 `& _# [% J* }
  66.                         }else
    . y8 N7 h5 S$ x% ^+ m$ J( _
  67.                         {
    ) _4 K3 {+ X% f7 m. X3 P
  68.                                 SendBuff<i> = 0x0d;8 x+ _( M1 D# e( b
  69.                                 mask++;
    7 ^/ {  [5 {/ s0 C# @+ _
  70.                         }        2 F6 q+ ~- I7 x2 d) K
  71.                 }
    : v7 p- Q. f7 m) u6 R0 l
  72.                 else//复制TEXT_TO_SEND语句
    4 z. [  K6 D5 ]* \
  73.                 {
    & _3 [4 F5 G# _4 I1 m' D: v, Z
  74.                         mask = 0;  d4 \0 g/ [7 |8 o3 n
  75.                         SendBuff<i> = TEXT_TO_SEND[t];) t! V' d1 t% f) g5 E
  76.                         t++;
    $ i, V# @+ o% \9 D- O
  77.                 }              
    1 k- l) C, r$ B8 u. a" [
  78.     }                & X  }9 q  N) ?+ f1 Z
  79.         - O6 k/ r5 B$ Z9 `. o9 s, g
  80.         POINT_COLOR = BLUE;//设置字体为蓝色        
    7 Z; h# \. N; H
  81.         
    1 O( z. L+ Y9 }' ^7 b2 E, M9 y7 H
  82.         i=0;5 z! k, F- u5 |8 T
  83.         
    2 A- f9 ^7 l8 \! A
  84.         while(1)
    ( @9 d3 V! {" v$ c
  85.         {
    % K' k1 l0 m/ f( q  b" E6 x; G
  86.                 t=Key_Scan();+ l8 j: K& X$ m1 L+ c# D
  87.                 if(t==KEY0_PRESS)  //KEY0按下. Z- Z9 @/ R2 T6 _. G' H
  88.                 {
    ! o3 x  }' ]; c
  89.                         printf("\r\nDMA DATA:\r\n");             - E, X- P+ e; c9 x
  90.                         LCD_ShowString(30,150,200,16,16,"Start Transimit....");! P' h5 ~" A! @2 Y6 z
  91.                         LCD_ShowString(30,170,200,16,16,"   %") ;     //显示百分号       : |4 \9 ]" L0 z" J7 z
  92.                         USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  //使能串口1的DMA发送     
    ! }1 V7 w+ |- x5 n2 V, G+ D
  93.                         MYDMA_Enable(DMA2_Stream7,SEND_BUF_SIZE);     //开始一次DMA传输!         
    , ~1 }* B4 ]: m$ Z$ k* ?
  94.                         
    4 _, w3 }6 A6 P7 J
  95.                     //等待DMA传输完成,此时我们来做另外一些事,点灯7 W* E0 N4 ]- V  N# i
  96.                     //实际应用中,传输数据期间,可以执行另外的任务
    % g! |$ h1 `# l9 ~
  97.                     while(1)! o! V, \/ M4 N% \$ d4 K  H9 i7 o
  98.                     {
    : C/ p# [3 }8 @. b" o
  99.                                 if(DMA_GetFlagStatus(DMA2_Stream7,DMA_FLAG_TCIF7)!=RESET)//等待DMA2_Steam7传输完成- A; I2 y0 j7 ?( V  H
  100.                                 { + Q. U8 T7 k" \1 x) N
  101.                                         DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7);//清除DMA2_Steam7传输完成标志* |4 k  z& H5 i# q2 v) C
  102.                                         break; % a( Z+ D+ i2 Q( n& ]
  103.                         }% A! V4 m2 N7 }$ A  S( s* ?
  104.                                 pro=DMA_GetCurrDataCounter(DMA2_Stream7);//得到当前还剩余多少个数据
    ' ?9 m7 p6 M- P
  105.                                 pro=1-pro/SEND_BUF_SIZE;//得到百分比         
    ! K4 l- Y0 Q) J7 b9 w6 b# {
  106.                                 pro*=100;                                  //扩大100倍) V( o1 f4 q! _9 w5 g  p" B
  107.                                 LCD_ShowNum(30,170,pro,3,16);         
    ! s, t* t( v! c& L; F
  108.                     }                            7 }  |2 w+ F7 o7 |
  109.                         LCD_ShowNum(30,170,100,3,16);//显示100%         
    7 Y$ a5 r7 p2 y
  110.                         LCD_ShowString(30,150,200,16,16,"Transimit Finished!");//提示传送完成( o- v8 [7 R$ O
  111.                 }" Z  V) M1 A$ D2 k4 \4 a8 F" c3 m
  112.                 i++;% `) i4 }7 o. d2 v$ X% R/ \* g
  113.                 delay_ms(10);
    2 f& K& k' @* T  A+ t
  114.                 if(i==20)
    4 c; i# u+ N! }* }! Z8 }4 f
  115.                 {$ p' R$ h$ Z$ s8 v3 c% k; }- ^4 _2 i
  116.                         LED1=!LED1;//提示系统正在运行        
    ! B3 w: }" |3 H* d' r% A
  117.                         i=0;: e# h& w" g, t1 M# S5 ~
  118.                 }                   - n; d: _* G  c, A
  119.         }               
    8 w+ c" Z- K. E' v" n- Z, t
  120. }</i></i></i>
复制代码
; Q. z; d9 ]* f+ s# W
05. 结果验证
& T$ T% m( l5 _: `9 H; I* p% I8 s& c
DS0 的不停闪烁,提示程序在运行。我们打开串口调试助手,然后按 KEY0,可以看到串口显示的数据。
& m4 B" y" Y4 ~% r% K% z% |; U; r. }, j
7 }$ A4 Q5 u  V
赞 收藏 评论0 发布时间:2022-6-16 17:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版