一,STM32H7 RAM介绍
2 I( P& `; G' J使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
6 ^# D0 Q6 B# w$ d& W
9 k7 C: r6 B: [" {; c; l4 u% |/ ~7 d4 t6 I
4 f. m: L* u; U5 Z% ?$ l) J+ M
: ]$ K: k) t) @* O# ?通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。
. A: U* b6 o0 s; W9 |- _6 I& A* Y# a8 u8 o i% U! {
& h5 C+ d7 }+ c9 y: ]3 H
/ m2 O/ r5 U; {既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
6 L) u+ s/ ^. m5 F) n
* s- A! S% g" K D6 x+ I& s9 u二 多RAM管理办法
' z# M: e* f& H4 A3 ZSTM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。
5 F% K" e' {% X. t首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap* ~$ T9 O1 Z# |8 {/ T, T* H
! @6 R* L. d" f# [
& K1 B' S, I5 l3 T* O* t
* N6 f; G4 b6 x1 K" I: K: `: U之后重新生成工程。
& l, N" {- [; h& A' d- e8 R
. ~( t a0 H& d! Z$ M: n1,TCM区域做为主heap
6 k5 i1 m: T. e. b# lTCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问9 R3 _7 P; w! R% D; s
: d0 T- r, A. L# r# d h
- ; *************************************************************
) o% k6 @0 K) x1 `/ V - ; *** Scatter-Loading Description File generated by uVision ***( |0 l4 c+ v2 ^' h2 O" m% u
- ; *************************************************************7 X) a, V: q( t9 P. p
( z6 w! a6 X I" a- LR_IROM1 0x08000000 0x00200000 { ; load region size_region Z; Q/ y) T) \3 q
- ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
+ U( _" r' V) `6 X: C - *.o (RESET, +First)
( B. P9 i8 I+ b* P" V/ e# S. y - *(InRoot$Sections)
5 ~. F1 @$ c! C# H' \ - .ANY (+RO)
; Y' g5 g* Y5 t) A - }
; h1 w7 w- U4 s& H# i! p7 b% ` - RW_IRAM1 0x20000000 0x00020000 { ; RW data
. I7 n- i1 b- K- Q+ m4 l - .ANY (+RW +ZI)- D" ^, h: A% r$ z# I
- }+ z# e: P, S7 H \' p1 m, {6 L9 H
- }
复制代码- struct rt_memheap axi_sram_heap;
+ A, U% H+ Z/ i' ^1 u5 E - void *axi_sram_malloc(unsigned long size)
3 s5 s. J8 j6 [7 U$ z. [# r - {6 H) N8 L6 E1 @" Z
- return rt_memheap_alloc(&axi_sram_heap,size);
/ E! D& [% ?" x I: u - }& j$ L" \8 v7 [
- ; g2 }) y) t1 ^* F
- void axi_sram_free(void *ptr)6 U# `2 y& v5 Y8 U
- {" U; J7 v l7 Y+ d/ l
- rt_memheap_free(ptr);
) o$ |; [( ~( H0 y1 Z7 A( v5 t - }) [9 w/ |, _5 J5 F! i7 f" {
- ( V# x2 @9 ~8 s2 M7 f- g
- void *axi_sram_calloc(unsigned int n,unsigned int size)
4 }( P# K! Y) S- N- ? - {: e) v6 C7 ?* d7 u4 f, [
- void* ptr = NULL;
7 c7 A5 o' O: l4 I8 Y& g w
* e' E8 m% r* C- ptr = axi_sram_malloc(n * size); O: _ ~$ H# u# S% z& t) ^! m+ D! r
- if(ptr)1 V& H" ]( j5 X% q" O! R
- {! @! O8 y5 e' x2 t! d5 U. k
- memset(ptr, 0, n*size);6 ]* D- [: W1 @$ q+ ]. b
- }
$ m7 J; X9 t. A, z+ s
& _3 A- L9 w7 j# d' [- return ptr;4 n+ z6 U# A, ~1 O! |2 G/ n
- }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)( c; [" j* ?! W; b: L4 D" d0 p( y
- rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END); Q% _8 S, g1 A" {
- #endif& O5 I* k0 T& n) B. R
- s8 C! U: A- `9 s- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码$ A9 t+ U# J8 S J+ E
% g/ d; L0 Y2 Z$ C- int main(void)2 x; i% d; C. L) Y R& l
- {$ g6 ], z' P0 ?2 H
- int count = 1;
5 ^9 n t$ b# L. ?# R - /* set LED0 pin mode to output */
: T1 T9 b1 h [- p. G5 K4 u; L% s8 @0 x - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);$ a5 O" N/ n/ c1 d2 m7 Q) D1 @
( V( Z# a# ~& K* ?3 S- char *test_ptr;) M: t; [, _" j3 ^' D) t
: R, t# g7 l# f! v% g- while (count++): ?; b% {* `- S c
- {
: k o% O* h4 I) \0 Z - test_ptr = axi_sram_malloc(100);* {. M8 v/ u: ?$ n& o
- rt_pin_write(LED0_PIN, PIN_HIGH);
# }# B/ t4 L! y, J - rt_thread_mdelay(500);
5 q, m4 H& e* o% _1 \! Q4 ] - rt_pin_write(LED0_PIN, PIN_LOW);8 o# C3 B( S7 z7 a) J# ]! b
- rt_thread_mdelay(500);* G6 d1 d7 g1 ~- _# e% a
- axi_sram_free(test_ptr);0 M9 }! Z7 A1 e/ G9 Y! S2 m7 J$ ]
- }, T5 w* l+ ?# Q8 b- m) y
- return RT_EOK;
$ W% w3 o7 k# n- Y( @5 `: C& t - }
复制代码 5 m+ K8 g- O9 j, ^
编译一下) h1 k, B, Q, n7 F2 D0 J) p
- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060 + e4 K2 w. x5 i0 E; f4 K# Z
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
" `1 F4 I3 Y J) F; O - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).
6 i ~! W# h" Q+ O) ] - Build Time Elapsed: 00:00:08
复制代码
7 k) `: U T* b' Q4 R/ n没有错误,没有警告,下载正常运行。+ F2 J* S. n* H2 [+ x
4 v* r: [- F9 v% h6 ]' s! f# L2,AXI SRAM区域作为主heap$ ]2 g9 C: D2 K
AXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快
: F+ I. I/ P! ?4 S6 Z. \5 \1 I, Z9 f" f
- ; *************************************************************6 M) K5 f: W7 |$ L! @# m/ s
- ; *** Scatter-Loading Description File generated by uVision ***7 p+ T$ u! w: h1 J; ~" f6 [" Q
- ; *************************************************************, w/ ^1 \# ^% k1 k$ Z5 \
- 6 G8 P2 w {% B ?( x) o1 O
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
J/ p. ]9 P' Z3 \ - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
# ?$ T2 Q2 t& H* D" | - *.o (RESET, +First)
4 B/ [9 [/ S; V3 ~/ u- G1 q, H - *(InRoot$Sections), y! C5 ], l) L5 @% s6 z3 O4 P0 L+ b- v
- .ANY (+RO): s$ n* S6 r3 D8 @
- }' [5 ^. q3 g' p6 r& |
- RW_IRAM1 0x20000000 0x00020000 { ; RW data; Y/ d0 j" ]- F6 {9 ]0 U/ }
- .ANY (+RW +ZI)5 ?5 G# w% b& ]
- }
1 P7 r8 f: p' @0 S: L; N& \+ R - RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data9 N$ ^+ I w6 @0 s. R# m
- *(.RAM_HEAP)* h. n4 S3 T, O% k; k9 ]+ J5 J
- }1 `0 M; h( y' H. }
- }
复制代码- #define STM32_SRAM_SIZE (128)/ C3 g* @$ b6 d8 h
- #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)' q4 K `% G3 {- i! ]0 J3 K/ ^( V
1 F4 ^/ o8 A, L7 T* A3 ~, L- #if defined(__CC_ARM) || defined(__CLANG_ARM)
* O7 A6 \" w W0 j* N K7 E - extern int Image$RW_IRAM1$ZI$Limit;$ j# K- @8 D* M+ o1 q
- #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
& W5 {; C6 P. ^* [' J - #elif __ICCARM__
1 @4 K" I: }! W9 x! M - #pragma section="CSTACK"
# }0 q) d) }" t$ l" \ - #define HEAP_BEGIN (__segment_end("CSTACK"))
$ h; z! j0 p. j/ u: [2 N - #else
' @# [, P, E h2 U$ K+ v3 H - extern int __bss_end;
% g5 a. l! y4 k/ v) C: | - #define HEAP_BEGIN (&__bss_end). d$ S8 ]. f6 _7 T
- #
复制代码- #define STM32_SRAM_SIZE (512)
9 U) n( g7 H+ r. x6 Q: }! ?( P, V0 @4 [ - #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024)" f' [$ N5 v& ^. q; z
- 8 `$ `5 _: ]6 K
- #if defined(__CC_ARM) || defined(__CLANG_ARM), r: V$ [ S" S: Z' `2 x. @$ o- Q- B
- //extern int Image$RW_IRAM2$ZI$Limit;
! {% j/ C, m" Z+ \3 c& P - #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit) @8 i; k4 n% ~. v
- #elif __ICCARM__; f. k% s$ w# Y. Q! Y
- #pragma section="CSTACK"3 u3 A* {9 T9 U0 @1 _7 y# E
- #define HEAP_BEGIN (__segment_end("CSTACK"))2 W7 h2 n- c9 @+ G. J4 P: F& L
- #else, d5 i/ y( u" G) Y* d6 {- S
- extern int __bss_end;
$ R) a! S/ e7 A - #define HEAP_BEGIN (&__bss_end)
4 Y8 c2 y X8 D8 Q - #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。
7 H, ^6 Q% }( @0 v1 Z7 Z修改完毕看一下,来测试一下0 v' L# G7 E0 d4 h/ u
. a7 D) p" h P( }
- #define LED0_PIN GET_PIN(B, 10)
/ i7 h+ Z, D2 T! y2 F& b+ i - uint8_t test_buff[1000]= {0};. |" Y! R9 v5 [7 C) E
- int main(void)
+ z8 V$ u% N+ m# q( _; t - {
: V' ^! r) H+ ^. S$ d5 N - int count = 1;
/ d2 r! p! \) p' h/ I - /* set LED0 pin mode to output */$ {! }6 m8 ^, s- v7 @/ C
- rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
( ]" P/ o. T1 k/ B. k
' A& o- u7 i! b+ Q- char *test_ptr;
+ {6 }3 }7 {) h& r) i3 { - test_buff[10] = 1;
( C1 `! I! Z* Z/ r - while (count++)' e2 z* h- k; V7 Q& [0 v4 p& q
- {
' ^& O( J' g2 P' g; \ - test_ptr = rt_malloc(100);
* t+ v! D/ I: J' f. } - rt_pin_write(LED0_PIN, PIN_HIGH);
' z H/ D6 P5 n }; I$ C E - rt_thread_mdelay(500);
: n% E) W, b' S3 Q - rt_pin_write(LED0_PIN, PIN_LOW);
( c+ @$ x) |1 E: s/ z - rt_thread_mdelay(500);- ]7 H4 {, v7 N/ v7 i y4 _
- rt_free(test_ptr);1 ]' S6 r, v2 r7 g) K9 j
- }0 |1 t; c* H& W9 h% C& M
- return RT_EOK;5 @. f+ r7 Q0 i, e
- }
复制代码 3 M4 D& g- ^" t% b# U
编译一下2 ^/ R, d* e7 a# D
- Build started: Project: project' b! \+ {7 Z" F/ ]0 {8 C8 A
- *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
. q9 q. V+ O0 N) @# n) f0 P - Build target 'rtthread'
, W" }1 s' E* b' i' B% W - compiling main.c...
# \6 K- B/ x: D) m$ v3 b - linking...! b; R4 A2 k n- k- n/ ~' G, |
- .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).
: A- ?& D0 E, \ - Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964 ) f) T& x+ R/ y3 A
- Finished: 0 information, 1 warning and 0 error messages.) z3 o4 f7 e/ S( ^' r3 r0 B9 }
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
0 Z3 k8 I- h* D% Q% k/ k- j8 @! h - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).
" m( M. A) M3 v2 _7 `2 x - Build Time Elapsed: 00:00:02
复制代码
5 _7 O" ^, {8 y3 C B& D: g0 s+ x有一处警告 不要紧,查看一下map文件: ~4 `# E; w- V0 d, B) ^% u/ @$ d
7 a! Q" B) K- v7 V
- c& [0 w) H: U, U
$ K e# F4 m7 D可以看到定义的test_buff是在地址0x20000898的位置。
/ O* d) m8 m; R: L( k- T5 d7 J4 Y* b5 P" U, u; S+ C# R
三 总结分析/ O# ~: t% @+ E; O3 X
实验成功; n! o4 U$ ?; C
/ k3 g3 j7 r+ Q3 Z' h" H
TCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
: l* I7 ^6 ?& ^/ O! i- n4 Q; ]& U1 p. V
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。- R/ |& I9 X( W+ J
" X$ O) L9 H' d# X& n1 A0 y4 [
7 c7 a( a' y# H) v0 F" X+ B) A6 w+ w1 ^3 f
|