一,STM32H7 RAM介绍
8 F5 `( ?) r# Y5 P( v使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
; @/ e8 ]" U* k* x6 Q1 G) V j
- w, l2 ?- w- |/ p N- R' |" Z* }( ~& w, e- {' b
7 f- O3 } g5 j
; X# ?0 p+ i7 e/ ]通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。6 G; Z& W* ?4 c* F& Q
5 B) J3 L3 u6 R2 [ y0 k n/ i8 q( {, z$ M
/ B7 v( W0 h7 R& l" t+ ~
既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
! @" M) P3 C& |7 d
) K2 T# h) V- l二 多RAM管理办法: l$ p7 J" q. ?9 v7 A) S. m
STM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。
% b/ D. S/ Q+ j6 M! ?首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap
) t6 R5 s6 E3 I% [( J0 T* Q1 q. c: o1 F: l3 I3 t
$ M7 k! L1 x2 W2 T- v0 p5 G# m, B& ?: s7 N- C. i7 S! D
之后重新生成工程。
2 ^5 p8 V7 C: g1 o/ R- t# e0 N- H; y
1,TCM区域做为主heap& b! f7 {% d( r: W
TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问
: J, [ b- x2 _: L% k
! H) g( H* R& X+ q- ; *************************************************************# d, N% ?; w- h) N
- ; *** Scatter-Loading Description File generated by uVision ***- O G2 P( Q/ c" h8 `
- ; *************************************************************
8 }; @+ D% e% u0 g. N" W6 P( ?' }9 Z - + E& l9 i: X1 Q4 d2 U$ ]8 x
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region- X( ?) C& H$ K" h! P0 {
- ER_IROM1 0x08000000 0x00200000 { ; load address = execution address% k+ I8 P4 E9 ]) Y7 I/ U
- *.o (RESET, +First)
4 R/ y/ `2 `) B1 n7 \; K5 Y! |, {9 [ - *(InRoot$Sections)
. F1 h& s6 |# X' W, R( L8 `" [ - .ANY (+RO)
1 T4 k0 h5 x* M8 _0 x - }2 m- H( m9 Y3 `" d! ^* P: g
- RW_IRAM1 0x20000000 0x00020000 { ; RW data9 U9 T1 v W$ j# J* p
- .ANY (+RW +ZI)- q: X4 c6 G: @8 Z
- }7 W5 B8 _. a. p6 `: H1 u \% a
- }
复制代码- struct rt_memheap axi_sram_heap;
7 c2 A; ~1 S1 ~; M8 e( f - void *axi_sram_malloc(unsigned long size)
9 W) G, [1 F; o2 K9 _$ w - {
# \' e6 k+ v8 U8 A: n - return rt_memheap_alloc(&axi_sram_heap,size);# T: q) }1 E% z) [. {2 S8 k
- }
5 ?1 k2 i) a( Z/ \
+ m! @- x; Q; {! `& {- void axi_sram_free(void *ptr)& h' b/ j' G, f" y
- {4 {8 m! R6 y0 y% w3 R
- rt_memheap_free(ptr);9 J0 a" m" Y; c1 q' K3 Y7 l; n6 S
- }
( q# S3 }/ }& s. K7 [$ F
+ F9 X! X |+ d" B. s, r- void *axi_sram_calloc(unsigned int n,unsigned int size)
: G. ~8 U* K4 V" d - {# |! w. k3 j# X5 h* |
- void* ptr = NULL;/ E, a* V, Y: L" X3 Q1 P, I2 r
8 A: z* [7 n, c- ptr = axi_sram_malloc(n * size);9 _% p7 }( p# o1 K8 d6 c8 K
- if(ptr)
5 |# E8 J6 [) z% s% ~" f# U - {- ]7 V4 n3 o3 E
- memset(ptr, 0, n*size);
" \9 ^1 U! Y! x# c/ B4 | - }
( H! S1 H& i- |" |8 I
+ F+ e; _, u9 n- return ptr;
. p: y' i. d) U2 F - }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)
5 { T5 ?$ N" F9 Z# p% B - rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
/ p. y$ G, {. b, F - #endif
/ ]6 ]2 V5 [ n+ \! E - % E, i/ o8 c6 [0 ]! J4 |1 w
- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码8 F& k! L* X* v7 M' \0 H
3 n8 B6 y7 ?- S' b
- int main(void)
f2 k3 K2 v* _7 G, ^1 G; h - {
/ ^( v8 ~7 [6 |% G! d - int count = 1;% p/ h/ N9 B8 |' S0 A( s2 g
- /* set LED0 pin mode to output */
2 M$ h1 z$ N* s! S8 Z' u5 c - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);* ~" |" O4 i& P4 P' a+ F
- - D# c& ~! s4 k0 X2 M% d
- char *test_ptr;
1 S) T4 q1 X! g: |1 c% Z
( k1 H* i, L6 d g% a* f- while (count++)) V, ~, I3 k+ C3 J+ @8 {$ d: P( ^ ]
- {
' `; g5 J6 V, q2 r+ y - test_ptr = axi_sram_malloc(100);
1 J( U: E2 m/ @( W9 H2 l4 c - rt_pin_write(LED0_PIN, PIN_HIGH);* `+ i! T3 S7 P. _# P: a: b
- rt_thread_mdelay(500);
+ |2 C# F- P0 D9 u* x - rt_pin_write(LED0_PIN, PIN_LOW);
6 ]) w4 V$ j7 l# e( D - rt_thread_mdelay(500);
" n1 g+ y9 `. s; ^ - axi_sram_free(test_ptr);7 f$ N$ c. F7 Y- [8 d) s9 C' ?" l4 S
- }* r; C# Y+ w* T( `' e; b" {) ~1 D, g$ H
- return RT_EOK;# h6 J8 n* z- D# N
- }
复制代码
0 M% p& d- M3 C- ?# }& q编译一下
2 S, j5 O/ c: o- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060
" ]4 M5 z5 |, f - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin! B$ E. M+ R/ Y/ b
- ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).
& L: v& y7 U0 T" _. F# @/ A5 \ - Build Time Elapsed: 00:00:08
复制代码 * M% l% e) P$ Z
没有错误,没有警告,下载正常运行。3 d1 y2 d4 ^! i. s1 b
' `% i; Y4 `) _4 ~6 X. N3 C
2,AXI SRAM区域作为主heap
6 G! J9 A. v$ ~ Z+ U5 {& _AXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快. S2 \ L3 G6 ~( K1 M$ @/ B
0 U5 k1 u; P5 q" f: c- ; *************************************************************+ _/ i/ w' h' I2 }6 I
- ; *** Scatter-Loading Description File generated by uVision ***+ X4 @, ?+ @" \# q" l2 B( g
- ; *************************************************************+ Y2 V( R4 a" k$ s8 G) u7 G
- 0 L' Q5 V- u- d) w6 G! C5 }
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
( h5 ]7 v# M' _& [ - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
) h- p# t; h' _. }: H: b - *.o (RESET, +First)& H: b# z* {/ t5 g2 `4 s9 N
- *(InRoot$Sections)
3 `+ ?+ n. m: n* K+ I) L' j - .ANY (+RO)# O' K: h. r& t' L" f# @
- }
* f6 i; o! J3 @6 n4 G - RW_IRAM1 0x20000000 0x00020000 { ; RW data
. F/ K; f# h0 E P6 y9 \+ ?4 U - .ANY (+RW +ZI)
4 k# H4 L8 q+ Y% r% `. s$ S1 | - }
9 n' Y/ S/ a, @4 s X. K4 ]& \# { - RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data# s+ v1 A, r9 N" U0 h" c
- *(.RAM_HEAP)! D/ L% \. K- r, [5 O* w9 U
- }
/ P3 _/ h+ }; K7 | - }
复制代码- #define STM32_SRAM_SIZE (128)# y9 o' [2 m- l7 W& k4 ]0 H
- #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)3 h6 f( S7 D5 C; H4 `
- + ]. h! x( c! ~) g+ Q% N
- #if defined(__CC_ARM) || defined(__CLANG_ARM)
* c; _; X3 i, I: r - extern int Image$RW_IRAM1$ZI$Limit;! f, p! [: H3 r T
- #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)* D' M$ F( ~/ M; v- L' b% c# s
- #elif __ICCARM__9 L, L2 N* _$ @' m- S ]+ _" u7 D
- #pragma section="CSTACK"' A! B6 g6 K$ y0 s0 M9 ]! I; p
- #define HEAP_BEGIN (__segment_end("CSTACK"))
" @1 ?1 |: ]" H& n# h _: d: | - #else+ T, b8 l3 j: D3 L+ r9 b
- extern int __bss_end;) ]/ X0 @/ n6 M0 ?9 z
- #define HEAP_BEGIN (&__bss_end)7 i2 k3 Z5 B7 H2 w! u v1 l
- #
复制代码- #define STM32_SRAM_SIZE (512)
& _$ i- g! r" |3 A- e - #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024)
) f+ u" ]2 V7 V8 |
6 ?( e) I; h' ?) x- #if defined(__CC_ARM) || defined(__CLANG_ARM)
5 v1 I/ I1 a" e D - //extern int Image$RW_IRAM2$ZI$Limit;
4 f H4 }! U/ `( ~ H2 S - #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)
: U- H' l: P) d1 ]: g; J - #elif __ICCARM__
) }5 |& w; L. X5 R! S( T - #pragma section="CSTACK"
6 D+ J, l& p! Y5 F9 F: l - #define HEAP_BEGIN (__segment_end("CSTACK"))
. R& i' n( | y$ w) x1 M* g - #else
. p2 T# `" I. {! o - extern int __bss_end;2 F/ q% ^' M) [- c
- #define HEAP_BEGIN (&__bss_end)
! C* P* l; G* v; X: H - #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。
$ B/ t" _+ {3 E5 U6 k$ S修改完毕看一下,来测试一下
: k6 p: M# q. f4 u7 ?3 r
# ]" Z& K* k1 x# {3 W6 W- #define LED0_PIN GET_PIN(B, 10)
/ Z5 W4 s% Y' v% [9 J k7 t$ P A6 [ - uint8_t test_buff[1000]= {0};1 a! U+ }0 @; n+ |* F
- int main(void)4 r2 f2 {6 z& P
- {
/ q- O. c s. l! j - int count = 1;
9 t4 f q8 O8 ?8 R# G7 B - /* set LED0 pin mode to output */
- |. Z5 v8 W9 M+ j8 S, \ - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);! J5 e3 [8 c) W! A
- 0 P: p7 J' S1 d
- char *test_ptr;2 j' Q" _8 }% V7 {9 q; f- Y; e1 y( J
- test_buff[10] = 1; $ |% N6 X* I/ x, v
- while (count++)
4 G0 @; |- b; D' h+ u1 p - {( P' f! ^. r' k6 f3 ` q' X
- test_ptr = rt_malloc(100);) q. v/ a" E2 w. A6 r
- rt_pin_write(LED0_PIN, PIN_HIGH);
6 n) Q9 R m4 }$ B/ r - rt_thread_mdelay(500);4 P3 p: w! m8 M3 |% a6 X; ]
- rt_pin_write(LED0_PIN, PIN_LOW);* {% x: W2 v3 @* m8 c( x( @, E# l
- rt_thread_mdelay(500);* W! ?$ b/ q3 K1 K0 ~( i! ^! a \
- rt_free(test_ptr);
6 h4 n* g: t1 |0 x6 Z7 f& O - }" l, @8 H: e. j; ]7 q% L
- return RT_EOK;
( c+ a9 C. ^ o2 {) o' o - }
复制代码
/ v! A2 T: ~- r0 Y编译一下/ B3 l# w, w, f) n6 R/ M0 z
- Build started: Project: project
+ U9 a( F- n/ @" z* a - *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin': s8 P; w: {$ d* i0 @0 V3 z
- Build target 'rtthread'3 R- l7 S1 z/ _& n2 e2 b M
- compiling main.c...
, [: D: S9 J( L5 K0 K; g4 [ - linking...
- {4 Z3 F- Y$ E. w - .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).
# t5 a1 A7 U4 J( _" g4 ] - Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964
! T* n( R- n& s$ w - Finished: 0 information, 1 warning and 0 error messages. c# O7 y* B* l. m: W; z
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin" T% T2 ^3 H, U+ ?
- ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).
- m" z# v" c- v$ C$ Q1 \4 B0 q - Build Time Elapsed: 00:00:02
复制代码 * g' o+ m! S; N( _3 T$ m6 e" t9 K! D
有一处警告 不要紧,查看一下map文件
9 n! o; T+ E/ H; u; t6 \
) @1 h1 E5 i. A1 _' s! |; U, y! l& E* ]; g- R: w
9 r, Q; n- T) l% @可以看到定义的test_buff是在地址0x20000898的位置。
- S) g8 M0 W) Y ^
1 S: E7 @* C* S2 g4 C) T6 t @三 总结分析
2 n6 |1 `5 F% j3 ]3 ]) H. F实验成功
. D; P3 p7 U/ b; u0 X; r3 i. O0 H+ U( R
TCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
- y% Z3 `+ P( I8 c: q$ }1 n6 t) G$ A: e3 l B; m
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
* Z m, e+ N. w/ C6 d* X8 B' a( G3 I
; n7 r! c+ Q/ O A
. b2 i Q3 \9 G n1 x |