一,STM32H7 RAM介绍
3 r6 g0 ]. q2 }使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
! ` u7 |$ x8 F3 d$ A, Y
5 `+ v5 q) A% s) n: _3 t, z* C9 I' ~ K) o
" k- e0 r$ `: ]/ D$ @# ?& ~% g3 S5 T6 P! V* `$ c( b4 \
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。2 T% o/ l9 M" [8 r1 r, P/ h
6 S6 s1 d G5 J7 q2 w$ y0 z$ U' ?: l, {7 a& B2 ]- Q0 {+ o
1 a& x; \$ E* j
既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
1 y- k3 i) T0 F8 A' L0 x: ~$ F* o+ @) Y& i& g6 A4 g" d
二 多RAM管理办法
1 H% T: r* B+ t6 xSTM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。: O6 M9 v# `4 R& }. s$ y. ?
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap W8 ]8 V) h) V) p/ P( p# v
- B7 r: D( x2 x) e% N! M0 h! f. m" `# X
, q9 a% m* y0 b0 H. r之后重新生成工程。
5 d! L0 e* \8 d) F) A. f$ Y7 \" ?
1,TCM区域做为主heap
" f$ ?2 x ^* J: V) F$ B& C) jTCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问
) I* }# ]- U# j" k
/ {* I! U5 n# f9 j" d% ?" j5 E j' G- ; *************************************************************$ t6 r# v. c6 B" @' l9 M- N
- ; *** Scatter-Loading Description File generated by uVision ***
5 L: B( f9 q; Y5 K; G" K - ; *************************************************************5 i- {7 s5 ?8 s8 ^; h I! ^
3 Y& @: |) ]( A# W- LR_IROM1 0x08000000 0x00200000 { ; load region size_region, v" B6 O' I! W
- ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
% C* G; t1 _+ @+ U# p I/ T v! \ - *.o (RESET, +First)
& w( d8 w3 v6 E' ^ - *(InRoot$Sections)# w1 l) R0 e3 r2 f1 `+ d
- .ANY (+RO)- B' a& \& e2 D1 I6 S% L7 V1 A; s
- }0 G6 v$ A6 u9 h+ x( k& r
- RW_IRAM1 0x20000000 0x00020000 { ; RW data
, b, O K9 C# C - .ANY (+RW +ZI)
: f7 t' A5 x# i9 Y! _. @ - }
4 x4 q1 V9 y# }7 ]$ r - }
复制代码- struct rt_memheap axi_sram_heap;( x2 j$ X$ \7 p, N) m' `
- void *axi_sram_malloc(unsigned long size)( f1 Q- t# w, b+ w0 l0 |
- {
' b1 k6 Q! O5 s) C - return rt_memheap_alloc(&axi_sram_heap,size);# P; q' @, N! d2 n' `7 U
- }
& [; {2 z) f2 K+ C
" @' q( q. m) Z- m2 r- void axi_sram_free(void *ptr)& c: t7 B! U8 T {
- {
7 s4 [) H$ [! x1 P% N' @ - rt_memheap_free(ptr);
# g( [5 |7 \1 z- O* H* U - }
" n5 w' }$ S3 }5 B9 e( n5 Z7 t+ D
/ I1 Y) c/ N9 W0 Y1 o$ V9 U- void *axi_sram_calloc(unsigned int n,unsigned int size). a7 l& v0 C6 W# C7 p
- {
' u& t A3 j* ^% D% V- U# Y; n( X# h - void* ptr = NULL;6 e- R$ d4 \) J/ _ C2 _
0 s/ b' P0 l8 l2 ^- ptr = axi_sram_malloc(n * size);
1 ?( @% ?% {! W. M# \3 q H - if(ptr)
/ o) g8 I$ k3 [7 y - {& v" _% f. i5 V* w7 U. k% l+ J
- memset(ptr, 0, n*size);: H1 V. E! s. g! z1 n; a1 j
- }
( h# Q# X* S, e" \7 C" ? - 3 M0 C' l) V5 L s# T4 J. p
- return ptr;- W' \+ j' _' ~* p
- }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)0 _6 R3 E( g4 E9 A
- rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
6 O2 T& N6 b* m - #endif
( }0 B' ]8 ^+ ~! g. { - * c9 Z& R1 A! e1 r3 z9 t
- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码$ C) @# P4 y; ?2 f/ y6 Z1 r
1 _4 B4 n$ x6 ?2 K, P: }0 x9 {4 ]- {
- int main(void)% G$ `+ L! S( ^! e
- { r( H* y4 L) i# |
- int count = 1;& s# ~9 Q7 ^, d k2 k w* c
- /* set LED0 pin mode to output */
5 Y+ n5 J3 P' @% [2 c4 C- ~ - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
8 A. j7 b# w& n3 {' ^5 b4 l - " Y- C$ }& s- c
- char *test_ptr;
, y+ T8 a; B K( m9 p4 C - ) y' f4 @: Y/ R5 s
- while (count++)2 b( O7 i, C& G# L" ~
- {
8 y6 i/ ?4 V; K0 d/ V - test_ptr = axi_sram_malloc(100);
+ T3 m$ Y' x1 x8 c. _! s, } - rt_pin_write(LED0_PIN, PIN_HIGH);
+ [/ j' `/ I+ ?0 M; I7 n3 i - rt_thread_mdelay(500);
, c+ y- g/ |4 ]5 R - rt_pin_write(LED0_PIN, PIN_LOW);
( r9 l& h, m) ]+ W - rt_thread_mdelay(500);! {" f( x L9 _) [9 V8 p
- axi_sram_free(test_ptr);9 g1 [9 O" B+ G$ k4 D6 M$ O
- }* k6 A$ |$ s9 c0 {, n+ T- @) K
- return RT_EOK;) \2 {; [- v5 p( g2 V
- }
复制代码 9 v% U( d" \# l! U3 c4 [2 Z1 T
编译一下
( }4 y4 ^2 v2 x- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060
, Y$ {1 c' y. B5 H# u8 P$ H - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin. c1 a7 Q/ ]; l @
- ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).0 D D J5 ~$ c$ [5 `: |6 T
- Build Time Elapsed: 00:00:08
复制代码
3 j/ |+ m2 }, H, l没有错误,没有警告,下载正常运行。) f$ x- B) l* j" N0 M8 _) o
, a+ r* ^3 R9 g9 e3 @$ ^1 I0 M" e2,AXI SRAM区域作为主heap
f! }- T8 M% m5 o0 w+ ^4 EAXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快5 }7 D7 K) U) \; w
& y( S& Y# y" y/ L. g- D- ; *************************************************************
8 Z' q* z* W! ?$ q - ; *** Scatter-Loading Description File generated by uVision ***
+ c. Y2 a& Z2 d( h5 A9 c1 r8 T4 u% | - ; *************************************************************, e! d' e5 v8 [+ `, G- [
8 O$ H* n- R0 @7 U+ }9 P- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
' ~. W' `" z/ q8 T - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
/ |" a/ F9 d- U' p1 D, f( X - *.o (RESET, +First)
- j r5 y, t. }8 Q4 D. E - *(InRoot$Sections)* t" `7 d4 i( V
- .ANY (+RO), @/ C1 W. Z9 K9 t; `& d
- }
" D" P( G+ |& ^2 @' p+ T - RW_IRAM1 0x20000000 0x00020000 { ; RW data( {/ L. ~8 i, D# e4 \
- .ANY (+RW +ZI)2 H# p) m! |8 R+ y' O$ N
- }
/ M! X1 @% V3 J - RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data
5 _5 I, [6 t0 k( i. A# B - *(.RAM_HEAP)# X; L3 L! m6 p" _
- }5 q# G* }% m. R
- }
复制代码- #define STM32_SRAM_SIZE (128) I7 a |6 L" B* N
- #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024): w* \6 U( r, t" c" ~0 ^/ k
: }9 m* m7 t/ m b- A' K! i- #if defined(__CC_ARM) || defined(__CLANG_ARM)
, k6 p" U% Q8 _( U6 ]5 f" ] - extern int Image$RW_IRAM1$ZI$Limit;
- Z0 Z+ _! v" G; U7 Z6 G1 u - #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
! J) g+ Q" Y- f- N; x5 Q, l6 I - #elif __ICCARM__
9 |9 r$ T* {+ i+ j. @7 j. C - #pragma section="CSTACK"
$ k) ?$ v% \8 [ - #define HEAP_BEGIN (__segment_end("CSTACK"))# ~% C9 q9 r) @8 c; @2 K) n
- #else; l- R: E/ p6 C! P0 ^
- extern int __bss_end;
4 q; ]/ x* U$ H% d - #define HEAP_BEGIN (&__bss_end)
' h6 ^' p, l: {/ i/ ^5 D - #
复制代码- #define STM32_SRAM_SIZE (512)1 h3 q; J& X) B4 u1 O
- #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024)
1 E- ]; Q7 k! }1 N0 e! Q1 O) ~
* v/ _/ p n6 L$ g! K/ L3 O" v- #if defined(__CC_ARM) || defined(__CLANG_ARM)
+ ]% D/ `" I; B8 k6 E8 G - //extern int Image$RW_IRAM2$ZI$Limit;
: _9 Z( _/ g) t7 k" T4 x - #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)
4 G' Q, C" i7 ? - #elif __ICCARM__6 U, N; a0 Z- c- \ l; u' M' E7 P8 Z" I
- #pragma section="CSTACK"
7 k ~% Q6 K1 J% U4 ?0 \) o! D - #define HEAP_BEGIN (__segment_end("CSTACK"))9 D+ h5 B, i8 G4 k
- #else7 K- h0 _$ G& a7 @
- extern int __bss_end;( V: R5 i" ~$ J& B. L
- #define HEAP_BEGIN (&__bss_end)8 B9 N, W+ R& c8 F! B
- #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。
: V5 T2 v' {) g* p' {修改完毕看一下,来测试一下) L2 ?& i; _; }* Q) F4 T
& I7 ?' ^" O) ^1 w. `0 y9 R; T- #define LED0_PIN GET_PIN(B, 10)8 |: B6 u+ p) b. r
- uint8_t test_buff[1000]= {0};2 b/ G# r0 h/ `) F4 v- c
- int main(void)2 _8 f5 \/ w! n, w2 l5 P, l
- { 9 v( F+ a: v* x9 I! Y* h
- int count = 1;6 m* e' K) B& u( j8 F% W3 u# I
- /* set LED0 pin mode to output */
3 i8 Z; R q1 d3 g* ~ D& e& ~. a - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);* ?; Y8 r% s; _
- ( }, E' U' ^* B) F& I. o/ |6 \5 y
- char *test_ptr;
, ]. Z; W/ l. J* B - test_buff[10] = 1;
. @, R# J' d- g - while (count++)
+ U% Z# B* F& I. N5 d" M - {
1 s J1 A' y2 K3 X! r+ |, Q# Z - test_ptr = rt_malloc(100);
: ]# ~- y5 b4 [7 A7 G) h ^: \ p - rt_pin_write(LED0_PIN, PIN_HIGH);, |- l0 h3 J8 X# z, k8 Z
- rt_thread_mdelay(500);' T4 ^) k) H* u+ j" w \
- rt_pin_write(LED0_PIN, PIN_LOW);, d4 \1 V; Q) S( i% f4 A
- rt_thread_mdelay(500);
; O: \! M4 W( w! U: c - rt_free(test_ptr);
! }$ L' h7 w0 h - }$ L" {8 T; Z u2 M8 Q
- return RT_EOK;
' B5 Q. S5 y+ J% m - }
复制代码 * z+ S' b% g! l" {1 Y4 r" o% g$ z
编译一下/ r& b4 T( S7 L6 _. U6 J4 t7 r
- Build started: Project: project
) D Q( q! Y: L8 {8 b - *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'+ M* K' ~# t- R4 A9 v
- Build target 'rtthread'( A& N( m0 B& G: N) p9 \' u+ p
- compiling main.c...3 U! y8 C8 v- {! c2 V5 s5 b
- linking...
3 n# w0 \" f+ m - .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).7 S! c1 }9 @ q. n
- Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964
: O5 o6 X _& @. t - Finished: 0 information, 1 warning and 0 error messages.
) S/ p% r- _6 l4 i3 w# K - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
: O1 J' N/ J4 I4 O; c+ ^3 I/ n" g - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s). H: G# N( B; R& @/ o
- Build Time Elapsed: 00:00:02
复制代码 4 k$ D7 M5 L7 t2 F
有一处警告 不要紧,查看一下map文件
0 ]+ g: S: y) M5 o( p$ i6 k" Y2 f
5 o) E9 n: l0 z& w, b9 Y6 |6 z
! l' X3 L) N N7 M2 F. |9 J9 N9 x可以看到定义的test_buff是在地址0x20000898的位置。
4 ]- c3 {7 ~0 g- |1 N
" m9 S. V9 L, d: M# c5 E% g' X: E三 总结分析3 E9 Q, W m$ \ ?7 i( L4 P- H+ k1 F
实验成功
% @7 b$ a2 D" q
( @8 Q) O1 O2 M7 YTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
) |0 j# I' c2 N7 E, G7 Y! y8 k7 u( m
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
0 L8 [# o! `* M9 M6 ~ W
# _: X3 Y P' v" @5 S; G* L4 E6 Y0 w. B% B+ }9 x5 {- \/ h, q
7 u9 ~; ?: {. z( z. {- M% h* |
|