一,STM32H7 RAM介绍 X& c! _' \* Q! X& j
使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示- q! ]! {6 Y- E: u
0 s# F# M% Q3 q9 f4 E
0 D, z# B% [3 x* F3 A
* i f9 x3 U9 @
+ K# z4 U A1 z0 ^通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。- ?9 K7 x' i! p+ S- G
5 _ H! R. t3 ?% K. C5 Z& G9 }% [. J4 d5 |3 w
" n* z3 P2 y8 H: U5 h, N既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
: x3 S. G. V( d! C2 ?# T5 ?* V
+ x+ e7 i% |: H) y+ l二 多RAM管理办法
0 L, {+ _" r- A, X% cSTM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。8 K) Y: d7 \ ]
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap7 G ^! N# C8 o. }7 ? [
# f+ V; M1 ^4 c' C- v; ]) P% W9 w: C$ C9 ?8 b
' q, }' J! D9 ]3 M/ {, y之后重新生成工程。6 Y! z& z5 Y4 ~* U) d6 h
5 h' W6 N ^8 |; I$ N7 e6 g; M$ R1,TCM区域做为主heap
! L* c5 i: ~ Q3 Z% ?TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问
# y/ u/ \; p2 l7 R
' l; T8 ~9 B5 P$ i# l6 ]- ; *************************************************************' Z B4 N# @% R1 V c2 x" O2 k# H
- ; *** Scatter-Loading Description File generated by uVision ***/ z$ J: n7 S% `8 S/ k% J- ?
- ; *************************************************************
% E+ L$ Q# D8 T: I$ s
3 G% d; U; _2 D" Y& R- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
0 ^( g) V' a4 i - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
1 `6 h$ [; p# @5 P3 { D - *.o (RESET, +First)
8 f. B1 u. W/ Z) S9 }2 k6 M - *(InRoot$Sections)$ B# H% U5 _- T. {- `
- .ANY (+RO)
; S0 ]) Z3 V7 [! W7 _2 R. _9 Y - }/ ?, o3 q* D4 t6 l
- RW_IRAM1 0x20000000 0x00020000 { ; RW data1 k3 K9 i& J: Y0 Y% p+ W
- .ANY (+RW +ZI) z+ t8 K; Y9 f8 N- R" K
- }
9 H x4 k$ h4 ?; ~- h: W! ~' E- p& u - }
复制代码- struct rt_memheap axi_sram_heap;7 P8 o5 D2 n$ P' T. R; t s ?
- void *axi_sram_malloc(unsigned long size)
+ p3 G: c5 s# c5 f( _+ Z3 V3 h' a6 @ - {! o* A' G* o. R8 S$ \% Y# x
- return rt_memheap_alloc(&axi_sram_heap,size);/ {! }& ~5 l" @! \6 g
- }
5 Y& Z: }' I+ L+ M" W/ b: g# ~; ^
' m+ m! o E. I; S p6 w- void axi_sram_free(void *ptr)9 z$ K, X/ k& ^0 t
- {
8 @$ ^* l7 D3 b- _# s+ p1 l - rt_memheap_free(ptr);
2 `+ a/ f& J3 r- a - }/ p* }/ r+ W3 g3 G/ o) J o) Z
- , b+ A! z, n! u# O6 S/ |
- void *axi_sram_calloc(unsigned int n,unsigned int size)
6 X" `# N/ ~2 @1 r( g - {
% g& ]* a6 g& K: c: W - void* ptr = NULL;
+ f7 v: a+ \7 e) {. N, i5 e
1 G7 g8 \& P' p8 C; H1 ?. }9 g, y- ptr = axi_sram_malloc(n * size);5 i1 e$ B/ q! }. g L' _3 m3 ~2 J
- if(ptr)
8 H& _0 T. Z& B* { - {, ~, \: o: m0 _$ J- ?
- memset(ptr, 0, n*size);
( |8 l% Q. }4 U! C ] - }
* E# i! q: N5 u' ~2 k
. d# c5 X& ]) W9 m0 B: [- return ptr;
/ {, \4 v) i x3 l( H$ Z; ^ - }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)- b# ?- c6 d# I; h8 L, I- A, Q5 \
- rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
1 ^: V2 Q T8 ]. y, c8 w3 Q - #endif8 z* ], i$ X3 y, V t' x2 o H
- 2 l8 a( K. e/ u! x: T4 d
- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码
: l, M& r' i4 [! g# u
- n/ Q' y# b Q- n% P1 k- int main(void)
/ g G- F+ t! @3 ~ - {1 V4 d7 M7 M, Y6 e1 A( Y
- int count = 1;
& g' k5 n7 a a8 f* i2 V. t - /* set LED0 pin mode to output */
+ Q3 j! T3 K9 v# G( Z D, q - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);3 [& \! z n+ ~: g7 z) n5 W' }
( a6 X. ?5 `3 C V- char *test_ptr;
# l: I4 t" P2 Q0 G$ }! r
9 G; T: m4 r: F* q. P- f9 D- while (count++)9 |. b4 ^0 X; | R! M) x& u' q3 Q
- {. b6 x7 r% h* X, X
- test_ptr = axi_sram_malloc(100);
7 i8 L" L0 h/ W* } - rt_pin_write(LED0_PIN, PIN_HIGH);8 K. s0 l- P6 i& l
- rt_thread_mdelay(500);
# b- V7 Y; o6 u, F1 r5 H, ~ - rt_pin_write(LED0_PIN, PIN_LOW);
* {* g9 W& s: N- g6 G* o% W - rt_thread_mdelay(500);# v1 E/ F0 J9 z: j {8 h
- axi_sram_free(test_ptr);( j* H2 p. T% @5 ]: h6 r4 Z
- }7 m9 D; i/ y9 A7 m
- return RT_EOK;* U/ p$ a/ g- I6 Q. M' P
- }
复制代码 $ T$ O. p* K u% Y2 d) l* h6 Z
编译一下 ~$ ?. F& { J
- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060
* Y. t% I: M$ R( v5 i - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
! D& v& j% F$ u L6 Z - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).
+ i6 S. R. U; t4 o7 K3 ^ - Build Time Elapsed: 00:00:08
复制代码 4 s, u& M' v: y
没有错误,没有警告,下载正常运行。
; I" z' n" i7 V# i# j7 l) ?: N, W& R
2,AXI SRAM区域作为主heap
% M6 z7 X; |. f3 l9 sAXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快
: w# s# W) a1 p0 i& H! h8 N( L" u/ O- `+ w3 D, o
- ; *************************************************************
4 f: n# P; Q% B( X, y - ; *** Scatter-Loading Description File generated by uVision ***9 z* ]; ?; V7 O6 L+ F, E. E0 D
- ; *************************************************************
8 V- ~" y* I$ e" U/ j: d - + Z. a4 `; w9 w' z) j1 G7 @
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
8 {' q4 e4 ~) | z5 A) _9 B* [& u - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
! f+ E) h( F0 j( G& a - *.o (RESET, +First)# e9 ^* {8 `, s' {' X1 U6 m
- *(InRoot$Sections)
; o2 i9 B# o: c6 r0 a; f - .ANY (+RO)' A& u+ b7 g p! s
- }
( o6 w) W: F) u( k+ f - RW_IRAM1 0x20000000 0x00020000 { ; RW data: m, X* l6 w3 Q' K* g" D
- .ANY (+RW +ZI)
0 w* |, y" m; E0 D) p - }
* w9 G8 N- X7 s" F2 K) @8 u5 _" C - RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data0 N1 [5 B4 Q; O2 F* _( }5 p) X
- *(.RAM_HEAP)1 c& e) Y* V; ] v
- }7 t2 K( Z0 y1 ~2 }
- }
复制代码- #define STM32_SRAM_SIZE (128)
* M( o: A5 W7 T# L - #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)
# M, y; G4 g1 v/ L. L
# f$ Z! C/ n, O4 Z: i- #if defined(__CC_ARM) || defined(__CLANG_ARM)
9 \1 b3 w3 C' I( v6 a* o L: E - extern int Image$RW_IRAM1$ZI$Limit;: o# ?4 ~- i8 N* a" n
- #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
# ], T: Y+ _$ m9 R( A& n - #elif __ICCARM__
& ^; ]" ~$ b9 H - #pragma section="CSTACK"$ u9 \' h2 O$ `& K& h
- #define HEAP_BEGIN (__segment_end("CSTACK"))( X' U. K, x6 L) o0 t J; }
- #else. y0 l- w/ M1 W+ Q+ o0 x
- extern int __bss_end;6 W: V7 m7 h! U8 t/ c, V' h
- #define HEAP_BEGIN (&__bss_end)3 U2 V) ?: w8 a( E1 B G+ K
- #
复制代码- #define STM32_SRAM_SIZE (512)( ]9 D4 N' z# ]& x- b- h
- #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024)7 S/ N) Q5 y. H) A0 p% c
- $ k' K" p0 t- _# J9 @1 M2 W+ o% l0 }
- #if defined(__CC_ARM) || defined(__CLANG_ARM)- @# O# T& o2 l" N" J( E: V* E) a
- //extern int Image$RW_IRAM2$ZI$Limit;3 _4 p: _+ S, d, g/ Q
- #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)) F3 K Z8 g6 L% c: a8 V6 j
- #elif __ICCARM__
3 s5 m7 P/ [, J/ Y0 w8 ^ Y) q - #pragma section="CSTACK"
8 q- l- K* R+ v) s! T4 o" N3 E - #define HEAP_BEGIN (__segment_end("CSTACK"))
/ b" r) h0 ?6 @ - #else; s/ [( G6 @4 O
- extern int __bss_end;
2 T% Z5 c+ p. M3 ^ - #define HEAP_BEGIN (&__bss_end)6 `! L2 F# ?- H1 o1 Z- S
- #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。
+ {% S1 v, Z; J8 k修改完毕看一下,来测试一下
. z9 V2 L4 N) N$ b: g: m r$ ]2 I: c9 P9 A
- #define LED0_PIN GET_PIN(B, 10)
( [( B( A, H) Q4 ?: D7 ? - uint8_t test_buff[1000]= {0};
+ o( f* e, t( g5 W+ U - int main(void)& \' a* e# j, V; g3 H3 y8 v% b
- { 0 p u1 W1 Z/ T; |6 t1 s8 t1 d
- int count = 1;1 v% ^+ u8 q( [
- /* set LED0 pin mode to output */
: N3 r$ y4 b9 H- B% ~7 Z - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
2 C& A5 x$ y) q' y/ w: B: Z2 e- ?: K - ; ]! R5 y) B' `& ~6 v- E
- char *test_ptr;
2 |2 X% k" q8 s, n" v - test_buff[10] = 1;
% U7 B( c0 { o* @2 [8 g - while (count++)+ @8 \2 v* w$ W
- {
/ {% W$ ]3 T& S* G/ V - test_ptr = rt_malloc(100);" x0 Y! R/ B) d6 x
- rt_pin_write(LED0_PIN, PIN_HIGH);) K8 y/ U9 I& N7 Z0 v
- rt_thread_mdelay(500);$ f1 S1 S. ^/ W
- rt_pin_write(LED0_PIN, PIN_LOW);) e# j0 l% \7 c. {; r; W3 G# o r
- rt_thread_mdelay(500);
h7 Z* B1 q8 o* B5 y - rt_free(test_ptr);- J0 w5 s9 a4 L
- }5 d: l- {, o: x( ~
- return RT_EOK;
9 G* d9 |" T& S2 Q& z& Y% V. Q - }
复制代码 " |: P1 @( t" ^
编译一下
% r8 m& T# o9 k& p5 u0 q- Build started: Project: project
. U4 i1 X( @! m+ s r& s - *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
f1 p& f" f. M" Y7 u Z - Build target 'rtthread': Q% S2 t( U/ g- O
- compiling main.c...
' @9 ]4 B/ Z6 P& | - linking...0 u @8 X1 {9 S8 K* u( q- s& u* W
- .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).* z# c6 U7 q* \) v, m1 H
- Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964 9 i* q% _) e1 @ f5 e/ w- B! `- f
- Finished: 0 information, 1 warning and 0 error messages.* [! l5 `, h+ q2 L% f6 E
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
: U! W2 n5 E+ A" \2 A* E+ L - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).: A5 v3 d% g, S& P# t0 k# Z* _, _
- Build Time Elapsed: 00:00:02
复制代码
* v- Z% x* _! m3 O* |有一处警告 不要紧,查看一下map文件$ T6 u0 c& P6 Z) {* i) [! B
9 g2 K- Z: B T/ N' f- v4 z- ^" H* W
, r {9 f& V6 V( ^
, M4 k% i: _* R ]" B可以看到定义的test_buff是在地址0x20000898的位置。! D( U7 M2 b: v/ B4 L, x7 H
) z1 m9 L: y& K5 Z三 总结分析
" d: @" q5 C! ^& Y, c7 z, a& c实验成功
% U# Z) _: j1 N2 _, ]3 U* J
0 z$ a5 C$ K" }! BTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
' Z1 h* e! w+ M" D3 M; C; Y; h: `+ |1 ^: e0 u9 s
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。0 _; J* b) n0 J. w" @7 h! @ y8 k [
3 {) |# ]& H* W
, Q }# |6 f) S6 _! i' }
4 o3 C, N$ r, U3 V' [" h p' S
|