一,STM32H7 RAM介绍' q9 r) B. E, {, m5 M
使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示" k& h7 s* m% f$ m& E! k' i. `
0 w+ E2 _: t, w
' p) V# D" q D+ d! j# J- P: u& O. j. f
* ^ m5 l B, o) \" L$ j |: ^
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。, I3 y! t* d& D5 I2 Z
$ j |" Q2 L. U" O0 c! m- j5 k) G8 H+ G
9 E- D7 y% p9 R/ \/ u7 y& R, _既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。# i$ p: h0 d9 X# j5 g
4 G% v5 P: k. R2 V二 多RAM管理办法% Q' i! Z! m( Z3 y0 W
STM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。! ]/ p5 E3 g* X0 z- ~) r
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap4 n: |. y& j3 ~0 j$ T
3 q/ P2 X5 [' E: y+ V
0 x7 A8 _, ^5 I- H6 ]/ u# M! \
! Q/ ]( g2 k& B之后重新生成工程。3 v' \4 I5 P' ^/ O1 J4 F
& j- B ]* s( y2 J5 S# \8 A" O+ _1,TCM区域做为主heap: h. k& s, V4 w
TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问+ `3 p7 @& F6 }! l
S' a4 p# v5 m" c$ \, l C
- ; *************************************************************3 z' W5 g( x7 v) `0 d
- ; *** Scatter-Loading Description File generated by uVision **** m$ M8 G6 g1 C' r# @( y1 \$ |+ T2 B
- ; *************************************************************% J% K, d- P, h7 P
- 4 q R) R& j3 D1 @, n8 P
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
: x1 N) H$ E/ r6 M$ e3 s4 z4 J3 P - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address# n2 g3 i. g4 Q% z
- *.o (RESET, +First)
4 s/ ?; V5 e; n5 P3 h - *(InRoot$Sections)& j: [) S) W" ]. b) j' Z) z
- .ANY (+RO)
! l K& M0 u) {: @7 k- { - }
8 m& N% I% o: `. Q/ Z" V - RW_IRAM1 0x20000000 0x00020000 { ; RW data
8 v0 F2 z* d* s) F' J- ? - .ANY (+RW +ZI)
+ b3 w1 M5 ]0 @% V8 m - }
5 C9 v7 g8 q# V' E/ H% O7 h2 ? - }
复制代码- struct rt_memheap axi_sram_heap;0 V3 P) o, w! V
- void *axi_sram_malloc(unsigned long size)
/ t* @1 g+ S& D" W5 w# T* b - {
, C% i6 T8 h( t& B [& d" O ^ - return rt_memheap_alloc(&axi_sram_heap,size);
0 d# M/ R! w4 [' f1 {% G% m, Q4 u - }# [+ q; y: _7 O7 ~; t
2 E/ b( C3 @: C" |- void axi_sram_free(void *ptr)
! Z2 T3 _0 T) H, j - {; `- L; J# P3 J# i/ G4 F$ x' a
- rt_memheap_free(ptr);8 H$ W9 t; G! D: } N
- }
" @0 Y9 v4 r. |5 u - 2 n" c* U! t- N* W, U9 R
- void *axi_sram_calloc(unsigned int n,unsigned int size)5 ?$ a1 @$ q( E$ L9 i3 ~$ w% H
- {
L0 B ~/ n) L - void* ptr = NULL;
. I9 E4 [- H! n# I/ I - : Q9 B1 Y+ g: Q) S
- ptr = axi_sram_malloc(n * size);
$ v7 Z/ j6 j/ l: P% ~ - if(ptr)
" r1 S& b/ ^+ E' P) F* J - {
$ ^+ \- m, [$ T' F; C - memset(ptr, 0, n*size);- F7 `8 B) H Z; a) y! F9 k _# y
- }6 Z; H1 p& t7 o! C0 C
- % ]% @0 I: x& T" |8 U
- return ptr;: H4 d c9 S* `' u/ u
- }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP), L5 ^8 ~) o0 N* H' D
- rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);3 |: d. a8 L3 [! t& m5 k+ M
- #endif4 c1 s) u) Y. _: r- j3 C4 d8 U
) k" a! X) @! e, }1 {* K- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码5 N4 o+ n# \ g- [! T% k
$ \ x# K" f5 ~* H
- int main(void)5 U0 T4 M3 w! U5 B
- {
9 D$ {# K6 Q: e: p0 s - int count = 1;
8 C6 ~! p7 [( m5 P1 I/ y: A9 ? - /* set LED0 pin mode to output */
, f: J( o' N9 J* I' {/ q- N - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
& O" _$ H' l7 g+ ?0 R, e4 c
7 j! E) f9 ?/ R L- char *test_ptr;" {) G! o( K5 I+ \7 @
- , p: p ]% ~$ v
- while (count++); _' D% {" M. U, R2 i
- {
' v, m Y- ` L/ U0 [% Y) \ - test_ptr = axi_sram_malloc(100);
3 n& c- g! @2 ]5 u' p6 U6 G - rt_pin_write(LED0_PIN, PIN_HIGH);
% f3 C: R9 m& P' [/ ] - rt_thread_mdelay(500); a- |3 l, v$ P: U1 q0 w5 I
- rt_pin_write(LED0_PIN, PIN_LOW);
1 H$ P! b* H, W# k& D R - rt_thread_mdelay(500);
' q1 u6 N3 x- j: n - axi_sram_free(test_ptr);
( I8 y& q; }7 O) N - }
" f ^2 U( E1 G - return RT_EOK;; @" { Q, Q: [8 a
- }
复制代码 ( r! Q" z+ q. F; {. ]
编译一下
5 d$ o" q! z5 m4 S4 W+ T0 r" Z- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060 5 ]( ?5 T4 Y1 a$ y/ z( y6 G# {
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
7 _, f9 d& _/ \2 `9 O# u" ^5 ? - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).
7 ?/ y1 C4 b* `# \ - Build Time Elapsed: 00:00:08
复制代码 . D5 o+ d; h$ q6 Y4 A: F
没有错误,没有警告,下载正常运行。
& X% d E/ p9 x% S7 A: i. |
4 J+ [! C/ n0 @4 }0 x; A2,AXI SRAM区域作为主heap( T u( W. r. D( e& \/ [
AXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快" I4 Q- E* L2 j$ [8 }5 `
3 O& g; R! |* w
- ; *************************************************************
' V+ Z# x$ c+ D0 m1 H; G - ; *** Scatter-Loading Description File generated by uVision ***7 L! \; N, X; C3 m( w' o
- ; *************************************************************2 Q6 c0 P$ R- K. h# c3 W* x
- 3 D& G5 s% o" n& L4 B
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
7 ? \3 ~& q$ ]2 q - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
! z9 |' _/ [; O# {7 D' x$ P j - *.o (RESET, +First)
5 J! ?% N( M& g$ L. ^& t& W - *(InRoot$Sections)
' b! |' W$ V# c/ F; m - .ANY (+RO)+ D; c! C& d1 _8 N
- }
5 [, m* U" E6 b) r - RW_IRAM1 0x20000000 0x00020000 { ; RW data
. H- F* T8 s8 }# H1 }# w6 c% J& | - .ANY (+RW +ZI)
1 A+ v# e( p+ Z' F - }4 @+ O! y% V3 t7 a4 B. C; K
- RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data; a: \- v% a. U+ K& A% r7 m
- *(.RAM_HEAP)! V. ~: K" n" k x+ {2 S
- }/ Y8 N C4 O# w
- }
复制代码- #define STM32_SRAM_SIZE (128)" D: p( M6 V$ A) |. a ? M
- #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024) N* u5 d) z: P( N
$ v% _, k, o$ |/ W: Q( \4 C4 H0 ]- #if defined(__CC_ARM) || defined(__CLANG_ARM)7 R: v* Q; i' {8 n# M
- extern int Image$RW_IRAM1$ZI$Limit;
- Z4 m2 b' A) X, N2 h8 h' a - #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
% C7 u. F1 P. T0 ]2 g, k. `; O; x - #elif __ICCARM__
6 D8 ~4 k. T. n. V3 I - #pragma section="CSTACK"
, R. @ c& E; `: p5 e% N) ^ - #define HEAP_BEGIN (__segment_end("CSTACK"))1 _* I3 W9 X6 t3 V& j3 T* u
- #else
" @% ]" F; U+ k# _( ^ - extern int __bss_end;$ }( L8 q* U& `% k: n3 x: k
- #define HEAP_BEGIN (&__bss_end)" N9 P+ o! H& @& o
- #
复制代码- #define STM32_SRAM_SIZE (512)
0 D! E' P) P9 ]# M3 _ - #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024)
\: b/ A, M. |" i+ O; o
% I6 C/ P1 x: X5 k# j0 O3 v" V- #if defined(__CC_ARM) || defined(__CLANG_ARM)
- v* x n9 b. W% G; x - //extern int Image$RW_IRAM2$ZI$Limit;5 |5 o2 F: D* k- _8 Y* M( a
- #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)6 C" }% Z3 d- m( {; y1 a. e4 s% w
- #elif __ICCARM__
0 f: H# O# V1 M9 T/ B7 Z# \ l - #pragma section="CSTACK"8 k/ w$ @8 z$ i2 x" X. q' ]7 G
- #define HEAP_BEGIN (__segment_end("CSTACK"))
- X+ i0 k1 w0 |# ~/ ^) |( o P - #else
6 q* M3 @9 |3 `( X7 X. g - extern int __bss_end;
6 \4 O. C/ E7 X - #define HEAP_BEGIN (&__bss_end)
* d! M' d W1 D# Z! B, t - #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。
3 Y _4 F/ Y# s8 T8 A0 c修改完毕看一下,来测试一下
$ R8 P9 D4 e% n
& e$ }1 q. g* X, W7 m- #define LED0_PIN GET_PIN(B, 10)
" w3 f, g# `- e! o5 X$ f - uint8_t test_buff[1000]= {0};1 |; u4 {$ ]+ k7 `' A/ d4 X0 I
- int main(void)
" f! g0 X4 h9 ?! D4 G - { $ M. f8 n; n6 X |# F1 U
- int count = 1;
, B' ]' M# l( c, p; I - /* set LED0 pin mode to output */
' a6 q/ b% Q' F. E* W - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
2 ^& U5 u. V N5 h4 u2 l
& e+ h( }' T- H: A& m' K4 c- char *test_ptr;) \. W& s3 l' m0 Z* c$ J
- test_buff[10] = 1;
0 y3 M$ E5 y7 c3 E" ^ - while (count++)
# C. J2 h% Q5 V' |* X$ P& F - {5 n3 x' s$ `/ G7 r/ X& c
- test_ptr = rt_malloc(100);
6 D, o0 ~4 ^# h* ]9 j" K - rt_pin_write(LED0_PIN, PIN_HIGH);
5 _! \& a3 x$ }+ j0 p/ t - rt_thread_mdelay(500);
$ T- o; s) W+ u$ F# q - rt_pin_write(LED0_PIN, PIN_LOW);: S4 S( L( t% L' a9 ^, T/ D! d
- rt_thread_mdelay(500);* c8 ?7 o, Y% w- R6 P
- rt_free(test_ptr);
# G" J9 g5 K9 K1 ^' A7 M - }
1 s" ^# U/ g# h ? - return RT_EOK;
. T% U, I! o1 i; @ - }
复制代码
: H* ?- i; @/ A编译一下% j2 W3 A+ p- y4 y9 t! m% u; }9 s
- Build started: Project: project, O" D. u1 Q0 w. _/ Z. s% @" W4 t% n
- *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
/ Q# Y+ Y) u( h7 ?. } - Build target 'rtthread'5 v5 p. t$ x; S* t z
- compiling main.c...8 |9 c& f C" I. F, Z2 |* e: k& p
- linking...) ?2 V1 n9 z! g, Q5 ^ A2 V
- .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).
+ K2 P. B7 L# u2 T - Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964
. u* M5 [) s% i) Y. p4 Y - Finished: 0 information, 1 warning and 0 error messages./ Y5 X+ X+ f K
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin( C, M6 N, p" s' Y
- ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).: j. E1 Q" A, \# l( \
- Build Time Elapsed: 00:00:02
复制代码 - u" u! |' j R0 l
有一处警告 不要紧,查看一下map文件, g5 I, Y& j* |& L: k/ ? ]: Y
' @) l/ G4 e! r
& v# v6 V* k7 W, |( V2 e3 n
* |/ p" |* y8 m5 p
可以看到定义的test_buff是在地址0x20000898的位置。/ M9 J" u- [ j1 M/ |% Q' t
3 I$ e# L+ g7 e* d三 总结分析
9 L$ ~7 I& v; _4 B7 D0 ?实验成功3 c, [4 q. s: x) ?) D
5 N, q+ p7 G" q& Q9 t2 o; Z" M! UTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
5 P1 Z# o. ^8 Q, ^& v4 G
% d5 {! v% {- v3 A/ i% Q5 I* LAXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。4 R2 U5 ^. L6 o2 N1 N* g
- U6 q6 ?. R& \) Y6 p! p: m
, [6 x; a' S9 J0 { \: I
3 N) \1 t/ g) a' x% G3 u8 x/ `& i |