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

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

[复制链接]
STMCU小助手 发布时间:2021-11-1 21:46
62.1 初学者重要提示% ^9 w7 C6 j4 j. W1 w3 J
  学习本章节前,务必优先学习第61章,需要对MDMA的基础知识有个认识。* q( ?; R% o" \( m
  
* x+ t  u, q5 C1 s  [0 G. ]62.2 测试条件说明
, d8 [3 r5 \$ T: jMDMA,DMA2D和每个都测试了四种情况
; o! b- O/ M' A: _* y0 [4 c0 `1 _5 m9 R) |6 M
  64位带宽的AXI SRAM内部做64KB数据传输。
: X  Z5 C' |5 E2 o2 s( J1 c  F  32位带宽的D2域SRAM1内部64KB数据传输。
7 j; C3 j" I1 b6 S1 E: k+ }  AXI SRAM向SDRAM传输64KB的数据传输。0 [. f; S% R$ Q5 N: I' f
  32位带宽的SDRAM内部做64KB数据传输。/ S* Q, U, m( ~  I) w
MDMA:& n+ \7 O$ K6 a& v- S
) o; \  p& Q' N
在D1域,支持64位带宽的DMA数据传输。
) n8 f5 d* f4 @* u- V4 B& \9 v( k1 ?, k5 H4 ?
DMA2D:
3 ?6 T$ B5 Z' p0 }- O4 W. X2 _8 N9 N在D1域,主要用图形2D加速。+ v" Z. i2 T  ^& ]- m. T! e! I

% T9 k9 _6 H0 x0 }2 qDMA1和DMA2:
; e; U$ F7 b4 U; g6 J在D2域,支持32位带宽的DMA数据传输。
2 f+ i4 l$ ]7 @0 W- O* j  j" ?
! h  |" t: j2 r( l% w/ ]" Z* \9 [4 v6 N62.3 MDMA性能测试程序设计2 n, ]8 v7 A) N, B7 A2 ~
这里将MDMA的程序设计分为以下几部分,逐一为大家做个说明:' a5 C& f5 \% a2 L  u

4 t: G. ?8 c$ K7 ?, |62.3.1 第1步,MDMA初始化
5 }/ x" S6 Z3 Q* y1 B# _程序代码如下,采用块传输,源地址和目的地址都是64bit数据传输,并设置16beat突发,也就是连续传输16组64bit数据。
; y6 M3 y1 [' V) W+ J5 ^! N# U$ ?
  1. 1.    __HAL_RCC_MDMA_CLK_ENABLE();  * y. E9 t5 T& U: x$ x
  2. 2.      _& p5 r1 \6 x- l5 b
  3. 3.    MDMA_Handle.Instance = MDMA_Channel0;  % `9 x. t* M& f9 L: @" @2 c! B
  4. 4.    9 l8 h8 x& ?8 J! j
  5. 5.    MDMA_Handle.Init.Request              = MDMA_REQUEST_SW;         /* 软件触发 */+ W  n# H+ [" ]) ^/ E0 |7 F. M
  6. 6.    MDMA_Handle.Init.TransferTriggerMode  = MDMA_BLOCK_TRANSFER;     /* 块传输 */
    5 b* H2 l1 L; }" v9 i* n
  7. 7.    MDMA_Handle.Init.Priority             = MDMA_PRIORITY_HIGH;      /* 优先级高*/  i; I  Y, L% s/ x$ a& K9 A
  8. 8.    MDMA_Handle.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE; /* 小端 */" U' m3 X; J  @* n* h$ ~- q
  9. 9.    MDMA_Handle.Init.SourceInc            = MDMA_SRC_INC_DOUBLEWORD;      /* 源地址自增,双字,即8字节 */
    5 S/ m5 w/ t- z' K% e; L" [3 _
  10. 10.    MDMA_Handle.Init.DestinationInc       = MDMA_DEST_INC_DOUBLEWORD;     /* 目的地址自增,双字,即8字节 */: g9 t7 R: q5 V2 c, v6 A0 d
  11. 11.    MDMA_Handle.Init.SourceDataSize       = MDMA_SRC_DATASIZE_DOUBLEWORD; /* 源地址数据宽度双字,即8字节 */
    ! i0 S  e$ O7 C8 Z, S
  12. 12.    MDMA_Handle.Init.DestDataSize       = MDMA_DEST_DATASIZE_DOUBLEWORD;/* 目的地址数据宽度双字,即8字节 */
    & J4 s4 Q' ^" z, \5 b2 `' ]6 D
  13. 13.    MDMA_Handle.Init.DataAlignment      = MDMA_DATAALIGN_PACKENABLE;    /* 小端,右对齐 */                    
    2 q6 I& E6 f6 V+ T! b0 j
  14. 14.    MDMA_Handle.Init.SourceBurst        = MDMA_SOURCE_BURST_16BEATS;    /* 源数据突发传输 */
    $ X: }, `9 z! ^+ @+ z" [9 H
  15. 15.    MDMA_Handle.Init.DestBurst          = MDMA_DEST_BURST_16BEATS;      /* 目的数据突发传输 */
    9 C% |/ N% k+ X8 {' m# O$ w
  16. 16.    2 p/ v1 m+ h0 o
  17. 17.    MDMA_Handle.Init.BufferTransferLength = 128;    /* 每次传输128个字节 */
    % h# \  h* I  S' t& X2 t$ D: j/ Q. t7 z
  18. 18.    2 J' C! V3 X4 |$ v% _
  19. 19.    MDMA_Handle.Init.SourceBlockAddressOffset  = 0; /* 用于block传输,地址偏移0 */
    2 p, y/ o, Q2 Y' P' \" L
  20. 20.    MDMA_Handle.Init.DestBlockAddressOffset    = 0; /* 用于block传输,地址偏移0 */
    3 r2 L# z$ C8 @& U0 B
  21. 21.    ; x0 `2 P. ~4 G# E9 Z, X6 R
  22. 22.    /* 初始化MDMA */
    . t5 n# y' P5 w
  23. 23.    if(HAL_MDMA_Init(&MDMA_Handle) != HAL_OK)+ e/ E8 a9 o2 {$ Q' Z, W
  24. 24.    {& a+ Q; |0 s, N+ M4 |. L- b
  25. 25.         Error_Handler(__FILE__, __LINE__);) C" i5 S" z& d2 w) u3 }1 w; g
  26. 26.    }% q2 ^& c' S5 c/ F
复制代码

) X/ x% C% N, r; P* R/ X$ n2 _4 l5 E* ]7 {% z
下面将程序设计中几个关键地方做个阐释:0 T9 x+ t( ]9 g2 W: w* X+ r

: H* y* A: S/ |0 n  t9 \1 K  第1行,务必优先初始化MDMA时钟,测试发现没有使能时钟的情况下就配置MDMA很容易失败。9 D, {, R, b+ a$ ]5 {: H
  第14-15行,突发传输的配置非常考究,每次突发传输的总数据大小不能超过128字节。
$ |* @" V) {' l, _5 ?  对于源地址就是SourceBurst * SourceDataSize <=  BufferTransferLength。
2 S' y- ^# V% B9 W  I8 B" r 对于目的地址就是DestBurst*DestDataSize <= BufferTransferLength。
6 w$ h! W3 q5 t: e3 r# G2 F) X比如当前的程序配置:; t5 D" W  W2 f6 T* g6 N1 \0 N
, ?3 h: {$ P! Z* f7 J5 k& {
SourceBurst * SourceDataSize = 16*8 =128字节( ?8 X( ?4 m/ A/ I* l

* v- X# u( ~- Q# _7 CDestBurst*DestDataSize = 16*8 =128字节
8 I) ^1 a+ i5 ?  k$ ~# y/ u' @  y4 X4 U7 m7 A% ^; x+ r  T
6 [/ ?! G2 k( F! \: ?& a$ [+ ]8 t

) d0 P9 J% [6 ?1 y" r) s" ?' @这里要特别注意一点,如果实际应用中最好小于BufferTransferLength,防止不稳定。; }6 H# u! L- J, X
+ U* e+ ~- w. {7 M$ G1 }% Z0 \$ A
62.3.2 第2步,MDMA中断配置
! h& f* `& Z2 p$ o. ~* w% Q& b" A5 a, GMDMA的中断设置比较简单,代码如下,注册了MDMA的传输完成回调:
9 g/ q' {+ G! U5 m5 |: C1 w2 Z- p( s
  1. HAL_MDMA_RegisterCallback(&MDMA_Handle, HAL_MDMA_XFER_CPLT_CB_ID, MDMA_TransferCompleteCallback);$ Q, f! P7 }7 I# H
  2. HAL_NVIC_SetPriority(MDMA_IRQn, 0, 0);6 c9 Y+ E2 {  h) D' l
  3. HAL_NVIC_EnableIRQ(MDMA_IRQn);  ! ?% X. p( q* t( V
  4. % W; g; n% Y) P& k+ b0 H; R1 E
  5. void MDMA_IRQHandler(void)# k# O- L+ G* J) A0 U+ |
  6. {& w( a, {: m0 L  I/ R5 K7 }0 g& A
  7.     HAL_MDMA_IRQHandler(&MDMA_Handle);4 q6 w: L; c3 k2 R1 c
  8. }9 u  L9 }6 ?6 T
  9. static void MDMA_TransferCompleteCallback(MDMA_HandleTypeDef *hmdma): L: J! `- a: l/ h. b
  10. {
    3 ^& P+ S, ?: D
  11.     TransferCompleteDetected = 1;
    % M: A- Z6 r5 v# u& O  ?
  12. }
复制代码

- C# g. b0 J' y+ P+ r2 c: V1 _( C, V& T4 z

9 _7 \  c8 v) V0 M0 U$ [! q在传输完成回调里面设置了一个变量标志TransferCompleteDetected,方便指示传输完成。! t5 W/ P! B5 ~" A
' ?. }4 I. t! C$ x" B, ~
62.3.3 第3步,AXI SRAM内部互传64KB数据( Q6 J) \  S) G: ?. u4 H# P( g9 m
通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0x2400 0000 + 64*1024里面:
/ q4 j; B" J% L& E9 e3 x8 _- h0 W8 j- \% M; E7 [
  1. TransferCompleteDetected = 0;
    5 a2 s, y/ I8 H  p& d/ \6 o+ X
  2. HAL_MDMA_Start_IT(&MDMA_Handle,
    . Y- {! J4 `+ N, g/ _8 A/ C
  3.                   (uint32_t)0x24000000, 3 ?: X0 [1 r( m! @4 k: ^
  4.                   (uint32_t)(0x24000000 + 64*1024), 6 T8 q( Z; H" g7 ~( ~" @
  5.                   64*1024,
    7 E. S6 g1 j0 ?. l6 l, }  Y( w
  6.                   1);' [% I' q! T) L: j$ g& q' U

  7. : z5 f, h! M8 g8 @; ?

  8. - C! l( \% Z6 `3 `8 c! F0 L8 @# ?- t
  9. start = DWT_CYCCNT;- R' |# X5 w! z* A% Q
  10. while(TransferCompleteDetected == 0) {}
    , n* l9 Q: z% ]& |$ B
  11. end = DWT_CYCCNT;
    ; _1 R3 p- R+ A  w
  12. cnt = end - start;
    2 P( i, F% Q0 V# s1 q* |# }" j
  13. ! _# ~, n  k  L, \! i
  14. //64*1024/(cnt/400/1000/1000)/1024/1024 = 64*1000*1000*400/1024/cnt = 25000000/cnt
    " c- _1 `3 E, C4 _. H& j1 p! G# d
  15. printf("MDMA---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

/ G! ?- e, X' f! Y5 `# S4 y2 g6 D6 F3 X
+ q& ^, T" E" o" X, l
通过时钟周期计数器测量执行时间,单位2.5ns。$ G# t& P3 c8 w: p" h+ }

, z2 O- w/ e5 A* h$ g62.3.4 第4步,D2域SRAM1内部互传64KB数据
4 `" c& {2 \+ _& z* _: G通过下面的程序实现将地址0x3000 0000开始的64KB数据复制到地址0x3000 0000 + 64*1024里面:
) G$ [4 m: N8 Y% O5 N+ M" h5 y
! R  P7 B1 i1 a& d+ G
  1. TransferCompleteDetected = 0;
    / N- N9 \0 e3 M7 g; S" q6 t
  2. HAL_MDMA_Start_IT(&MDMA_Handle,
    , q% J. p) f2 A" @) _1 G% b
  3.                   (uint32_t)0x30000000,   g% F" L, A( W1 i: H+ |
  4.                   (uint32_t)(0x30000000 + 64*1024), 6 q; |1 B6 F9 B. D5 C6 S
  5.                   64*1024, 6 O# C/ I( }+ r- t6 c
  6.                   1);# F1 H5 v; I$ \

  7. 3 |: F" a& J" s; _: V, b' Q: _
  8. start = DWT_CYCCNT;2 A6 W9 `0 T& Y" }
  9. while(TransferCompleteDetected == 0) {}
    1 A3 p" L- U: y+ i9 G  j! d% O
  10. end = DWT_CYCCNT;9 q' G# ]! z: L4 {" _& x
  11. cnt = end - start;
    , G* {3 O* k( n$ z8 c, L

  12. & `) _6 Q  K5 S
  13. printf("MDMA---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

- R% z0 B( y+ a+ ^# B) l通过时钟周期计数器测量执行时间,单位2.5ns。/ d3 p1 }; o! C! B5 D! G) u

1 {2 y! _# A1 Z, x/ C* s/ O62.3.5 第5步,AXI SRAM传输64KB数据到SDRAM
8 T' `& r% |4 n9 c2 O通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0xC000 0000里面:. z% @0 @( a% e- B

0 z, i5 e7 u, ~  v8 O" b
  1. TransferCompleteDetected = 0;
    7 y" a. T8 [. I6 G0 ]
  2. HAL_MDMA_Start_IT(&MDMA_Handle,
    6 `8 e+ |$ z3 c
  3.                   (uint32_t)0x24000000,
    , t& a# K' m5 @# a
  4.                   (uint32_t)0xC0000000,   i5 o- G1 [; i6 `& f) p
  5.                   64*1024, * @. |- K; s( u$ c% N
  6.                   1);! U; o# Q) _) }% k8 C- _

  7. ; e  \2 I+ g; z3 g4 t
  8. start = DWT_CYCCNT;" O+ b" k8 Z5 m1 ~2 s: j
  9. while(TransferCompleteDetected == 0) {}
    % Y9 E: W% U) A
  10. end = DWT_CYCCNT;
    / }. y( {  L7 O& z6 K$ z
  11. cnt = end - start;5 v5 H' s' T2 G4 ~. V# A
  12. + Q7 B( `5 h5 s0 z1 H
  13. printf("MDMA---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
. c8 J; F8 U+ ]% U' ~2 W1 B

1 d* F* s- ~( H5 _4 W6 l* i' E; ~( ]! N
通过时钟周期计数器测量执行时间,单位2.5n。
0 @; q- J7 I& _& q9 G7 F' b1 g
' h, F9 d" J+ w0 a- L62.3.6 第6步,SDRAM内部互传64KB数据
/ A9 H$ B# a! J+ r& p9 j通过下面的程序实现将地址0xC000 0000开始的64KB数据复制到地址0xC000 0000 + 64*1024里面:2 C" p& }: M3 Q2 k+ R1 F$ R$ j5 r

0 m" _" p3 \$ g2 S* w/ i& P! \" m
  1. TransferCompleteDetected = 0;' Q4 v/ b: I& f( o2 W
  2. HAL_MDMA_Start_IT(&MDMA_Handle,
    7 p3 k3 E4 M) D" k; P( g- B! N; Y* v/ l
  3.                   (uint32_t)0xC0000000, % M- d6 ~$ m" [# m. a' f
  4.                   (uint32_t)(0xC0000000 + 64*1024), . J5 _$ f3 q2 T5 o
  5.                   64*1024,
    ! W: q1 y% P+ j  E& K
  6.                   1);
    1 A+ E( _! c& r( [# V
  7. ; R& ~' b  g8 s: ~$ J- X; x

  8. + W2 `0 B. c! O: ?) j
  9. start = DWT_CYCCNT;
      t% F$ g* }6 n9 k' d
  10. while(TransferCompleteDetected == 0) {}' v" k! d& i0 W' f
  11. end = DWT_CYCCNT;
    # n3 L) ?/ r* G' _- ?7 k
  12. cnt = end - start;
    : D3 t$ c- ^8 C% h! E1 w! s
  13. 6 |# o* q# o8 u
  14. printf("MDMA---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
3 |+ J5 d" w5 L2 Z/ b5 J$ `3 U
通过时钟周期计数器测量执行时间,单位2.5n。
# ^1 n) T. g0 ]0 G" N4 D* F
' ^: f+ W- y' R6 t* F62.4 DMA2D性能测试程序设计
* T. A7 g+ b! o+ K( `+ L, K, l7 v这里将DMA2D的程序设计分为以下几部分,逐一为大家做个说明:4 D: S/ L! u8 M5 o' |; C6 H9 x

7 h$ R; n; I/ r62.4.1 第1步,DMA2D初始化
$ R1 _5 r- P9 C: C3 l配置DMA2D采用存储器到存储器模式,前景区和输出区都采用ARGB8888格式,传输64*256次,每次4字节,即64*256*4 = 64KB数据。8 N& @  b6 h9 B4 F+ f5 j* x

5 W+ }0 I( M4 @* M1 Q
  1. __HAL_RCC_DMA2D_CLK_ENABLE();  4 S5 s4 x( W6 I2 b
  2. ( {: t- R* Q0 ~$ R
  3. /* DMA2D采用存储器到存储器模式, 这种模式是前景层作为DMA2D输入 */  
    / H4 D7 s" |6 q9 C& k0 g
  4. DMA2D->CR      = 0x00000000UL;% j" N1 W$ n$ m7 p) S8 x8 R
  5. DMA2D->FGOR    = 0;# W. j/ T3 b. E; Q. N  s* k8 w# Q
  6. DMA2D->OOR     = 0;
    8 G6 k' _' v) M0 r

  7. ! A1 _* Q& j2 C( O. H! r
  8. /* 前景层和输出区域都采用的ARGB8888颜色格式 */- }. C+ a; {  P8 ?: n2 B; R9 k+ a5 ^
  9. DMA2D->FGPFCCR = LTDC_PIXEL_FORMAT_ARGB8888;) T) i: l1 E8 I2 I
  10. DMA2D->OPFCCR  = LTDC_PIXEL_FORMAT_ARGB8888;
      n' W' ^8 U) l4 o" o
  11. 1 l& M7 F  s* I
  12. DMA2D->NLR     = (uint32_t)(64 << 16) | (uint16_t)256;
复制代码

" L$ s+ x/ i$ Y% ?" l' _7 r$ a3 e2 l62.4.2 第2步,AXI SRAM内部互传64KB数据; j. E+ g6 L0 c3 f! M
通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0x2400 0000 + 64*1024里面:
; V8 ~$ O, _; D& T
  1. /* AXI SRAM的64KB数据传输测试 ***********************************************/4 L8 u- o/ f: }( g; H$ b! V
  2. DMA2D->FGMAR = (uint32_t)0x24000000;( }) w  j8 ]; i; p3 T
  3. DMA2D->OMAR  = (uint32_t)(0x24000000 + 64*1024);0 G  B) A* _4 K7 y' T( c( b
  4. DMA2D->CR   |= DMA2D_CR_START;   9 x; s- t+ D* `8 Z! }% j
  5. # C$ i- Y. o- s/ F+ T7 H
  6. start = DWT_CYCCNT;6 }" H" y' x' I4 h
  7. /* 等待DMA2D传输完成 */0 |( e, A& h6 G! ~, ?
  8. while (DMA2D->CR & DMA2D_CR_START) {}
    & @0 C( G4 |. g( o+ B8 n& l& u( k" q
  9. end = DWT_CYCCNT;
      [3 D5 `- h& E& @1 y* t
  10. cnt = end - start;4 o; Q$ n- @& r) y$ H. `

  11. 3 t" Y5 G9 a/ y3 P. O
  12. printf("DMA2D---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

8 M$ O. F) `! k" q! D* h0 d通过时钟周期计数器测量执行时间,单位2.5ns。
8 s3 x) y0 S6 C+ i! I5 [+ S% a; V# I% _8 r: u6 @0 A# G$ j% Z
62.4.3 第3步,D2域SRAM1内部互传64KB数据7 ?, h/ r" R: C$ m9 i
通过下面的程序实现将地址0x3000 0000开始的64KB数据复制到地址0x3000 0000 + 64*1024里面:
- [; m% l% J/ L" u! L
+ ]  h* J0 q& D6 d
  1. /* D2域SRAM1的64KB数据传输测试 ***********************************************// Y3 }/ T  ~3 S( F
  2. DMA2D->FGMAR = (uint32_t)0x30000000;/ b' |2 l# ?4 v, i! U  f6 f% |
  3. DMA2D->OMAR  = (uint32_t)(0x30000000 + 64*1024);
    1 B7 X$ B& |5 q+ a- u8 o/ w6 Q0 K
  4. DMA2D->CR   |= DMA2D_CR_START;  
    % Q: ?( x# H0 z+ b; y# U) C
  5. 0 x  A. ]+ r1 y/ s* v, k! o
  6. start = DWT_CYCCNT;
    + k% z/ J1 A/ j7 ]& q
  7. /* 等待DMA2D传输完成 */- h% \# M) t7 H
  8. while (DMA2D->CR & DMA2D_CR_START) {}
    ) l  [  j9 C% u! Y: @0 g7 {3 n$ G" ?
  9. end = DWT_CYCCNT;
    0 U8 ~, f1 [2 \! e
  10. cnt = end - start;
    0 R+ U) S9 N2 _& x" A$ P, M

  11. ' {7 ^/ ?# @8 c
  12. printf("DMA2D---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

* J) t7 Z( I0 v6 _2 q2 t9 |! _通过时钟周期计数器测量执行时间,单位2.5ns。
6 Q3 C0 A; I' I
+ k3 u- B$ V: [6 ^8 L62.4.4 第4步,AXI SRAM传输64KB数据到SDRAM
5 K8 G# `3 q1 H; t! E通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0xC000 0000里面:2 \8 T/ Q$ o( ~
  1. /* AXI SRAM向SDRAM的64KB数据传输测试 ***********************************************/2 A  q5 ]8 b$ [$ C
  2. DMA2D->FGMAR = (uint32_t)0x24000000;
    6 X! x0 d3 H1 ?, }
  3. DMA2D->OMAR  = (uint32_t)0xC0000000;
      S: s1 }' t1 I% s
  4. DMA2D->CR   |= DMA2D_CR_START;  . @( {$ {5 `; R+ {- W

  5. 5 i3 u0 a4 ]: |. k
  6. start = DWT_CYCCNT;6 p% Y  h0 H  ~/ W
  7. /* 等待DMA2D传输完成 */, u1 R. ~* |7 i8 h5 D' n% @  j
  8. while (DMA2D->CR & DMA2D_CR_START) {}
    / ~& |+ N' s5 _, n7 G5 f
  9. end = DWT_CYCCNT;
    * |- U, z, c6 X$ f9 R0 f  O
  10. cnt = end - start;& T, J0 j* E6 l) _! v3 `

  11. # A! J# Y8 E5 s, \; h% z4 |
  12. printf("DMA2D---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);  
复制代码
, R9 ]! B& n( w7 x/ N
通过时钟周期计数器测量执行时间,单位2.5n。4 @2 L5 n& \5 ^! H' o& F, i4 ]

: T% w3 t; U- C, J: @8 [62.4.5 第5步,SDRAM内部互传64KB数据
) O( K9 K3 J' d1 C通过下面的程序实现将地址0xC000 0000开始的64KB数据复制到地址0xC000 0000 + 64*1024里面:
, e+ t  [2 s7 t( u2 O  u
  1. /* SDRAM的64KB数据传输测试 ***********************************************/
    ( G+ b% E: p: q: D( F0 W
  2. DMA2D->FGMAR = (uint32_t)0xC0000000;3 N* Z0 _+ H: b" }) `9 j/ X
  3. DMA2D->OMAR  = (uint32_t)(0xC0000000 + 64*1024);
    6 K% C" O7 E+ [& d( D
  4. DMA2D->CR   |= DMA2D_CR_START;9 v% N; O6 b( @$ t0 T
  5. 7 M# a- i! h; h& _' \
  6. start = DWT_CYCCNT;5 e+ W7 v0 q# K2 D
  7. /* 等待DMA2D传输完成 */
    6 k0 `4 E1 h5 W$ _7 e% {
  8. while (DMA2D->CR & DMA2D_CR_START) {} / q. ~( l5 l8 z) g
  9. end = DWT_CYCCNT;0 |$ q+ M. ?" v% E* |6 D; ^2 e2 M
  10. cnt = end - start;    # a9 Q6 o/ T) j, A. f% }2 L0 u& g' y
  11. . t" ?- ?. q& y$ @
  12. printf("DMA2D---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);   
复制代码
) h2 o6 _& {( @2 E
通过时钟周期计数器测量执行时间,单位2.5n; |: U2 j& B. V: O. B

! S7 O( J! I, l  @4 }62.5 通用DMA性能测试程序设计
* \3 T. S+ J3 Y9 Q0 H& ?& k; ?4 p这里将DMA1的程序设计分为以下几部分,逐一为大家做个说明:
( A( i( I( c5 n7 F- r$ U$ p0 m3 o* z. s& k. Q
62.5.1 第1步,DMA1初始化' E/ C) W, y. k' r9 x0 U4 h  \( Y$ R
程序代码如下,采用存储区到存储区传输方式,源地址和目的地址都是32bit数据传输,并设置4beat突发,也就是连续传输4组32bit数据。4 i/ s& ?9 n9 P2 ^/ N3 H" W$ z
  1. 1.    __HAL_RCC_DMA1_CLK_ENABLE();  E3 }" @! }# v2 N" |, }
  2. 2.   
    0 x. \. P1 _- p- X
  3. 3.    DMA_Handle.Instance                 = DMA1_Stream1;
    ( s: S: S( g& K: G
  4. 4.    DMA_Handle.Init.Request             = DMA_REQUEST_MEM2MEM;  : w2 N- \* V' [
  5. 5.    DMA_Handle.Init.Direction           = DMA_MEMORY_TO_MEMORY;: r/ ]& ^1 j8 r; V  m! I
  6. 6.    DMA_Handle.Init.PeriphInc           = DMA_PINC_ENABLE;! t5 d1 A# r+ F9 T! h! l; l7 k
  7. 7.    DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;- i. F. Z/ i( D8 {' E/ U9 U
  8. 8.    DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    8 y; U+ v4 k. P! b8 r( m7 t$ d
  9. 9.    DMA_Handle.Init.MemDataAlignment    = DMA_PDATAALIGN_WORD;( L& U: c* f" q5 R
  10. 10.    DMA_Handle.Init.Mode                = DMA_NORMAL;
    ; q0 x8 N# \! m# K- j: p4 q$ J3 S
  11. 11.    DMA_Handle.Init.Priority            = DMA_PRIORITY_VERY_HIGH;
    , k* p$ p3 O( D& d% E8 P8 i
  12. 12.    DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
    * R$ U. y& z( l
  13. 13.    DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
    " t; E# z) ~2 O3 s' }, u
  14. 14.    DMA_Handle.Init.MemBurst            = DMA_MBURST_INC4;     /*WORD方式,仅支持4次突发 */
    ) c2 _: g" S9 k+ w9 `& `
  15. 15.    DMA_Handle.Init.PeriphBurst         = DMA_PBURST_INC4;     /*WORD方式,仅支持4次突发 */6 I2 q1 g5 s  T5 V- K, Z
  16. 16.    DMA_Handle.XferCpltCallback         = DMA_TransferCompleteCallback;
    1 s) M  b  }. C/ e$ d0 ]0 N
  17. 17.   
    0 c! E7 e$ {* X3 M( a# z
  18. 18.    HAL_DMA_Init(&DMA_Handle);
复制代码

9 `2 F! M- W  R$ F8 a! @' c8 @8 c下面将程序设计中几个关键地方做个阐释:- [2 A8 m3 r$ u( ~/ ~5 S
; b6 s/ {5 {7 {. j. X4 m
  第1行,务必优先初始化DMA时钟,测试发现没有使能时钟的情况下就配置DMA很容易失败。& i$ }9 D& c3 l0 D6 h' _
  第14-15行,突发传输的配置非常考究,这里要特别注意数据位宽,FIFO以及突发的配置。
- c& M* b3 k) f$ T  m: `9 d) r( p! U* \- @3 j: p$ R
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

2 c# ?" t  N# R" _3 `  ?" o' x3 U. A' j
! ]- M; F8 a: b5 b3 b+ F, F8 \程序中数据位宽是配置为32bit,FIFO配置为满,那么突发仅可以配置为4beat,即DMA_MBURST_INC4。2 V+ n, Z( M* Q( ^9 j

/ ^3 i4 K$ L8 L5 H  第16行,设置传输完成回调函数。
" ]3 e! {! N* ~  a: }62.5.2 第2步,DMA1中断配置
0 |' g( M! g* i' Y3 {: s$ n& ?DMA1的中断设置比较简单,代码如下:
) [& ^9 ]- L0 \% v) q
5 P6 Y$ u5 b; f) x$ H4 C
  1. HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
    4 K3 F# V8 n9 S' ?. ]! N
  2. HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
    ( v9 o# Q! e" v( ~" p& f

  3. . _7 I8 R( j% Y5 W6 D) L1 u) [; c: L
  4. void DMA1_Stream1_IRQHandler(void)) D4 ]; E( V3 f( {6 k# U( |
  5. {7 q4 a  n2 B- L7 _% t  s2 ^$ b
  6.     HAL_DMA_IRQHandler(&DMA_Handle);
    0 z& X3 h0 G) Y3 T1 A3 j
  7. }- Z. C3 f" [. _7 k* h) A
  8. static void DMA_TransferCompleteCallback(DMA_HandleTypeDef *hdma)4 ~6 k, J# Y+ A
  9. {( _7 o9 q4 `& f8 v
  10.     TransferCompleteDetected = 1;8 D# A" g' c$ p8 J
  11. }
复制代码

8 D" F# I8 ^% S5 k/ G' W+ ~  [% j在传输完成回调里面设置了一个变量标志TransferCompleteDetected,方便指示传输完成。) O& Y- n# Z7 H+ \

# l* N" \; v/ B4 h62.5.3 第3步,AXI SRAM内部互传64KB数据
3 C+ N# p' d( d, b9 }5 V; J1 S通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0x2400 0000 + 64*1024里面:# C9 z! R( ]% A$ t$ ?7 c# l

! f, {  S4 {$ W6 Q% ^
  1. /* AXI SRAM的64KB数据传输测试 ***********************************************/
    & w$ k3 l7 z$ y& _) h4 p1 q
  2. TransferCompleteDetected = 0;3 B2 [) L* `) T2 @1 u9 O# o- F
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x24000000, (uint32_t)(0x24000000 + 64*1024), 64*256);" P) P2 V8 u& z: z7 x" v& {
  4. : P$ |0 z; l1 G/ \: a" ~# [1 q
  5. start = DWT_CYCCNT;! [8 T3 i! F# j* g* N; \
  6. while(TransferCompleteDetected == 0) {}
    / }. U, O* [$ F4 W& D
  7. end = DWT_CYCCNT;! [1 w" E1 z' c" i
  8. cnt = end - start;& H* F- p8 K" n3 O. P

  9. 6 U$ c! H7 t. o+ H& O+ |- D
  10. //64*1024/(cnt/400/1000/1000)/1024/1024 = 64*1000*1000*400/1024/cnt = 25000000/cnt
    : x* s& G( v. ~  Q. A3 \
  11. printf("DMA1---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

/ K8 `" {" Q8 X通过时钟周期计数器测量执行时间,单位2.5ns。
$ a' A) B3 r7 _* w5 Q2 N, I% v1 c% Y7 |9 K! F
62.5.4 第4步,D2域SRAM1内部互传64KB数据
6 b, [/ G6 _3 D' l; Z$ F4 _通过下面的程序实现将地址0x3000 0000开始的64KB数据复制到地址0x3000 0000 + 64*1024里面:: b2 m. ?3 I6 K7 x) [

8 x6 s( q! {7 }* ]2 g+ J( q  W
  1. /* D2域SRAM1的64KB数据传输测试 ***********************************************/" K; a' w5 @2 \) Y+ f0 T9 W+ F
  2. TransferCompleteDetected = 0;
    # m/ K# G9 r! Q+ V+ |" U* v& b
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x30000000, (uint32_t)(0x30000000 + 64*1024), 64*256);
    0 J8 K! C+ E! `

  4. , m8 V& A% [/ Z3 j- h5 I
  5. start = DWT_CYCCNT;
    $ g- {8 T& h! ?
  6. while(TransferCompleteDetected == 0) {}
    ( a/ x; k# a2 w( E5 w: n
  7. end = DWT_CYCCNT;
    : x6 V/ y3 R6 }! c* x5 b
  8. cnt = end - start;# t/ J9 ^; \3 A
  9. 3 j- b3 b5 z% x' L9 z: k  d6 @
  10. printf("DMA1---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

% T- ?+ H# A0 {% L通过时钟周期计数器测量执行时间,单位2.5ns。
! I: M, H/ i! K8 Z! P
# h7 `' A+ J2 v8 F62.5.5 第5步,AXI SRAM传输64KB数据到SDRAM9 V& Q" v3 P# o6 J+ U) C, ]. S
通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0xC000 0000里面:
& t5 [+ {* P6 a  H! H  c
  w5 y9 f+ K2 F% c0 M" A
  1. /* AXI SRAM向SDRAM的64KB数据传输测试 ***********************************************/2 l( r0 Z; }! S: Q/ ?7 s, m
  2. TransferCompleteDetected = 0;  V* [! h6 L, S5 D+ ?
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x24000000, (uint32_t)0xC0000000, 64*256);
    ) U! L  b: e" u; P" B
  4. 4 ~9 j/ l5 \. A1 v% ^! L7 x
  5. start = DWT_CYCCNT;9 |$ A- |8 Z/ `% A; A* M
  6. while(TransferCompleteDetected == 0) {}9 k" l3 l9 ^2 ^* O
  7. end = DWT_CYCCNT;/ O& }3 N+ f4 m$ I# `2 A- c
  8. cnt = end - start;' T$ F, K7 @( H& Y1 b

  9. & O- [2 {! E) n. P+ v
  10. printf("DMA1---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
    ) D; y/ o8 {5 B" Y  \( l
复制代码
' r0 n' e9 l( }2 Z; L
通过时钟周期计数器测量执行时间,单位2.5n。
; s) [- V3 ]1 x& U
/ Z7 J1 b# I/ m- l3 ]. A62.5.6 第6步,SDRAM内部互传64KB数据
3 c) ]% c7 B4 u# v通过下面的程序实现将地址0xC000 0000开始的64KB数据复制到地址0xC000 0000 + 64*1024里面:
! Y1 E/ `! I5 w6 _- \7 W* g
  1. /* SDRAM的64KB数据传输测试 ***********************************************/
    ( b# ~2 D1 s& W2 h
  2. TransferCompleteDetected = 0;3 y9 g. P9 z- L0 e/ \
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0xC0000000, (uint32_t)(0xC0000000 + 64*1024), 64*256);    & k' P5 _- \8 N/ r

  4. $ ~/ q& ?9 S1 H
  5. start = DWT_CYCCNT;0 `( A' v( f  O. w4 v, c' C4 V
  6. while(TransferCompleteDetected == 0) {}
      J3 r) x4 B  z" \" v7 w
  7. end = DWT_CYCCNT;
    / P- L( b9 r; t1 E% M1 a! R
  8. cnt = end - start;
    & `( G0 v8 E$ B' Q% l
  9. ) a# R* a& z* ?* B& I
  10. printf("DMA1---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
* {* t! n9 ~9 Q$ z& Z: b
通过时钟周期计数器测量执行时间,单位2.5n。
, b1 }' x2 W* i( u* t- B/ z0 {' N8 I9 [9 B# M
62.6 MDMA,DMA2D和通用DMA性能比较
* l8 ]' W( t. b) c- C最终测试的性能如下:: `+ J8 a" Y: V( o  X# V

; o/ t( o8 `/ I7 j" _
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

5 T1 Z' `6 i- W1 k5 }5 `2 H
0 n8 l* u) Q/ E: Z+ t# V可以看到DMA1的性能跟其它两个不是一个级别的,适合搞搞低速的外设。/ r7 O! f" @! k$ f2 P

# L$ q( x' N  |: ?/ ~2 q' d  qDMA2D和MDMA互有高低。* w8 ]# c6 X- ^2 z: p
: r' e1 D; V9 d7 c! P7 i
62.7 MDMA驱动移植和使用
3 q+ ]: k0 t% y) [$ p* vMDMA驱动的移植比较方便:# G4 v% f4 J. z" C, S1 _

$ w' D+ R& l* |+ M8 _  第1步:添加MDMA的HAL库文件,简单省事些可以添加所有HAL库.C源文件进来。
4 `4 R; Q) w; ]# {  第2步,应用方法看本章节配套例子即可,另外就是根据自己的需要做配置修改。  z6 |% V( C2 [- y6 `
62.8 实验例程设计框架5 O4 `; n! R3 X# H2 f
通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:1 X7 I1 Q; c; t, i' h/ U

. o' X/ p3 V4 L6 G7 d
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

1 O/ z0 i/ _4 U: J
, Q1 m7 E: G# I& A- G2 K  第1阶段,上电启动阶段:
, ^( J5 Y; g" l4 M: [5 a
8 O5 I+ N" W6 v* ?: B; v这部分在第14章进行了详细说明。7 a2 Z( P; v/ Q
  第2阶段,进入main函数:) q- i  |* Q9 U# @" _3 B1 Q  d

. E& k/ K4 D% V( `% ?3 S9 \ 第1步,硬件初始化,主要是MPU,Cache,HAL库,系统时钟,滴答定时器,LED和SDRAM。
* c% J6 H! F0 W0 s, e  R5 ] 第2步,测评MDMA,DMA2D和通用DMA性能。) u6 f2 N/ h2 a4 A& A2 q  e. l1 S6 T# F* I
62.9 实验例程说明(MDK). ?9 z2 ^: z7 K2 `
配套例子:
+ k- w' v6 _- J; F
7 Q# c. v/ @7 d7 P7 F1 H0 Z1 QV7-038_MDMA,DMA2D和通用DMA性能比较. c0 {1 a  u- k4 s, s2 D/ n7 O! u

2 L; M6 v: ?$ ?7 r3 _实验目的:
' R- O" Q/ n( u+ l, Q: c, L) X8 c8 ?/ ]
比较MDMA,DMA2D和DMA1的性能: x$ g  O1 \9 `+ K7 c7 p
实验内容:. D( E* O( ^1 Q9 ~! e8 m9 R

, \4 {5 n2 w6 _/ P" s  s: t: ~0 I" p MDMA,DMA2D和DMA1都测试了如下四种情况:
: @3 u. o3 t% M3 {, A. e/ ?5 V4 x+ ~7 @$ X/ [% Q/ y; w% v
64位带宽的AXI SRAM内部做64KB数据传输。! M( [3 ]" ]) O& _9 p8 t: o$ `% ?
32位带宽的D2域SRAM1内部64KB数据传输。4 w: a8 e$ i, i  _4 I  v
AXI SRAM向SDRAM传输64KB的数据传输。
! @; e( j  z1 C$ K- Y32位带宽的SDRAM内部做64KB数据传输。
2 A6 f/ B; X! B' J8 C! \) V上电后串口打印的信息:; k4 p8 ?2 R8 R
  B1 K2 g6 D0 W4 _
波特率 115200,数据位 8,奇偶校验位无,停止位 1* C  m4 P+ v, B
. q* h1 `% g( _' V- a
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
9 u; E  ^# H- G0 x: q5 I7 ]

  @" y9 g, y( y$ S程序设计:
. `) }' o' {3 d, d- M! r
# z& Q- o2 D8 n" [9 D  系统栈大小分配:
$ O8 g) X" K- \5 A# W: l
3 O8 i: h8 R4 L& Y3 f. [( ?9 a
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

. }% d1 K: |; d
% l* E$ n* B/ W' n  RAM空间用的DTCM:
* b4 r: a: Q( i
0 l5 q* k& q5 j/ o# a+ I3 o; X
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
' R" z5 V; T( T6 P
& J0 ?0 \- p( u
  硬件外设初始化5 L7 c* w% d7 I% U  f
* X6 ]2 V& g8 u. S7 m# A/ k
硬件外设的初始化是在 bsp.c 文件实现:
' N. }5 S* ]" [" @% @4 j) V8 o& e' E+ S# r( `( c1 x
  1. /*5 G. a: ?/ I/ \  _" r% g. J- n' [
  2. *********************************************************************************************************; `) ^% o1 j$ J9 Q+ ^9 e: n4 u
  3. *    函 数 名: bsp_Init3 D# M, f: `' @; J
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    ! e6 A0 @# `4 H5 `
  5. *    形    参:无
    / f. w$ m; s: k$ o' K1 I  g& B
  6. *    返 回 值: 无
    $ S" m6 ^8 M+ x% ]* D1 Z( t; i
  7. *********************************************************************************************************
    - i+ ^8 ^* O0 ]" i5 o) _
  8. */; d; \% i) p% j3 H
  9. void bsp_Init(void); ?& {  \2 }) W' V6 J0 x4 Y
  10. {: m1 x! ~; L- p8 A
  11.     /* 配置MPU */
    , y2 Q2 }# H% P9 D8 ]
  12.     MPU_Config();9 Q" O1 i* O: o* X/ {' ^$ ~
  13. - P/ D! z& U( R/ a: b
  14.     /* 使能L1 Cache *// l7 s# m3 j. F! E7 E
  15.     CPU_CACHE_Enable();
    7 s: r  p9 @3 G9 s

  16. 6 H) N6 `/ ^& {  R% X3 v. i
  17.     /* ( I: G  a5 B- ~4 h% c* C
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:/ }+ ~, ]( L5 ^* Y5 ?; Y
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    5 q# t4 a5 b+ h. D& q
  20.        - 设置NVIV优先级分组为4。" Y% S) @  a* e6 u
  21.      */5 x- E( N# {; x1 {9 l& f8 R
  22.     HAL_Init();4 M- S3 v0 ^1 v8 J
  23. 4 l* K. A& e$ R% }
  24.     /*
    5 A* O/ P) b: A" d# W' ^
  25.        配置系统时钟到400MHz3 L  @( h: m5 L* D$ @0 w
  26.        - 切换使用HSE。
    0 f, E: ?# ^7 r! x
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。. y+ Y" c. H+ c" P7 a2 n" s
  28.     */& ~. C6 x. \; f# Z
  29.     SystemClock_Config();
    / i% N6 i- K2 J9 B3 J6 E3 B* g

  30. ) V& T9 R# J; M( U1 }) b
  31.     /*   P) N* A) s, X8 z  W: O' A
  32.        Event Recorder:
    2 C$ J. T4 M& ~
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。+ p6 Z5 b2 N/ R, B/ H4 d3 s
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    1 e# ]. L" x3 r' F( b, M' g
  35.     */    + c) W# k; d; ]) U8 y
  36. #if Enable_EventRecorder == 1  8 q! |8 J0 e; l3 J) ^. y) ^) K
  37.     /* 初始化EventRecorder并开启 */. ?6 f( e9 s. g8 u, Z+ B
  38.     EventRecorderInitialize(EventRecordAll, 1U);* \6 a' T, W; L; n; t
  39.     EventRecorderStart();9 M$ d6 y; D" L# A& K
  40. #endif& n2 U. M1 L- T' j- I* L
  41. 1 u- d) d1 z9 k& [& J* k
  42.     bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */       ; j8 x8 G4 E8 {4 g* u, @# ]! G
  43.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */6 X7 H9 Y2 H# p3 S* A1 H' h" G
  44.     bsp_InitTimer();      /* 初始化滴答定时器 */% d; Y. V: ~/ W6 H7 z
  45.     bsp_InitUart();    /* 初始化串口 */# T2 X# d1 G1 s* |' t
  46.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    . d& ^* R% l; }+ B* f
  47.     bsp_InitLed();        /* 初始化LED */    ( G7 x6 `! M' i+ t) @: n5 J
  48.      bsp_InitExtSDRAM(); /* 初始化SDRAM */$ }) {6 Z# e( m, U" @
  49. , f# z& j$ i8 D: T* p" T) d' M! S
  50.     bsp_InitI2C();     /* 初始化I2C总线 */# U$ \- P/ l& j$ G# a% }
  51. }8 }0 I( i3 D% J3 S
复制代码
# L$ O( i& o# D

! ]6 K1 V  X  _9 }# }; _  MPU配置和Cache配置:- W2 x) Y7 K  f7 P/ G
; j) E& G4 M3 e7 l
数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区和D3域的SRAM4。DAC的数据缓存开在了SRAM4。9 S0 [% u0 @9 {6 U

9 a. A3 B& M8 i% Y/ G( ?" ~" ~" o# I" B' e
  1. /*
    6 K* Z; q2 v% n
  2. *********************************************************************************************************3 R0 Q7 _8 E# [- c6 ^6 Q& `
  3. *    函 数 名: MPU_Config$ A- d( _  Z/ r1 I) o, o) P3 @
  4. *    功能说明: 配置MPU2 `4 P6 p; b' \; \
  5. *    形    参: 无
    ( D# w- \' G* ?) \
  6. *    返 回 值: 无
    & Z& R. p2 X& i. _% a, y# d" u7 @
  7. *********************************************************************************************************& B, i: z! J4 k1 w
  8. */
    - s  H2 @. b0 M! x6 \
  9. static void MPU_Config( void )
    $ t' t* U. v% }9 G7 s
  10. {
    % `! \" s; G  }# w5 b; ^1 a2 J0 e# G+ B
  11.     MPU_Region_InitTypeDef MPU_InitStruct;
    # k8 K8 z! h( J9 i1 W

  12. / v1 v/ z" P6 a1 n; v" s/ \
  13.     /* 禁止 MPU */
    0 ~2 ], k2 j& f1 a8 ?
  14.     HAL_MPU_Disable();8 R. S- V6 A. z" X* G

  15. # D! y$ j2 m8 B6 S
  16.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    2 d! _, }5 M+ C' _4 e) G% v
  17.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;) u8 P! J, {$ H9 d" P+ {( J4 T2 \; k
  18.     MPU_InitStruct.BaseAddress      = 0x24000000;
    # G4 D. n4 `: l/ t
  19.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;- B, H6 v# c# z0 r. A/ h. ~
  20.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    5 v7 `' v6 L/ s% F" p
  21.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;. @) y( ~. a: i  Z! X% `# _1 S5 _
  22.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    ; w, K6 w. s& t5 s9 `# Q
  23.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;7 X; h! A9 Z) V
  24.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;' u, F" s! V+ s( q! q: W
  25.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    2 S8 n2 F" `9 t- F8 _  z# q9 d
  26.     MPU_InitStruct.SubRegionDisable = 0x00;
    8 `; @4 t, q- m& l$ Z: O
  27.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    2 i8 A; [( x) C+ z
  28. & h9 a, B/ R& h2 b* u' `8 Q
  29.     HAL_MPU_ConfigRegion(&MPU_InitStruct);; j8 i; ~9 ^: V" v
  30. ; c" k* C; X! x: A! o% G

  31. ! {: [2 \6 s; n/ X  F4 y
  32.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    8 i. v% ]' H" y3 y
  33.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;( s; I9 T' n6 x& _" _
  34.     MPU_InitStruct.BaseAddress      = 0x60000000;3 @' G+ U. ?/ I. Q
  35.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    - l2 ]3 {# X0 H/ f+ M
  36.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    4 L& I$ X- D0 e$ z7 r
  37.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    % T; A. u0 s; B0 p; a: p
  38.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    - a! k! ~4 L2 {# a9 j$ Y
  39.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    1 o" O! c& d% r5 F" z" b
  40.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    ! B( N2 S# `1 p6 N
  41.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    & R) H. U0 k) O! x% p
  42.     MPU_InitStruct.SubRegionDisable = 0x00;( A  I; l+ m+ j; g$ H
  43.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    " B! K: o0 O% P: l

  44. ' r  i  i- e& b0 o
  45.     HAL_MPU_ConfigRegion(&MPU_InitStruct);- ?- ?1 n7 W5 z3 g' t8 \
  46. ; f- o: L7 S2 w$ X1 T
  47.     /* 配置SDRAM的MPU属性为Write through, read allocate,no write allocate */+ m8 n( x8 |) L# d" r+ s0 T  u* N2 P: G
  48.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    : t/ H" z/ c! u: k6 U! G! |
  49.     MPU_InitStruct.BaseAddress      = 0xC0000000;
    & g3 j$ B2 K& O/ d0 y/ y
  50.     MPU_InitStruct.Size             = MPU_REGION_SIZE_32MB;
    ; y! R4 b  M9 K) k7 p
  51.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    ! Y9 l7 U) r. q* U4 ]
  52.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;: G6 _) x( u' y4 Q, C: I1 R4 [
  53.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;9 P" i* z; z1 Q8 M
  54.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;' f' L6 g1 k7 e& p! V. R: r) o' W
  55.     MPU_InitStruct.Number           = MPU_REGION_NUMBER2;
    $ C  B+ l# j& \- ]* D+ c4 h6 w
  56.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;/ c4 j- d0 w; @! z+ I
  57.     MPU_InitStruct.SubRegionDisable = 0x00;3 E; F6 n6 H+ Z; W& ]* w* q
  58.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;7 B! N5 k% r4 |9 P/ e
  59. & o1 _2 m% r6 j" i
  60.     HAL_MPU_ConfigRegion(&MPU_InitStruct);6 H" X7 [5 _/ f5 x

  61. & n# d  U+ @: s) M
  62.     /*使能 MPU *// x7 E" M& W# ~; b+ W* z4 s) t; v9 w
  63.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    & R/ r. Y- K' q; q, H
  64. }5 q$ e) x( V2 x8 n$ r, Z5 q

  65. % L9 _( J4 g7 k0 H& D* S7 ~& |
  66. /*
    ' N# {; L; q3 f% {9 B
  67. *********************************************************************************************************
    ! i$ d2 r* y# j/ P  U
  68. *    函 数 名: CPU_CACHE_Enable/ C) `: ~) y) |1 y- q& S9 g# x
  69. *    功能说明: 使能L1 Cache
    ; \( q4 e3 w& ?9 C' O+ M
  70. *    形    参: 无7 D" _4 O8 [) Q8 D; J, J
  71. *    返 回 值: 无
    / S8 ~, e2 D  v( d) X1 x* u
  72. *********************************************************************************************************
    8 i! w1 X' J& k4 m
  73. */. v: x! b8 V# _2 T% l5 e3 c4 N3 ^3 v
  74. static void CPU_CACHE_Enable(void)
    , o2 ]1 ?! l' G
  75. {
    6 P% X6 h. |" O* i
  76.     /* 使能 I-Cache */
    9 W; W/ v9 P9 L0 G5 e' l
  77.     SCB_EnableICache();
    6 _$ A" x/ j& r2 D' ?4 o

  78. 6 q2 Q; i+ q. q8 g3 V. n- S
  79.     /* 使能 D-Cache */2 o6 K/ X5 }# a
  80.     SCB_EnableDCache();: k/ ?7 Z( |  f& H" S6 |
  81. }& o4 [4 u5 h. U8 x
复制代码

' D; f" Z! O+ E4 a& w% J
. I- e. z$ p0 I4 v. V; M 主功能:
% e8 J; \5 o+ Q: n; v0 ~9 I* {$ c( C% K  P: P6 t4 M
主程序实现如下操作:
) h' l! x# B, J! `* t  g' L: \9 b9 j$ E& m* z; y: v4 v; l5 S& @
测试了MDMA,DMA2D和DMA1。
, q2 c4 D9 q8 }8 X+ R
  1. /*
    # c7 f* V# N, E
  2. *********************************************************************************************************  r+ u! j7 r: {( `# b2 i
  3. *    函 数 名: main0 l5 G* q+ L+ I. X- Q
  4. *    功能说明: c程序入口
    1 ^5 J& H5 A: f) n0 ^
  5. *    形    参: 无
    ' T% J% Z9 p6 ]7 E  |8 f
  6. *    返 回 值: 错误代码(无需处理)  W! v( n0 B  y& k: k; H2 Y
  7. *********************************************************************************************************
    ) }$ E# [% D0 e7 T, N* p- @' M
  8. */
    / n/ b: H6 v* r+ k0 `) E$ @
  9. int main(void)
    0 n4 D5 R9 {4 ^; O/ }7 b
  10. {
    + s: S; h' U2 i- j' P
  11.     bsp_Init();    /* 硬件初始化 */
    2 `$ d* Y- `0 a9 h8 i( I% a
  12.     PrintfLogo();    /* 打印例程名称和版本等信息 */' Y1 e5 O5 M6 c( \( c( q" q  ^
  13. 3 j' O  J# m: }6 s/ }% ~5 X% K, U; J
  14.     MDMA_SpeedTest();( H- g9 U& Z1 K( y
  15.     printf("----------------------------------\n\r");
    5 K- j* ~1 E$ R1 }) B2 S- ~
  16.     DMA2D_SpeedTest();
    2 x  s( }+ ]- `' V0 w
  17.     printf("----------------------------------\n\r");   
    7 y! Q" S9 M: m! t
  18.     DMA1_SpeedTest();
    , A" ^9 |, H- ^9 d' p! g% u

  19. 8 |2 R1 n$ H5 @
  20.     bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器,软件定时器0 */: F( Y5 U) G  q' ]3 p5 R6 c

  21. / K/ @+ x7 V  {5 k3 C" h! ]" W
  22.       /* 进入主程序循环体 */: l9 V/ t, \  o4 ?) ~4 J! n
  23.     while (1)" K- e, `; E- i7 T4 ~+ N1 A
  24.     {
    % [  t* v  w0 r4 H0 Y( d) |7 @
  25.         bsp_Idle();
    - E, i, W' p1 g( B' w

  26. " w! K2 g# x! `$ t6 Z: a% ]
  27.         /* 判断软件定时器0是否超时 */3 }% X4 |% n+ {$ y
  28.         if(bsp_CheckTimer(0))
    $ {. C! |# a, m" h' y* `" v
  29.         {
    3 ~1 Z. y1 X3 |# [* I
  30.             /* 每隔200ms 进来一次 */  ' o. s2 t2 T6 {6 I) r: G
  31.             bsp_LedToggle(2);
    : I) g8 |7 f/ @$ D" `0 I) T
  32.         }
    / q. K+ M5 t) b/ z9 Z& `: ~
  33.     }) }$ B$ ^% s6 _& P8 t5 ]+ s& O9 i
  34. }
复制代码

3 e7 a. T" M6 f. N. B; j# M- Z  e' w4 X# q. V; C
% ~; A. a! _- X% R. \  C8 U
62.10          实验例程说明(IAR)
+ }% a5 P' G3 N+ x! w2 z4 X: C配套例子:
7 z* t- Z* O3 n' @& K+ _+ O! _! ?6 M, w1 p% W
V7-038_MDMA,DMA2D和通用DMA性能比较7 {% W. w1 [6 n( v
( h% L. p- L" \1 ^
实验目的:8 ~. h7 W# W2 _8 ^! w# H/ S/ R- `
# _3 b1 G3 q6 N! s( {
比较MDMA,DMA2D和DMA1的性能
, `  |# N$ f. |# G( v2 y0 ?实验内容:, _$ s2 ~  ?; w1 u

0 K( e7 \( q- z6 {- n# O+ [ MDMA,DMA2D和DMA1都测试了如下四种情况:
4 L! R1 Y+ O  p
1 v, g7 p( t7 B9 y64位带宽的AXI SRAM内部做64KB数据传输。! [, v  S1 A  v
32位带宽的D2域SRAM1内部64KB数据传输。# z. B. R: ]. o  k4 L  d
AXI SRAM向SDRAM传输64KB的数据传输。
0 X9 @( J' Z4 Q, m( A32位带宽的SDRAM内部做64KB数据传输。1 f, A+ N' X. y5 N# [; W
上电后串口打印的信息:
' J3 a5 b) u1 t- [9 L# H( `; {5 R4 Q2 e, T% e6 Y: ?  w/ _6 C- q
波特率 115200,数据位 8,奇偶校验位无,停止位 15 S, U0 B$ V$ Q' q! {$ @  J4 ~
. F) \2 l  R, O. D  s& g
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
/ i$ b; [1 U6 h2 M) J+ o; _; K  a
) i7 ^" c' [3 F7 f& s
程序设计:
: m( Z& \% ?! c. j( M$ I  r: S8 O& `+ P9 Y
  系统栈大小分配:
& ~% l$ R( a' x+ V2 j) Q8 {
& O1 s* o4 C7 k7 J, c" @
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
. Q$ p8 w/ @2 N2 h" Q, g2 ?: \
3 M; y( L' ?, C/ f
  RAM空间用的DTCM:5 S) ^0 c) n- c$ ?! x
$ A+ z, T9 ]# b+ `
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

9 h# V3 W, v/ g! J7 y0 m: B9 k  x2 \8 Z' L! e( c! r7 C) o7 F8 ~
  硬件外设初始化8 W& |5 c8 a1 l# _- r0 ], K
5 X% @$ p+ V1 G6 I0 j0 z; q
硬件外设的初始化是在 bsp.c 文件实现:& t2 p$ X5 d$ B0 C2 |: ]& Y4 a

. B5 @& I' Q1 X$ X+ [
  1. /*5 W! p) I* n/ Q0 x$ H
  2. *********************************************************************************************************
      D: V+ u; n; A, c
  3. *    函 数 名: bsp_Init
      F- M! ^0 O0 R$ i( Z
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次1 r7 b: \9 k4 \6 a- }# g( J
  5. *    形    参:无/ g* a$ @  u  u! ]3 Q+ ^  Q4 k
  6. *    返 回 值: 无8 e3 s* Y' |2 e8 f6 f0 Q5 D
  7. *********************************************************************************************************6 v8 K! P% C* ^  R+ F# g% E  X) P5 F4 O' ]
  8. */$ k; K. E& s# Y* \( i* V3 d
  9. void bsp_Init(void)
    " F4 W. h' H- d8 k% R2 q6 ?
  10. {! j7 I) z) w  c7 P* `
  11.     /* 配置MPU */5 t; h! A7 u7 d! O! [
  12.     MPU_Config();
    6 j7 Z  _4 D& m$ }& f$ H. Y

  13. * R3 W: d( I% j! @
  14.     /* 使能L1 Cache */
    & M$ ]* m1 T9 x# M8 |) w- r5 \
  15.     CPU_CACHE_Enable();
    2 s6 l4 `7 u/ Q9 J9 U4 K8 K

  16. * `- E) p$ X7 ?, n; O& w
  17.     /* 3 f5 x$ _: ^0 @( Q7 T  ]. g" A
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:) G: q8 C7 D/ u+ n" n
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    7 t! T/ g4 G- D4 i# v& y! `! }
  20.        - 设置NVIV优先级分组为4。1 M! a5 E* u" v- p$ Z( b0 f9 y
  21.      */
    4 h0 C0 ^; D: c5 q3 E
  22.     HAL_Init();) M/ z! c6 L7 \8 e: z
  23. ' M& D; i5 m4 K5 {* w
  24.     /* + i& J" m: G- l8 V: X7 o; T
  25.        配置系统时钟到400MHz
    6 `- k" E/ U+ g9 t9 e( K
  26.        - 切换使用HSE。) {7 ^  O$ L+ f& A1 X, I# X" U
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    9 Y1 P5 o: ]% Q' U; p
  28.     */) @! D% f6 Q, c5 b/ G
  29.     SystemClock_Config();, j5 ]" l. k, G) H, i; @
  30. . [% G/ ^# r7 z
  31.     /*
    + B: j4 _$ c: F1 q/ a2 f0 F
  32.        Event Recorder:
    + F- c' q- M8 d* X- X5 i- h
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。# V, _; V6 O+ Q3 m# _
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    2 y  r7 T0 C+ N& {7 G" P
  35.     */    5 C" f8 Y8 F8 H, T
  36. #if Enable_EventRecorder == 1  
      f" ?' N$ @9 m2 z. I: H) N
  37.     /* 初始化EventRecorder并开启 */
    + {2 B. D. Z: ?, R' i% ~/ g
  38.     EventRecorderInitialize(EventRecordAll, 1U);
    & [( G9 r5 _- z" B; ^- [( O: k
  39.     EventRecorderStart();
    , I1 |2 N7 z" K  \/ i: w; k0 d
  40. #endif
    2 V0 W9 N; R0 Q/ V4 y9 r
  41. * M' r& V& D4 a* h9 S
  42.     bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */      
    4 u6 E! O4 \1 \. S# r" w: z( }
  43.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    ) E9 ]' C. B) P/ J
  44.     bsp_InitTimer();      /* 初始化滴答定时器 */5 f) m/ b8 n, j* e+ |2 h7 S" L' [
  45.     bsp_InitUart();    /* 初始化串口 */1 M' O: Q5 ?" G( G/ n3 i6 V  i; c
  46.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
    " W/ F; @$ l- u. E3 }# l+ Z
  47.     bsp_InitLed();        /* 初始化LED */    9 ~* u: \- ^7 i( c8 Z1 Z
  48.      bsp_InitExtSDRAM(); /* 初始化SDRAM */6 ^. G( j3 b- ]! G# N! K  {; U
  49. * H: S! W/ k8 w
  50.     bsp_InitI2C();     /* 初始化I2C总线 */) a; c' H$ N) N( [
  51. }& N6 k9 K! _6 K* j1 C* o
复制代码

! @2 q) e' ^2 M+ f1 h0 K1 K# T/ ?
/ R5 [/ q& q' a% m; l" o( T7 t8 c  MPU配置和Cache配置:
, l- r" Z5 i" U3 @) F; r4 I
" A- p+ @- M5 i2 I$ q9 d( U数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区和D3域的SRAM4。DAC的数据缓存开在了SRAM4。& G& Y5 F6 D( w- e5 I

2 c* S0 K7 M) \* }
  1. /*1 k% P2 {! e. H/ d4 k  h. q
  2. *********************************************************************************************************
    - V1 ~/ v  e, k0 P
  3. *    函 数 名: MPU_Config2 {- i6 [/ H3 M+ K' u& W( ?
  4. *    功能说明: 配置MPU
    / E4 s# T- D$ _& L! J5 [4 s
  5. *    形    参: 无8 Y' g6 s8 x5 P$ n4 Z" c
  6. *    返 回 值: 无
    & Y, s6 s8 }; ?6 L) n, \
  7. *********************************************************************************************************
    * x/ [  a( n1 W. V0 M
  8. */% j) ~( v9 t3 U+ J4 R6 o$ T9 ?
  9. static void MPU_Config( void )
    & w0 [) N# o2 O8 G$ D/ g
  10. {9 m4 A8 N3 A5 Z2 Q
  11.     MPU_Region_InitTypeDef MPU_InitStruct;& [% {' Y* W& W8 L$ w  F

  12. 6 q0 c, E! f8 |1 g: Y) A
  13.     /* 禁止 MPU */5 e0 a, f! m) z% ]5 e: _+ r
  14.     HAL_MPU_Disable();
    . ~+ G. r$ O% r8 S) w

  15. + N: M) q. J5 X+ f# r% i7 R% d- A
  16.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    9 p/ x3 K1 c  H3 f! l/ d5 p
  17.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;& t0 t9 T( |6 ]* L* U
  18.     MPU_InitStruct.BaseAddress      = 0x24000000;7 j- c: R+ z( [$ a- a
  19.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;1 e$ m/ o; Y) r* s
  20.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;" X) n1 R* |9 ]8 q
  21.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;' `' V( R) G0 c, K2 A
  22.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    4 f, `8 I; u6 n) n8 h
  23.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    . f; U3 C( j' g
  24.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    : b* u# L3 a/ K: E) U
  25.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;; \& C% O. ^( T( e
  26.     MPU_InitStruct.SubRegionDisable = 0x00;$ e% _* [7 ~! B+ G+ J4 b: p
  27.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;8 ~; T: G' N) |( B: g1 k
  28. 2 d+ X1 a$ a4 y. d8 i2 D# _3 z
  29.     HAL_MPU_ConfigRegion(&MPU_InitStruct);$ P2 j2 ^! Y5 v' f5 i7 Z: ^* p

  30. , W: ]& |* K; N

  31. 9 N9 F9 G' v  O& ?' S. z2 H0 R' W
  32.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    1 _. e8 _# {) @4 G/ B$ Q
  33.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    9 r, S  }! a2 ^' r- b0 r
  34.     MPU_InitStruct.BaseAddress      = 0x60000000;/ \5 f* A# D$ `0 ~3 w2 P
  35.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
    + U/ u6 o* s  D1 g: W  t8 G( k% v
  36.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    ( d- i9 R1 x+ E, A( L. d: f
  37.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;1 T' C2 X5 r, g5 m" N
  38.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
    . r; _0 V( J( R
  39.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;9 {& ?4 L0 @6 Z) ]/ @5 t, O# J
  40.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
      f6 @: J5 B5 z& p
  41.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    3 N) @* t% j; l3 X! w8 u) F: E
  42.     MPU_InitStruct.SubRegionDisable = 0x00;
    + k' O, x1 L$ a. m* I' o$ [0 o
  43.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
      U5 h' t1 l  i; {5 b3 [0 h

  44. ( W% N. q5 O! q% @
  45.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    ; B2 D$ f- k" \, s/ K

  46. 0 l& N  v/ c/ l
  47.     /* 配置SDRAM的MPU属性为Write through, read allocate,no write allocate */, b6 l2 T: v, C4 z4 C3 j
  48.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    7 Z& ^# ]; y6 {" s
  49.     MPU_InitStruct.BaseAddress      = 0xC0000000;7 J$ N1 B8 u5 A* o6 c- r
  50.     MPU_InitStruct.Size             = MPU_REGION_SIZE_32MB;, I8 Z; [: O' S2 ]' u' _
  51.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;$ y- w5 `( `6 G2 Z$ ]4 F0 T) Q- e
  52.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
    - ?: h! ], D7 n7 {
  53.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    ) H# q$ \& D& _6 c
  54.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    : |8 q) x4 U$ m$ G
  55.     MPU_InitStruct.Number           = MPU_REGION_NUMBER2;
    6 y6 k% U! h. R2 p8 _" @
  56.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;. p. J7 A; W  T, v
  57.     MPU_InitStruct.SubRegionDisable = 0x00;2 e6 d1 Z: O9 Q. ^, A& I3 Z2 B0 n! Z
  58.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    5 \2 [) w4 j: ?  J8 W
  59. * g9 s& f0 l& _7 p- g7 P$ E
  60.     HAL_MPU_ConfigRegion(&MPU_InitStruct);( U4 b4 n; q% S3 U* [7 G

  61. 0 D# u# @# Z, R* r, }
  62.     /*使能 MPU */
    ' T. M2 c+ N% Q# G9 k1 i/ w8 H/ U
  63.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    4 p$ D$ e1 E8 _0 d/ k# y1 _
  64. }
    ' s) U7 G. x- P
  65. : p# x" z) f- z6 ^" V& u5 E; ?
  66. /*
    $ S4 E# K/ v8 u3 S4 @8 d0 n
  67. *********************************************************************************************************! V: C- q2 _! n3 e: q! w% y" Z4 t
  68. *    函 数 名: CPU_CACHE_Enable
    % T( {5 i6 [( {) X# H
  69. *    功能说明: 使能L1 Cache
    7 [5 O: y& B8 F6 b9 @
  70. *    形    参: 无8 Z4 m# W0 P5 H5 |& k" W
  71. *    返 回 值: 无4 a# ?# e& e1 Q, Y. {
  72. *********************************************************************************************************( p4 E0 H: [: I( g, @. J
  73. */
    7 H4 l* \5 p3 Y. e1 {
  74. static void CPU_CACHE_Enable(void)1 E9 E8 n+ Q/ v+ B! Q: i5 _- u$ z% d1 l
  75. {" j3 g$ t+ J3 ]- M
  76.     /* 使能 I-Cache */' u9 @" l2 f9 U( g
  77.     SCB_EnableICache();  \7 D/ h5 A' A1 Y/ a) K% l

  78. + K. H. q7 v' }) |
  79.     /* 使能 D-Cache */
    3 B: D: u/ W, c  H
  80.     SCB_EnableDCache();
    3 }/ U2 Y5 ^; {
  81. }
    # P, _/ n% o( {" k
复制代码
0 N$ `9 q- n3 X

0 U$ Q# B1 v7 I2 D1 \6 h  g  主功能:
' x2 [7 X4 D$ x% G, h9 S8 W) \% b7 p. q5 K" k/ X
主程序实现如下操作:) m7 }5 X/ c( q* b; C

' U; m6 n4 J$ f* A  V5 S  测试了MDMA,DMA2D和DMA1。
/ N# {# {, @0 E
  1. /*, L( u. A3 I$ F2 n; p
  2. *********************************************************************************************************
    ! ^5 w) @# {+ N9 A8 e
  3. *    函 数 名: main
    9 o4 l! `$ z5 D! s5 {# p
  4. *    功能说明: c程序入口
    & \6 b4 A) k4 W# A) c9 U) E& p
  5. *    形    参: 无
    * ~7 z% h( W" W! E' K, [
  6. *    返 回 值: 错误代码(无需处理); T( m. i$ i+ N2 n. `! f
  7. *********************************************************************************************************
    4 i7 ^2 Z* Y0 u# L2 e! h% P$ F
  8. */
    ; O  l7 g, }$ M- R. r" ^
  9. int main(void)
    ' l7 S+ s5 D( m  ~
  10. {
    ; K" f+ }7 Z) l. ]3 E
  11.     bsp_Init();    /* 硬件初始化 */" _& _4 Q4 q4 ~/ U
  12.     PrintfLogo();    /* 打印例程名称和版本等信息 */# T; d$ n7 I9 f* s

  13. + N3 M9 J( o" \% ?* ]# n! [" O1 q6 i
  14.     MDMA_SpeedTest();( w: N* D! Y2 \9 I0 \  g, F+ }
  15.     printf("----------------------------------\n\r");
    7 Z' }  f4 p) O+ a& e$ z
  16.     DMA2D_SpeedTest();
    & B$ W: g/ F, @9 U5 ^& r$ t0 Y+ a$ M
  17.     printf("----------------------------------\n\r");    / \! _+ P- s, p. B6 P1 X8 S7 ]. T
  18.     DMA1_SpeedTest();$ }! ?' |# Z* V5 Q/ ^1 a7 m

  19. / R1 L7 `; Y0 R- g2 Z
  20.     bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器,软件定时器0 */6 z/ _& J; g# M& I4 j  c

  21. 6 ~# m* \; W2 ^. e1 L% A2 Y
  22.       /* 进入主程序循环体 */- a& K2 p$ [! X$ U7 u5 D8 X
  23.     while (1)
    ( Z" X' s  F7 D+ w' B7 r- K
  24.     {
    " e6 `" q1 h( \. i8 n: _3 y
  25.         bsp_Idle();- F0 }! Y) Q6 [1 H, i0 u
  26. 3 z. L! ]$ E! P; g
  27.         /* 判断软件定时器0是否超时 */
    5 U) C$ B) @# G- w6 M0 m
  28.         if(bsp_CheckTimer(0))6 C- j- }, G. T$ h" A  x8 u8 E
  29.         {
    ' E- @0 S0 z& G' V/ X0 m
  30.             /* 每隔200ms 进来一次 */  
    ( O( R# \/ l! `$ S- G! N3 P1 z
  31.             bsp_LedToggle(2);1 k6 U# A/ E3 [- P1 g
  32.         }
    1 f% y* m# d! h4 U$ L
  33.     }2 x+ e9 P8 t- N9 J  Y
  34. }
    : g) E, z/ Z; L6 l9 e! T2 ?
复制代码

( U; x  N' N1 V1 j$ l5 M- G* S4 d1 q) `; c0 t8 j
62.11   总结8 U) e2 Q9 J4 W- x% G6 X' O
本章节涉及到的知识点比较重要,以后用到DMA的地方比较多,可以根据性能选择合适的DMA。" j/ `2 e! r/ @. T8 u4 E9 d* x/ h
# j1 s/ ?0 W+ k( x
% w% p" C+ r$ d" K2 C
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 手机版