一,STM32H7 RAM介绍
& p" S- N- b& A' C9 V# ~使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
7 g ]! U+ E& |/ R! f. Y7 k/ N- a# _ W0 D% Z6 b5 _# Z/ U
2 v" E$ W5 R8 e$ f+ O- W% k
X J! c/ G0 o5 M% N0 r
2 {& P: S4 y- @* e
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。0 F4 R/ B, `* X9 s8 q; \
% r3 \' n& W! O1 r
$ T1 N f- w' ]4 C- B
' P. K+ A" h1 _& ^4 U既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。2 _% ` n. W9 |, _+ D
, K& \. B$ X% g3 p
二 多RAM管理办法! t# H; a: c# ]1 O! G3 F/ w
STM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。4 Z Z8 c8 R; J6 g
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap
6 W0 ~7 I" w1 Z! G: a" \" N' F, \; v# |6 p, T; K0 s! D+ N4 w L, M1 t
4 h) c. @7 y0 K+ [
( {. m$ C* P/ T" J! ?1 I2 w3 L之后重新生成工程。+ B/ N L. i. \
7 P) B7 e2 j( r4 \2 E1,TCM区域做为主heap
) Z' J+ ^+ z* ]( l6 _TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问' h( |: z- W! U- g3 J. [! S; v
0 t/ n) s) h. v @6 F1 r+ }- ^! E
- ; *************************************************************
8 n C4 I0 z& [0 ]7 ~ - ; *** Scatter-Loading Description File generated by uVision ***+ {' _/ T$ N& z% t& s7 ~
- ; *************************************************************
. Y% q% D4 v* B' b' G, g - : h/ A# N, M# C- k/ G9 Q$ \
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
Z. u$ J7 | T. M3 B - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
3 @0 S5 I( J, S2 t W9 s; J0 c6 ^ - *.o (RESET, +First)! K5 g( G0 f8 e
- *(InRoot$Sections)
" ]) Q% P' O/ m2 u+ l$ J, q - .ANY (+RO)
3 n) Y. Q% ?1 l - }
8 Z6 J; {4 ? C1 U. d - RW_IRAM1 0x20000000 0x00020000 { ; RW data* }4 l( O% Q* {
- .ANY (+RW +ZI)3 ]& o# K; E/ r- {( G
- }
& e, m7 ~& V+ s3 i8 W - }
复制代码- struct rt_memheap axi_sram_heap;
6 \3 m- l" }, y/ | - void *axi_sram_malloc(unsigned long size), j7 U5 j/ v/ [$ ? U c! [/ B
- {
0 e, G! r7 t7 q6 P7 s y - return rt_memheap_alloc(&axi_sram_heap,size);* b A" y1 |- X4 z( |/ b$ B. l
- }1 o2 Y9 `* h* z( l0 t
- ! [9 d, s& I1 o* W6 _: Z, Z! i
- void axi_sram_free(void *ptr): C5 ]' |& j+ p( [( ]
- {7 l5 z- d: b" G. t4 _! R
- rt_memheap_free(ptr);
) I6 d1 c4 O& H W$ h9 C* n - }0 U, T& ~: [* W) H
. P {9 J' I7 g$ i6 x- void *axi_sram_calloc(unsigned int n,unsigned int size)8 d+ Q7 x) A, U) R) w; M8 A
- {: y4 P4 G/ k% g
- void* ptr = NULL;
, G5 T: L5 @/ `& x
# X# v/ n+ A T+ H# V% i- ptr = axi_sram_malloc(n * size);- q8 @" m9 H) a3 E* \
- if(ptr)6 v2 o7 o! [$ I/ E
- {
8 S% W; J' @* h; s5 }$ a, N - memset(ptr, 0, n*size);. f6 Q: M3 x& @% w, B
- }4 J8 M* X- s/ Z' d* ]) O
- 6 y: O% x* H: O% P5 S
- return ptr;
8 l- I; p2 h9 l% m' u. T* W - }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)
' o8 t5 ?% O1 F2 Y - rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
. M. O' i. D# ~8 m/ h - #endif
8 {8 y. }$ e$ F$ u - ' d3 M: t/ \4 f1 z
- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码
4 S d% a6 }7 K. ^* v" r
( m5 u- C7 Y: U7 \- int main(void)! ^9 J+ w& [ ?3 F8 y
- {
+ B4 T, q! S; t8 r- W. F( c" m - int count = 1;- L1 p7 i3 x5 d, H
- /* set LED0 pin mode to output */
6 G; v: j4 _" M - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
# d- ~" n3 O; P, x: h* ~; P - : u% g1 e2 u/ t: R. ?" \% a! g: T, n
- char *test_ptr;3 \: h& B3 u" f0 t% t X0 n% A
- # q! d% y" k8 U+ J P3 q* c
- while (count++)
@9 u5 h! P* Q; w( ], P( u - {
" X& V6 G; H2 T - test_ptr = axi_sram_malloc(100);" O9 F1 R; y& B1 Q+ E8 C
- rt_pin_write(LED0_PIN, PIN_HIGH);
1 p( C/ M4 q0 g; B4 v9 e' ~0 ~- o* c - rt_thread_mdelay(500);3 P7 W; i+ ~! b
- rt_pin_write(LED0_PIN, PIN_LOW);6 d$ R0 G1 B6 f4 ~. A; }
- rt_thread_mdelay(500);
* Q) y' }: M9 I9 k R - axi_sram_free(test_ptr);
8 h: \" |9 k1 l# ^, ^! D( w - }# R5 u- Y+ M& x7 ^0 k
- return RT_EOK; ^* k0 K0 F: ?4 g3 o7 P+ d2 @
- }
复制代码 % Q" N% A* S6 _0 f' \
编译一下 t) |' V1 X1 Y6 [
- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060 8 j9 U" m+ s: }! A7 Q) y1 l
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin) e$ t: z2 y- F( J
- ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).7 T) k C( Q2 ~. F! h( s+ [% n
- Build Time Elapsed: 00:00:08
复制代码 # \) V1 r* l8 n
没有错误,没有警告,下载正常运行。
& q; u8 ]/ o, s
$ k9 y3 q9 p& t4 ?2 p4 X7 J2,AXI SRAM区域作为主heap
8 n8 o9 t K4 U* p. bAXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快
! y; ^4 q T; r6 ^5 W4 Q7 g, A, ?1 P6 P7 I
- ; *************************************************************0 S7 [. U5 v6 Q3 q' b& Z, ]. X
- ; *** Scatter-Loading Description File generated by uVision ***/ z# l0 |. S4 X5 |1 o
- ; *************************************************************% A* C) m; @1 K7 G4 z0 v
0 s/ E/ `# ]" y) x6 X- k4 k- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
) a( O, B2 f: k6 j- c& w - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address& b5 @$ d* _: n$ p' x
- *.o (RESET, +First)+ r9 ?; z0 s% X3 v2 y6 y
- *(InRoot$Sections)
% b) a4 ~) R# |+ F - .ANY (+RO)
% }% |4 c% {) D, Q - }0 w! K1 ?0 T" R4 e
- RW_IRAM1 0x20000000 0x00020000 { ; RW data1 g; t" e5 S. I4 @ G9 M% x
- .ANY (+RW +ZI)( ?8 \1 O8 h6 f
- }7 Y# V! ]5 N; M& E6 \6 p" f( ?9 W0 H
- RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data- f! d$ Q. s& V( ~! n3 M
- *(.RAM_HEAP)+ v7 x. ^6 Q! p4 C4 m: S. q
- }
$ P) E- n q1 l# ? - }
复制代码- #define STM32_SRAM_SIZE (128)
1 x+ M% O* N; P - #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)& L4 G) Q( |& s! Y1 ?4 q
- 4 Z- n# y3 l% G% `
- #if defined(__CC_ARM) || defined(__CLANG_ARM), @0 s( A. Y1 s
- extern int Image$RW_IRAM1$ZI$Limit;
8 C) K9 u g" N& d o K5 U8 v - #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
/ u+ {2 A/ Y/ Z - #elif __ICCARM__
9 O, n5 I2 ]; \1 T: B8 [( J* h6 E - #pragma section="CSTACK"
; V7 j1 r. d7 o# x- n' @ - #define HEAP_BEGIN (__segment_end("CSTACK"))6 N/ ]1 c$ T/ r( O" O
- #else: G4 N9 y: B' H* G
- extern int __bss_end;2 a5 D& {* c& v1 d( l# ?$ ~
- #define HEAP_BEGIN (&__bss_end)- y: ^& s! s" H6 f5 M. [ g- t: q
- #
复制代码- #define STM32_SRAM_SIZE (512): D* i0 e$ @# F- m) J' ]
- #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024)
9 W4 ]- Y, P% V8 D9 f - 3 H" E6 F) z" [! h. ?
- #if defined(__CC_ARM) || defined(__CLANG_ARM)/ ~2 k5 R2 ~9 c* }- O5 X q2 M
- //extern int Image$RW_IRAM2$ZI$Limit;
$ m8 @: O8 ~1 ^) R9 d - #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)
5 }. |! `# I, L8 b7 H) Q5 C6 P - #elif __ICCARM__: n# s5 u2 g$ W6 J4 M* w0 t9 x
- #pragma section="CSTACK"9 _/ A( v M7 \3 F* h$ q# O
- #define HEAP_BEGIN (__segment_end("CSTACK"))! S) e. S1 d; [
- #else# n6 G2 u6 Z! A j
- extern int __bss_end;
4 S( @( B* q, i( r - #define HEAP_BEGIN (&__bss_end)
7 P7 @0 L& e8 E3 A" G - #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。
/ S9 o1 N& K6 g修改完毕看一下,来测试一下8 e" C/ g. }1 F
0 s" C5 }' N# W7 x' b$ G3 w
- #define LED0_PIN GET_PIN(B, 10)$ L4 b; y0 }- f+ j9 `. C8 {
- uint8_t test_buff[1000]= {0};7 K# p5 V! a2 H2 r1 _
- int main(void)
m) S [5 _. E& q% y6 C4 S6 T) o - {
7 v/ r# z# l; G6 v* I+ ? - int count = 1;
- i% Q3 o' c: N& L7 ?4 x - /* set LED0 pin mode to output */
' r" q; J( H2 T' T. J - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);$ X1 G- T2 r" [+ i
- ! L, [- t& o# V; d% y! h: ?
- char *test_ptr;
) h1 h; m" H, Y) |4 O6 `' t" q - test_buff[10] = 1;
0 P9 x% o* g' J; ^ - while (count++)
. o r9 Y/ B v/ F1 V - {
9 D7 T8 ~6 h- L3 {8 K) U - test_ptr = rt_malloc(100);
/ G; g. g8 I. n! t& M: k" R - rt_pin_write(LED0_PIN, PIN_HIGH);
* p' I& y3 d7 S% B - rt_thread_mdelay(500);# A2 I0 j/ @2 d8 \+ b4 d8 q
- rt_pin_write(LED0_PIN, PIN_LOW);
9 L: K& P8 p k3 r, p - rt_thread_mdelay(500);- g/ X& X7 n ]# y
- rt_free(test_ptr);
, Z [2 _ a, X! C) @: p2 v4 \ - }5 I; f6 t- k* h N
- return RT_EOK;
0 Y# o( U9 d% I3 z - }
复制代码 + y2 h2 l' f' G7 V/ }
编译一下
" N4 B' ~6 n! J- Build started: Project: project" t" @( V* Z0 P. `6 T+ y; t
- *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
" A8 P {$ R- Z6 w" U) L - Build target 'rtthread'
, {# d; }* _4 U$ d9 w- n. b3 @% ? - compiling main.c...! J* g4 n" U9 _* ~% v
- linking...: @! i! I" l: x) r; G M
- .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).1 _8 R" _7 x$ X& F- B' O" G
- Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964 % P, _- J9 A L# L: q% X+ Q: W. x) W8 g
- Finished: 0 information, 1 warning and 0 error messages.( i v2 V$ @7 V& d
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin8 N: W# v8 y. q1 S; M; N
- ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).
: k# K" n% {- u1 O" V1 U- j - Build Time Elapsed: 00:00:02
复制代码 / B$ F/ |' p% [9 p% X
有一处警告 不要紧,查看一下map文件/ B& I1 N# i+ a; Q$ H1 c
. s) y" D3 e3 @2 {: G' J( `
0 i) B; w' Y5 G) o1 C) `
) Y( E: z/ X( A5 `, o/ z Y, E4 E可以看到定义的test_buff是在地址0x20000898的位置。
+ a* D% L' ^+ \, n/ M
7 H ^- g7 p2 o" w) h. c3 i三 总结分析
1 {- Q7 ^* [( A& c实验成功
h% s* V& C( J4 {$ M
: {2 `5 k& V* O- W! jTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
0 i5 L, r. {5 e2 \: s; d7 p) x$ W! f8 {& f: O/ i- i
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
/ i. i0 v9 Y2 A
9 ]3 j9 ?0 w, V6 E
; y- G" j( R& v6 ~# ]) [. N! V6 L x
1 o3 \, i5 w" f. y/ }; V |