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

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

[复制链接]
STMCU小助手 发布时间:2021-11-1 21:46
62.1 初学者重要提示- O, S3 F! N" I; I3 r: C; |; [
  学习本章节前,务必优先学习第61章,需要对MDMA的基础知识有个认识。
, [* Y1 O8 I( z2 s4 D0 T. u  
. S$ U9 }+ \0 D! q5 }5 o62.2 测试条件说明1 R8 J" ?9 f, A1 N8 E3 `
MDMA,DMA2D和每个都测试了四种情况; a% ~. h% }4 F1 z, @

4 m9 Q5 y+ B* A3 e7 ]  ^3 v  64位带宽的AXI SRAM内部做64KB数据传输。
1 `( F7 O3 R. {/ C5 t( \7 n  32位带宽的D2域SRAM1内部64KB数据传输。
( m! O' M1 U- V8 N  h  AXI SRAM向SDRAM传输64KB的数据传输。# N' c8 m/ u$ ^0 V- E' h! g
  32位带宽的SDRAM内部做64KB数据传输。! b: e4 M$ v' Z$ U1 w" Q
MDMA:
- P  @' N% t# h  Q0 U+ e/ o8 ^
& g$ I5 ~: k9 P; e1 G" P, r1 h2 |, N2 L在D1域,支持64位带宽的DMA数据传输。
( G! B( l; {6 L+ a, d, `' k7 O
3 @& }# G% |6 pDMA2D:
( u6 E% b! ^" o* h) j在D1域,主要用图形2D加速。
- a0 F+ p7 K, ^  E. a: u) W3 L8 {5 z+ E; q0 v3 @- v: G
DMA1和DMA2:
& O9 g4 j3 x- `  M) M在D2域,支持32位带宽的DMA数据传输。
4 Y2 ]" Y. D' A
1 ?: U1 Y) a) }8 q6 o2 r; F62.3 MDMA性能测试程序设计
% c( }! [/ y) l, V# v; b这里将MDMA的程序设计分为以下几部分,逐一为大家做个说明:7 R/ g& w! ?4 Q
, b4 R- O: S4 t  K9 c7 |) o" i
62.3.1 第1步,MDMA初始化( V/ K2 X$ @: g+ D5 j
程序代码如下,采用块传输,源地址和目的地址都是64bit数据传输,并设置16beat突发,也就是连续传输16组64bit数据。
0 r7 ^) M% [( j. R4 j9 o2 |7 M+ U7 z  \) u% o2 I
  1. 1.    __HAL_RCC_MDMA_CLK_ENABLE();  
    0 ?1 U5 ]5 w' G2 _# r0 W
  2. 2.   
    ) s# P* c% V' f4 Q1 O
  3. 3.    MDMA_Handle.Instance = MDMA_Channel0;  
    9 |# b" _, u1 v, @+ ]
  4. 4.   
    & B  O8 P* J. t- U
  5. 5.    MDMA_Handle.Init.Request              = MDMA_REQUEST_SW;         /* 软件触发 */5 M! M" H) y9 r+ D: Y
  6. 6.    MDMA_Handle.Init.TransferTriggerMode  = MDMA_BLOCK_TRANSFER;     /* 块传输 */# d8 c) u3 {" z
  7. 7.    MDMA_Handle.Init.Priority             = MDMA_PRIORITY_HIGH;      /* 优先级高*/
    , s6 F. H; o2 |3 f+ a
  8. 8.    MDMA_Handle.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE; /* 小端 */
    . j# ?$ w4 v& t' v* n
  9. 9.    MDMA_Handle.Init.SourceInc            = MDMA_SRC_INC_DOUBLEWORD;      /* 源地址自增,双字,即8字节 */
    : F! ]; {2 y0 ~) M
  10. 10.    MDMA_Handle.Init.DestinationInc       = MDMA_DEST_INC_DOUBLEWORD;     /* 目的地址自增,双字,即8字节 */  q- l$ K, K, Z4 N+ m
  11. 11.    MDMA_Handle.Init.SourceDataSize       = MDMA_SRC_DATASIZE_DOUBLEWORD; /* 源地址数据宽度双字,即8字节 */
      f1 n2 a8 J' J. V+ i8 x( w
  12. 12.    MDMA_Handle.Init.DestDataSize       = MDMA_DEST_DATASIZE_DOUBLEWORD;/* 目的地址数据宽度双字,即8字节 */. b7 }+ P9 ?; g+ }( j
  13. 13.    MDMA_Handle.Init.DataAlignment      = MDMA_DATAALIGN_PACKENABLE;    /* 小端,右对齐 */                    
    2 u7 V; r! e/ i" y# L& g
  14. 14.    MDMA_Handle.Init.SourceBurst        = MDMA_SOURCE_BURST_16BEATS;    /* 源数据突发传输 */4 n2 y. g9 _( ~3 s! Q9 w
  15. 15.    MDMA_Handle.Init.DestBurst          = MDMA_DEST_BURST_16BEATS;      /* 目的数据突发传输 */' s3 L) |" C) d- v
  16. 16.   
    7 N' E; p4 J! E4 n' w# M! ~
  17. 17.    MDMA_Handle.Init.BufferTransferLength = 128;    /* 每次传输128个字节 */" g) ~' f* ?. R% R$ j& N
  18. 18.   
    / O& C- z9 T( q  L2 \
  19. 19.    MDMA_Handle.Init.SourceBlockAddressOffset  = 0; /* 用于block传输,地址偏移0 */9 i/ G% Q9 y) j+ l$ B" l1 Q
  20. 20.    MDMA_Handle.Init.DestBlockAddressOffset    = 0; /* 用于block传输,地址偏移0 */
    0 s3 w9 n0 S4 M: {# t  k: v/ j
  21. 21.    ( G! y' h) ~% A3 I/ _
  22. 22.    /* 初始化MDMA */$ V. [) s0 l0 J  R$ `, _2 j
  23. 23.    if(HAL_MDMA_Init(&MDMA_Handle) != HAL_OK)1 f% s& \6 w& r$ _
  24. 24.    {. n; V. t1 R! S4 U, u. ]
  25. 25.         Error_Handler(__FILE__, __LINE__);
    : e- k% C& Z  L$ q$ F
  26. 26.    }
    1 R8 g& G$ m" Y" p
复制代码
' ^9 \/ ~: A! U  ^) T1 j5 J- m$ K7 x2 X

5 i0 g: S" m4 J. f4 U下面将程序设计中几个关键地方做个阐释:% ^4 w( Y0 g  E# a  R
6 F% J/ {, N. ^8 D  Y1 ^# f! i
  第1行,务必优先初始化MDMA时钟,测试发现没有使能时钟的情况下就配置MDMA很容易失败。
  x# l' v6 C  K# m- q8 k  第14-15行,突发传输的配置非常考究,每次突发传输的总数据大小不能超过128字节。
2 J6 S+ H: U8 ~+ W3 w  对于源地址就是SourceBurst * SourceDataSize <=  BufferTransferLength。
- X) J) {$ X" n; N0 `2 s, } 对于目的地址就是DestBurst*DestDataSize <= BufferTransferLength。" L; B9 P" f- [+ b
比如当前的程序配置:+ Z9 ]* Z/ @; E$ o! S
5 H" Y; J# U, N! J3 e/ {
SourceBurst * SourceDataSize = 16*8 =128字节# ?7 O, U4 X3 @  S( Y
% J1 v# w3 t5 d1 O
DestBurst*DestDataSize = 16*8 =128字节
+ q% B4 \4 M7 u( V+ I+ M9 I" y3 w1 C  b5 V$ H3 Q0 u

( W; x/ @- `" w& @. s5 N' \0 A; D" B% t# y6 Z. S" M9 K# |6 U2 Z
这里要特别注意一点,如果实际应用中最好小于BufferTransferLength,防止不稳定。
" L3 a) I4 K8 H3 y6 `) f9 n5 k! H5 \' r+ }1 c$ D9 a* {5 b6 H; Z
62.3.2 第2步,MDMA中断配置
! ?9 E' M. h" m1 \6 @MDMA的中断设置比较简单,代码如下,注册了MDMA的传输完成回调:; Z$ ]- J# D( N( _8 O/ v1 Q
: O6 h; w4 X; k: T) W, \
  1. HAL_MDMA_RegisterCallback(&MDMA_Handle, HAL_MDMA_XFER_CPLT_CB_ID, MDMA_TransferCompleteCallback);) ~" u& e0 W( P9 f( O
  2. HAL_NVIC_SetPriority(MDMA_IRQn, 0, 0);6 R# [3 x; F' k6 b1 _' [6 J) d; N' F" R
  3. HAL_NVIC_EnableIRQ(MDMA_IRQn);  ( h3 ]! w: [# c9 S! b8 k3 h
  4. : e( E) O5 q' N  x' ^9 i$ o
  5. void MDMA_IRQHandler(void)
    ( M+ J4 ~3 n5 i$ y9 y. p& h
  6. {
    * o: T/ P% [- }$ f9 w% I# y) A3 T
  7.     HAL_MDMA_IRQHandler(&MDMA_Handle);
    8 L- [& I- E: B8 D. F4 c
  8. }7 ^% ~5 W. O4 e4 L4 s! j/ f! o' ^' P
  9. static void MDMA_TransferCompleteCallback(MDMA_HandleTypeDef *hmdma)* l% o; S8 G. g  b9 X
  10. {
    ; ~( N! K: @" Y: U0 j
  11.     TransferCompleteDetected = 1;
    # @  x5 @8 Z  @5 w
  12. }
复制代码

& {) Q) m/ j# K, Q; F
( |; {# I, n. H/ i0 ~" m' R6 p0 P$ G2 P$ b* x9 S! x9 _
在传输完成回调里面设置了一个变量标志TransferCompleteDetected,方便指示传输完成。, t. [! @" ]9 @0 R# v, T2 r. ]

: s: h3 E8 N  E! d7 _8 _2 S62.3.3 第3步,AXI SRAM内部互传64KB数据5 |/ E$ P1 x/ k$ J& q8 X, D% Y
通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0x2400 0000 + 64*1024里面:2 \# B8 Y- k( _; [
/ M% F- ^: O5 }  C
  1. TransferCompleteDetected = 0;" d- t0 R) \+ r* K
  2. HAL_MDMA_Start_IT(&MDMA_Handle,
    3 m& ~0 O6 a# \# W, n
  3.                   (uint32_t)0x24000000, 7 i' Q; y* x) @" L6 f
  4.                   (uint32_t)(0x24000000 + 64*1024),
    5 F& N8 M1 W0 ^' t5 K4 W; z
  5.                   64*1024,
    & h* ]( J+ N! [4 F1 u/ W8 m+ p
  6.                   1);
    ) M8 y4 j7 s. P; r+ E( D; d/ T

  7. # T$ p( Z) G' X( D9 d

  8. 4 h  L$ l2 _& ~' Y0 b( X2 @: H5 m
  9. start = DWT_CYCCNT;8 q4 e! `% Y( G$ P
  10. while(TransferCompleteDetected == 0) {}) m! m8 q, L, y6 a
  11. end = DWT_CYCCNT;9 Q/ a* b8 ~% B) T7 X$ [
  12. cnt = end - start;7 P" P, a" X, _# W, w

  13. ' P4 M+ ~. B: F3 A
  14. //64*1024/(cnt/400/1000/1000)/1024/1024 = 64*1000*1000*400/1024/cnt = 25000000/cnt) b2 ]/ m* O6 i( w/ N* w6 \
  15. printf("MDMA---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

( c) o: u% o( n+ @* w& ?' x8 k: n1 s4 _
! w0 ]# X4 ?8 |& h
  X! b1 K' K$ O2 `通过时钟周期计数器测量执行时间,单位2.5ns。
6 T( ^- @7 i& a, f/ Y- q
/ I# Y: z7 u; x) y/ g3 U3 B* H5 C62.3.4 第4步,D2域SRAM1内部互传64KB数据# c$ Q" G0 C, v! V* `
通过下面的程序实现将地址0x3000 0000开始的64KB数据复制到地址0x3000 0000 + 64*1024里面:2 l0 H3 L2 L6 l: r: H! ^5 [

: [. }% D4 w: c3 D6 ~
  1. TransferCompleteDetected = 0;) s4 T. C+ ?) o$ L
  2. HAL_MDMA_Start_IT(&MDMA_Handle, . R$ q* O$ n# n- j
  3.                   (uint32_t)0x30000000, ; U+ c  v8 W; R/ x
  4.                   (uint32_t)(0x30000000 + 64*1024), , u. f' r4 H% v& s& W3 f
  5.                   64*1024,
    7 D1 E* v" {5 q0 ~/ W
  6.                   1);
    . C* M) }, ~! X# I. L1 z! h, o% K
  7. ! ~2 @' P$ s, I3 q3 h& b
  8. start = DWT_CYCCNT;2 K% |" M3 K/ U9 b9 k* R9 ?
  9. while(TransferCompleteDetected == 0) {}
    % Q, g0 S! \$ Y! q
  10. end = DWT_CYCCNT;
    3 t* g7 s& f% y! `* M# a8 y6 a* Q
  11. cnt = end - start;# G4 Q# a0 b' S& V
  12. # a* B+ q  ?4 ?6 [' Y* B7 S
  13. printf("MDMA---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
  X+ Z2 @* Y: G8 p# _1 _- [- {
通过时钟周期计数器测量执行时间,单位2.5ns。* c) P1 x- ]* z5 T
0 W1 \9 g+ g) w
62.3.5 第5步,AXI SRAM传输64KB数据到SDRAM$ `2 @* w0 Q% }7 A- X* J
通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0xC000 0000里面:3 X$ v! p7 k$ p* ^9 v) f4 M8 S6 U9 ?# q

/ y% X7 m4 m* G9 H# J( F. B3 h4 {
  1. TransferCompleteDetected = 0;: M4 j5 ?- O% V7 E3 q
  2. HAL_MDMA_Start_IT(&MDMA_Handle,
    - t; p5 Q, ]! n  c/ j
  3.                   (uint32_t)0x24000000, ) ?$ c9 p6 W! k, V: x; ~+ B  p
  4.                   (uint32_t)0xC0000000,
    : z/ \+ j4 U1 r, |* c- f/ R
  5.                   64*1024,
    / w, Z4 K2 b4 t& d
  6.                   1);
    * Z9 Y. i4 G1 u4 I

  7. , g, y8 N# n' C
  8. start = DWT_CYCCNT;
    9 O$ _& t* w" k9 s
  9. while(TransferCompleteDetected == 0) {}( C/ t. C! t. q5 j" J
  10. end = DWT_CYCCNT;1 L1 v: D3 N: I3 P# v7 D# y
  11. cnt = end - start;: I9 h8 T: t" A) }; _
  12. / E% N2 n8 a5 f) y
  13. printf("MDMA---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
9 B+ T9 w& s; X+ U; j7 x

; m5 E9 C/ G, }; W6 o
0 c5 `* A: M- h通过时钟周期计数器测量执行时间,单位2.5n。# `; m+ A$ _8 ?3 v' y, _2 e
6 r* P9 i  X  c8 ~) o7 R3 }
62.3.6 第6步,SDRAM内部互传64KB数据8 {7 |: {5 o  Z% K5 o( W% R- X4 y
通过下面的程序实现将地址0xC000 0000开始的64KB数据复制到地址0xC000 0000 + 64*1024里面:, ]* O$ n# X5 h6 U

: R3 ?, G* Z* C) Z6 a' I
  1. TransferCompleteDetected = 0;
    & x/ }/ A( K( Q8 W/ v5 {
  2. HAL_MDMA_Start_IT(&MDMA_Handle, . j0 M' |8 B7 x1 A: ]8 o1 _1 `
  3.                   (uint32_t)0xC0000000,
    . D! G. A7 g4 ]% S+ k1 H( V: C
  4.                   (uint32_t)(0xC0000000 + 64*1024),
    7 y9 n) S* y2 @8 }. a) m
  5.                   64*1024, % T& ]% C9 G/ ^* E
  6.                   1);
    2 M# x3 W7 U' E4 a/ b, D' U

  7. # Z* O) m( d) n7 }

  8. 5 Z& z9 m; n, G+ M: g/ a! ~* I, }
  9. start = DWT_CYCCNT;  }9 `2 w) g- H* e' ]: F
  10. while(TransferCompleteDetected == 0) {}! A  j$ l1 t/ ]% O$ n$ ~) O
  11. end = DWT_CYCCNT;
    5 b. Y$ K" C6 }1 A
  12. cnt = end - start;
    & E. N5 P- t8 B

  13. % s: `; y5 M' ^+ ~' A) P" U
  14. printf("MDMA---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
) B' L* u8 |4 X8 |7 T
通过时钟周期计数器测量执行时间,单位2.5n。+ E0 b* [  y( u& o0 [
; ~# n5 B( Y6 B& M, r
62.4 DMA2D性能测试程序设计! _+ s3 n8 P5 ~0 G  ~# p4 y$ r, ]
这里将DMA2D的程序设计分为以下几部分,逐一为大家做个说明:
8 `5 ^# e: X" |- Z. O
7 g; U& N% v$ a0 j62.4.1 第1步,DMA2D初始化% o1 ]" Z/ B* B$ m5 Z, x6 M: `/ _/ m
配置DMA2D采用存储器到存储器模式,前景区和输出区都采用ARGB8888格式,传输64*256次,每次4字节,即64*256*4 = 64KB数据。- U5 V) ^. {: R5 y" ~. ]

. `" k0 M7 n5 F4 C2 c) d* S
  1. __HAL_RCC_DMA2D_CLK_ENABLE();  / G* ~' p; h7 _$ b# u3 v
  2. 8 T! j$ ?8 R/ J( G5 Q
  3. /* DMA2D采用存储器到存储器模式, 这种模式是前景层作为DMA2D输入 */  / j9 }: D% g& n0 m- y
  4. DMA2D->CR      = 0x00000000UL;
    4 T5 x* T5 `" o* k+ v
  5. DMA2D->FGOR    = 0;
    : p; R. o* N, l; @! }3 V5 X
  6. DMA2D->OOR     = 0;3 j$ ~# @: m; `% m; |* l
  7. 5 k' S, q) @. u) K: m9 S' @
  8. /* 前景层和输出区域都采用的ARGB8888颜色格式 */
    * d* a9 a5 |+ ^9 c  W* d% F
  9. DMA2D->FGPFCCR = LTDC_PIXEL_FORMAT_ARGB8888;3 P' M( v4 g2 U) E$ S
  10. DMA2D->OPFCCR  = LTDC_PIXEL_FORMAT_ARGB8888;9 F6 B3 n' I) }8 X4 b
  11. 6 \; L' q& m8 t- r6 F. ]; \' m: q7 N$ e0 Z
  12. DMA2D->NLR     = (uint32_t)(64 << 16) | (uint16_t)256;
复制代码

3 e2 s- T! g1 {9 y: p! V3 v. o62.4.2 第2步,AXI SRAM内部互传64KB数据- |# ?- F" O1 |- ^* U
通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0x2400 0000 + 64*1024里面:
* V" B5 X& r0 H: o2 N0 \
  1. /* AXI SRAM的64KB数据传输测试 ***********************************************/
    , T6 C; A; t0 \" Y) j: {$ G
  2. DMA2D->FGMAR = (uint32_t)0x24000000;
    % d$ a; N( c) w: ?! X6 K/ ^' j
  3. DMA2D->OMAR  = (uint32_t)(0x24000000 + 64*1024);
    $ `9 ?. I; t: f4 y* Y& _  @
  4. DMA2D->CR   |= DMA2D_CR_START;   0 h! d# g2 R5 A3 f- g, ], f

  5. 6 {) W: R/ e6 A1 H
  6. start = DWT_CYCCNT;
    + |7 |- m: t& g5 I7 d
  7. /* 等待DMA2D传输完成 */1 J+ g0 h3 z; K- t8 W7 |
  8. while (DMA2D->CR & DMA2D_CR_START) {} 6 b/ G; _! M3 m) H' }# f
  9. end = DWT_CYCCNT;
    ' C5 l9 S. n) k' f
  10. cnt = end - start;
    5 ~: A( v: X8 L$ w
  11. - M% T; }7 \: Y1 G" U; w% h# p, {
  12. printf("DMA2D---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
2 I% ~% {- Y5 W$ j
通过时钟周期计数器测量执行时间,单位2.5ns。4 n  ^8 s/ P! x& n: _" C

7 J3 N/ U$ r, q# j62.4.3 第3步,D2域SRAM1内部互传64KB数据4 r/ N+ r% n: }
通过下面的程序实现将地址0x3000 0000开始的64KB数据复制到地址0x3000 0000 + 64*1024里面:* j; ]2 X* W# G: ^7 ~3 h, P2 b

! k# ]7 R/ G2 @, h
  1. /* D2域SRAM1的64KB数据传输测试 ***********************************************/; \! J0 l5 e1 L! _( l
  2. DMA2D->FGMAR = (uint32_t)0x30000000;' w1 t$ \# H, _8 K' i7 l4 q, Z
  3. DMA2D->OMAR  = (uint32_t)(0x30000000 + 64*1024);
    ! b; G3 l9 G- {5 |
  4. DMA2D->CR   |= DMA2D_CR_START;  
    ! `! n* P" \3 d+ u

  5. 4 B: A$ g: X* B$ M5 y( |1 o
  6. start = DWT_CYCCNT;
    ) n0 w) N( Q0 F( W
  7. /* 等待DMA2D传输完成 */) _  L3 U6 X! f2 f* T% n' Z  b
  8. while (DMA2D->CR & DMA2D_CR_START) {} 0 c6 X6 {( G5 X- l1 z$ F
  9. end = DWT_CYCCNT;
    / h" r( {) f) n* s" _) E# x
  10. cnt = end - start;2 D  P  ?% g- e8 w

  11. & g3 r! @' _9 m+ k# M( p( e8 ~
  12. printf("DMA2D---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
  H$ ^* m3 l; B3 v- j1 @
通过时钟周期计数器测量执行时间,单位2.5ns。
5 |6 n" p- G. T" j' `2 l: u/ p5 n: S0 b) I6 f5 d
62.4.4 第4步,AXI SRAM传输64KB数据到SDRAM
# f! z, t. Q2 V# w  M, c通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0xC000 0000里面:
' o0 l4 S- I1 C2 x
  1. /* AXI SRAM向SDRAM的64KB数据传输测试 ***********************************************/
    6 k$ {; S  K# B+ f& ?0 x" h
  2. DMA2D->FGMAR = (uint32_t)0x24000000;8 O/ f; j% l5 S- c& J
  3. DMA2D->OMAR  = (uint32_t)0xC0000000;. p0 e  g3 B) J8 Z% S
  4. DMA2D->CR   |= DMA2D_CR_START;    L6 V# {9 g1 `* a2 J
  5. ) W, l1 v5 `8 }% d
  6. start = DWT_CYCCNT;5 B$ e2 k1 L. @) g$ R5 U4 Q
  7. /* 等待DMA2D传输完成 */  U, x' ~0 o( m9 ^# c
  8. while (DMA2D->CR & DMA2D_CR_START) {} & f3 m% Q# m7 A5 v- a+ R# h6 N8 E
  9. end = DWT_CYCCNT;8 `7 \" ]' m8 l2 ?. [: L+ V
  10. cnt = end - start;" X( {2 g: U2 G

  11. & s5 z6 n. b2 U8 k
  12. printf("DMA2D---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);  
复制代码
0 ?6 _/ V' Q0 ~. x. o) \" I* E
通过时钟周期计数器测量执行时间,单位2.5n。. ~  F8 [5 Z& m# i( B

# [  i% L7 T+ f( I; `% ?62.4.5 第5步,SDRAM内部互传64KB数据
1 N9 U9 V" Q& [; T' x通过下面的程序实现将地址0xC000 0000开始的64KB数据复制到地址0xC000 0000 + 64*1024里面:
) E6 S/ g* m% H* |  \
  1. /* SDRAM的64KB数据传输测试 ***********************************************/
    % q' {. F/ d1 a; {( R- ~  _8 G
  2. DMA2D->FGMAR = (uint32_t)0xC0000000;
    5 b7 G% G3 }0 X* D/ B; y. o" E. @7 `
  3. DMA2D->OMAR  = (uint32_t)(0xC0000000 + 64*1024);
    6 t* A% ]1 |+ n" W/ b4 T7 |$ K
  4. DMA2D->CR   |= DMA2D_CR_START;% \8 ]3 X4 }" h" @" l
  5. : M+ i' S! ^! [: d
  6. start = DWT_CYCCNT;8 D8 o+ t( I4 a5 o
  7. /* 等待DMA2D传输完成 */
    # ]$ a% b9 i% S! v3 G
  8. while (DMA2D->CR & DMA2D_CR_START) {}
    ! r9 e7 b( [! C  i
  9. end = DWT_CYCCNT;
    $ I) g; `2 l$ r2 z! ?4 b# B
  10. cnt = end - start;    ; l7 c. z9 E+ I9 \. v4 |
  11. ' r, h% S9 M  _- F% _) ~6 e
  12. printf("DMA2D---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);   
复制代码

7 x6 v  K! ^1 f2 h" S通过时钟周期计数器测量执行时间,单位2.5n
# b' e2 u* H$ g: [9 r9 C- w0 ~6 S. m0 f/ _
62.5 通用DMA性能测试程序设计6 b" c% ^  }# f; p" s
这里将DMA1的程序设计分为以下几部分,逐一为大家做个说明:
, v% Q! v9 ~  ~' J; n
& M. I  G+ P- e+ B62.5.1 第1步,DMA1初始化
! S7 e: h: x% h$ c程序代码如下,采用存储区到存储区传输方式,源地址和目的地址都是32bit数据传输,并设置4beat突发,也就是连续传输4组32bit数据。: {, p& j9 j' V- J7 J1 M/ e
  1. 1.    __HAL_RCC_DMA1_CLK_ENABLE();
    * G; z1 F- j! E+ |' N: Q
  2. 2.   
    ! o! s: T# v% \: [5 o. y% e
  3. 3.    DMA_Handle.Instance                 = DMA1_Stream1;
    5 Q/ Y* _* A& c3 V, _+ k/ v
  4. 4.    DMA_Handle.Init.Request             = DMA_REQUEST_MEM2MEM;  
    6 M3 o& s) S- T+ N- l/ M# V
  5. 5.    DMA_Handle.Init.Direction           = DMA_MEMORY_TO_MEMORY;
    - O- a* b+ l& d' }$ p
  6. 6.    DMA_Handle.Init.PeriphInc           = DMA_PINC_ENABLE;$ K, h/ f/ t! E2 G  }% g
  7. 7.    DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;
    ; o6 D3 s/ I& F6 n* [9 n- _
  8. 8.    DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
      D. r9 U) o/ {( S* Q) X6 C4 v1 v
  9. 9.    DMA_Handle.Init.MemDataAlignment    = DMA_PDATAALIGN_WORD;
    : }+ U; f' w: C+ E0 s
  10. 10.    DMA_Handle.Init.Mode                = DMA_NORMAL;
    : X( h4 b$ I* `3 K( \
  11. 11.    DMA_Handle.Init.Priority            = DMA_PRIORITY_VERY_HIGH;
    7 x1 W0 e+ Q- l+ q2 m
  12. 12.    DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
      |+ @$ C& ^- ~& M: x% ?5 a! {9 O6 V
  13. 13.    DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
    ; g& B1 b7 s7 y7 F$ \& N) t' b" }
  14. 14.    DMA_Handle.Init.MemBurst            = DMA_MBURST_INC4;     /*WORD方式,仅支持4次突发 */
    . H( W4 w" P' d& I
  15. 15.    DMA_Handle.Init.PeriphBurst         = DMA_PBURST_INC4;     /*WORD方式,仅支持4次突发 */
    ) Q( W6 Q1 R& O8 V( S
  16. 16.    DMA_Handle.XferCpltCallback         = DMA_TransferCompleteCallback;( j9 g- o; `/ T2 W# q
  17. 17.   
    ; W( A" H2 G$ {: x5 d) x
  18. 18.    HAL_DMA_Init(&DMA_Handle);
复制代码
. k+ z/ {2 n& M4 p6 L
下面将程序设计中几个关键地方做个阐释:
. @8 C6 m% g' {9 }/ j9 s. E
% a% w( n1 a3 j+ q6 w- b8 M  第1行,务必优先初始化DMA时钟,测试发现没有使能时钟的情况下就配置DMA很容易失败。/ g$ z% x$ T8 y# h0 w) }3 J. w5 ], k+ [
  第14-15行,突发传输的配置非常考究,这里要特别注意数据位宽,FIFO以及突发的配置。0 e- b6 K" R3 k+ r
" U  ?( \) f( N% L* A9 `9 H
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
( W0 T) V2 z2 L
, _& Z, w* @: {$ Q3 |
程序中数据位宽是配置为32bit,FIFO配置为满,那么突发仅可以配置为4beat,即DMA_MBURST_INC4。
' Z+ r+ t- y. S/ _4 }  B  i; Y4 X1 U# q
  第16行,设置传输完成回调函数。
$ d: e3 `, v8 z' j. Z8 c62.5.2 第2步,DMA1中断配置
) Z3 [; J" w/ S. BDMA1的中断设置比较简单,代码如下:
  ~2 T3 |8 ?5 z- s7 ^# z$ {7 y! ]$ u5 l4 A6 c  J. z% U6 x! P' c
  1. HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);- P9 U1 a& y' \: v: X8 ^+ n
  2. HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);9 c6 c' w* k- i; i7 A/ G- s

  3. 3 ?! }2 z7 k4 K& X. {
  4. void DMA1_Stream1_IRQHandler(void)" m( y( b* `; U. P- t
  5. {
    % ~7 z7 E4 f8 g1 Y5 ]# L, M
  6.     HAL_DMA_IRQHandler(&DMA_Handle);# ?: |% Y  {* C0 A: R% ]
  7. }: a! R1 K$ s0 T) {: X! T% H4 N# {
  8. static void DMA_TransferCompleteCallback(DMA_HandleTypeDef *hdma)
    ( w/ W! `8 u! t3 x1 b; u% Q
  9. {! V  y3 i3 A2 ?/ M0 n7 g
  10.     TransferCompleteDetected = 1;
    % F" P0 S1 Z) L5 n  K
  11. }
复制代码
: k! K; ?, g% v" A
在传输完成回调里面设置了一个变量标志TransferCompleteDetected,方便指示传输完成。) ]! J7 g& J5 Y
/ g  S7 J) a" P  w3 c
62.5.3 第3步,AXI SRAM内部互传64KB数据* K: m2 z9 {  J0 i" F7 T& j  A/ I
通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0x2400 0000 + 64*1024里面:/ j) ?) I( _2 U, _
( P- J3 E; L, y5 S) R8 J6 d6 C+ O
  1. /* AXI SRAM的64KB数据传输测试 ***********************************************/
    ; y/ h: h+ M+ I3 U
  2. TransferCompleteDetected = 0;  a" j" F" _/ s0 `5 c+ u
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x24000000, (uint32_t)(0x24000000 + 64*1024), 64*256);  k3 M. ~2 y2 K  s7 Q: L

  4. 4 ^/ M" L) Z8 z2 f( q
  5. start = DWT_CYCCNT;  }% b8 _; B- |2 _- ?8 W2 f* v7 M) t
  6. while(TransferCompleteDetected == 0) {}
    ) O) Q0 Y4 e7 @" z8 ]3 a( X5 R  K
  7. end = DWT_CYCCNT;( a2 B+ P" `/ t0 D: R+ T
  8. cnt = end - start;. }/ N* b5 d1 t$ q$ H; S4 p
  9. 6 |+ k( z, O& o& b+ `4 a+ n
  10. //64*1024/(cnt/400/1000/1000)/1024/1024 = 64*1000*1000*400/1024/cnt = 25000000/cnt: i9 R5 Q" D* \, F( q* t/ C
  11. printf("DMA1---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

# _* N# a. B" K" ]通过时钟周期计数器测量执行时间,单位2.5ns。
3 j$ ?2 _4 u/ x6 N+ m" q
0 E- n. W" L) _* I( w62.5.4 第4步,D2域SRAM1内部互传64KB数据
# M# h4 s' ~: I+ l通过下面的程序实现将地址0x3000 0000开始的64KB数据复制到地址0x3000 0000 + 64*1024里面:
( t: J: C; B2 P8 G2 ~9 P" [3 m2 M: @( N* K( E8 _
  1. /* D2域SRAM1的64KB数据传输测试 ***********************************************/
    # O/ o( N7 E7 o1 d  s$ e" _
  2. TransferCompleteDetected = 0;! p4 H/ w, o9 B) T* T
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x30000000, (uint32_t)(0x30000000 + 64*1024), 64*256);
    * N$ b  K& n0 G. W  U8 J/ [

  4. ; d1 Y- \; c0 p. h& D
  5. start = DWT_CYCCNT;+ b+ m3 ~: Q/ N' ^! b/ B$ W" J, @
  6. while(TransferCompleteDetected == 0) {}- T- E$ J2 m- g! o
  7. end = DWT_CYCCNT;( }- U# D: _, f! _+ ~9 g/ A
  8. cnt = end - start;
    ! n, t  t7 J+ s' ^& S

  9. # Y4 p& p( R4 J; P" f
  10. printf("DMA1---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码
7 E" Z0 d- B& E
通过时钟周期计数器测量执行时间,单位2.5ns。
8 Q! O  _% ^5 g3 j( |) _% j: ?" C( M" H; g$ B' S" O/ f! t$ L% q$ {
62.5.5 第5步,AXI SRAM传输64KB数据到SDRAM
2 ^" X0 E) D) H* v+ F通过下面的程序实现将地址0x2400 0000开始的64KB数据复制到地址0xC000 0000里面:3 B' G- M' y* `
$ n2 c' Y* b- ?+ p* b/ D5 S" I
  1. /* AXI SRAM向SDRAM的64KB数据传输测试 ***********************************************/
    3 Y- v, h5 Q  Y
  2. TransferCompleteDetected = 0;
    8 N, x4 v3 k: l# m. Y3 W
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x24000000, (uint32_t)0xC0000000, 64*256);
      Z: j! `5 Y8 ?* G  H5 N2 ~7 ?
  4. 2 M" E/ x7 U) l9 z; ?
  5. start = DWT_CYCCNT;( L' H& h2 `8 X9 E9 M  b
  6. while(TransferCompleteDetected == 0) {}
    - E8 D0 o! Y7 s2 |8 X
  7. end = DWT_CYCCNT;, ^  N" e! o2 r; E* E, S
  8. cnt = end - start;6 I2 n* }% ?4 i' ?" [

  9. / A7 ~$ A. V* Q0 N+ Y8 i
  10. printf("DMA1---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
    3 D+ _  a7 F6 w0 ~2 G% t( W- g
复制代码

" _) |$ ~7 A' T) ?. d$ |通过时钟周期计数器测量执行时间,单位2.5n。
& d4 M! L1 G- B: h0 z  p+ M# i4 Q: B$ G% M) p
62.5.6 第6步,SDRAM内部互传64KB数据
$ W0 F* v$ }, O, w; m7 Z3 Q$ d0 b通过下面的程序实现将地址0xC000 0000开始的64KB数据复制到地址0xC000 0000 + 64*1024里面:: c( d2 F! x, r
  1. /* SDRAM的64KB数据传输测试 ***********************************************/
    6 _; w) g! T0 M: J: Y
  2. TransferCompleteDetected = 0;
    4 g3 d" k, E1 ^; r; S+ O
  3. HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0xC0000000, (uint32_t)(0xC0000000 + 64*1024), 64*256);    * i! @5 z( E3 l0 s( U
  4. : a7 y! Z+ x; V( P0 R" m
  5. start = DWT_CYCCNT;
    % R% I. G4 b8 H6 K9 n* I$ n- j$ A
  6. while(TransferCompleteDetected == 0) {}
    0 ^! h: Z- y: G, r
  7. end = DWT_CYCCNT;6 t* ?  A* M2 r- n3 D, K
  8. cnt = end - start;
    5 w* q  ]  r! X& [: H9 @

  9. : a7 w5 ?! |, O+ Z, N! y
  10. printf("DMA1---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
复制代码

& A* n. {" Y6 l% \通过时钟周期计数器测量执行时间,单位2.5n。' i0 r/ c  f! i6 S  _
2 R$ J# j1 p0 `
62.6 MDMA,DMA2D和通用DMA性能比较
& e: B' b# F9 l2 g9 L最终测试的性能如下:
; ^( e3 g" p* N3 @
2 V, Z' a: o% }
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

  T" R5 }/ f2 r8 @
2 r1 Z$ F$ p/ v4 W0 ?  I" s: c可以看到DMA1的性能跟其它两个不是一个级别的,适合搞搞低速的外设。: }; ~0 f2 B. O$ Z8 @5 U
5 z% r6 w& `( b
DMA2D和MDMA互有高低。  M7 j% L& u$ M+ f" Y0 c; X# K, C
: a2 B! Y3 r& T7 r; X5 ]
62.7 MDMA驱动移植和使用
/ }0 U, a, z" A- k, qMDMA驱动的移植比较方便:
: A" q/ {8 f. I& M; W/ t7 W8 \- N& r% V7 x# T* t
  第1步:添加MDMA的HAL库文件,简单省事些可以添加所有HAL库.C源文件进来。5 o! o2 U* K: Y0 K+ q
  第2步,应用方法看本章节配套例子即可,另外就是根据自己的需要做配置修改。
6 }/ k% t# ^3 |1 k" l9 c" w62.8 实验例程设计框架
, Y! u) N& y) v, [6 U通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:) d  e2 s2 P2 i" v5 w% N9 n- W

, E  H8 M0 q7 i! H0 ~
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
, H$ u/ c9 F9 |) W0 u! m4 F
! H! I6 M8 y+ R9 G; d/ _
  第1阶段,上电启动阶段:+ L8 Y4 o7 N" ?0 J# _
; L. `% t) R6 s/ r
这部分在第14章进行了详细说明。5 r" R+ @0 W! [+ X
  第2阶段,进入main函数:6 P- _+ Q8 Z4 c! f! x
' R- O* K0 \6 u/ D4 b4 ^) e8 i4 E
第1步,硬件初始化,主要是MPU,Cache,HAL库,系统时钟,滴答定时器,LED和SDRAM。6 q4 E& d, t# {# j# o; [) V  K
第2步,测评MDMA,DMA2D和通用DMA性能。, A; \* g3 a) Z+ S9 n
62.9 实验例程说明(MDK)$ W, X' b0 _! |7 a! g/ A
配套例子:
9 a. `' k5 u+ h$ y
- ~6 w' m% g- @V7-038_MDMA,DMA2D和通用DMA性能比较
( r/ l3 V9 u. }: Y# @! K$ ^7 `- C' A5 H9 q$ U
实验目的:* ^9 r! [1 g7 U- |! }- F$ Z* w
6 @% N, v$ _: E: y0 @! S5 H: k
比较MDMA,DMA2D和DMA1的性能% `6 }4 Z! X9 H4 V3 l% ~: q( c* j
实验内容:3 ?) C5 k% o; q9 I% b

3 B9 D) w, {( d4 k MDMA,DMA2D和DMA1都测试了如下四种情况:+ a; t; x5 f9 a1 a7 t

/ R6 }5 {/ d* {2 x64位带宽的AXI SRAM内部做64KB数据传输。* E' u0 J1 N. d5 h) T& d6 s" W# D
32位带宽的D2域SRAM1内部64KB数据传输。6 g# g- G3 g* q" J, W. Q
AXI SRAM向SDRAM传输64KB的数据传输。) K$ h6 x! M, m
32位带宽的SDRAM内部做64KB数据传输。- W/ e- I: q2 ^7 A  N$ s7 Y
上电后串口打印的信息:0 ~% ?& }" j& J( c
  C% ?- y- P: _, n3 ]9 c5 i
波特率 115200,数据位 8,奇偶校验位无,停止位 10 [" {2 o' B$ Y2 r! x) |* Z; H

- `4 e6 J9 S9 J. t; x- q
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
" a4 q* W6 A0 H6 E

; [* N- D* @) |- |5 k: X程序设计:
4 a" s# x' B! {% B. e& X" R
+ p% [2 m3 S# n) y% e; y7 e  系统栈大小分配:1 b8 o. J- p' ~+ R% G6 _2 w
2 m8 W9 N* x; N% w
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

% H5 t( h7 Q  ~3 _# J% |+ ]
/ m7 u8 C* C6 p  RAM空间用的DTCM:
7 H! a5 g0 j/ T: K* _
- I- `& _' g" K/ s- z
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

* A* }2 I$ v" b/ S9 G% r
. S/ e1 Y- V! c  硬件外设初始化+ l& E/ Q( R+ q+ ^: x  Y

3 r$ H# a* A9 W( J硬件外设的初始化是在 bsp.c 文件实现:
7 E; b7 l5 H1 C6 p) Z) I. a7 _+ \9 W3 \8 G
  1. /*
    0 w6 v6 i( c) K) [8 n, r6 K
  2. *********************************************************************************************************
    6 w- n# i+ d& K8 b
  3. *    函 数 名: bsp_Init
    ( k& u7 E. b6 j, M+ |. q
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次4 E2 H6 |/ h8 X$ N- y
  5. *    形    参:无( ]4 _0 ]' ?  S8 a$ V
  6. *    返 回 值: 无" x5 F% W1 _9 o' z8 K2 H7 t6 Q
  7. *********************************************************************************************************
    % ?+ p7 C6 ]4 E9 R: P
  8. */5 Z2 s; J% l7 n. ]
  9. void bsp_Init(void)
    . n& t- M8 w& n" h: i  {
  10. {
    2 ^5 Z3 @1 K1 [" G. T9 l
  11.     /* 配置MPU */
    ' f. Y; ~: l4 p9 ~( w* {1 Y: c
  12.     MPU_Config();* l: O9 A: x7 d
  13. , ~) G9 P- ?* _2 _5 R
  14.     /* 使能L1 Cache */* u! H) N" F; e5 E
  15.     CPU_CACHE_Enable();& t3 G4 t8 H# t! X, ?5 G
  16. 2 R9 C: a& q1 r8 v: W
  17.     /* 1 \4 J2 |" N! M! Y2 |0 P
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    7 B( |% x  w5 {
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    - q6 S8 h4 ?9 m# \) ~. z
  20.        - 设置NVIV优先级分组为4。( d; e$ U. t0 j& G( Y
  21.      */! j$ U) R" |/ d
  22.     HAL_Init();1 m, S+ X( Z! y/ e# t  M

  23. 7 y$ d0 A' L$ F7 x) w- P) T
  24.     /* & |) L2 m5 |, ^: }3 q
  25.        配置系统时钟到400MHz' X" o$ J  k$ X) y4 w8 J6 n
  26.        - 切换使用HSE。3 l) x- [! K6 W8 t7 F: {. c
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    - n7 a6 ?6 W: {: a0 h4 f
  28.     */
    ; o0 I5 P0 B/ Y5 ]. I
  29.     SystemClock_Config();
    " ]. }8 `3 l8 f( f

  30. " G) i7 s. `5 K* G* `
  31.     /* . w4 g. t4 V* {
  32.        Event Recorder:( i7 v; D: t# H; @& [1 Y! @
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。* m% I# Y4 Z4 t* d1 [) N2 q
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章* ?  I8 Y- c( W& Q, ~  H
  35.     */   
    $ R# |9 k3 D( v% p' P
  36. #if Enable_EventRecorder == 1  
    ; V" n8 m4 R3 D4 [- N, w7 {1 l
  37.     /* 初始化EventRecorder并开启 */2 k# Q- q) d7 ^% N' ?4 S
  38.     EventRecorderInitialize(EventRecordAll, 1U);* E; `  C# {! d! D9 _
  39.     EventRecorderStart();
    % b- Y/ e4 h1 M  }* A  h$ ~
  40. #endif
    6 C4 ~1 ~" G1 W/ w2 y/ k! V, O, H

  41. " e$ c% ?. ]7 @. [: W- F  s) B, j
  42.     bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */      
    0 v# d$ K3 b- H: t* V2 b0 ^+ s$ C
  43.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    ! f. G+ ^( n8 `- Z# u
  44.     bsp_InitTimer();      /* 初始化滴答定时器 */5 h7 W1 u0 a1 u
  45.     bsp_InitUart();    /* 初始化串口 */6 ]4 b" M1 p- Q& g% q  N# y* |
  46.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
    ! L( E, @0 l! F: M
  47.     bsp_InitLed();        /* 初始化LED */   
    & \0 K$ c" n: |6 l8 x. R5 ?  L( Q$ S5 j
  48.      bsp_InitExtSDRAM(); /* 初始化SDRAM */
    ; J; J; Q0 y( Y8 U1 s/ ]; O% ^; C
  49. + d' S- Q" T7 G+ q
  50.     bsp_InitI2C();     /* 初始化I2C总线 */
    ; h3 L7 T5 a* ]) T- t
  51. }+ ]- Z) l, a9 W7 n' E1 Y
复制代码

4 [8 O5 q5 i2 \: r; q9 w
# a" M3 d1 Y1 Q  F  MPU配置和Cache配置:
# T$ B( Y/ x/ j2 x% W. Y: _, I; j$ j  K) a, v
数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区和D3域的SRAM4。DAC的数据缓存开在了SRAM4。
6 s$ V6 C- y+ E# Q
1 \: j; c, @* d" z- N0 o
  1. /*( S! g6 M# N: X; a9 `
  2. *********************************************************************************************************: i6 x) @) S, y
  3. *    函 数 名: MPU_Config
    7 n  B; C* P2 U% c$ q, d
  4. *    功能说明: 配置MPU2 l. s2 E& y' ~! T+ Y% ?( P' w
  5. *    形    参: 无: F. q: ~4 _1 V/ T
  6. *    返 回 值: 无8 Z6 ?) ]* k7 h$ i1 v
  7. *********************************************************************************************************
    . |3 K( x) k  P( D* `6 m
  8. */
    - C$ f+ ^$ D: j1 ?+ [" v
  9. static void MPU_Config( void )! ]& L4 [. o, K( @2 T
  10. {
    ( w/ w: v7 C4 C$ ~$ Z  }
  11.     MPU_Region_InitTypeDef MPU_InitStruct;" B9 [" y# |9 ^$ K1 e5 o

  12. 2 g0 v3 \$ g, \: k
  13.     /* 禁止 MPU */  K" K: w5 F8 R, M( I$ @8 e" {  p
  14.     HAL_MPU_Disable();, n$ Q- E6 J, t8 P, L2 x

  15. " `& w* C& D: v. W6 n( C$ F
  16.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    " M2 G3 V& C2 F$ G' V
  17.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    & ~$ l, w& x8 `
  18.     MPU_InitStruct.BaseAddress      = 0x24000000;9 P7 L) t. r% F, ?
  19.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;, m" U3 P3 z  X" M. j$ r
  20.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    0 \) o3 W* V1 b- I/ J& O2 l2 y
  21.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    , e0 S  h& f4 m8 l
  22.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    + _9 y$ f: B$ n- s( x
  23.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;$ J7 A9 `. p2 E# |3 T! h8 t4 q
  24.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;: U( }2 u/ m" k2 C( [
  25.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    9 N1 Z9 s. J: S1 X& |0 n
  26.     MPU_InitStruct.SubRegionDisable = 0x00;5 q8 t1 s+ B5 I4 ^# F: U% W
  27.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;0 Z3 I8 o% R- u+ @( V( N- I
  28. 5 z) F, ~' ^; @9 Y: K
  29.     HAL_MPU_ConfigRegion(&MPU_InitStruct);' _# ~: ^( x2 u/ n+ _8 p8 }

  30. ( S# e. U/ b6 ^9 q$ o8 w8 U
  31. 6 v, r6 g: c- c
  32.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    + R: d$ P" P. P8 m4 Q
  33.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;' ?# P5 L& P; l+ G1 v& {6 {# M
  34.     MPU_InitStruct.BaseAddress      = 0x60000000;  }5 z4 b" {: L& [2 v1 L
  35.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
    7 a8 [  J* n! w6 r
  36.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    $ U* a( C. G# ]) r
  37.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;% h4 S2 Q$ b% G' Y" {3 `, V
  38.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    7 t2 z1 ^7 k( T6 D
  39.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
      J- u) V9 {5 ]  C& h" M3 q$ r
  40.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;  b5 B# c$ g3 x1 ~0 `
  41.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    ; q% K: B; C. E, ~+ n6 {
  42.     MPU_InitStruct.SubRegionDisable = 0x00;1 q# k8 E& r* {, |6 R8 H
  43.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;7 {1 e( n1 n7 o+ F3 ?/ ]
  44. , n9 K# q  E) W1 B' @1 o( K1 g
  45.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    1 \! y! M  J0 D& B

  46. ; t6 }4 b- L7 I5 }! `
  47.     /* 配置SDRAM的MPU属性为Write through, read allocate,no write allocate */
    8 M) A% G  Y4 r  X/ n" E: m* Q
  48.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    & F* y% q. }9 s0 P- T6 D
  49.     MPU_InitStruct.BaseAddress      = 0xC0000000;1 X+ a: R7 }3 P2 d' ?
  50.     MPU_InitStruct.Size             = MPU_REGION_SIZE_32MB;
    1 i9 P5 b2 S3 g, v% _% ^' l
  51.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;1 T* o/ J* D, O, N2 [3 E
  52.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
    # Z& k+ \9 \  x
  53.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;. E. b+ V% y" ~8 v
  54.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;0 n$ C; t! H/ v0 @# E' I( t# O' P2 y8 i( \
  55.     MPU_InitStruct.Number           = MPU_REGION_NUMBER2;
    : {8 X# \$ H' y8 {# u6 y  V
  56.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    / _( K0 `3 d. ~3 k8 b% g6 `% X
  57.     MPU_InitStruct.SubRegionDisable = 0x00;* J% h) u, J" e
  58.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;% g6 l. r& [* K  N5 k- ~
  59. 8 y  z! Q  k. c" I, P/ g
  60.     HAL_MPU_ConfigRegion(&MPU_InitStruct);) i5 e6 m+ p! P% C" }; I$ i
  61.   x8 a& g) }7 j8 P4 N' g
  62.     /*使能 MPU */
    9 i' Q; S1 t1 K- B: ?, H; q
  63.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    * {# S% I- T6 V- R; a" ]& N- W( b
  64. }
    ! u0 o0 }4 K4 n. Z; t

  65. ' m& C, S& }) z' C! d8 s" T; y
  66. /*( a2 e; K% H) g1 p( M. F
  67. *********************************************************************************************************: p7 E/ v! I0 c! e& [
  68. *    函 数 名: CPU_CACHE_Enable
    + u* x" h0 V" a9 l1 P2 R
  69. *    功能说明: 使能L1 Cache
    * C* o2 L) ]9 y2 O7 I! c9 e; A  d
  70. *    形    参: 无
    3 |6 v: n. _' q5 x: r2 z) Z2 H
  71. *    返 回 值: 无4 Z2 ~9 b1 k; V; p. \
  72. *********************************************************************************************************
    , Q& B( S7 q! I* s" Z8 t, w: `
  73. */+ Z. \+ U7 P8 H7 D
  74. static void CPU_CACHE_Enable(void)7 r, X# W% c7 ?. ^4 P
  75. {" S% M' a  o3 H7 c- t5 J
  76.     /* 使能 I-Cache */. E6 n2 v/ f; H( h9 F
  77.     SCB_EnableICache();
    & m# s9 b6 N1 `* o
  78. # I5 Z  {  ~, M$ K
  79.     /* 使能 D-Cache */
    4 ~: C  @0 _5 O6 Z1 e% ?
  80.     SCB_EnableDCache();. R, Q+ L: ^( I' C' v: r9 [
  81. }
    " a4 _8 d/ K2 j/ U
复制代码
6 D6 |5 n9 Q3 `( M7 \$ v2 l! y: Q

# p) y, p7 S  F 主功能:
6 F5 l; N5 \2 T0 o6 z+ Z! O6 x4 L
主程序实现如下操作:
  J7 Y2 G0 K7 u) V/ Y6 h$ _: F) S+ B
测试了MDMA,DMA2D和DMA1。
  y& {+ w& ^% {6 ^/ Y: D7 F% [! N, J' c
  1. /** K( w/ P1 g3 x) B# H2 Q, O
  2. *********************************************************************************************************! j3 M7 y, x' E1 ~7 U
  3. *    函 数 名: main0 Z6 F- @" y' q7 ]' @& m
  4. *    功能说明: c程序入口4 m- }9 L% x7 _/ t' ?8 o' t
  5. *    形    参: 无* t* M! k0 O* ^. y4 `
  6. *    返 回 值: 错误代码(无需处理)2 H% [6 m; L3 p8 V7 R: J
  7. *********************************************************************************************************( R2 G6 ^, Q, E
  8. */: W4 ]/ c, q2 R4 x* g* m
  9. int main(void)
      Y: O$ A: @: o
  10. {7 y3 S: w3 W% T$ _9 }' u
  11.     bsp_Init();    /* 硬件初始化 */6 p; E$ u6 F* g
  12.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    , {; y4 I  g% E8 H0 g  B
  13. ) D2 t" }# p$ \
  14.     MDMA_SpeedTest();; a6 \- {) H* I1 ?3 Y  v! {7 a
  15.     printf("----------------------------------\n\r");
    " P( I6 F8 [8 Q5 i
  16.     DMA2D_SpeedTest();
    + N5 ?$ _& _+ F- ^7 o) a  n
  17.     printf("----------------------------------\n\r");   
    - @& @+ m- Y6 f) L
  18.     DMA1_SpeedTest();
    " c* |$ X7 @3 f* w# {
  19. + s+ Q/ ]! c' \6 V) A& r% m
  20.     bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器,软件定时器0 */) F5 D# v) n! f8 S6 }# s
  21. 3 {4 u/ a) t) w/ {9 R2 B4 n5 F
  22.       /* 进入主程序循环体 */* T, b" @2 `. s- j; y
  23.     while (1)7 w4 {4 J; Z0 {: |) f
  24.     {
    0 w; O: t/ R* _' u" _% g! d
  25.         bsp_Idle();
    # r0 `) l2 }+ ^
  26. ) W8 C2 M/ l% K/ F6 v' T2 S
  27.         /* 判断软件定时器0是否超时 */8 D3 P& z& i; b" J
  28.         if(bsp_CheckTimer(0))* K$ f7 u" g& |( `9 D5 p
  29.         {
    % o  ~) Z8 B4 I, q- s# C
  30.             /* 每隔200ms 进来一次 */  7 S- C5 E' @4 G6 m
  31.             bsp_LedToggle(2);& K! B: ]% ^) C  f% k
  32.         }4 y8 I- g1 [' V1 n
  33.     }
    2 N% ]: q, h6 c9 _/ Z
  34. }
复制代码

/ ]  E. v7 f/ p, t( j: B* C. i+ K: ^" H+ E1 N

! N7 f' O; c$ _( X! J$ m62.10          实验例程说明(IAR)
$ U8 }* Z* P* _0 E0 r配套例子: : |  E' M: y+ |; p- I, M

, N) v1 L" s' k% D# W4 [0 s  aV7-038_MDMA,DMA2D和通用DMA性能比较. D" u: a7 ]* `) F5 _6 _, M

) t; T1 w- x& @实验目的:8 a3 t1 I9 i7 N9 U& a  e5 z: V

4 J2 L- o/ |- Q& m* {比较MDMA,DMA2D和DMA1的性能
) s; l# k8 s: n2 O, b  T1 a实验内容:" }) L/ H% B1 b9 V4 i

( |  \: f3 v, I' P! Q  o MDMA,DMA2D和DMA1都测试了如下四种情况:9 y. {* }" k0 g$ S& h* a
4 a7 i# Z9 D7 I) H5 |( v+ n( Y
64位带宽的AXI SRAM内部做64KB数据传输。
+ q# n% }, O* f; l- M32位带宽的D2域SRAM1内部64KB数据传输。
4 b9 T& V2 K+ K' N. D; OAXI SRAM向SDRAM传输64KB的数据传输。
4 R/ ^$ W' t1 q/ r4 x32位带宽的SDRAM内部做64KB数据传输。
- i- |  J5 I  |6 a$ \上电后串口打印的信息:# F! V: v. E5 ^: B. u# X
, h& t- U) {$ c  z7 E9 e: A
波特率 115200,数据位 8,奇偶校验位无,停止位 10 Y7 q- }6 E, Q* W1 b& H
4 B0 P4 e- L/ L, U
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

) M. f) P9 u( q( `$ w. e
, _$ H; `) m" i. Q: Z' q程序设计:
7 |( r  q; X" |3 J0 `) l. H/ w) h4 D2 E2 E( c2 ?3 a* q
  系统栈大小分配:3 F2 Z- `. P( ~2 {

! O& N& l1 ?$ V3 N( E8 ]8 z" q
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

" g  f' U  r: B' z( h" ~, b
$ @2 h" u, d" Y. b  RAM空间用的DTCM:8 \0 d; d* c& o4 J5 a7 v- |' F

" E) i. F- c6 m& x) \3 h
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

! ]: N. n0 n" P! x- }) m0 P; x2 C* b, o2 \: |8 P
  硬件外设初始化9 d/ v# P$ ^4 J# g" Y

: J7 M3 y2 L# V9 E& |' E  K( L, b硬件外设的初始化是在 bsp.c 文件实现:
; `2 x+ A% n7 W! L
) J$ y& U% t9 X
  1. /*! s& p- E& {, A5 H" Y' h* M
  2. *********************************************************************************************************! `7 e6 O8 M& F; P
  3. *    函 数 名: bsp_Init
    9 Q4 J: {0 F; x4 T0 g: X5 L' s
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    % P7 i# F+ ?$ j4 K/ s
  5. *    形    参:无' G% r# b" m! r3 p2 C
  6. *    返 回 值: 无
    - r8 d% X* i( g' j. \
  7. *********************************************************************************************************& F3 K$ B  e, J- k$ Z) X4 _
  8. */
    ; Y5 T  K. A- \* B6 B
  9. void bsp_Init(void)
    # R  A5 H7 M& v, n/ I
  10. {
    ( G2 s' l/ A) T/ h7 R! g8 u+ Q
  11.     /* 配置MPU */5 z! J& b6 W* n9 A8 e9 W
  12.     MPU_Config();( ^" L+ }$ C8 X4 _: A0 e$ y
  13. , ]% l: Q" j3 ]0 r1 `
  14.     /* 使能L1 Cache */
    % F* v3 K2 a; Z/ n; X% E9 j
  15.     CPU_CACHE_Enable();
    - t1 ?3 l! K( l8 m( ~
  16. ; h1 A6 S; x8 v3 @
  17.     /* ' f/ F/ F& c! a' I5 ^: M5 o1 D. q, c
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    $ l- a% _2 r. g* K8 Z6 ]% @5 I
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。; Q: _) x% N$ h( K5 Y: j
  20.        - 设置NVIV优先级分组为4。
    6 Y% ^# J" Z/ k& Y
  21.      */
    * |; ~2 \2 }5 w. L1 G% {/ n- Q
  22.     HAL_Init();) R* h; M# G( p% G; Y3 ~
  23. + e1 s& Y& t7 Y
  24.     /* % I$ Q' f8 ?2 i
  25.        配置系统时钟到400MHz% _; a3 [9 y0 ^3 T1 n0 h1 o$ ~
  26.        - 切换使用HSE。
    ! E8 m9 b' S& M+ _( C
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    - s5 M& p/ b" q3 `) ~8 B
  28.     */
    4 S7 y# n. x% A( E6 ]% ]
  29.     SystemClock_Config();
    # d3 W! W* x7 k- h
  30. 1 |# ^% T) p6 |0 u$ E6 L
  31.     /*
    # _1 k$ P8 }6 r. j7 }
  32.        Event Recorder:/ q; ?: N0 I* O  P' M3 ?
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    3 e- u  T$ O6 H( I
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    ( P0 T2 [3 n9 N- A
  35.     */   
    % W6 [% k4 J  o  Y+ F6 S
  36. #if Enable_EventRecorder == 1  
    1 [. C1 p" F% S" y2 H: A2 s" k% |
  37.     /* 初始化EventRecorder并开启 */
    9 J; k# |5 h" n7 j' Z
  38.     EventRecorderInitialize(EventRecordAll, 1U);5 p! @7 y  v( f, z
  39.     EventRecorderStart();
    # K4 @, H# d; W% p( {! [
  40. #endif
    / e! z5 x: N# ^9 ^/ F- X# m

  41. & _% r" w7 D' _) m$ {' y6 E* a
  42.     bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */       % f3 ^* P5 F% T) y- @
  43.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */# O1 U5 [- R- P1 J* `  Y( k
  44.     bsp_InitTimer();      /* 初始化滴答定时器 */
    , ?! s( y: m$ o8 j
  45.     bsp_InitUart();    /* 初始化串口 */2 V( A$ c( h5 Y/ X6 R) [9 g, L
  46.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    , Q; ?- U/ S; l# g  U1 P( j
  47.     bsp_InitLed();        /* 初始化LED */    2 R: I) y5 o: x$ U
  48.      bsp_InitExtSDRAM(); /* 初始化SDRAM */* R  t* P) L7 A& X
  49. 9 U% r9 ~1 A; ?- l- ^: J
  50.     bsp_InitI2C();     /* 初始化I2C总线 */
    ; s7 b& U+ b3 z' o. ?4 Q* C, F# [! h
  51. }% k% }+ c6 g: K
复制代码

0 E" u  S# d+ R' j! S9 o/ S6 |$ D" O4 \
  MPU配置和Cache配置:
& R1 p/ z5 j& V( u; ^7 l, Z# q) p
数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区和D3域的SRAM4。DAC的数据缓存开在了SRAM4。
% j" L8 D9 n& T
- {, R2 p; @( @1 k5 N, D& J) q2 {
  1. /*; N- ^: \& Q7 u1 |( z3 o
  2. *********************************************************************************************************
    ' K. P( o) E- [
  3. *    函 数 名: MPU_Config
    * e# f8 Y1 ~- H' l, ^2 D; Q+ `
  4. *    功能说明: 配置MPU0 v& v; w, N! }9 C6 X" @9 B
  5. *    形    参: 无$ Z! n9 L9 y. X3 v
  6. *    返 回 值: 无5 _7 ?" l$ i# x9 Q) c0 N; V" K8 X
  7. *********************************************************************************************************
    + z# F" y3 G3 o: ~4 o% @; R$ ]) I7 Z
  8. */
    * z7 Y2 I  u! G. g+ Z- @% s
  9. static void MPU_Config( void )
    . W3 Y1 z  v* R9 S( X& j
  10. {
    7 E3 t& E5 w) J
  11.     MPU_Region_InitTypeDef MPU_InitStruct;
    7 b7 }& R, c9 _8 q- T
  12. ! @) u, C; }9 l2 g
  13.     /* 禁止 MPU */
    % W( Y" Q7 C% ?8 d" L7 M% j6 o7 @
  14.     HAL_MPU_Disable();3 V2 s! j4 y7 E, g
  15. ) l( C- B1 o( m
  16.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */; m3 v% K$ c$ O& r
  17.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;$ x  l/ [& @) ~
  18.     MPU_InitStruct.BaseAddress      = 0x24000000;- o* t! Z+ c) Y. h- `
  19.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    2 Z; y( d$ U; B5 F
  20.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;0 t- ?% V3 }; ?+ o" ]
  21.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    * {/ f: A/ n' T; }+ \9 h( B
  22.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;- S+ R2 e7 ]$ ^% i- e
  23.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;  x% e; V2 V& e+ O3 S
  24.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    / g. g: d8 ]. b" j
  25.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    % Y/ c& {, u& ?2 y& X( a! i
  26.     MPU_InitStruct.SubRegionDisable = 0x00;
    " p% [3 G4 A% L. t  g. Y
  27.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;+ \" Y2 O/ \% `- t" g1 Z

  28. $ C. Q. y- T8 @4 {$ Y& \6 c9 H
  29.     HAL_MPU_ConfigRegion(&MPU_InitStruct);/ m' N3 p* Z  H. \# o) ?# y

  30. 3 S$ k; _. z- P7 _' g4 I- T7 M

  31. " j, O/ j. x# p% W, C
  32.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */% H5 M& a6 K3 h; p
  33.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    % y; p' J4 m5 ]7 K# h8 @
  34.     MPU_InitStruct.BaseAddress      = 0x60000000;$ T3 z9 ?6 N$ [$ w
  35.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
    % S3 p) C5 _6 P6 K1 Z3 ]6 k2 _
  36.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    3 A  a9 U  K: A6 d- x
  37.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;2 E* x. H2 [1 A4 {
  38.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
    8 d$ U6 e& T& b& e! N
  39.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;' e! m$ u, |8 ]+ C' k
  40.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;1 f! T) o2 I. R# C
  41.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;$ d$ [2 D" z4 p7 ?; ?/ N
  42.     MPU_InitStruct.SubRegionDisable = 0x00;
    ! ?: e$ N) n& `% b. l
  43.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    ! I. m7 Y3 w3 G- T8 e  V/ z

  44. - r! s$ b) k. s( {: ~
  45.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    / g! C  Q& N0 o/ M0 Z
  46. 1 C% K0 F4 ?$ i+ ~$ j- r
  47.     /* 配置SDRAM的MPU属性为Write through, read allocate,no write allocate *// D& X. Z  S, e  ~7 W+ S
  48.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;$ r# c  C$ K2 ~7 f. k4 W) [
  49.     MPU_InitStruct.BaseAddress      = 0xC0000000;5 S; T  n' ]  ]$ ?' V
  50.     MPU_InitStruct.Size             = MPU_REGION_SIZE_32MB;# E/ Q* g) o/ s# C" H, U: W) p& o! c
  51.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    9 g( ]- V' D, t0 Q: S/ L
  52.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
    7 r! G3 c9 G7 q+ E
  53.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    ; Z+ x5 d5 X6 N8 ~% `/ Q2 W  C
  54.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;8 K1 Q; G' {3 P: c4 D) L
  55.     MPU_InitStruct.Number           = MPU_REGION_NUMBER2;1 [. L, ^$ Q1 t. B
  56.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    * a2 i$ W  R* D6 P; ~. s9 l( `( u. {
  57.     MPU_InitStruct.SubRegionDisable = 0x00;! q( O' o9 L: T
  58.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;  r, r) X3 p* J- F/ o! o

  59. 0 }- \+ ]) ^& E) P9 G
  60.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    & ?6 Z( M: p- ?3 W* R8 ]* @& T$ o

  61. ( W) T% O/ P+ g* E' _
  62.     /*使能 MPU */
    * C! k2 x* Q% r2 ?& J/ [
  63.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);2 n3 `5 t* v# J: V% o
  64. }* I9 s. D, F: d3 q, x; Y* _
  65. 7 p. A) s9 m# ]% @' r
  66. /*. ^, U# D* I! F2 a) ^9 u
  67. *********************************************************************************************************
    / U. a; b' d: T* m* q# j; |
  68. *    函 数 名: CPU_CACHE_Enable$ f" U, g3 y' A3 [; d% ]& }; U
  69. *    功能说明: 使能L1 Cache
    2 ?* q% D9 y" `
  70. *    形    参: 无
    3 L; f7 i* u- b/ _6 i" _  e  N
  71. *    返 回 值: 无
    : b! U1 u/ h" @
  72. *********************************************************************************************************
    2 s) g7 A+ B" I/ s4 Q
  73. */
      @% w9 v5 z& t' G' h. w
  74. static void CPU_CACHE_Enable(void); j  u$ O3 J; q+ j5 X  h
  75. {" p5 T! [" V' Q
  76.     /* 使能 I-Cache */
    1 Q( Z: K5 q) E4 |
  77.     SCB_EnableICache();
    & }( g! s  ]' N' h% m
  78. % \! @; H. y# \$ W8 a' j
  79.     /* 使能 D-Cache */7 E- G; D# \, E/ i
  80.     SCB_EnableDCache();
    6 W5 l7 O" g. g6 O, b8 {* ^
  81. }( Z/ @) F' V# F7 l
复制代码
  g5 V5 X$ R, w+ F  u
0 S/ h1 @5 C9 \6 w  x9 W+ N+ E6 t
  主功能:% o; x! A; C1 ]% J( K
4 r# `6 x# V+ s  |  h8 \
主程序实现如下操作:9 e' i6 @8 a, G( n

' h% X( w' s7 j; x7 A- a7 `  测试了MDMA,DMA2D和DMA1。
$ i' R1 {5 D  A, _
  1. /*
    0 d' v. S8 h! F5 D- P; E. H
  2. *********************************************************************************************************5 c* G: i$ N- [5 ]% P
  3. *    函 数 名: main, [( v4 Q5 r" T  U
  4. *    功能说明: c程序入口
    ' G0 Y& t# P- p6 _& \& s, O/ _) h+ T
  5. *    形    参: 无
    3 N* ], o7 b" v0 M. a: ~6 t% T
  6. *    返 回 值: 错误代码(无需处理)" F0 Z: F6 _1 N) J) @/ g9 t
  7. *********************************************************************************************************
    9 g3 L& Y& s: `7 @/ s3 p% g9 a3 L
  8. */0 d" O* {0 `# _* Y, r, ?
  9. int main(void)
    8 h% ?: |9 q- m4 T+ B) G, {1 F
  10. {
    " p. u& r' r1 i, C5 I) T
  11.     bsp_Init();    /* 硬件初始化 */9 {2 ^! I& n( {/ |0 O+ W& z
  12.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    8 v6 W  ?9 l8 p7 y; `: `' c3 Q

  13.   Z/ n! W) A8 S: c. F9 ^, X
  14.     MDMA_SpeedTest();
    - \6 j# ~" m! C7 X& W" |+ d
  15.     printf("----------------------------------\n\r");
    . B4 k  I! {3 a! l
  16.     DMA2D_SpeedTest();
    % C8 z6 N7 k  e4 b8 P
  17.     printf("----------------------------------\n\r");    . D) T' J2 H  E/ S7 [' ~: ~
  18.     DMA1_SpeedTest();
    * q0 W$ @" m8 D* Y; \

  19. ! {/ ^, N4 e+ e7 g! j: C4 d
  20.     bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器,软件定时器0 */4 @$ o- ]( F- s) p7 r9 z
  21. : a, F8 V0 X; s8 D$ F% W6 L  s
  22.       /* 进入主程序循环体 */) t. g; R" i3 }: \# o8 k) Z
  23.     while (1)
    # n3 E7 O4 ^+ _7 c5 z" K# B
  24.     {
    : V7 D" i+ h! ^+ P6 q) H. \
  25.         bsp_Idle();" \& V. F. B* l( k3 ^2 z

  26. - y0 @- J8 d2 m5 @8 o) O: b* w+ n
  27.         /* 判断软件定时器0是否超时 */
    * ]6 E$ H7 ^% d3 p! P1 w
  28.         if(bsp_CheckTimer(0))+ i1 I8 e, N$ g$ `
  29.         {! N% k3 X) h5 l
  30.             /* 每隔200ms 进来一次 */  
    6 A, B4 V5 k$ r. L
  31.             bsp_LedToggle(2);
    / Y2 A- ]6 e! Y/ `" `4 U
  32.         }
    : [& k  d# l1 q9 D! H2 j
  33.     }
    + f/ a. q9 a8 [2 w, W3 U
  34. }
    3 v4 ^0 j+ s9 W* U0 d/ e8 y, [
复制代码

. S7 E8 X: I  [; L
( o1 k6 k; L" s9 I62.11   总结( O4 R: G2 v3 F7 Y% O+ b7 l9 ]
本章节涉及到的知识点比较重要,以后用到DMA的地方比较多,可以根据性能选择合适的DMA。
1 N& s% ^" z# y5 C: `- ^+ M* x. N6 j  F

% h8 v8 f3 R: _1 z# A
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 手机版