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

【经验分享】STM32H7的MDMA,DMA2D和通用DMA性能比较

[复制链接]
STMCU小助手 发布时间:2021-11-1 21:46
62.1 初学者重要提示
: Y# F* H% m" p- G4 ^  学习本章节前,务必优先学习第61章,需要对MDMA的基础知识有个认识。
, V& ?2 y+ p/ I+ B6 C! u7 P+ u  
- m" S9 q7 ~9 X: p62.2 测试条件说明. X  g1 n7 B" ~& W' G
MDMA,DMA2D和每个都测试了四种情况: G' q) }. r3 A3 \& l& A% l% D

6 V; |) m  J4 B2 I' k, J2 q1 y9 b  64位带宽的AXI SRAM内部做64KB数据传输。+ t$ ?4 Y2 B3 V- i! {$ j
  32位带宽的D2域SRAM1内部64KB数据传输。
9 e. j, `# z$ N( K" J5 c& P6 Z5 T: D, Y  AXI SRAM向SDRAM传输64KB的数据传输。
$ O& y3 Q" I5 |: X: t  32位带宽的SDRAM内部做64KB数据传输。. X* e9 O/ N) C) p
MDMA:6 e8 |  D; t6 f0 H
( C' f$ C" D# o' ~7 Q8 l
在D1域,支持64位带宽的DMA数据传输。
( f$ K# B& C  w- b( |! J% m* S3 `6 b* M3 U$ H$ ^
DMA2D:3 h4 M" Y, t" N0 |
在D1域,主要用图形2D加速。' n- T! j6 _; A' o! d  U1 }6 W

! V" Q' ~. W4 a! ?DMA1和DMA2:  A. o6 ^9 z" y. {, H3 e: d1 ~# q+ o! ~7 W
在D2域,支持32位带宽的DMA数据传输。7 x& _9 ?% B+ d0 v4 U

8 N! s6 [8 d" K- c9 J8 L62.3 MDMA性能测试程序设计2 n& X9 {4 X7 [+ ~1 L, p
这里将MDMA的程序设计分为以下几部分,逐一为大家做个说明:  Y5 D6 y# ?7 a2 V

; R$ x+ Z- v: G6 Z$ {8 F: N62.3.1 第1步,MDMA初始化2 o3 m" ^4 q4 v. q' _
程序代码如下,采用块传输,源地址和目的地址都是64bit数据传输,并设置16beat突发,也就是连续传输16组64bit数据。
. g/ [- M) m+ D& ~+ \5 |
0 r9 w3 u7 Y( A+ x; _' I# g
  1. 1.    __HAL_RCC_MDMA_CLK_ENABLE();  - B8 h! g$ x+ I* j& T
  2. 2.    7 t: a3 p) J, T% O' K
  3. 3.    MDMA_Handle.Instance = MDMA_Channel0;  
    6 X& p" c" d/ s" C9 S4 [
  4. 4.   
    * V8 u- s6 L' |* u9 S" S& M
  5. 5.    MDMA_Handle.Init.Request              = MDMA_REQUEST_SW;         /* 软件触发 */: C. b1 ^/ Y1 t
  6. 6.    MDMA_Handle.Init.TransferTriggerMode  = MDMA_BLOCK_TRANSFER;     /* 块传输 */
    * Y5 L% y) D  v
  7. 7.    MDMA_Handle.Init.Priority             = MDMA_PRIORITY_HIGH;      /* 优先级高*/" L7 T" A0 ]8 p; q5 F' B. I
  8. 8.    MDMA_Handle.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE; /* 小端 */7 M6 E! y6 R, L" L
  9. 9.    MDMA_Handle.Init.SourceInc            = MDMA_SRC_INC_DOUBLEWORD;      /* 源地址自增,双字,即8字节 */- ]: U  B8 W1 Q( J. q3 u7 @9 j5 b
  10. 10.    MDMA_Handle.Init.DestinationInc       = MDMA_DEST_INC_DOUBLEWORD;     /* 目的地址自增,双字,即8字节 */
    , \2 C/ k2 J# L
  11. 11.    MDMA_Handle.Init.SourceDataSize       = MDMA_SRC_DATASIZE_DOUBLEWORD; /* 源地址数据宽度双字,即8字节 */" N& N1 ^' ^3 f, d
  12. 12.    MDMA_Handle.Init.DestDataSize       = MDMA_DEST_DATASIZE_DOUBLEWORD;/* 目的地址数据宽度双字,即8字节 */9 J! z2 _) d5 b+ P: M2 W
  13. 13.    MDMA_Handle.Init.DataAlignment      = MDMA_DATAALIGN_PACKENABLE;    /* 小端,右对齐 */                    
    4 J5 ~7 N* i! k' u2 d9 q" I& F" |
  14. 14.    MDMA_Handle.Init.SourceBurst        = MDMA_SOURCE_BURST_16BEATS;    /* 源数据突发传输 */
    1 x* f# i0 D- \: Z2 ?0 n+ Z7 W
  15. 15.    MDMA_Handle.Init.DestBurst          = MDMA_DEST_BURST_16BEATS;      /* 目的数据突发传输 */4 _# ^  H3 ?' A. d/ z: O
  16. 16.    7 b# w6 Y2 q$ f4 G# [  o
  17. 17.    MDMA_Handle.Init.BufferTransferLength = 128;    /* 每次传输128个字节 */
    % F2 W7 L8 W; ]: J6 B) N- O
  18. 18.   
    7 M4 x1 }( H) `
  19. 19.    MDMA_Handle.Init.SourceBlockAddressOffset  = 0; /* 用于block传输,地址偏移0 *// Q! Y( n/ E1 W7 }
  20. 20.    MDMA_Handle.Init.DestBlockAddressOffset    = 0; /* 用于block传输,地址偏移0 */
    ' e7 o1 P. I/ M! T4 V
  21. 21.   
    / |- O. A$ h" E$ x
  22. 22.    /* 初始化MDMA */
    5 r: `% i; ]7 j4 [7 [1 B
  23. 23.    if(HAL_MDMA_Init(&MDMA_Handle) != HAL_OK)8 v/ S2 G5 H9 P5 E
  24. 24.    {
    * S  L+ t9 {3 v$ d% |
  25. 25.         Error_Handler(__FILE__, __LINE__);1 L& `6 x! {. ?. _1 [9 O! d6 U
  26. 26.    }, n$ _( |- x% o7 G- u: f
复制代码
; U; m4 @4 x6 f3 q* f  h; l
3 D! C$ D: d" h0 `) C9 Z
下面将程序设计中几个关键地方做个阐释:
* a# {7 J* ?6 F7 P: B% t. {7 p; k6 T" M7 d5 d( v/ a% [, J
  第1行,务必优先初始化MDMA时钟,测试发现没有使能时钟的情况下就配置MDMA很容易失败。1 S$ K  H8 s9 C+ n8 a
  第14-15行,突发传输的配置非常考究,每次突发传输的总数据大小不能超过128字节。+ Q& A0 s0 u! H2 f0 k
  对于源地址就是SourceBurst * SourceDataSize <=  BufferTransferLength。7 d) v; Z% a5 M% u& |" w9 t) S6 b6 ]
对于目的地址就是DestBurst*DestDataSize <= BufferTransferLength。
9 c6 ~$ a1 o: ]1 k+ e% u比如当前的程序配置:" Q' |6 G1 q- H6 l1 s, Y& L4 ^, d

. q7 _2 C$ v0 P1 Q) W8 j  M' oSourceBurst * SourceDataSize = 16*8 =128字节
+ K: C0 \0 R+ n  j) _3 v
" ?" ~% k( a7 m0 o' m% XDestBurst*DestDataSize = 16*8 =128字节( x+ L# S/ q! y$ |  C
; s# M6 E8 U  q! e5 _5 o5 N- t/ L# U
* A# e+ r( u# c/ H

. s$ |0 c1 R7 \& m9 L4 f这里要特别注意一点,如果实际应用中最好小于BufferTransferLength,防止不稳定。
- y! Y& b/ Q- j4 t8 o, ^# f
& m6 ~, P3 ^  I62.3.2 第2步,MDMA中断配置( w1 R. g4 d5 F  q0 f( ?+ L2 A* Q
MDMA的中断设置比较简单,代码如下,注册了MDMA的传输完成回调:; c* `8 T: z( N: M: Y% n

! r: ~( ^" K3 q$ o% W
  1. HAL_MDMA_RegisterCallback(&MDMA_Handle, HAL_MDMA_XFER_CPLT_CB_ID, MDMA_TransferCompleteCallback);
    + y& \, |/ ^; @" m
  2. HAL_NVIC_SetPriority(MDMA_IRQn, 0, 0);
    3 q4 Z" ~* X7 Q: m. |/ E$ m7 @% t
  3. HAL_NVIC_EnableIRQ(MDMA_IRQn);  
    $ h1 O2 Y8 O' ^+ R" c* {- _
  4.   D6 M1 U- r' f7 e: j2 @2 k
  5. void MDMA_IRQHandler(void)
    9 l8 N; \$ K+ p& N
  6. {5 W) ~: F" f4 \" f
  7.     HAL_MDMA_IRQHandler(&MDMA_Handle);& |- c5 ?4 [4 h/ z$ e
  8. }
    & v$ u" C/ `% S5 y" _
  9. static void MDMA_TransferCompleteCallback(MDMA_HandleTypeDef *hmdma)
    + D, ?5 [0 i. f0 z2 u
  10. {
    $ y' p1 H+ T, `8 J) ^+ @  K1 |
  11.     TransferCompleteDetected = 1;
    9 ], O% ]+ d5 i
  12. }
复制代码

$ ?% u& l8 X2 ]+ l) x) q
6 T! l) E, K$ t
5 X8 N" k* w" B7 }5 H在传输完成回调里面设置了一个变量标志TransferCompleteDetected,方便指示传输完成。
4 i# @2 s0 E9 @1 Z. O" S4 m
8 m$ ?& {* W$ h" |5 u* _62.3.3 第3步,AXI SRAM内部互传64KB数据
$ D5 O" V$ w9 Y' v3 u. V( u" k通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0x2400 0000 + 64*1024里面:
9 ]1 o' \8 W* I) L+ O* q& Q
( x8 g7 B, C. C1 W( O
  1. TransferCompleteDetected = 0;4 m: N( D5 h/ P4 r5 {/ _( C
  2. HAL_MDMA_Start_IT(&MDMA_Handle,
    1 C! i$ M3 D1 R9 o9 y
  3.                   (uint32_t)0x24000000,
    . B9 [, A6 A9 a4 G+ F
  4.                   (uint32_t)(0x24000000 + 64*1024),
    9 f; M8 H: n( u( s" s7 _4 b
  5.                   64*1024,
    ' m* o, d& d$ j/ ]$ N- ~/ e& Z
  6.                   1);7 a! |1 r' g( F0 x+ ]8 y& y

  7.   B0 g5 Z% a4 |: H% `

  8. ) s* _0 D; A) }& s
  9. start = DWT_CYCCNT;- x3 A, d# |' C2 p% e
  10. while(TransferCompleteDetected == 0) {}( d4 l7 Z7 H9 P; A5 S; y  P4 ~
  11. end = DWT_CYCCNT;
    4 l" V# \5 i- b% f# m0 h
  12. cnt = end - start;' E0 Z% N; F/ H4 {# e

  13. 2 {3 U9 y+ c0 p" _. `( K
  14. //64*1024/(cnt/400/1000/1000)/1024/1024 = 64*1000*1000*400/1024/cnt = 25000000/cnt
    + x4 O/ e0 m- ?! A1 N
  15. printf("MDMA---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
5 M9 Z) ]9 i" a/ T, Y* z. K5 m' s! m

: C. _1 P% `+ I) M8 V* g1 m
2 J/ u3 n# F& y4 p9 g通过时钟周期计数器测量执行时间,单位2.5ns。
5 ^) u3 u9 Q- ^. ~8 k4 `  v8 [5 z" Q: e
62.3.4 第4步,D2域SRAM1内部互传64KB数据
% i% v  }! X0 \) j1 _, s8 M4 x通过下面的程序实现将地址0x3000 0000开始的64KB数据复制到地址0x3000 0000 + 64*1024里面:/ F( n% j! [& g! d8 L& d

5 x& r1 z# |& j9 L; \7 J: N# u
  1. TransferCompleteDetected = 0;2 ~+ e' K, v3 q: A7 j( e9 P
  2. HAL_MDMA_Start_IT(&MDMA_Handle,
    $ F7 ?! Q! i) a4 g2 _6 y" x/ A
  3.                   (uint32_t)0x30000000, 3 L/ p0 H( J; h% D2 D" H9 F
  4.                   (uint32_t)(0x30000000 + 64*1024), 6 v  D- s) s' t, h
  5.                   64*1024, " S1 j# c" x/ ?0 u
  6.                   1);
    % m* E2 M& V1 \
  7. ' v7 B  d: J. ^' k$ p6 R1 Y" G
  8. start = DWT_CYCCNT;+ N6 t' K" ^( f) ?! {3 m+ W
  9. while(TransferCompleteDetected == 0) {}) D* U+ b1 y% `9 `' ~, X
  10. end = DWT_CYCCNT;! A8 X/ u9 ]5 z" B
  11. cnt = end - start;8 Q/ z+ }" r& z1 P

  12. 0 _& z8 T! _0 y- E+ [" y) y
  13. printf("MDMA---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
# K8 m6 h/ A1 Z1 T) v+ N
通过时钟周期计数器测量执行时间,单位2.5ns。
, m: D  n! q9 C0 B9 N& s( R5 m* F! r$ S
62.3.5 第5步,AXI SRAM传输64KB数据到SDRAM
! Q! _8 f. ?! x) J+ X通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0xC000 0000里面:
: e, l4 S6 X, b- H; G* W
' @8 r$ y% K( B2 t7 w/ s
  1. TransferCompleteDetected = 0;
      M7 O" _7 o7 `- |
  2. HAL_MDMA_Start_IT(&MDMA_Handle, 0 c4 Z2 Y+ b/ q' y6 ?
  3.                   (uint32_t)0x24000000,
    4 f/ x  c& E* m+ v- F
  4.                   (uint32_t)0xC0000000, / C* I: O' y) ~- @' ]! _
  5.                   64*1024, ( p3 w. [( @5 Z9 u+ J# G
  6.                   1);4 F9 f2 C: q2 t  S. E+ E

  7. 6 k% c6 }& \: r+ T3 I( m% r
  8. start = DWT_CYCCNT;% ]& k+ {& M' Z7 J5 N4 x5 b
  9. while(TransferCompleteDetected == 0) {}; d& b, [* E, O  p
  10. end = DWT_CYCCNT;
    8 U$ n  ]7 I( I
  11. cnt = end - start;
    . }8 p7 [6 ?: T3 K3 L) t4 e
  12. % R9 L7 L# B( P/ n5 q0 @
  13. printf("MDMA---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
8 O+ R; |  h+ ]# c
7 j, q" ^- d0 S

- N2 K- }% o" @1 u/ M通过时钟周期计数器测量执行时间,单位2.5n。3 A# l2 ]5 B- e; I5 ~6 }

0 _* h- I' \! p- Z62.3.6 第6步,SDRAM内部互传64KB数据
3 M& ^6 d* L9 H5 q/ }通过下面的程序实现将地址0xC000 0000开始的64KB数据复制到地址0xC000 0000 + 64*1024里面:3 R1 M+ N+ A  N2 }
  d" G, W: z  D  B8 n% o" G
  1. TransferCompleteDetected = 0;
    , l6 d8 b. I& i3 ]* w5 M, L1 Q% S
  2. HAL_MDMA_Start_IT(&MDMA_Handle,
    0 s5 I! |) M1 w1 K+ l
  3.                   (uint32_t)0xC0000000, # w, `( ^' R& |9 ]/ o4 Y
  4.                   (uint32_t)(0xC0000000 + 64*1024),
    / w; a4 w( F3 h  v0 V
  5.                   64*1024, % S9 y$ p$ J# q7 \$ v
  6.                   1);  _8 K* ?' x0 D( e
  7. & I, t" K/ n2 E- s% v
  8. 1 |3 @! b0 {$ ^% ^7 F' E
  9. start = DWT_CYCCNT;7 j: K( U  W/ E, ?$ e/ b
  10. while(TransferCompleteDetected == 0) {}) Y8 m# p0 T$ `2 ]7 L6 J4 F
  11. end = DWT_CYCCNT;
    ( p- H- X6 H; n- M- M
  12. cnt = end - start;  ^" R" {" T* e1 {1 c2 p
  13. & E) L7 O! A) C( V3 }! B
  14. printf("MDMA---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

, Z1 x0 A1 R. J通过时钟周期计数器测量执行时间,单位2.5n。
4 F( k, l7 t& v/ m- Z
6 s! J9 \3 B3 B% C, ?. A' s62.4 DMA2D性能测试程序设计
7 h7 `' K1 F" Y. y这里将DMA2D的程序设计分为以下几部分,逐一为大家做个说明:
' N( z. _1 ~/ u+ D, F. ]4 P7 D: {: t/ o1 x
62.4.1 第1步,DMA2D初始化
8 E3 V8 o5 F  h- Z配置DMA2D采用存储器到存储器模式,前景区和输出区都采用ARGB8888格式,传输64*256次,每次4字节,即64*256*4 = 64KB数据。& F3 ?5 G) W- i. c

( R6 H8 M; M8 d  }0 y9 P
  1. __HAL_RCC_DMA2D_CLK_ENABLE();  
    2 K3 w. e7 p& k% F
  2. 1 R! c. `6 r6 V( h: L
  3. /* DMA2D采用存储器到存储器模式, 这种模式是前景层作为DMA2D输入 */  # d+ h8 m. ?8 |( q% o) k5 f4 X5 B
  4. DMA2D->CR      = 0x00000000UL;8 Z% c1 @: H# z8 f* N  I" d% E7 S5 F
  5. DMA2D->FGOR    = 0;
    7 o3 A- e8 Z! z( T. B& R" h7 p! F
  6. DMA2D->OOR     = 0;
    5 o3 s9 l# O6 V" O% W

  7. 9 N" Y+ C2 v! e# @& Y& ?% H8 t( a
  8. /* 前景层和输出区域都采用的ARGB8888颜色格式 */
    / k! k: S. B* w0 t( {4 T9 U7 a: n
  9. DMA2D->FGPFCCR = LTDC_PIXEL_FORMAT_ARGB8888;2 E2 V- O. ?# s5 l# G) I. A
  10. DMA2D->OPFCCR  = LTDC_PIXEL_FORMAT_ARGB8888;
    / f8 Q- ~) \' Y8 A/ B. A1 E. a& E5 p8 v

  11. ( w$ ?' h* Y1 r. K. w- @- s  d
  12. DMA2D->NLR     = (uint32_t)(64 << 16) | (uint16_t)256;
复制代码

& n( p; q3 L& `4 R62.4.2 第2步,AXI SRAM内部互传64KB数据
0 w; P( _, g5 Y# i7 A通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0x2400 0000 + 64*1024里面:
9 r& u, R: a/ ^. F
  1. /* AXI SRAM的64KB数据传输测试 ***********************************************/) t2 K0 D8 l" g- p8 f& W
  2. DMA2D->FGMAR = (uint32_t)0x24000000;, Z" Q5 Q* n( }! j) {; S
  3. DMA2D->OMAR  = (uint32_t)(0x24000000 + 64*1024);1 R% t- k* r% d1 P1 g
  4. DMA2D->CR   |= DMA2D_CR_START;   
    ! _/ {( Y. x. q- L: I) }' ]
  5. . p% w$ o& V* O4 ]; n' |8 J0 y7 J
  6. start = DWT_CYCCNT;
    ( a7 _' f/ P" f) L/ a0 _, C1 k
  7. /* 等待DMA2D传输完成 */
    8 q/ m  L. |* B. t
  8. while (DMA2D->CR & DMA2D_CR_START) {}
    7 j. q# V* C9 }. L/ ?
  9. end = DWT_CYCCNT;
    / ^7 G8 Z2 B6 v5 N. a" t) o( w
  10. cnt = end - start;
    ) V3 a7 y* O0 B7 K/ b1 R  f

  11. ' M7 J9 t: z# s6 Q$ e3 R1 [2 {
  12. printf("DMA2D---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

  o- m8 y( b* q0 T通过时钟周期计数器测量执行时间,单位2.5ns。
4 k$ P- f; h' a/ D9 w
; j( I" L( f6 `% g/ Y1 P! P62.4.3 第3步,D2域SRAM1内部互传64KB数据; O, m- [. j2 x3 s1 v* [  X
通过下面的程序实现将地址0x3000 0000开始的64KB数据复制到地址0x3000 0000 + 64*1024里面:
9 G/ u3 N8 s, W! D$ o6 f* D! a. v" C# E1 y# S% m- q+ y- U& P+ `; e
  1. /* D2域SRAM1的64KB数据传输测试 ***********************************************/) j( T, y% Y& q; q- `4 E
  2. DMA2D->FGMAR = (uint32_t)0x30000000;
    ) J. K7 \* S2 A! l$ K3 p2 R9 r
  3. DMA2D->OMAR  = (uint32_t)(0x30000000 + 64*1024);
    " J. W5 \3 l/ m( o9 L0 @- W* _' F
  4. DMA2D->CR   |= DMA2D_CR_START;  ; u# M. ?7 V: @- t; O" }

  5. " _6 S, `, W% e4 n5 |- Q
  6. start = DWT_CYCCNT;
    0 X9 U4 h% t. m" Y5 g4 H
  7. /* 等待DMA2D传输完成 */
    - h, |3 U% U" v4 m, U- \$ l
  8. while (DMA2D->CR & DMA2D_CR_START) {} , ~# g$ F0 J: a6 g! D% O0 F, v4 V7 ?
  9. end = DWT_CYCCNT;
    " V6 a( |/ v/ k6 F$ Z% Q; U
  10. cnt = end - start;
    + ?" j7 O! G- m7 O& k- c; x  S
  11. & o; I! C& O" x$ P
  12. printf("DMA2D---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

+ ]' d* b6 D6 p6 {! T; d通过时钟周期计数器测量执行时间,单位2.5ns。
. H$ y# R0 `4 Z6 ^% k8 F8 i0 B" q# {5 v# ~
" _' C$ c) \5 |$ K% N62.4.4 第4步,AXI SRAM传输64KB数据到SDRAM' f; R: A/ ?; q, G$ C
通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0xC000 0000里面:
9 b7 P  ]+ s; P  I- }+ {- L
  1. /* AXI SRAM向SDRAM的64KB数据传输测试 ***********************************************/. x" Z# c7 Y( X, A: n; ?# Q
  2. DMA2D->FGMAR = (uint32_t)0x24000000;- o8 p/ H! G  Z% W
  3. DMA2D->OMAR  = (uint32_t)0xC0000000;5 H4 @- s, I/ F1 S/ L! f
  4. DMA2D->CR   |= DMA2D_CR_START;  1 a# ?$ x+ I! ?! E( n: y' Z* r7 F0 m
  5. 5 G6 s( g( C1 t( s7 E
  6. start = DWT_CYCCNT;
    3 M  u% `% [8 T
  7. /* 等待DMA2D传输完成 */
    ' y  v/ D) D/ S) {
  8. while (DMA2D->CR & DMA2D_CR_START) {}
    8 t9 H9 k, i4 ^/ A
  9. end = DWT_CYCCNT;
    # C6 f4 T6 H- Z4 E8 I
  10. cnt = end - start;! k; T8 A( b% ~9 f9 U, S% S: s
  11. / h, H3 }3 I: ~* L2 [8 K) y
  12. printf("DMA2D---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);  
复制代码
+ H# f" S; }; X% V1 h* w
通过时钟周期计数器测量执行时间,单位2.5n。# ?! A+ O$ x3 }' B  U# R

! i7 L7 B- F$ h. a2 ^( |62.4.5 第5步,SDRAM内部互传64KB数据
- b4 N# D0 ?0 v/ l+ D; w$ b( R通过下面的程序实现将地址0xC000 0000开始的64KB数据复制到地址0xC000 0000 + 64*1024里面:, Z! j/ v7 ]6 D
  1. /* SDRAM的64KB数据传输测试 ***********************************************/
    , l/ s% N) y! M% M
  2. DMA2D->FGMAR = (uint32_t)0xC0000000;$ j# U; C- }/ w8 F5 `6 X0 z+ }
  3. DMA2D->OMAR  = (uint32_t)(0xC0000000 + 64*1024);0 e; k/ ~7 ^1 n' v
  4. DMA2D->CR   |= DMA2D_CR_START;
    9 N. d* r" Y( z0 Y

  5. , J; K  ~2 C. z
  6. start = DWT_CYCCNT;
    - E  G  x  }: C
  7. /* 等待DMA2D传输完成 */
    / u; x: F) Q3 [0 ?2 U9 [' v: y
  8. while (DMA2D->CR & DMA2D_CR_START) {}
    ' {! X/ f( w2 n* e
  9. end = DWT_CYCCNT;: c# n# a- e* `: J: o/ P3 ?* b+ x  I# [
  10. cnt = end - start;   
    8 Y# R- @/ ^3 m+ ?( o7 _

  11. 4 ^2 m$ l6 Y# ~+ P
  12. printf("DMA2D---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);   
复制代码
$ `8 [; ~5 V. s8 X* t) Z6 j' h* `
通过时钟周期计数器测量执行时间,单位2.5n: n" D9 L  s5 r

) ]! M4 G8 Z: |0 Q! m* S4 y62.5 通用DMA性能测试程序设计
1 G* @2 g9 B, ], r( L+ _1 M" C这里将DMA1的程序设计分为以下几部分,逐一为大家做个说明:' U1 g# e0 H# s/ v- A$ T% M

5 n' n5 p2 o, D/ E! ]: R" g7 d62.5.1 第1步,DMA1初始化
# N2 k# P4 C- c$ c; ]程序代码如下,采用存储区到存储区传输方式,源地址和目的地址都是32bit数据传输,并设置4beat突发,也就是连续传输4组32bit数据。
( [8 F7 w5 h; O7 z7 Z$ T
  1. 1.    __HAL_RCC_DMA1_CLK_ENABLE();: y( |( [4 C+ v' n+ f, f8 R
  2. 2.   
    $ f3 t6 @2 @3 ]  L% L9 Z. R, g. r
  3. 3.    DMA_Handle.Instance                 = DMA1_Stream1;
    - h" v( `2 C, }0 }: u5 Z8 i: D. s
  4. 4.    DMA_Handle.Init.Request             = DMA_REQUEST_MEM2MEM;  $ ~7 ~& O, x2 @* l
  5. 5.    DMA_Handle.Init.Direction           = DMA_MEMORY_TO_MEMORY;  C8 O9 O7 \2 i
  6. 6.    DMA_Handle.Init.PeriphInc           = DMA_PINC_ENABLE;
    5 x' k3 ?" M8 j! Z
  7. 7.    DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;
    7 w7 Y$ b2 }/ U) ]
  8. 8.    DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;4 @# D, c8 \5 N. O3 m4 D
  9. 9.    DMA_Handle.Init.MemDataAlignment    = DMA_PDATAALIGN_WORD;
    " a7 ]6 ~1 X( y% A3 A
  10. 10.    DMA_Handle.Init.Mode                = DMA_NORMAL;& F! b7 u1 v$ c  t  {
  11. 11.    DMA_Handle.Init.Priority            = DMA_PRIORITY_VERY_HIGH;& S. R, p8 K# _1 ?# p1 ?
  12. 12.    DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;7 m) B" }: |( ^. s. B" X
  13. 13.    DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;' ]9 z1 B+ y. f4 R' Y3 _  f
  14. 14.    DMA_Handle.Init.MemBurst            = DMA_MBURST_INC4;     /*WORD方式,仅支持4次突发 */
    ; ]1 q8 C: v7 b0 H: u  A, i/ M
  15. 15.    DMA_Handle.Init.PeriphBurst         = DMA_PBURST_INC4;     /*WORD方式,仅支持4次突发 */" I! h% ^' C: M
  16. 16.    DMA_Handle.XferCpltCallback         = DMA_TransferCompleteCallback;+ O7 c$ D# o" Z5 \  J; d: t
  17. 17.   
    , Y: F0 E4 P. _  I; U7 ^
  18. 18.    HAL_DMA_Init(&DMA_Handle);
复制代码
0 R, e9 l1 F* P# M+ Y( M
下面将程序设计中几个关键地方做个阐释:: b; c# d6 U( k. K1 v

0 e" G- r, G, X* m. m  第1行,务必优先初始化DMA时钟,测试发现没有使能时钟的情况下就配置DMA很容易失败。
- Z5 F" c  r2 N$ @7 J' r  第14-15行,突发传输的配置非常考究,这里要特别注意数据位宽,FIFO以及突发的配置。/ R5 ~9 Y# M) f& O
% D; Q. p& v9 F: O: \' Z
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
$ E9 R. P  S1 N5 _' S) m

" L- y# b, j6 Q) ^; `程序中数据位宽是配置为32bit,FIFO配置为满,那么突发仅可以配置为4beat,即DMA_MBURST_INC4。
  l! |0 @; K! d2 t. e* p7 p: |- _, N0 {* v) Q6 L
  第16行,设置传输完成回调函数。
$ j6 D+ \" G& J9 y( h8 X$ V# y5 p62.5.2 第2步,DMA1中断配置# W6 e' G/ t. A* L
DMA1的中断设置比较简单,代码如下:
% l9 h$ ?  r4 T
: a; v+ U6 q$ c: X% f
  1. HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
      r8 c9 i2 A" u- ]! W* Y
  2. HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
    # `) N* r: }. N$ Y5 [0 I
  3.   D7 Z$ V  W" l+ {
  4. void DMA1_Stream1_IRQHandler(void)
    0 l& V5 P3 Z; L- u# F% y3 I
  5. {
    ! Y8 |- S3 Z, m/ Y* E/ S3 X* B: t
  6.     HAL_DMA_IRQHandler(&DMA_Handle);) p: s* }; v0 [7 @) i" x% M
  7. }
    $ H, F; g* a/ g  z* a# u3 h
  8. static void DMA_TransferCompleteCallback(DMA_HandleTypeDef *hdma): h  l* w& ?  Y' W: U
  9. {
    ) p* e# F1 s$ J6 x; t. a9 m
  10.     TransferCompleteDetected = 1;
    ; q4 l( w5 n6 t$ R' }
  11. }
复制代码
. N1 |' D1 W* E9 Y1 H( q* K
在传输完成回调里面设置了一个变量标志TransferCompleteDetected,方便指示传输完成。% v3 q/ N; F! d% y8 u+ J

' ]5 i: B7 K+ h; X62.5.3 第3步,AXI SRAM内部互传64KB数据4 K7 v! W  R! z: Z, o9 i; K) C
通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0x2400 0000 + 64*1024里面:
+ i1 R- z5 d! v+ |0 }3 o, X" \" x0 w, P! I" Q3 A
  1. /* AXI SRAM的64KB数据传输测试 ***********************************************/
    3 s* @' p) T) P
  2. TransferCompleteDetected = 0;
    ' ]9 p# J1 r. n/ ]8 a1 z/ Q
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x24000000, (uint32_t)(0x24000000 + 64*1024), 64*256);
    - C3 i0 {8 [  y( n, n8 ]

  4. 3 e% W5 t/ M" N) ]
  5. start = DWT_CYCCNT;' n; ?' h- @" u4 @: Y0 t/ ?9 I& `
  6. while(TransferCompleteDetected == 0) {}
    + y8 m; H7 q+ r& t! z# F
  7. end = DWT_CYCCNT;# }5 u2 R0 ~6 o# x, c/ H
  8. cnt = end - start;2 W& t1 r9 a& U$ t6 Z6 |' n' m

  9. ; m+ ^* x- A0 P/ Z0 {+ ~, h$ a5 C5 z
  10. //64*1024/(cnt/400/1000/1000)/1024/1024 = 64*1000*1000*400/1024/cnt = 25000000/cnt7 E) B5 c  G: z- @: v
  11. printf("DMA1---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
  p1 u/ {5 W, J9 q, o
通过时钟周期计数器测量执行时间,单位2.5ns。
0 |9 D' N' q; y7 W" n6 c6 I( }! O& j5 D0 t% O6 i" i4 C3 Y8 Y
62.5.4 第4步,D2域SRAM1内部互传64KB数据
8 L2 X. @: c6 ~6 b' `2 q% m通过下面的程序实现将地址0x3000 0000开始的64KB数据复制到地址0x3000 0000 + 64*1024里面:4 E- d% i! `0 n. l# o/ X6 E
+ S7 j6 c; v4 `5 P! j! h
  1. /* D2域SRAM1的64KB数据传输测试 ***********************************************/
    6 t. q* X* y, `% h9 x" `+ k
  2. TransferCompleteDetected = 0;+ C% }6 W0 j+ @5 C1 S$ A* x4 ^% w
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x30000000, (uint32_t)(0x30000000 + 64*1024), 64*256);( c. p6 i1 J( {) |
  4. 5 A: n  ^! |) |! T6 B8 l
  5. start = DWT_CYCCNT;
    ( J. y. @% E2 N$ c  I6 y/ `  k
  6. while(TransferCompleteDetected == 0) {}
    5 A3 L* {7 J4 \4 i
  7. end = DWT_CYCCNT;
    * @7 M0 i0 ^; p' G: @
  8. cnt = end - start;
    ) S3 z2 X; Q, l: o: k' B
  9. 4 p* h  d8 W1 A4 h: U% }
  10. printf("DMA1---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
! P2 |4 A' j. V2 b$ |0 C
通过时钟周期计数器测量执行时间,单位2.5ns。' G, ~9 N, a+ I' ~

0 x4 Z$ X4 |( B' H% z& P5 E  l62.5.5 第5步,AXI SRAM传输64KB数据到SDRAM
8 ^) w5 B8 V3 z  `, v通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0xC000 0000里面:
) r. {; d. g  N0 j
* m* o6 w- l6 [1 d, d& Q; F' Y
  1. /* AXI SRAM向SDRAM的64KB数据传输测试 ***********************************************/
    3 O' |" L" W: ]
  2. TransferCompleteDetected = 0;& \# k7 m& o- v( y* Q, D
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x24000000, (uint32_t)0xC0000000, 64*256);
    2 {- d- N1 e7 |
  4. + r, R/ [+ A  Q
  5. start = DWT_CYCCNT;1 y  H/ _/ ?, w" N6 Q# S6 S
  6. while(TransferCompleteDetected == 0) {}
    - a; ~! f; M6 q" r, Z
  7. end = DWT_CYCCNT;: N* e( K; q  N; j+ k
  8. cnt = end - start;
    # x, ^" ]: ^5 e

  9. 9 t! V+ a8 O: O( V" B
  10. printf("DMA1---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);2 y* a( u  ]) A/ _1 T
复制代码
# ~: X: k8 m! m9 R
通过时钟周期计数器测量执行时间,单位2.5n。
$ T2 c' r0 ~# Y  j! D
, P8 t/ x6 f" f1 n2 ]) j3 q/ H' f62.5.6 第6步,SDRAM内部互传64KB数据
6 D8 w  X6 ?5 y$ B. ]2 q+ R' u通过下面的程序实现将地址0xC000 0000开始的64KB数据复制到地址0xC000 0000 + 64*1024里面:- ~5 t: A& k0 @: y/ M6 a
  1. /* SDRAM的64KB数据传输测试 ***********************************************/3 n# A  |5 A  |
  2. TransferCompleteDetected = 0;
    $ }7 q8 s; f( ?( J4 Y' Q6 O  a
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0xC0000000, (uint32_t)(0xC0000000 + 64*1024), 64*256);   
    * W  V$ w1 @% W! f$ s

  4. 6 `; A# u& q5 x, Y
  5. start = DWT_CYCCNT;
    0 u' C4 e2 P& w+ z
  6. while(TransferCompleteDetected == 0) {}4 w" }0 ]% M8 l) _9 c& N
  7. end = DWT_CYCCNT;
    5 V% w$ q2 r9 f. Q5 Z  O9 H* S
  8. cnt = end - start;4 D; I# n) I+ P, a& a! h0 n

  9. 4 Z) e9 L3 \/ i5 J* g
  10. printf("DMA1---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
' ^' d$ f+ _: n, n: Q; I7 L' s3 @
通过时钟周期计数器测量执行时间,单位2.5n。$ H. J' l9 [0 n. T# X$ m
* P: z4 p0 @5 f8 C4 T6 t
62.6 MDMA,DMA2D和通用DMA性能比较
* I  \9 c) f' R5 U& @! n最终测试的性能如下:/ q' T7 S7 [; v1 O8 g$ i  {1 v% {- ^

% e  p" D' K: @$ \- E
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

* V1 W$ C5 u, q; A& I
# |+ N, \# I# V. [  m. l可以看到DMA1的性能跟其它两个不是一个级别的,适合搞搞低速的外设。. A8 `. k/ K- k* X6 J
4 H5 a7 J5 z+ F
DMA2D和MDMA互有高低。4 u+ n/ X  z. [, n. L0 L! P
5 l; C( S6 k' k
62.7 MDMA驱动移植和使用8 m% D( T! w. e2 x; Q. ~* H
MDMA驱动的移植比较方便:
5 D5 U5 K% K+ d1 K6 Y1 U* g  V: c3 E- u, A
  第1步:添加MDMA的HAL库文件,简单省事些可以添加所有HAL库.C源文件进来。7 y# I* U# G6 C) A2 n4 h
  第2步,应用方法看本章节配套例子即可,另外就是根据自己的需要做配置修改。& c# L2 l. R4 h. f; d6 K
62.8 实验例程设计框架
# ]4 v! _% }0 _) z2 E通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:, z* H* z" X% k6 N* \5 M8 T
. z" O; f& L7 p( d3 w1 F9 N
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

) {) V5 m' ]- x% t$ J8 C4 n" h, J, i% ?7 I! q# r; V
  第1阶段,上电启动阶段:1 C  a! t8 C% q0 W* z4 B
7 d, ^% i5 c8 }: G0 `3 o# I
这部分在第14章进行了详细说明。
& E3 y6 l( `6 z+ l  第2阶段,进入main函数:. W: K7 F; l2 \( A1 a4 C

) n0 E" G% O& W! \# | 第1步,硬件初始化,主要是MPU,Cache,HAL库,系统时钟,滴答定时器,LED和SDRAM。
+ k! H: {  v' M5 k& @ 第2步,测评MDMA,DMA2D和通用DMA性能。1 C) q5 G' o, z( ~5 u
62.9 实验例程说明(MDK)
) g: Q( R' A+ a' p0 J配套例子: 4 J2 V. L- ^2 U6 a: f
5 a  `& ^7 G4 i5 |- I
V7-038_MDMA,DMA2D和通用DMA性能比较
& ?( j0 W; d7 d: F7 V* L" ?4 E' u  t7 z
实验目的:
) H* |& _0 q0 c$ M
! I( q; e& Q: }* R8 u& [比较MDMA,DMA2D和DMA1的性能
8 s" O* O/ e/ {实验内容:
$ U8 n( c# b6 r2 y7 @8 s/ w0 a1 w  ^  C  b/ Q
MDMA,DMA2D和DMA1都测试了如下四种情况:
& H' _4 s( L) P1 x: A& T9 A' m& R. d4 v2 {% {5 d; f4 T( T# J! g4 c, P3 ]
64位带宽的AXI SRAM内部做64KB数据传输。
8 I/ r8 y: i4 r7 F$ w, ~32位带宽的D2域SRAM1内部64KB数据传输。
3 t1 B/ q5 L2 l' _4 K& _AXI SRAM向SDRAM传输64KB的数据传输。; d  l2 N. d( @" d8 _
32位带宽的SDRAM内部做64KB数据传输。
* T3 e1 u7 c4 T上电后串口打印的信息:
3 j8 Q# `7 f( n
6 u6 L8 @- m$ c" |波特率 115200,数据位 8,奇偶校验位无,停止位 1
0 g  ~& f* _$ g' {2 d4 k( `0 n& f
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
" t1 v# J9 \: ^; c6 A
5 v7 x" M1 |8 F" Z: k
程序设计:
. I* S8 x  Z! n
& K2 c% ]/ H, E  系统栈大小分配:
' a; [1 M; }/ s! X" C" I% `- o5 j3 g. B+ `; G4 U4 u8 v
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

$ @( ~6 h! h0 ^' Z" Z
: {  D! ]9 [* t4 k  RAM空间用的DTCM:
7 b( S: _( h+ p7 L- \- [
+ z' N0 ^1 E' i$ h3 o1 N! J
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
6 C3 \' Q6 B* O
$ K7 ?2 [/ h0 C9 s, I9 A
  硬件外设初始化7 k" v+ X$ _) h2 `) J
0 w3 W. j( m# e$ k1 \, h
硬件外设的初始化是在 bsp.c 文件实现:
/ v9 ^' W6 G' @+ \7 d+ [$ ^, m+ Z5 v+ a2 n# o' t
  1. /*
    7 |- l/ n, g( K& Z$ u8 |) b
  2. *********************************************************************************************************) z( R+ Q; d; K: A1 \, P
  3. *    函 数 名: bsp_Init( H1 g" _! m' N! Q1 p( R
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    $ h1 L( ]" o! G: }
  5. *    形    参:无3 B" s4 c8 z9 ^6 @
  6. *    返 回 值: 无9 _  ~6 c! l5 g) a
  7. *********************************************************************************************************
    / q( J# b) S4 m8 V6 M' H+ l
  8. */7 C6 `9 T/ T% }
  9. void bsp_Init(void)
    ' }! t" s8 O' L, a* g- n
  10. {; F, V7 l* l* b
  11.     /* 配置MPU */
    1 w  V  {* {% z$ _5 F, X( ^) @
  12.     MPU_Config();
    - w' `. I4 Y1 k' |: O
  13. " z4 n9 Y5 }  |9 {# o  e6 }
  14.     /* 使能L1 Cache */
    ; P/ w  a% R" _: |: N
  15.     CPU_CACHE_Enable();# ^, Z0 [- @8 q' ^( X9 o+ L7 S# Q
  16. * _* g( P: w3 H! d
  17.     /* & u4 q8 @' t4 {0 U  G3 b
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:" S3 D* G& v9 g/ M# J
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    : Z9 m' X; W$ C+ W8 A* h& u8 c
  20.        - 设置NVIV优先级分组为4。; m5 N6 h& _8 N- E! L
  21.      */
    / z4 d1 k; ]7 J0 u" n9 o" u
  22.     HAL_Init();2 h+ w( [+ R( k( M! @5 p

  23. % x# L; s2 @6 K5 a) ^2 O. e6 |
  24.     /*
    ( o, c/ u, i, {2 q. m. c
  25.        配置系统时钟到400MHz# G4 Y+ C8 e6 p- x8 L$ K
  26.        - 切换使用HSE。
    : B3 B: o* l9 h& q0 R
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。' n6 ~/ U8 {. v( V% ^
  28.     */
      e6 I5 l- t  ?# |/ q
  29.     SystemClock_Config();, Y- \5 c1 p! i# n
  30. 0 F+ A$ @1 v3 o& w
  31.     /*
    , ^; D: W& m6 i7 `6 {2 G; M
  32.        Event Recorder:
    ; N" z2 g+ R$ L9 @5 C, ?. C7 L/ T
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    3 r, ~# }* O, v
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    - U$ I; I0 ]( c; ?! }1 i
  35.     */   
    # q% e5 r6 [! C9 G, |  Z8 A
  36. #if Enable_EventRecorder == 1  
    & ^: i" I8 N% j
  37.     /* 初始化EventRecorder并开启 */. y+ I  L' U7 h, L  H* A
  38.     EventRecorderInitialize(EventRecordAll, 1U);
    ! }. J& i/ D1 t. O
  39.     EventRecorderStart();; z$ K' \9 h' m% ^" ], s$ n
  40. #endif
      ~3 }6 [0 d6 p$ L

  41. * W( P, }% Y& z5 N- l  N' Z$ V  t" w( f
  42.     bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */       4 K  T' E. [3 W0 D2 A, x; r8 b* U
  43.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */7 ~1 X( Q. b& j- x
  44.     bsp_InitTimer();      /* 初始化滴答定时器 */# a, S( @( D- \$ s0 w1 d4 d- f+ _% l
  45.     bsp_InitUart();    /* 初始化串口 */
    8 e. x; C4 T4 M$ f9 H$ u
  46.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
    9 G& w; L% u" e2 g4 K
  47.     bsp_InitLed();        /* 初始化LED */   
    ( X" L5 t9 h* V+ e* a2 k
  48.      bsp_InitExtSDRAM(); /* 初始化SDRAM */
    4 B7 f' ]$ V+ @' i" ^# c( V* a

  49. # U% r& p7 ~& s4 {2 I
  50.     bsp_InitI2C();     /* 初始化I2C总线 */
    # P, Y# s4 N& ?( V: s/ d) v( ^7 v3 E
  51. }
    3 _5 ]8 u6 Y/ b# p; q. B
复制代码

. l+ {# z( q8 n& u
% k$ H* A: C! S, V6 R: @" c( A  MPU配置和Cache配置:! _% A0 G' \6 ~5 v  }  _- c3 J$ n
& V- v# P1 b0 {1 }% J: D- D0 Q# ^: C
数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区和D3域的SRAM4。DAC的数据缓存开在了SRAM4。
. }. b9 Q/ M8 Y9 [# u! i! C: z+ r
  1. /*
    + ~# t& Z) D% j8 L9 \% g& `
  2. *********************************************************************************************************6 R$ i) \( P/ a" l0 ]
  3. *    函 数 名: MPU_Config
    3 O: u, P  V8 B1 S) ?# B+ H- ?
  4. *    功能说明: 配置MPU# Q9 H5 D% d0 @/ _4 ^1 J
  5. *    形    参: 无
    / j) y% M0 o% ?) ^' ~+ S$ }
  6. *    返 回 值: 无
    : M. ~' {! @1 L9 A  Q
  7. *********************************************************************************************************
    . ]/ o, x# l) h8 z; V, d+ u
  8. */( d* {1 }" C% G
  9. static void MPU_Config( void ), `3 g  ?( `- O2 O& {
  10. {
    ! t. G! M* ?) K
  11.     MPU_Region_InitTypeDef MPU_InitStruct;
    * f$ z! ?; V- z# {, R
  12. ! V8 a5 @) `1 W8 }  P6 p
  13.     /* 禁止 MPU *// K: u3 |" F( C
  14.     HAL_MPU_Disable();
    % E" Q  Q5 P/ {  E- c
  15. / U; _& |& X' ~/ P- \, s) W2 @) y  O
  16.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    , S2 H$ X) s1 }4 G% ^1 U
  17.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    7 F& K9 D1 l7 b6 k
  18.     MPU_InitStruct.BaseAddress      = 0x24000000;
    4 V# X4 O; u, f8 ^; p+ n3 d
  19.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;: t/ P  i/ C+ G0 q) R# Y$ f- K' Q1 Z1 c
  20.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;. _5 [/ z% _; T6 x
  21.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    " y: q; c9 Q  ^. _
  22.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;9 s% A: o2 t, Q
  23.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;6 u) R; \2 B2 p# Y
  24.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;/ R& c1 z1 N: h
  25.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;) Q% V% C( w2 T' z: i; i
  26.     MPU_InitStruct.SubRegionDisable = 0x00;
    $ Q5 `3 c" S& z& w/ i6 B
  27.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    ( u. `8 u% x9 \: `* Y% }" ?) m$ i
  28. , Z( Q* P  U' e1 ^  U4 W
  29.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    ; u" D) ]. w. Y& `  N3 J: P- M

  30. ) W" E+ G! X# C- D

  31. + _; s, Z' P) r% |: C: R9 L; l$ C
  32.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    # @+ D  ?8 T6 l4 [  H# [
  33.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    ! u( u! L( B3 u% p7 f
  34.     MPU_InitStruct.BaseAddress      = 0x60000000;, c4 ?7 w5 V# }8 W3 v- N0 ]
  35.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    5 d. D7 I3 _+ N5 @$ }4 |7 B& h/ {+ f
  36.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;6 i0 H0 P, a! i$ {0 F4 v
  37.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;" L" ?: b# o( b- ~6 a6 Q
  38.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
    ! J/ m/ `7 M( j. _7 a6 Y
  39.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;, y9 m; D" w% J8 h, O0 y: ^0 ]' Y
  40.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    $ }4 ~) o( }) S8 C! W( z
  41.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;2 W* c1 U0 ^: d6 D
  42.     MPU_InitStruct.SubRegionDisable = 0x00;
    $ @0 |$ [) s1 n% _8 }
  43.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    6 B% a. g1 @) u9 I; _

  44. : v; V: L  w3 G, [7 i% B) [  D
  45.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    - o: Q' m! y6 U4 E' v
  46. . T6 Z: h& P- s. T0 v0 y
  47.     /* 配置SDRAM的MPU属性为Write through, read allocate,no write allocate */4 d: E, k' \' v# j! V
  48.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;9 z: k1 K9 ~" \: K
  49.     MPU_InitStruct.BaseAddress      = 0xC0000000;
    $ D+ E& r" A( w. m
  50.     MPU_InitStruct.Size             = MPU_REGION_SIZE_32MB;
    8 o  ~/ W& C! Q2 L# b
  51.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    * \& M8 O7 y6 t, h
  52.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;+ |0 m( X( Q" I: j+ d. t# @  K
  53.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    % O0 I/ W4 j/ Q2 y8 t; |
  54.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    . h* z5 y1 Y. @8 m  X
  55.     MPU_InitStruct.Number           = MPU_REGION_NUMBER2;% {8 _( p$ t4 ?9 G. D' l2 Z  h
  56.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;2 V7 `9 f& G  f5 Z
  57.     MPU_InitStruct.SubRegionDisable = 0x00;
    4 q0 y- H3 ?: ?; b
  58.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    4 F9 E( o5 `5 y+ ~
  59. ) R/ A1 U$ v9 e/ [+ b# @) b8 D
  60.     HAL_MPU_ConfigRegion(&MPU_InitStruct);, ]/ s/ }% x- g: X2 L
  61. " x* ~2 ~. y/ U" x( X1 C* K
  62.     /*使能 MPU */! L4 `. O+ G! }' X$ l$ `
  63.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    % L& q2 C5 I+ C- f  g
  64. }( Y9 T- `% d/ f) t) _
  65. / P: |  p7 c- v* Q6 G# k; O: t$ u8 @
  66. /*) T& _% l3 W/ F0 l6 L
  67. *********************************************************************************************************1 r/ a6 i3 Q- C9 v8 v) h0 Z. a
  68. *    函 数 名: CPU_CACHE_Enable& l! y& c3 K" p1 B7 {6 I
  69. *    功能说明: 使能L1 Cache
    , q1 }( D: L  G( d
  70. *    形    参: 无
    6 @/ S/ H# A5 X6 S
  71. *    返 回 值: 无
    ( h* H3 O/ M" Z- ~, m/ P
  72. *********************************************************************************************************- T  E( c: I$ l6 }" K( a3 C
  73. */  N* w  g# |' M0 V
  74. static void CPU_CACHE_Enable(void)
    4 n. k0 @" E7 ?/ n, U/ t( Q5 [* P
  75. {4 O- B1 n8 ]- j+ W
  76.     /* 使能 I-Cache */. j3 p' j6 e, r8 i$ t7 v: ~& n/ _
  77.     SCB_EnableICache();
    2 R, w, e6 Z& G8 ^: s/ r4 t
  78. / @2 i" q! R& w7 s% D  f
  79.     /* 使能 D-Cache */
    9 i2 |2 o1 K) e1 u/ |; r
  80.     SCB_EnableDCache();
    ) F; l% f9 _" ]4 m
  81. }
    8 m, m: s  x0 y* V
复制代码

3 L+ K1 Y& @! t2 Q  m# U2 z; \, v
- e, |* k% T. \8 O. Q8 x0 b) H 主功能:: g) M& O  C) \3 l( }8 |$ q
" A' X9 T" y3 v* ^: k! R
主程序实现如下操作:
4 b, I4 y) o3 A4 _; a( ]) i1 o7 p0 L8 _0 u1 a/ w2 \
测试了MDMA,DMA2D和DMA1。* N, ?5 B; r6 J  b: W/ O0 q& M6 J
  1. /** u, ~: [1 T. X9 p0 A
  2. *********************************************************************************************************3 o7 H5 B; ~& S
  3. *    函 数 名: main! ~3 g9 x* K1 U. q% e" i
  4. *    功能说明: c程序入口, g' _7 w/ b' g/ _7 w5 f& E
  5. *    形    参: 无
    $ ]1 v; u' s8 {. y. r9 @0 h/ J
  6. *    返 回 值: 错误代码(无需处理)
    3 n- _8 q# j2 ?7 [; L3 W1 x& f
  7. *********************************************************************************************************
    ; _1 e1 H: U" y5 p
  8. */- j% S: B5 t7 o9 K3 p- x: M! }. S
  9. int main(void)
    5 B, O3 C9 O% `
  10. {8 @$ Q9 _/ f& i: u
  11.     bsp_Init();    /* 硬件初始化 */+ g4 }5 Q$ e/ j4 `6 T! k; g' C
  12.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    & O" Q1 C7 C8 N
  13. - b" X7 O% U. S' z+ x
  14.     MDMA_SpeedTest();3 H" h8 t2 @3 v5 q" i4 ?
  15.     printf("----------------------------------\n\r");
    * I0 q8 R; _) b' f
  16.     DMA2D_SpeedTest();
    , e" P  ~3 d9 N1 w: q
  17.     printf("----------------------------------\n\r");    , m& t" y% N' E+ p  g7 b  I& M/ \1 \
  18.     DMA1_SpeedTest();
      p0 D' }- K& K( p# R5 r' i# j
  19. $ G  r( r+ j; ?5 K
  20.     bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器,软件定时器0 */, ^9 ^3 ]* m- J

  21. + P- b$ M' N% v
  22.       /* 进入主程序循环体 */
    : x' Q; F" R# Z6 w0 ^4 R
  23.     while (1)
    ' G% x, x( y. g
  24.     {' o- k2 v* w1 }+ g& X, A+ ~3 \  V" _
  25.         bsp_Idle();3 l" O, N" o# a# |! x
  26. 5 r4 d9 m, K0 Q3 ?& n
  27.         /* 判断软件定时器0是否超时 */& I* _/ h$ K4 y# \  P, E* H' O5 I. [
  28.         if(bsp_CheckTimer(0))( V, B% f" @" o3 ~& s
  29.         {
    ! F2 k  N3 J. Z! }# h: L
  30.             /* 每隔200ms 进来一次 */  " |* a5 K& L# ^3 x9 X& }9 a- |, X
  31.             bsp_LedToggle(2);: N; V4 k; m9 k0 O- P% a- h' u, {
  32.         }
    0 K' i, c6 {. ^3 r
  33.     }' q8 i2 {- S' X# Y+ U
  34. }
复制代码
- z5 y/ z  I" t7 o* d

' `# i) c5 h2 V) t) K
7 j: S9 x/ f5 W) A3 S62.10          实验例程说明(IAR)
+ Z2 S; A4 v2 l! P2 @2 ]配套例子:
! ?7 d* M1 R- y, y& X7 M
) C" d; \0 e, T& e/ t. P% \V7-038_MDMA,DMA2D和通用DMA性能比较
$ u( Q" L& o/ Q6 q& J+ I% A$ e5 I( _% M+ R* \- X# \( ~
实验目的:
7 |. I. ]! w2 i% S3 o- l4 e& S, ?* ]( d, L/ c! X1 q# Y9 E" S
比较MDMA,DMA2D和DMA1的性能" Q+ g/ x% c6 p( g" m/ O( _- D
实验内容:
7 c9 R; y0 g1 u
  m8 G; W+ E% Z, V, ]* _ MDMA,DMA2D和DMA1都测试了如下四种情况:
9 s; E! L7 L5 Q. b$ E* j& f
  _& Q$ W- Q1 ?5 s7 G% C1 Y4 i64位带宽的AXI SRAM内部做64KB数据传输。
! X. u! v" r+ R32位带宽的D2域SRAM1内部64KB数据传输。3 M, |+ r- \. T( ?1 W
AXI SRAM向SDRAM传输64KB的数据传输。7 e5 |$ _0 P$ [4 `8 k( t
32位带宽的SDRAM内部做64KB数据传输。4 S) D- s$ [. ~+ Z# _+ a7 f
上电后串口打印的信息:
# v5 l: t" q3 @5 B7 R) H; w& U4 t: h/ m* m
波特率 115200,数据位 8,奇偶校验位无,停止位 13 e6 H/ H2 o- _  ^! ^3 K

: n/ j, a/ L, G2 {" b2 P
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
, X* l/ C! f- O% N" P
  ]9 g6 N5 z  {" D  I6 e+ `8 k
程序设计:
: N9 u  M8 @% B) E8 f1 C! z
) _* N1 U2 W' g6 D3 E  系统栈大小分配:
( L! s0 W2 Y+ `5 X! j! W% r" j6 G8 f; f. g& S% z0 [& m
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

3 B$ ]0 D# u- N: i4 {9 z2 M1 q
. w5 G" w- y+ V6 P  RAM空间用的DTCM:) P0 h) H4 g) h, p$ |+ V3 S
- X* \$ D. t6 O& u  `
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

# G6 A3 i$ W  W4 k3 D
( X3 ?7 c* H5 P/ G3 ^% \# C9 G  硬件外设初始化- N0 _& W4 h0 e& W" s' [. {7 w
6 ]5 C: e) w9 |. w( V# w8 X$ W
硬件外设的初始化是在 bsp.c 文件实现:
5 u% O3 i1 x! j1 n# _9 L( Q" M' q, Z/ S4 P! t3 E
  1. /*
    - Z2 C) u) l3 S! h: i6 x
  2. *********************************************************************************************************
    3 O" K! w; M7 w
  3. *    函 数 名: bsp_Init
    $ h7 w$ z! p8 y4 R) t% n9 j5 v
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    ) N* O, W* o( S5 X# U
  5. *    形    参:无8 a5 _5 t% ^! A8 u5 P
  6. *    返 回 值: 无- v0 Z# U' Z, g- b9 T8 ^8 o' [
  7. *********************************************************************************************************2 ?; m6 h$ y; }% z
  8. */
    7 t7 d% _4 X/ Z# h9 t1 ^* r; O
  9. void bsp_Init(void)) U# G! k+ i; I) Y) x7 }
  10. {
    ; a% D4 V# o: S
  11.     /* 配置MPU */
    7 ^+ K5 y& Z; U- A* |
  12.     MPU_Config();# L! r2 f! D$ f) r- Q- j8 a
  13. # u9 Y' [- z2 t' v1 v9 L! i
  14.     /* 使能L1 Cache */0 {8 m' x" m2 {+ o, U" h  l
  15.     CPU_CACHE_Enable();
    2 O: K/ [4 i2 Y1 c  f1 ^( ?

  16. , D( K' d( W3 N/ ?' t7 \5 |
  17.     /*
    3 |( q5 X) l: e5 }4 w  X2 M
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    + W8 F* O: @3 s8 [$ e: R; B' i3 i5 P
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。+ d8 Y+ w& L5 p2 V* t  s
  20.        - 设置NVIV优先级分组为4。
    ( L4 ~+ f& L' Q* K7 H7 _
  21.      */: N  Z% U3 o  ~& V# ]9 U% b
  22.     HAL_Init();& \; ^4 O! [  {* T

  23. , A) n2 s/ x; P
  24.     /* 5 m7 {2 ]# \! U) D$ C8 C9 D6 u; C) Y
  25.        配置系统时钟到400MHz
    : L+ H4 K) T( K4 S
  26.        - 切换使用HSE。
    / A5 _) P. q/ F# [4 S; w, ]: }
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    5 F, J! v4 h2 \" m* O
  28.     */6 P( ^# H5 @, M" N9 B
  29.     SystemClock_Config();
    5 s) R$ s: q# }+ _

  30. 1 `6 U$ S8 p: ?; @- S
  31.     /*
    . C9 G7 o  j2 H; [$ w! M. y5 l
  32.        Event Recorder:8 H9 M6 B" I) \) }6 d
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。" c9 Z. [9 u( o' Z  W% |0 s! s
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章5 i0 Z0 Q5 d$ q4 q
  35.     */   
    ' K1 F' g2 A. R; z' R
  36. #if Enable_EventRecorder == 1  
    ; {$ V* |( x& p& }0 W) M
  37.     /* 初始化EventRecorder并开启 */
    7 `/ A" L3 h$ w3 {, }; b* O
  38.     EventRecorderInitialize(EventRecordAll, 1U);
    * l- _& G  ^0 |8 {
  39.     EventRecorderStart();
    4 f! H, g0 [8 Q4 V
  40. #endif
    2 ~0 F0 u! D, i; U4 {: c3 b/ y
  41. 1 f* t: x3 P6 ]/ [
  42.     bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */       / y& g7 `5 I: _; V% K9 x0 t+ b
  43.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    ; X0 F) m7 j4 C( i) b
  44.     bsp_InitTimer();      /* 初始化滴答定时器 */
    ( j: z" E5 q: e- O, i
  45.     bsp_InitUart();    /* 初始化串口 */
    6 p& m! p3 S4 R( A' J/ J1 _
  46.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    5 K/ o. R. A; T  s+ [0 ?
  47.     bsp_InitLed();        /* 初始化LED */   
    0 ~: S, J5 ^8 [& a+ g, K
  48.      bsp_InitExtSDRAM(); /* 初始化SDRAM */
    & B+ Q. F9 L6 _; \4 W

  49. 1 ?+ V# Z+ P, E9 c7 ?
  50.     bsp_InitI2C();     /* 初始化I2C总线 */
    , ?1 Q% S: P/ M' {/ _
  51. }
    ; S1 b7 B. u: U. D. _, w" M
复制代码
9 g3 _( l5 [3 `# M- l

6 D6 V" O+ o7 ]+ v- S/ u8 m; R  MPU配置和Cache配置:6 j/ C9 A+ b4 I3 i! [) R7 k) p

! i+ |% j" @; b数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区和D3域的SRAM4。DAC的数据缓存开在了SRAM4。5 w4 A% p/ G) O
+ ~# J& n) {# l, z
  1. /*3 M' K+ v0 |; x" f" v
  2. *********************************************************************************************************% Z. F* V- D3 [/ L" X
  3. *    函 数 名: MPU_Config
    # U* N. \: B% D) a) p2 u
  4. *    功能说明: 配置MPU9 r, B: I" @# {; o) m* J2 [
  5. *    形    参: 无6 o8 r# C6 r7 b' Q$ x4 }9 K
  6. *    返 回 值: 无6 a6 G; E6 }; E* J# s. f
  7. *********************************************************************************************************% \5 y. F+ K1 x6 F; p$ Z( K( N
  8. */
    : h, c7 W' M# H9 x/ \
  9. static void MPU_Config( void )3 p# q5 J2 d2 c. T9 Z( V& |- L, o
  10. {
    , X; u5 ]0 ]7 y1 E
  11.     MPU_Region_InitTypeDef MPU_InitStruct;
    - I" ?' S* F. `# P5 ?% P
  12. + Q* ?4 |- {0 z2 n. M3 z  H' X/ T
  13.     /* 禁止 MPU */0 q+ K' C/ a6 O
  14.     HAL_MPU_Disable();* z  F5 }. P* n. X

  15. 6 x/ k# t+ F- T; A4 b  X4 S4 u
  16.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    , P5 I5 I- V" M1 Q+ v9 O( O5 b" o* I
  17.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    - a( Q3 z" K& f; D' t
  18.     MPU_InitStruct.BaseAddress      = 0x24000000;6 P! ^' l) P2 ?: `( U
  19.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;0 |+ r8 I9 v, X" q% d9 M
  20.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;& P# Z/ E$ r" w; |; h& i' D, C& A
  21.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    # ]4 K8 H% A: C( b* w6 U: J
  22.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;; `2 P3 Z# o2 c& `+ n) P1 b6 y
  23.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;5 A1 ^7 c. ]/ y: |
  24.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;1 ?: q' W* V# s# G0 K1 n1 S
  25.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    * U! g7 ]5 ]2 S3 n& H6 F( r
  26.     MPU_InitStruct.SubRegionDisable = 0x00;
    5 `  a2 X9 O. l' B1 e
  27.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;  G- v! H' u: z0 W

  28. : K2 F$ _( @$ h( o' o' d8 }) {- I
  29.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    , n( w5 S" o# C: ]- ~3 w" `
  30.   d/ _4 K; C% ^3 W6 H* L; j: a
  31.   L* U0 \( g( A
  32.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */+ R; W+ d$ G  C, D6 {8 T
  33.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;  \6 z; r. E# v
  34.     MPU_InitStruct.BaseAddress      = 0x60000000;/ x$ U" \. t+ v
  35.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
    ( E" O- f$ }! P6 e
  36.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    / ^% o# N& C' ?
  37.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;# V  A% a' D5 l" H/ `0 ?' e
  38.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
    9 ~" u* p5 I/ e! g0 n. B+ z: A
  39.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    6 q& F, T5 i; Z7 w9 V( Q8 ]
  40.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    + z$ I% `/ j( e/ {
  41.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;' P# g1 R6 T; u. e7 d
  42.     MPU_InitStruct.SubRegionDisable = 0x00;
    ! r# o  `" K, y/ {) W3 u# a8 n( a
  43.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;7 B' ?: b* h+ `- W

  44. , r2 p' I& U& |4 [3 _" q! v
  45.     HAL_MPU_ConfigRegion(&MPU_InitStruct);) q% W$ Z, c: A- }6 ^# S4 g
  46. $ O3 m+ R' n: R) Q+ W  \
  47.     /* 配置SDRAM的MPU属性为Write through, read allocate,no write allocate */
    7 o) e. E* e* U6 U( Q4 O
  48.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    , e' ]4 f) a8 x, u+ v
  49.     MPU_InitStruct.BaseAddress      = 0xC0000000;
    + s5 O$ `* _3 F/ }# q; W" x
  50.     MPU_InitStruct.Size             = MPU_REGION_SIZE_32MB;, W1 s6 M4 j. ]- J. u
  51.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;/ Z: x1 ]4 @7 g7 C
  52.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;; v+ H; }( ^% h7 m8 C; P
  53.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    + M3 I, Y- \8 @: l# a8 M
  54.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;8 a: n/ A; _7 P1 K' c8 y
  55.     MPU_InitStruct.Number           = MPU_REGION_NUMBER2;% m/ h0 F  s1 f8 [1 T
  56.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    , {+ ^1 u' Z1 w
  57.     MPU_InitStruct.SubRegionDisable = 0x00;  m) E5 E8 N+ [/ _: p  N" y" [
  58.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
      S9 }7 u2 P; b
  59. ) B6 r) \( K# t' b0 S7 D2 V4 M
  60.     HAL_MPU_ConfigRegion(&MPU_InitStruct);$ z7 y% Q- t) h* Z# i0 h0 j2 J
  61. ! {2 m) Q* N- B! ]/ |9 ^/ L
  62.     /*使能 MPU */
    0 m1 t9 O  r- m+ a- D/ V" l
  63.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    6 r7 P9 R8 R" ^- {
  64. }
    - R5 T4 G# Q) n/ a* n

  65. 4 _- }2 l; n3 n7 T3 e; n6 U( y
  66. /*1 p0 k. Y4 s! v5 v( T/ z
  67. *********************************************************************************************************
    - ]. m) S* l7 u$ Y" y  F) [' u) e
  68. *    函 数 名: CPU_CACHE_Enable
    ! Z  r. J4 n; ~5 B5 A
  69. *    功能说明: 使能L1 Cache
    1 F9 A) U) I: ^8 k" N1 i
  70. *    形    参: 无% e, K* N( G% f6 R+ L
  71. *    返 回 值: 无
      V7 ?* s: ~* c& B
  72. *********************************************************************************************************0 P) K; E* {. g
  73. */- k  j, [$ z: X. x/ f- G# s
  74. static void CPU_CACHE_Enable(void)( n, i% t1 L: e1 J( Y8 S
  75. {
    ! M/ G8 ~7 F, F0 _" H- g' S
  76.     /* 使能 I-Cache */
    6 J! G3 u& Y8 Z( u! [$ v5 o
  77.     SCB_EnableICache();  h) P7 V5 l) e& F9 N) j
  78. . L5 J' B) H# |" }1 u
  79.     /* 使能 D-Cache */
    ! E/ o  q. `) n
  80.     SCB_EnableDCache();
    $ w7 G1 J' \6 u1 X0 k$ _5 ~
  81. }& `- `. G1 v/ I: }" j
复制代码
9 n- x1 C& K6 J5 F' P- H: A

2 o% c& O* _7 P0 `+ O8 F8 u0 z  主功能:
$ J$ j" T) h! P8 q6 \( v" \$ }$ B! D7 a$ D  x5 x
主程序实现如下操作:
$ ?2 s  w3 x. O6 [1 d4 X# c% d9 G0 ?* d7 q) Z: o
  测试了MDMA,DMA2D和DMA1。
7 O7 @3 u+ G/ k# ]' C" P8 L1 G! F$ @' p
  1. /*+ [- O; c' c; x: F6 a
  2. *********************************************************************************************************
    ) j# S% ]' _  h: a! N" K0 `- N
  3. *    函 数 名: main) Z' ^2 k& w5 @0 H
  4. *    功能说明: c程序入口2 N5 e+ K6 i( W2 i
  5. *    形    参: 无! [0 s1 G* K( ]7 o5 [
  6. *    返 回 值: 错误代码(无需处理)0 O3 o& j3 F( J9 `- C, ]! |' }
  7. *********************************************************************************************************& M2 C/ y8 b% ]( b: ~
  8. */, r) G* u$ o+ y$ M+ _! Y; X( i
  9. int main(void)# _+ t) [6 {" p; C# ~. K
  10. {
    : q, O1 ~( w% @: {
  11.     bsp_Init();    /* 硬件初始化 */& ~* c; o% H  V3 j
  12.     PrintfLogo();    /* 打印例程名称和版本等信息 *// v4 I$ L& n0 H3 E) K
  13. 2 ^: m; ?$ C, J" i
  14.     MDMA_SpeedTest();
    : M5 I% p& ?9 b' h7 C# ~
  15.     printf("----------------------------------\n\r");! a+ }! y- w8 H- v* w+ Q0 W7 c
  16.     DMA2D_SpeedTest();: [; [. u! m# v9 f+ j. Y
  17.     printf("----------------------------------\n\r");   
    " x7 ~# D) I  }* e$ |5 M5 I( E
  18.     DMA1_SpeedTest();3 o6 x+ d' m# `8 k: B
  19. & w% J6 }, d5 {! M
  20.     bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器,软件定时器0 *// t! _7 \. E' H- E

  21. ! }5 ]2 q' j. d7 m) N0 [
  22.       /* 进入主程序循环体 */
    " v) W% H5 B) L4 ~
  23.     while (1)
    : Z( b% m  s; \8 e9 v
  24.     {$ s  z# t# `0 q' I& ?7 \' y0 _: F1 a
  25.         bsp_Idle();# q3 Z2 e1 G$ N
  26. & k$ o; {, T: e. V
  27.         /* 判断软件定时器0是否超时 */) C* b6 r7 I2 B$ T, \7 c% q- v- w
  28.         if(bsp_CheckTimer(0))
    % c$ B0 [1 y+ Z5 n; h
  29.         {
    ' J: n7 m, c; y
  30.             /* 每隔200ms 进来一次 */  ) T  L3 `# }6 |& D. M2 {  }
  31.             bsp_LedToggle(2);' L+ F4 s/ D$ Q2 v0 }
  32.         }$ s6 R! J7 y' J' G5 {. o9 n3 ?. l( n& c
  33.     }
    ) D, o. ?9 h& H4 Z$ X
  34. }
    - M% @; e# C6 L: W8 m$ n9 e( V
复制代码
$ c6 q: c) W% _% z7 D- B

5 m' ?7 n9 {5 c2 i. V62.11   总结
$ m9 a% ]' o# n: Z8 Y& B4 c5 @) b本章节涉及到的知识点比较重要,以后用到DMA的地方比较多,可以根据性能选择合适的DMA。
& Q) W7 y3 b1 y/ }% [
! X2 m' L' p% d2 z/ R9 H  s5 r: D: q
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
收藏 1 评论0 发布时间:2021-11-1 21:46

举报

0个回答

所属标签

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