一,STM32H7 RAM介绍
/ [4 C% Z* l# r; o( \! ~! y9 e) X使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
9 I8 T V: q ^$ J& S8 i( F; x! J( w+ |1 g+ L5 r% A/ K) w
1 x! p0 @0 t" |$ C0 m# O0 c- m- c/ q8 D3 Q$ ~2 a) D
9 C( {4 a: Z5 F0 e7 |
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。0 \- g: [: A* F: j
8 U& Z1 t" G N( z1 a8 I+ C H x
: [$ n; w) O# c* E K8 {1 T: E" J既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
; y! P5 k# _' n$ O" X% [0 \( d1 g" T7 m: M( a8 r9 X9 ~6 s6 W2 s8 C& @/ G
二 多RAM管理办法) p( t7 x( f1 P a6 Z( u
STM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。
; G/ n% M' J) n首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap/ a4 Y; z8 A9 N& f9 [ ~& `5 F
% `# x: D* W% n9 A! o, `
0 I) V S/ f, E& x3 B- h8 l8 k1 L# a; d# @9 f, X9 S$ R2 z
之后重新生成工程。1 y- b& U" j1 s1 f- n* j
& c* l3 j, }$ q1,TCM区域做为主heap
- V5 Z( J. f2 s! r! z5 w3 X! jTCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问
1 L' N7 ]1 O- S8 K5 T5 Z2 B# M4 k C+ G) @
- ; *************************************************************. D! j. `5 z6 z3 H. `
- ; *** Scatter-Loading Description File generated by uVision ***
* l0 \- W0 c1 c" t5 d. } - ; *************************************************************
: g) i6 H8 |7 l& T, P) d' F0 o% _
! M# a* `8 y! R( t6 }" ?- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
* e- p3 u- A; K8 i& B3 b - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
9 X. |3 S3 o1 e5 i6 v# \; O - *.o (RESET, +First)
9 {; D+ C) ]) R1 I0 X1 { - *(InRoot$Sections)9 h# B& V$ z1 D
- .ANY (+RO)
- k2 S2 B! c9 g4 t4 Q" F7 l* y - }
2 _& }' B+ y0 F - RW_IRAM1 0x20000000 0x00020000 { ; RW data0 x/ L8 u( \, C
- .ANY (+RW +ZI)) x3 J. {6 a3 J/ S# `
- }
& i$ z( L% d2 C2 f: p - }
复制代码- struct rt_memheap axi_sram_heap;: s2 U B9 g" C6 k/ y+ }7 ?
- void *axi_sram_malloc(unsigned long size)$ g$ ^# l' d3 ?) j
- {
- Q1 ~3 w2 d6 E8 }; f& |8 O8 p - return rt_memheap_alloc(&axi_sram_heap,size);
, }% b& u- u; ?9 n4 N - }2 x5 { a/ d" W1 B( g6 l( ?
$ v' d* e9 D% \* h# p' f+ t4 s- void axi_sram_free(void *ptr)3 z3 e& i% x+ M+ N6 l3 D
- {9 k+ b) [2 }1 l) s W- e6 t( U
- rt_memheap_free(ptr);8 \% A" |) ^9 D7 u3 L( G: P
- }7 q; u8 Q, H/ G8 s' C- ?0 h
) f1 L0 k) c, `/ {" V& Q- void *axi_sram_calloc(unsigned int n,unsigned int size)
9 [0 e- N0 {( i6 O: D - {; [# g; P( V' B |' L
- void* ptr = NULL;
9 s1 ]: ]5 R, L+ u* _
- }8 l% n1 D- ]& R- J6 m6 c- ptr = axi_sram_malloc(n * size);
7 \+ y) T' N' s' q - if(ptr)
2 x0 a" [3 b4 Q8 |: ^1 v6 G: B - {- f* j0 m3 z# {
- memset(ptr, 0, n*size);
) ?5 P2 k) F% S, A* X* T) W - }$ S9 W, a& T+ k; a" S! Z/ k
7 N' W$ I9 y) m: N- return ptr;
2 M# n% q0 n0 O. }6 L3 { - }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)& h o- M; a }3 s
- rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
$ c4 z# w4 A* u; v% V6 t5 C( }' z- d! U, U - #endif
6 u9 J3 Z7 ?& u: h" d2 C
& Q5 o2 u1 X+ c. g. J- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码+ W7 \7 ~8 g' n9 }' n' J
5 W: `1 S1 M) Z; Z* y3 Z- int main(void)
0 J9 n* [# S1 }$ Y - {
" V: g7 J' B6 J+ j c - int count = 1;
( M( n4 R) @1 V' ~: X- S2 r# ` - /* set LED0 pin mode to output */9 I7 [4 U: E) z
- rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
) g' Y( a( R3 d4 D' K2 W
; K! `" i' F, l( e) f- char *test_ptr;) N. p' W. I1 k
8 u6 l( F9 `, e+ h6 ]6 x @( ]- while (count++)2 n& {' \3 `! {3 ^" e7 s4 O
- {
3 K) h* s8 o1 c( h! ^ - test_ptr = axi_sram_malloc(100);( @ i3 ^7 L4 d( `0 k
- rt_pin_write(LED0_PIN, PIN_HIGH);8 o. M( x' q; }( t/ h* q4 ^2 b
- rt_thread_mdelay(500);8 z/ Q) B2 A6 m5 l, ` c
- rt_pin_write(LED0_PIN, PIN_LOW);
/ u( W, G m+ f U0 _ - rt_thread_mdelay(500);! {) f4 z5 X- ~2 d$ P
- axi_sram_free(test_ptr);
" C W+ g; S9 L N* L$ |3 h; { - }
9 O$ j5 B+ @- }& B' s8 h+ [1 ~ - return RT_EOK;6 Y( V+ ?$ I4 c2 ~- B( y
- }
复制代码 / ]. N( M% r# Q* P! ?& @
编译一下
& g' q+ y* D- P- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060
7 F8 }" a) ~8 I, f - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
1 V2 e0 _. a- p8 S% D9 @+ [) `3 e - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).! C! {' g$ C Q& y8 l4 _
- Build Time Elapsed: 00:00:08
复制代码 # b8 \* O$ H/ q8 }( M$ `
没有错误,没有警告,下载正常运行。
8 T+ r7 i# S# R* V, G* Y5 y1 O) K" O1 _# ^& I8 |8 @4 p
2,AXI SRAM区域作为主heap
) c' ~5 ^/ h, r. j! U9 OAXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快
+ [9 \+ V* X8 x N: G5 R2 u" C/ d1 W, M; w n" r( d0 o
- ; *************************************************************5 D6 X7 s& c3 H+ b5 j
- ; *** Scatter-Loading Description File generated by uVision ***
0 H) D8 h# K- b8 ^! f0 H t - ; *************************************************************
+ W5 D; h, B2 V% S+ T
5 E" R5 F$ T! [3 v! r9 t7 i- LR_IROM1 0x08000000 0x00200000 { ; load region size_region* L5 N* V3 m2 G
- ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
Z2 R0 k3 X& {8 A& i2 \4 M+ Z5 B - *.o (RESET, +First)
8 U' R! C" e' o2 B# S y( q7 @- } - *(InRoot$Sections)
$ O% R: Y' g5 k- a( B6 ^# f - .ANY (+RO)
' ]6 a! }: z ?$ v) H- s - }) G f, h+ J5 z, \
- RW_IRAM1 0x20000000 0x00020000 { ; RW data
9 ?3 _4 M( x" i# ^* W+ V# Z% u - .ANY (+RW +ZI)
+ F9 ~, O; F" z4 ?( D - } @! f6 h S- n
- RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data$ ^: D- j0 N* `, P+ R' P0 U
- *(.RAM_HEAP)
, a. I3 g2 v6 n9 n$ P4 K4 A& n$ L# a; g - }" c0 T; n: T$ r
- }
复制代码- #define STM32_SRAM_SIZE (128)9 k3 K$ f9 b' s' l0 a( J( C% D
- #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)
9 H0 S/ P e) W7 j. [9 O - % h) h8 B2 a& D, N* r
- #if defined(__CC_ARM) || defined(__CLANG_ARM)
& Z! f' }2 K8 S: z( s - extern int Image$RW_IRAM1$ZI$Limit;
5 }) r1 }$ u4 n+ C0 L- `% C( A6 G4 o - #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
9 o0 z7 Z0 \- c2 Q9 r' v. S! R - #elif __ICCARM__
4 g7 B& q( [7 Z5 E - #pragma section="CSTACK"
* P M7 a- y, D' d - #define HEAP_BEGIN (__segment_end("CSTACK"))# [- T3 K; z9 s
- #else6 j) H3 O7 `# S2 W, ~
- extern int __bss_end; {+ u+ G. X. X3 k6 \+ Z
- #define HEAP_BEGIN (&__bss_end)
7 ^! @; D, @# [9 G - #
复制代码- #define STM32_SRAM_SIZE (512): k& m) R! Q% u3 _) m3 @
- #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024)
+ L* R7 n% W l* D - . ]5 I3 J" S& O( ` A& J
- #if defined(__CC_ARM) || defined(__CLANG_ARM)
) u0 F+ h4 r p" O7 x P" a; K - //extern int Image$RW_IRAM2$ZI$Limit;
8 b" w1 E/ `4 b - #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)
5 m" ^% f- F B4 I0 @/ j - #elif __ICCARM__
3 g# P6 ^+ I2 x2 S- J5 T - #pragma section="CSTACK" P! y, Y# V6 }' l. ^
- #define HEAP_BEGIN (__segment_end("CSTACK"))
, e) A9 F3 m8 m" @% S& k4 t - #else& e! o& Y4 s2 Q
- extern int __bss_end;; e0 T8 K( s4 j, F
- #define HEAP_BEGIN (&__bss_end)
' `, y6 d* r* m$ K, { - #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。& m( |6 [. }2 t5 X* Y1 _
修改完毕看一下,来测试一下8 D% V+ }9 w" I$ X2 E
6 ^2 } S2 h6 j' b5 @( |. r# K) @- #define LED0_PIN GET_PIN(B, 10): N% l% G2 X9 S/ q+ C
- uint8_t test_buff[1000]= {0};; J8 ~9 Z0 i3 F6 A
- int main(void)
$ ^. D3 u C1 f6 ` - {
; k y6 `6 x5 K! t7 p! N' G m1 @' P - int count = 1;
9 {$ A6 q" v9 V9 c - /* set LED0 pin mode to output */
6 n; s6 m* ], z, h/ g9 F - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
, U0 _0 s) @# y4 B8 k - 1 p. g9 z2 B2 e% [
- char *test_ptr;9 T) o1 o0 ~ ~$ K
- test_buff[10] = 1;
" ]( ^ |5 D5 T - while (count++)
_% p/ |/ q, w& M0 {5 n - {2 K' ~# [/ k& ] y& H7 ]
- test_ptr = rt_malloc(100);$ v8 N! ?! ]0 `: B% n7 g
- rt_pin_write(LED0_PIN, PIN_HIGH);/ e4 [* Q8 p8 B6 k% [% n* Y
- rt_thread_mdelay(500);) F$ M8 _6 @! \) Z% L/ Z: ^
- rt_pin_write(LED0_PIN, PIN_LOW);- h) k& X) ~2 h9 Y) [
- rt_thread_mdelay(500);
0 v% i0 A" E( P9 w0 L/ Y - rt_free(test_ptr);
3 e V* s6 s' A0 F6 A - }
, l! f6 p | t - return RT_EOK;
7 j. @% r9 p p2 Z - }
复制代码 / C2 M' F1 k+ Y; j0 R
编译一下. L# w2 M1 l4 l8 B2 m( e& x
- Build started: Project: project( H% b( Q; B3 {. i9 S2 a- ?
- *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'2 Q4 D9 @1 ?. P0 t7 n M
- Build target 'rtthread'+ l+ o3 ], h& E( X% c6 L
- compiling main.c...
: S3 A, T% p& U - linking...9 k4 A( v; l+ t2 Y2 |9 X0 g
- .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).1 Z2 i8 s8 [4 @. x! [- y
- Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964 . u& G. [6 y# q; k5 C
- Finished: 0 information, 1 warning and 0 error messages.1 x9 {2 p4 t$ B+ A q
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin& [" ^6 w9 @8 {5 S5 d/ R
- ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).- s# a1 [2 r2 a$ S. L1 {
- Build Time Elapsed: 00:00:02
复制代码
, ?$ G7 ~ w1 \+ G6 ^9 {% h7 U有一处警告 不要紧,查看一下map文件: a0 D% U) ]: S/ D, F, b9 h& u
5 m) B7 ~3 w2 k1 E2 z
+ ^9 n7 b c& f& ]: F/ v% g
$ |( V* m _. B( e可以看到定义的test_buff是在地址0x20000898的位置。
+ W# l- j) y* A, l( a
+ N6 n4 C: b$ ^, V: s三 总结分析
# H5 m6 \/ d4 m- M2 K实验成功
h) O3 k8 ~; a, [% S$ p) L* y2 a
6 w5 [% _5 X: Y, H* V O) V3 YTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
" l! j$ I$ f7 J+ U7 q
5 \2 N# `4 p# r0 f' b& m' r1 c- uAXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
4 ~! i# D2 g1 x4 s
- _3 Y( a6 u% {: o; n7 }6 P/ }. R; t' c- |4 Q
* K( G9 q7 {) k9 Q+ ^ |