一,STM32H7 RAM介绍
5 O" \# A7 B! y6 Q! e' [' A使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
8 ^& g1 Z" N0 N0 s
E7 a; I; w, k% s
, V3 T4 X2 S# A) [8 d* Y! B8 n; t
1 x, G" I/ C0 k' m1 Y; {- k, o1 a7 j1 g9 ~ j
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。
, Q) v5 m; k& Q. Q% n* a, I# O0 |8 ]3 M( z$ o" N0 Y% m% C
4 @' O/ f; {8 w7 Q. r( P& v8 T+ |( o3 k( Y8 z' u. E7 e
既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
) C$ X2 @& I& {0 |) P% D
- X3 f# M4 {+ @- H二 多RAM管理办法2 _3 ] Q' n# \) B8 j. w
STM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。9 E1 K# D; p2 ]3 j1 u) Q& z
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap# E* ~9 k/ y) Y! ?% Z; W. d
+ n1 q8 d! D. q& T
; r* b3 J7 F1 T% r) E/ E& g2 K" e' `
之后重新生成工程。- {3 R. h" B: E7 C
! S7 ~6 C% k2 `, l0 ^; }1,TCM区域做为主heap! ~" }6 w: m2 K0 M
TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问
$ ~5 ~4 i& f6 d# T
3 I I* D x, v* _- ; *************************************************************
# L. a; s0 g, ?: h. ~9 c - ; *** Scatter-Loading Description File generated by uVision ***
M1 |3 k! H2 w2 j3 i2 P: ?" q - ; *************************************************************
+ y; k( H% h& F: w1 k: l" ~ - + C [8 J* j2 i! T5 V( Z
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
2 w3 n4 C* \; h - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address5 H1 F) G2 f7 |3 J8 ^9 V
- *.o (RESET, +First)
6 q5 l) l% u9 n+ O3 Q7 X- d0 z - *(InRoot$Sections)- F( {1 w# B* x2 Q3 d7 ? }" ^
- .ANY (+RO)- S1 a! a( C* ]4 L U. P' `
- }7 B& U1 T6 g- } v% {8 u
- RW_IRAM1 0x20000000 0x00020000 { ; RW data s- {& H. k& f1 E3 Y* T' w c
- .ANY (+RW +ZI)8 K/ b. e! N1 r# _& g2 v3 K7 b# l8 @
- }
+ U, H" Q }/ _; w - }
复制代码- struct rt_memheap axi_sram_heap;6 H6 x6 G6 T1 L5 c
- void *axi_sram_malloc(unsigned long size); i& v0 H9 Y% h4 q0 c$ R
- {$ a& A9 Z! a; V- \8 b( }
- return rt_memheap_alloc(&axi_sram_heap,size);
8 Q$ K' N& k8 ? - }
- p/ }# D" t6 Y7 `9 u# X( l - ! U# I+ \8 V+ P. h
- void axi_sram_free(void *ptr)( C4 d) A! y6 A, X" o8 ~
- {' X; P9 F% X( N1 n; U
- rt_memheap_free(ptr);
}$ C2 ?: ^8 Y; t: k8 v: d - }
! k8 x+ E) ]2 c; g8 P2 ~" ]& J
1 `" s7 _5 R6 U, F3 [- void *axi_sram_calloc(unsigned int n,unsigned int size)
! D2 N$ g. e; P( Z - {# _8 p4 y1 h" H* L; ?5 ~1 x
- void* ptr = NULL;4 y" z; q* [- X2 ?
, _: ]: E+ }) X* x# V# `6 D- ptr = axi_sram_malloc(n * size);
4 C, i2 [( q/ W" o2 A - if(ptr)- w5 F! s7 T9 w6 D- M
- {2 ?5 |5 y; [# r, y
- memset(ptr, 0, n*size);1 H' ^ |, A& Z: C) o, D$ j5 o
- }/ ~) A2 D0 c$ ~
- 7 P0 C* `- b- I" R$ ?) R
- return ptr;
: M# {3 m3 e% x' L - }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)
* b: n: Q$ s8 Z1 o/ m+ J. h ?+ m - rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);1 B" Z' K: o' h. n8 @
- #endif1 @- Q5 I* i+ N- B9 U
0 m! X/ ?! `1 s$ Y- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码
" K- e) c- h( b8 `) E W3 f5 F) f& A6 ^0 c( x9 l! G/ Y
- int main(void)* s; {2 N2 {8 Z& E* X
- {7 ]. S3 q2 g. \8 q) g# h8 g. l
- int count = 1;7 x: t0 @' ~# v1 t; m _( S$ M7 M
- /* set LED0 pin mode to output */
" t; ?% @( }- K& x0 U( v - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);4 C) O w' [' G& o1 D" q
- 3 n/ |4 Z$ } u: s( v
- char *test_ptr;# I: H! B9 M4 F
0 p& P- J2 P) L% f. V( ?# I- while (count++)8 d4 a% j% k( M( `1 {1 M# r
- {
- ~) X: K3 j+ }. e1 T3 f - test_ptr = axi_sram_malloc(100);
; L) }; I' K# o9 F - rt_pin_write(LED0_PIN, PIN_HIGH);) k$ Z( C l1 \ J6 v) V1 a' ^
- rt_thread_mdelay(500);
2 |& `: z& i* F. ] - rt_pin_write(LED0_PIN, PIN_LOW);/ G3 V5 h4 L* x+ y! Q n' }8 G
- rt_thread_mdelay(500);
9 V* h+ S% l# B9 s( ^ - axi_sram_free(test_ptr);
/ } U& y. r% o$ u' x - }% T7 V. e9 C% }4 E+ F
- return RT_EOK;# C- M0 o- U9 J: ]
- }
复制代码 7 ]" P' [5 @- O/ J( W- s- I3 _# l# t
编译一下
% G, b. w2 y% {' B) {- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060
* C1 Y; _0 P& k$ e4 V7 P - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
$ j# M4 {, v: U" W7 s - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).0 b0 |% N: S" k$ H/ I
- Build Time Elapsed: 00:00:08
复制代码
: U' R2 o9 d) |! V) m没有错误,没有警告,下载正常运行。
; P) z8 t, y4 b" }
9 `5 D. g9 S" X# M( \! r i2,AXI SRAM区域作为主heap9 d8 q% X# v5 @
AXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快) | f. T; y. X8 Q0 {
$ K1 C8 _+ D, d- a% C- ; *************************************************************
: `( t4 W( k P3 L - ; *** Scatter-Loading Description File generated by uVision ***
/ ?$ q/ g6 A; n6 t - ; *************************************************************
! a4 a- l+ ^ U3 Z
; U2 Q/ {0 L+ d6 @# _4 O- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
1 w1 `" Q8 T( H& m( D& h9 J" b - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
& Z1 ^7 d& j1 u8 l8 l' o- r @: M - *.o (RESET, +First)* m, u. l5 ] a7 R
- *(InRoot$Sections)
" S. R1 t7 z/ }' @' n3 z o - .ANY (+RO)" h8 Q! T8 W- r
- }( N, t6 m2 L. o* v( J l
- RW_IRAM1 0x20000000 0x00020000 { ; RW data4 k" D+ L- F4 l5 n5 Z0 d$ S7 k
- .ANY (+RW +ZI)) V- q) U6 u4 Y$ M8 ?
- }3 k; G+ M7 m; X! ^- f* Q
- RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data5 B% K! f5 W! M6 F8 O) ^. r" Z) y: `
- *(.RAM_HEAP)
9 m- B) g& w' B7 z - }/ H4 h2 J! o: e- X
- }
复制代码- #define STM32_SRAM_SIZE (128)
, I4 N+ s& u h d& U- T - #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)# e- G1 m7 q" z. \1 d6 b; u- g7 D
5 `8 r+ t' ^+ B! T- #if defined(__CC_ARM) || defined(__CLANG_ARM)
9 b6 z. ^4 s" _; K: F# r3 e& O - extern int Image$RW_IRAM1$ZI$Limit;# b+ I! d2 ?1 L0 M% ?
- #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
4 A2 i7 F4 O* q5 e, l - #elif __ICCARM__
4 z2 `" N2 v3 [( e5 t( {% W7 W - #pragma section="CSTACK"7 o. X$ K* Z/ t6 H4 K; \! s- r
- #define HEAP_BEGIN (__segment_end("CSTACK"))
- c: B- j: b9 ~/ m9 |- q. s, l - #else
/ q1 R+ n( B+ i8 L! {( M2 }5 w - extern int __bss_end;
8 L3 P& }8 L+ q4 R - #define HEAP_BEGIN (&__bss_end)
$ ~* S, @4 Z7 v - #
复制代码- #define STM32_SRAM_SIZE (512)
! |4 W# V, \ E' W& j, C- h - #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024)" i0 Q$ `4 k+ H. x; p0 b7 H
' M. [2 ^' w' } N3 m/ k- #if defined(__CC_ARM) || defined(__CLANG_ARM)" G% T3 `/ u) \" y4 c
- //extern int Image$RW_IRAM2$ZI$Limit;
* P5 ?; x" s2 t8 [8 l0 i- C3 Q - #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)
0 e* `2 |( A% j - #elif __ICCARM__
3 a! C3 K) Y+ ~2 s) h/ f- K - #pragma section="CSTACK"' k, |* U8 ?$ i& O
- #define HEAP_BEGIN (__segment_end("CSTACK"))) ]( B- U5 u1 n" e5 Q) p2 s
- #else. Z# s" O9 R b8 A
- extern int __bss_end;
- @' m7 s/ V" I' M# p& ` - #define HEAP_BEGIN (&__bss_end)0 J( J9 T) F- S* x/ x; A- ]
- #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。9 P9 o0 @- v1 ?
修改完毕看一下,来测试一下
& S& M# x2 f& D2 y
+ n0 k% l4 g- q; @- #define LED0_PIN GET_PIN(B, 10)4 P) V' y4 _, R) O- ~: d
- uint8_t test_buff[1000]= {0};
1 G) t% q, u& V2 }1 a$ ^ - int main(void)" V1 g3 a4 x; w) x8 S
- {
( C+ ?3 t! \7 ?) U) m* {8 y, c - int count = 1;
% n' n5 ]$ J, d) O- `6 l - /* set LED0 pin mode to output */' g3 B" T7 n' @5 N9 @% s
- rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
; H. z p1 q k6 z6 @5 U+ f6 g
! U0 P7 C- q$ K% T- char *test_ptr;. y9 h( F+ B( t- h& _6 B7 {. o
- test_buff[10] = 1;
4 R: C3 i+ s$ P5 O) b - while (count++)
( T) W) X: d: E9 F, |( K! ^ - {' k% Z2 I; u3 Z1 F, j$ `3 |
- test_ptr = rt_malloc(100);
6 n. V& J8 f2 n$ R" m8 @$ ^& w - rt_pin_write(LED0_PIN, PIN_HIGH);* a7 p w/ g/ n! @# B/ S" j( W
- rt_thread_mdelay(500);2 D4 H+ u9 `- a5 y% D/ r& a" _
- rt_pin_write(LED0_PIN, PIN_LOW);! N3 g2 C) q" ~: S
- rt_thread_mdelay(500);
5 {0 |6 @4 L5 d2 Z - rt_free(test_ptr);! X/ [$ ?7 L' X; u7 k
- }
7 o! g. s5 b6 T- N5 ?( y - return RT_EOK;
3 f7 U# ?; v5 U) ?2 p1 B - }
复制代码 $ d/ b; a8 @( L
编译一下: o2 O* U8 |: ^$ Z& {9 q% I
- Build started: Project: project( {0 J3 r* c/ g# p7 K
- *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'4 |% @% p. Y* n7 {/ q t/ [
- Build target 'rtthread'' m3 _: n4 z. ^1 J6 G! f
- compiling main.c...1 G. c" y# G; i6 U; Z* M
- linking...
7 o. h( U; X n' T - .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).+ J3 n& @5 B. d
- Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964 - x) h$ _* f- ], `
- Finished: 0 information, 1 warning and 0 error messages.; V6 Q3 }6 W8 h- }: y' c
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
( p( m5 ^5 d: x1 b: }8 Z8 V# e8 J - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).
( \2 I5 O2 B1 X& T" V0 ~+ c - Build Time Elapsed: 00:00:02
复制代码 ) l8 j: c; d$ O8 M1 `
有一处警告 不要紧,查看一下map文件
' f, w0 i/ c. o3 p! r7 y; y) m# P: \5 ~4 }/ o
. Z+ J+ W6 b0 N
2 @, ^! S, S& _! R% ?5 V9 ~可以看到定义的test_buff是在地址0x20000898的位置。
9 ^5 ?9 k! s3 N; g( i4 `! ]4 \, D1 A8 Y- ^& s2 f
三 总结分析
, T( c7 C5 Z; n+ C& U实验成功/ P. U. n# ^6 r. B/ }; i8 \. c1 U3 N
) u s6 y* D; j4 BTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。, y2 H1 r9 X, D" A5 D9 f5 Z
# m3 N5 ]+ M, N, Y
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
+ O/ S) Z6 O! B4 r! G" r: c( D+ P* b
+ }; U# T" _" e" @
7 y: j$ ]7 a! L0 k1 A! [" u; K7 [) E& `$ p$ @4 R
|