一,STM32H7 RAM介绍' n- h5 M3 ^& W
使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
3 I' T; V/ j4 h" g! ^# W
% b. u4 ^ e4 h3 p O/ h$ H1 o: r7 V& S# S s3 w$ I
: ^* A' G( T$ P# v1 ~% @
/ }2 m) N3 {% U9 R W
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。5 |& T' L4 N6 f, B) Z
1 x ?9 \7 [& K6 L* G
0 @$ t5 M2 |0 R8 Z: Q. S) X7 R, z9 x( u& X+ l2 K) {3 }
既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
; W9 T- e7 w8 C' e. b1 o4 f. i, G$ D
二 多RAM管理办法
0 [' u2 L. I/ q; |1 pSTM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。
" ~5 v* Q) b. ~. n \首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap% E) Q: w* \) n4 J& ] e
: t6 e* u0 ?: u0 F
3 Q6 ]: {* R, @8 V0 Z {
+ T) F* n$ v3 I1 j1 ~7 q# @8 J
之后重新生成工程。; C$ W# u5 |% l0 G8 Y- [
* f2 d) X+ n/ `* k/ E
1,TCM区域做为主heap
2 v. ]) J% @2 @TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问, ]( q6 ~& R6 I% t/ f4 B7 g
3 N/ N+ P/ B$ Z+ A: f U- o/ [- ; *************************************************************; u6 k* C$ e2 ^7 L$ R1 X
- ; *** Scatter-Loading Description File generated by uVision ***
& e2 `: l$ u( F# C - ; *************************************************************
( x) h7 }8 I5 D) Y' R, P2 Q - i0 F& ~. @0 q% R3 O
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region9 l! P0 f0 G1 w* |
- ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
. [& R# |5 P/ `1 P$ z4 d - *.o (RESET, +First)1 {$ T% w8 E0 m1 B
- *(InRoot$Sections)" U: o" [$ z! b: O W( C
- .ANY (+RO)
1 y! i1 C, ?6 x4 K" u/ j - }
, A. a1 u- }5 y% Z* a; o, w( C; U - RW_IRAM1 0x20000000 0x00020000 { ; RW data
8 r+ ^) L8 `- W( Y! \ - .ANY (+RW +ZI)+ ~/ w) W x& I
- }
* X$ x5 Q) O* E - }
复制代码- struct rt_memheap axi_sram_heap;
# b" d1 S* p& f8 s- K* m( N - void *axi_sram_malloc(unsigned long size)) ]! t; e8 E8 o$ e0 t1 ? u
- {
6 `9 Q U" U( H+ b - return rt_memheap_alloc(&axi_sram_heap,size);
0 Q/ J1 _1 e/ x( a - }5 N- p# i$ i/ e& v9 U3 z* }% }6 P6 z3 c
' O/ h% S$ C J* x P7 a- void axi_sram_free(void *ptr)& X3 z% x( k# l4 [
- {# c& b* {* _" G
- rt_memheap_free(ptr);
' K3 ]6 A# I7 k9 ]) Z& t, J5 w - }) }, U# U9 E; ]4 p y! Q ` e
- 4 F; ^2 F6 i% c" y
- void *axi_sram_calloc(unsigned int n,unsigned int size)
1 `0 K3 b/ _8 |5 T' g" |, ~ - {
% W8 ?7 E! U8 v' j M - void* ptr = NULL;% p, t: n1 w/ e6 B( d
, O5 h* t& Z6 U2 {7 a' y- ptr = axi_sram_malloc(n * size);4 N4 {- ?* N3 G( b
- if(ptr)3 ?$ w& b8 F) B. L0 ?
- {
. H" G" ]3 L, n - memset(ptr, 0, n*size);' |/ L& O: r" M, G) _- Q
- }" Z! S1 I5 a1 D; f3 W+ r! P
3 P8 M" C+ D+ v2 X5 }$ j- return ptr;2 A! f( X1 R" n; H$ A5 ?
- }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)
2 S3 w: l( V3 }# n, P1 ] - rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
. G+ n' X8 Y7 @$ B. [& @ - #endif
( b7 q( K9 b; r" O A7 q
& Q$ o* x& d* ]8 d& i- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码
$ B% z# m; z* G9 _( u$ L
3 G e/ i+ ?1 F5 ]- int main(void)& v+ h1 |! Y2 Q0 s6 Y8 E V, F
- {
9 t+ F! |* k) f6 P i& l - int count = 1;+ U& C2 M/ a$ V! {: I+ S
- /* set LED0 pin mode to output */& `* w3 ], ~3 z
- rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
0 F! x" N: ]" ` - M3 W* k2 y1 y% @" v
- char *test_ptr;
- w+ s8 I$ H; N6 E3 r( ]
5 H& Y8 m1 V+ a3 }3 e# N9 k- while (count++)0 z$ C+ y0 I# l( }5 I
- {
2 ~# P% _+ n: _0 H; f$ @: C! o - test_ptr = axi_sram_malloc(100);
) ]8 c0 M' M# ]* [0 D0 [3 a - rt_pin_write(LED0_PIN, PIN_HIGH);
+ F3 R' x7 |& d- y. R; @2 t - rt_thread_mdelay(500);' Y- {3 S) D/ v
- rt_pin_write(LED0_PIN, PIN_LOW);- s- j& {- T/ I! w r
- rt_thread_mdelay(500);
# c- {7 z' c- u- e; u# h5 ]& Y - axi_sram_free(test_ptr);$ Y3 V2 v- F/ i; s N4 c$ v
- }
4 C1 `+ \1 ^( o8 C ]( u - return RT_EOK;2 A9 y3 j" I. L" ?- S4 d d
- }
复制代码 + m z V% l' q7 o% G2 Z& q+ F, r
编译一下
" n! }; R2 _# ]% | G2 L2 S- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060
9 ^, g0 A% D7 I* u( M8 O" a* p/ h - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
0 k+ K7 `, G& @ [ - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).
( K) O }/ T6 N5 r - Build Time Elapsed: 00:00:08
复制代码
* \/ F' M% r9 z没有错误,没有警告,下载正常运行。7 A8 T1 n6 O% a0 B1 d
# v8 G2 i1 S8 b& a! n
2,AXI SRAM区域作为主heap
8 |5 r7 ~# l' I: eAXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快! s- R2 `4 h9 O7 }6 ?7 q5 h
* q; l3 F$ o/ m* J5 V- ; *************************************************************
# \- u, Q/ v" a3 E& v - ; *** Scatter-Loading Description File generated by uVision ***/ O8 E+ q7 z% c6 `) S
- ; *************************************************************
& J+ M3 d0 f! m( S" Y1 D- w) f
; \, U, H$ u& q" n: z- LR_IROM1 0x08000000 0x00200000 { ; load region size_region/ M! O% a7 P& S& b3 F0 K9 a+ O
- ER_IROM1 0x08000000 0x00200000 { ; load address = execution address3 O2 I( R |+ e
- *.o (RESET, +First)# H8 z7 \6 {* c4 F( A
- *(InRoot$Sections)* o, }( X/ B5 U- Y7 f
- .ANY (+RO)
5 H" E/ [; j: y& |* K- b - }3 Z& B! l; e( f9 J# [
- RW_IRAM1 0x20000000 0x00020000 { ; RW data
+ G r1 V8 B6 O) u0 n- R - .ANY (+RW +ZI)9 p, j/ D8 S. Z+ W4 L
- }: U4 |5 w3 Y% v" U
- RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data- | ?+ X$ s3 _0 V2 B6 p
- *(.RAM_HEAP)% X4 Z1 t; b& _+ ~8 y8 D+ W
- }
, {/ y7 A& G \5 N! ]# Y; |+ A - }
复制代码- #define STM32_SRAM_SIZE (128)
2 h" g1 h: Z8 Y. { - #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)
$ T4 g B( G, ]: d I9 H; m1 _
! Q: \$ e6 u0 Q9 b- #if defined(__CC_ARM) || defined(__CLANG_ARM)4 w* y6 b+ |: k$ h7 p" g$ r
- extern int Image$RW_IRAM1$ZI$Limit;% k; l4 ~1 @, S: ~5 R& R: z0 w
- #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
% w+ l) q2 `+ B - #elif __ICCARM__/ |) z* Y1 j4 N8 ]% N
- #pragma section="CSTACK"
3 h D' m$ Q. f$ m& p9 F+ V2 ]% v - #define HEAP_BEGIN (__segment_end("CSTACK"))
0 `. K' O5 ~3 [* f - #else
$ i6 x) u, O( p; L - extern int __bss_end;
: Z' u. d! P r/ |( p1 z F$ R - #define HEAP_BEGIN (&__bss_end)
' {& h1 `6 }4 A+ E - #
复制代码- #define STM32_SRAM_SIZE (512)
1 K6 P1 {( L8 H7 n2 o* z! l/ h - #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024) X" J8 A* ^: D ~
% Z9 q& Q- z' X! G! S- #if defined(__CC_ARM) || defined(__CLANG_ARM)/ b6 i/ S' B/ T' \0 B: F
- //extern int Image$RW_IRAM2$ZI$Limit;
: |7 A& D5 W( A; \) u - #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)
. C4 s! K$ d; H; E6 a0 w6 n* j - #elif __ICCARM__
' I o* k$ h4 {. U2 ] - #pragma section="CSTACK"8 O: O; q6 W$ X9 d3 O
- #define HEAP_BEGIN (__segment_end("CSTACK"))6 k [/ P9 E. Y1 R8 z
- #else- p; E0 J' n1 u* [* x- j1 C. Z
- extern int __bss_end;
1 o4 @) v- M2 r- F - #define HEAP_BEGIN (&__bss_end). U% k/ o- \& q5 Y) q" D3 I
- #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。
. q! O* Y4 S1 c8 {; {. L7 G4 Y修改完毕看一下,来测试一下
" A3 T0 [' d! A7 N0 ^! P( \- g P8 P, ^ ?7 N
- #define LED0_PIN GET_PIN(B, 10)* J% c+ K; g8 {5 l) R( ]
- uint8_t test_buff[1000]= {0};! l# L1 b- H D8 _
- int main(void)
! c) i: W9 O/ k) ^' K) h' j - { 0 s4 ]" ]9 K7 X: W4 q( c8 p5 h, I
- int count = 1;/ [0 }! W o$ Z7 L Z4 D4 |7 I
- /* set LED0 pin mode to output */3 k' H/ Y) o0 l( m8 S& j! N
- rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
E7 \4 j0 R8 {4 O E) W - 1 [/ k4 b) @5 ]$ L
- char *test_ptr;: d# E3 M+ T6 F! M- W
- test_buff[10] = 1;
8 C0 \! Q' d* m V - while (count++), ^, C1 ^5 @2 W1 F# S" H
- {2 u) d; ~9 c* w; y/ u7 e2 `/ q8 ~( H
- test_ptr = rt_malloc(100);
% l% c2 i/ s. ^( A. g" K8 c - rt_pin_write(LED0_PIN, PIN_HIGH);5 O7 b H. G1 B1 y a
- rt_thread_mdelay(500);
. N. N7 c6 g, s p - rt_pin_write(LED0_PIN, PIN_LOW);
9 s8 m* k3 B+ C: F - rt_thread_mdelay(500);: R: k; ~" |$ O! N: @0 k- A- X( c
- rt_free(test_ptr);
, n% e% J/ O' y# h/ [& F- @3 b6 A" ~ - }5 R9 i+ y4 O- M P
- return RT_EOK;* T$ J% ? V! B* {. P! `
- }
复制代码 - C8 J1 S* C3 K! u4 ~
编译一下
$ o# @, t5 p+ R$ M4 r3 C- Build started: Project: project. g4 G8 Z0 n. U# |- `5 V# C: y/ X. J
- *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
: u( I8 L- y6 F: W+ ? - Build target 'rtthread'
- V6 q6 M' [5 h) [& Z4 G+ U( Q - compiling main.c...0 g6 p t! A: a5 g# v
- linking...
R' Z* s4 f! x/ p9 V2 f- [6 F - .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).5 o3 S4 U; J5 z" |
- Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964 1 F: j7 _ D3 i( u+ K
- Finished: 0 information, 1 warning and 0 error messages.
) d6 S g) S5 q/ @; a% q+ H7 c2 } - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
6 k4 r9 n2 {( m# N& Y - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).
3 r2 C; R P# Q - Build Time Elapsed: 00:00:02
复制代码
. k8 t5 R, y* t+ Q9 l) F% c: T& g" [有一处警告 不要紧,查看一下map文件 r$ F: h4 w1 b( `
W: o- Z x' J
8 k9 g+ z( q" q/ {- b5 ?' ~7 u
1 R% r9 j7 e5 q9 O1 Q+ w
可以看到定义的test_buff是在地址0x20000898的位置。
/ Q0 y Z7 Y& [ q# V4 M- m- _2 S& ~2 o
三 总结分析
' {, q9 Z! u$ H& ~8 \: }实验成功
+ f' x2 ]1 Z& O. n0 r
9 Z) J' x: [. N& ?, h& PTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
4 i1 D5 Y. e& R1 j5 N7 n' u. w' M5 d$ q5 k
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
' j8 f$ O$ U* i6 X1 G
* A- Q, R! T: F
" V" S. m! Q. f$ `( X+ M G5 p3 a* P3 Z
|