一,STM32H7 RAM介绍9 S& q- [+ D [4 l5 C- g
使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
' c7 T) a! b% L6 L$ |
/ `6 @6 J* c1 S* W( v4 I8 o9 q) _ {; V( i9 Q' u
- n# @0 N. n S9 i$ f2 z
[% ?, ^/ R5 ~7 N# t3 ~通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。
8 G! r, z; n9 f2 e7 K2 u! r6 w
- f4 G* Z; C) I6 ^+ C! x5 r, ]9 e* a; k
6 m$ o1 Q) A; j5 s" a( `: `3 |, }既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
2 ^3 U; ~% _: C- B+ z7 F$ d7 N% ?
6 h, u& d6 G! P6 }2 H二 多RAM管理办法
. u/ S$ v! U' Z( K) c8 cSTM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。 r0 V$ p- ~3 U i8 Y, _
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap
7 ~0 G" o: `( i
" S4 Q) n+ E) ]8 `( O* M% U- Y7 K& B! i5 d2 r0 Z% q& U
# P; \# G9 n I之后重新生成工程。 r9 n, U& Q. b8 x! N% w! Q( p
" L; Z* X( q- M8 n7 |9 l9 `1,TCM区域做为主heap
9 ?5 h# y, G( L. a- ]0 JTCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问
6 @! E2 \* Y T4 g5 e* {) Y
$ f( ]* c2 G8 Y- ; *************************************************************8 B% \0 G* f& v: c) B: f
- ; *** Scatter-Loading Description File generated by uVision ***& r3 ~+ @9 O2 b) s# e* d0 `
- ; *************************************************************! {6 q& O) j7 l* ~, q2 D* @* K- d' Y0 r
- " X- s4 M" j* G
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region/ D/ c8 q# l6 \
- ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
( d. j$ n7 }- B L# q. ^ - *.o (RESET, +First)9 i S8 v8 ?6 i3 c# T2 z4 o w
- *(InRoot$Sections)
! @ F4 f4 r$ r) x4 f9 W7 Q i - .ANY (+RO)
6 V! E) L/ z$ e G$ U+ f2 G - }" z+ B* b) `% M8 X4 r
- RW_IRAM1 0x20000000 0x00020000 { ; RW data
* h3 H; E4 y- `; | - .ANY (+RW +ZI)
j+ T* K/ A# t+ ~ - }
- O$ A3 k( B/ c7 a z - }
复制代码- struct rt_memheap axi_sram_heap;2 t" \9 Z# w7 [5 {5 Q- F
- void *axi_sram_malloc(unsigned long size)6 G) j+ j+ C+ U# x
- {
( A7 _' g1 {! j! L1 q% | - return rt_memheap_alloc(&axi_sram_heap,size);
" f% ]7 v4 J6 ^. q, D - }, I6 W! p5 l" z) Q1 T! X0 Q# n8 i
. ~5 o- ^: [$ I. ^; I) @- void axi_sram_free(void *ptr)
, v) m9 |' n5 ~2 W0 k" [ - {7 Z) b, S8 p# ]
- rt_memheap_free(ptr);
; i2 F2 C' p. n% ?5 K/ B. B - }
; \( y0 S; ^0 H3 o9 M
- U" I! A8 E7 Y& x- n& h- void *axi_sram_calloc(unsigned int n,unsigned int size)
E' a1 | g X2 }# t - {" {. I! z/ k% c' Z7 F0 ^
- void* ptr = NULL;8 L. N, ~+ @+ w! @' D; {( n7 X" H, e- H
- 7 Z' z+ J+ U# o2 L
- ptr = axi_sram_malloc(n * size);% A9 r( Z' J& B4 R; x
- if(ptr)2 b9 T G, \; D. |- P2 b
- {# r4 O( U$ p4 f3 \
- memset(ptr, 0, n*size);
0 F& B& W3 f5 H' x) D5 ^ - }
' D' ]$ o8 W, C# B9 M+ ?
4 \% Z9 z& Z; i- h/ H" S) u4 c- return ptr;( K* l3 w; T- x1 i( ^1 {
- }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)( B% m7 b; L, R
- rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
( U$ S4 O8 t1 d! t7 A - #endif
6 |) T2 Y/ [# L4 m - $ `3 d* M' ?: H' I6 c0 R8 O
- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码& I9 t" n* m) B# \- d4 _
0 Q. f0 [* w( A6 s: e0 G6 M, B: v. K
- int main(void)3 l! K; w' N( O9 v
- { P( L. m, t% o' a4 ?3 r+ Z g, G
- int count = 1;/ U" Y3 D2 L0 X7 [% i" M! C* W
- /* set LED0 pin mode to output */
/ T% F( B% H+ B$ T6 J5 R - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);$ W/ B3 I3 {8 X1 e7 Y+ R
- 2 R1 A5 M( G9 O9 b( A( X
- char *test_ptr;
6 D2 G2 ?' u1 h
9 [/ @4 @ ^2 J$ A' [- while (count++)5 y5 d3 k9 s8 I7 d( {% U* V& A
- {
' P8 O$ m: V0 f( ?' Y: ^3 K u - test_ptr = axi_sram_malloc(100);
; g$ I2 K+ p0 Y1 [$ i - rt_pin_write(LED0_PIN, PIN_HIGH);0 ?' J6 K$ F, e: ^
- rt_thread_mdelay(500);1 @- G7 I0 ~2 u9 ~! L
- rt_pin_write(LED0_PIN, PIN_LOW);
7 v3 E! u% ~& ?. j - rt_thread_mdelay(500); @5 r8 p# p/ L: I7 p- j$ {
- axi_sram_free(test_ptr);
3 r, {* {" Z1 r$ t/ D' Y% u - }$ g& L8 _2 H1 E$ O% K9 S' q4 Y
- return RT_EOK;
' _- F4 v7 E0 ` O; y, } X) A% c - }
复制代码 3 a9 @' k' F# o; B3 l: B
编译一下
: X4 X# ]1 Q* ^) p/ G- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060 ! L h8 M- r" R6 O) D4 v) M# T
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
1 {) q) c4 Q) ~/ r* ? - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).8 q0 c8 D" x: T7 V0 w" t, ^
- Build Time Elapsed: 00:00:08
复制代码 * k4 w. A9 K3 ~: {: G, [2 a, O
没有错误,没有警告,下载正常运行。( c( V. z9 Q% W! ] v) `
/ b/ c" @& C0 X2,AXI SRAM区域作为主heap
( y+ P0 H4 B: l( _+ A: b+ t; d9 ~. SAXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快
/ H/ F2 u- Y- i; B! R" B! o2 j% r7 f Y$ C
- ; *************************************************************. e Q& N, i# r* t% _! ~& d& b
- ; *** Scatter-Loading Description File generated by uVision ***
! P7 b6 f. N3 _ - ; *************************************************************- D6 g' A5 W/ A& A% w) ^
- 2 ^' _1 c. y2 ~
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
+ [+ Z# _8 U- K - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
) u2 s8 d% V! v) o: e; l - *.o (RESET, +First) b% e) O+ t% n6 {
- *(InRoot$Sections)
. q: D# F; S5 j* B a - .ANY (+RO); b; h6 n8 F0 @4 m5 G
- }( {1 k9 ^( W% ]6 D) C ~
- RW_IRAM1 0x20000000 0x00020000 { ; RW data
0 ^. D7 Q; |* v U1 l - .ANY (+RW +ZI)* w1 x% Y! m* _8 l) Z
- }6 Y* [+ _0 U9 O
- RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data
" T- C7 P+ j3 A+ Z, S; J - *(.RAM_HEAP)
* u+ q2 l+ y' G, j! n' z/ h8 h - }7 `' D% M/ H, `% Y- N# M7 P9 p2 g
- }
复制代码- #define STM32_SRAM_SIZE (128)
' l7 K3 {3 d5 Q& c1 {3 D0 B" ]2 Z% S$ M1 _ - #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)8 J8 e% B# y, l4 z6 W) q
- ! P$ g- Z0 o6 ^$ ^% N7 ^( x
- #if defined(__CC_ARM) || defined(__CLANG_ARM)/ G- j- f1 I9 q5 p( `; [ X
- extern int Image$RW_IRAM1$ZI$Limit;: }, C: a& X( o9 ?, H h
- #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)2 n: `: q& h' T
- #elif __ICCARM__
3 i7 J8 r+ y G2 |& @9 }6 y6 D" _ - #pragma section="CSTACK"
- O s9 r1 ~4 B& B0 @. j - #define HEAP_BEGIN (__segment_end("CSTACK"))& t* x8 X; D& \2 c+ J
- #else8 ~, q! E* k2 l9 A9 u
- extern int __bss_end;$ G+ W- y8 `4 K
- #define HEAP_BEGIN (&__bss_end)
* B' ]+ z3 Y/ M, k4 C6 d - #
复制代码- #define STM32_SRAM_SIZE (512); X8 B1 ?7 ~& v: p8 c
- #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024), z/ y) s* N& n* t/ v2 E3 y3 o+ R7 i
- % n" V6 t5 A N, {0 O: G1 n
- #if defined(__CC_ARM) || defined(__CLANG_ARM)
# M# b" T! n$ A/ j1 f0 k9 b5 T - //extern int Image$RW_IRAM2$ZI$Limit;5 Q' G0 S _1 P4 v9 |* \( n& ^0 O
- #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)
, q# o; ~% M( G" z# V4 `( J) w - #elif __ICCARM__! }! I! Y9 w1 s, b- x" l% G" X3 S
- #pragma section="CSTACK"
6 y7 t4 n& s; D - #define HEAP_BEGIN (__segment_end("CSTACK"))% u. N9 l' o5 j4 F _
- #else3 ^! D# B9 T7 C4 z! s9 m
- extern int __bss_end;
/ F/ u/ H5 M0 J+ p - #define HEAP_BEGIN (&__bss_end); t2 F) g m6 @6 T4 ^6 U2 L
- #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。
% M# C" C* k+ a$ l+ r$ i5 G; ]修改完毕看一下,来测试一下
8 v: r; S% J, _$ y( W
9 N Z; l% |6 n6 R& ]! N3 j- #define LED0_PIN GET_PIN(B, 10)
" v5 O0 i0 M& `1 e7 q9 r+ A: V - uint8_t test_buff[1000]= {0};, c% `" a- N" b5 _
- int main(void)
$ _; ?/ J) _- I8 Q - { & d* x/ Y1 r, ]' W1 X( r/ @
- int count = 1;0 [6 ?% M, G, n, q6 D
- /* set LED0 pin mode to output */
0 g+ _/ y7 U8 ^$ J+ Q- s - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
2 K* [: O. \' f+ m% q - & ?5 D& S e! ?! f
- char *test_ptr;0 j2 y0 S8 X z" k( m1 d, S2 _( J3 p
- test_buff[10] = 1; 7 }1 s' Z0 F% N# P. e( z+ ]8 _
- while (count++)$ d4 `1 Y& f$ h( b7 ?4 B
- {! ^: ]9 J+ B% F, r6 |
- test_ptr = rt_malloc(100);2 N; e8 o. ?5 X! c D
- rt_pin_write(LED0_PIN, PIN_HIGH);
' l5 ]- @7 c/ i5 B - rt_thread_mdelay(500);# `4 t2 }) a/ W: @% |
- rt_pin_write(LED0_PIN, PIN_LOW);2 q; w; S* ~3 @) M. z4 [
- rt_thread_mdelay(500);
( ~ m- M$ K) M4 ?( z* \+ A5 u; w - rt_free(test_ptr);
" ?0 Y& G6 L# V- ^, V8 V! m2 r - }% S, P L' Z3 v/ J: W4 F% ?2 y
- return RT_EOK;4 t! ]. I1 ?7 r
- }
复制代码 # y' G% @1 w4 z& l& X1 G
编译一下. o$ k6 I2 E: _$ H* b3 {8 x
- Build started: Project: project
9 I4 @% M: A+ e8 X/ C8 }$ { - *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'! I1 X. x% z/ V6 m* z
- Build target 'rtthread'9 }6 |, P" @+ D9 M( n1 w
- compiling main.c...
D+ n; n+ R$ O - linking...
7 X+ o( e0 B" | - .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).! d- O, f7 }5 ?& ^
- Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964
; M* ?3 H# f: {$ ^8 l - Finished: 0 information, 1 warning and 0 error messages.
% j7 f4 l! t3 t' Y: H - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin/ M7 z* U4 G1 ^4 j. O
- ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).
; A: F2 {) {8 g0 \4 Q( g - Build Time Elapsed: 00:00:02
复制代码
. n$ w7 T4 R) Q5 S有一处警告 不要紧,查看一下map文件
. L, _; D) L' I9 F3 S! Y8 P, N, N E/ p& E
% w/ E6 d2 N8 Q# }' }% l( {7 U# @7 I
可以看到定义的test_buff是在地址0x20000898的位置。
L9 Q8 M; Q" x8 z) q; R+ K2 ?
" N% J1 g8 G$ r6 x. _1 a& I三 总结分析. \4 a* b/ n2 h( `( n( Y
实验成功
3 t, H3 i2 Z# s. k9 w p f; _- }
1 p. @( X7 Y0 K5 B: eTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
( _. l+ y6 G" \3 l& \3 c0 I$ ^3 J; Y% X0 D! u7 J
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
5 j! p; Z! y8 \4 h4 g
+ z) x0 B$ z. {' l9 l6 j3 `& N7 {9 H! _
4 U7 ]3 \" O( K
|