一,STM32H7 RAM介绍" r. R2 z+ S9 S1 W8 C# f' a
使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
4 Z% q `4 L/ G7 d
0 |" M9 t v' T5 L8 B3 V
/ x, v5 C/ ~3 M+ I7 |( g% x5 W! j9 B7 j1 O
. F: @# T. r9 x3 @通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。) W: H5 W# J+ p- G( ^
0 {$ ^: u9 w, ~6 N/ Z, @# z
3 h: e- w; [8 d/ p: q7 U! O5 u- e* E) t1 O- O2 a ~
既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
! t2 W0 g5 `8 z8 Z. u
. W0 B' C& y; `二 多RAM管理办法
: y0 ?, _7 e/ L& J/ O2 d! NSTM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。7 o/ Y5 t9 Z, d2 y5 N$ t1 v, t
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap
8 S2 S' |6 B! W e, P$ S% q1 `' o: s
% {- L, t' E7 Y# y" n# X3 o: s: r% D! ^. D1 M
之后重新生成工程。, l9 F4 n/ ?# P/ u4 I! v
' F! o% X$ E* ^) p/ Y0 b2 R
1,TCM区域做为主heap% l6 q4 H' J" [
TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问, s8 f# n9 q! M! E+ T2 }
# c3 W. G7 u) U- q9 C8 i9 ]- ; *************************************************************1 ]- Y- @, ~2 q4 b5 P4 Z7 E
- ; *** Scatter-Loading Description File generated by uVision ***
# y' ~! |2 E* s$ Z; | - ; ************************************************************* G0 C9 f" F' b8 @
- ( f1 h, }! n l# n
- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
# z: {5 R$ `1 m7 E1 k/ N - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
& q4 M# p! f& Z* Z5 Q- E) L. [. h - *.o (RESET, +First)
6 H4 b: P8 P2 H: T( m - *(InRoot$Sections)% o. h5 B/ X; [$ ^$ y8 a9 _
- .ANY (+RO)7 V) I K# A" W0 h
- }
& N9 G) h* Y0 H9 m- p - RW_IRAM1 0x20000000 0x00020000 { ; RW data' e! X8 D7 K0 p" T
- .ANY (+RW +ZI)
$ E; |& I) j7 O N$ Y- g - }8 _" q$ N. L8 v. L
- }
复制代码- struct rt_memheap axi_sram_heap;. x- i T1 P4 d6 b
- void *axi_sram_malloc(unsigned long size)* k. x% v- r! n# y4 ~
- {3 I0 a9 Q y" ^7 k$ x. u- x
- return rt_memheap_alloc(&axi_sram_heap,size);
5 Y: V; p A" c3 m! d3 E - }
" W6 q5 w1 b* M$ Y( u
# j! U, _, y; w7 s, J- void axi_sram_free(void *ptr)
/ n, N% U' j6 o8 K - {
: a- Z. j" c7 O4 E( s) Z$ g3 [6 H+ R - rt_memheap_free(ptr);
, R2 O3 [. P) V' X; E5 Z - }
' I) c: h: i; Z% z: U& {& v - # E4 C6 }$ a8 q# W, O8 C/ s
- void *axi_sram_calloc(unsigned int n,unsigned int size)
+ `; f% Z" E2 O7 d, B' ?6 T9 o8 f - {
y5 q) p9 l6 u! W1 b1 \5 A& ?6 c% ? - void* ptr = NULL;4 C# U, }. y8 c
: d( I. } {+ [' ~& I9 R- ptr = axi_sram_malloc(n * size);
1 k" M7 y0 B, V, {; Q - if(ptr)5 u0 e" d/ w7 W/ Z4 U5 X5 g
- {
+ `1 U, \3 c$ h! j4 p( U - memset(ptr, 0, n*size);; s3 y' L( j2 J
- }
# `# X: g- c c
9 w) e D' \- R. @& ?! F- return ptr;
0 H8 @+ G- j! Z5 j0 Y9 S W2 P7 F - }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)
. Q9 D. E4 a! n% K4 K" F, s - rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
+ i5 R0 d8 R! m) {4 a9 l' K - #endif; `, E; U" j- ]: D
- / ~, r6 X3 U5 |
- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码1 H' q' ~* P* z6 H
4 X, F6 S; E/ {) h v6 T
- int main(void)' o+ O# b( `1 v9 T
- {
- @0 l+ s9 T- _) s: K" U, K, m5 L - int count = 1;
5 o( ~: U' z# j& d - /* set LED0 pin mode to output */1 e6 C0 S- @! y1 U: V! M
- rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
" ?8 h) H7 M% A, w - ( h# J3 i) v. h g8 E/ E
- char *test_ptr;. X$ Y6 r6 _* y
0 p" S8 l) o$ R4 y: A+ _* ~% d- while (count++)
7 m4 ?7 y' b0 D+ |) ?0 E - {
_6 {; A! ]6 I4 j - test_ptr = axi_sram_malloc(100);
7 N+ z6 }1 y9 `! C# l( b/ n - rt_pin_write(LED0_PIN, PIN_HIGH);
. J( p6 u1 J9 Z0 v - rt_thread_mdelay(500);! d9 e9 @3 \+ T" n4 E
- rt_pin_write(LED0_PIN, PIN_LOW);
( Y9 o( G6 M) ]9 H6 g( n - rt_thread_mdelay(500);# P4 k6 D0 ]+ D! C2 [1 M
- axi_sram_free(test_ptr); e1 F$ E# a1 t# {
- }
, c$ F$ A k1 Z3 t - return RT_EOK;# c2 J2 u3 M+ w; S3 s0 W
- }
复制代码
& R9 I# Q* c3 ?1 J, [编译一下2 B" q% ?' x7 m" ^0 @4 M
- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060
$ W6 v' a3 \9 O! k8 [6 h - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin# [3 b2 u9 P R0 A8 G
- ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).0 u. U ~- w) A9 Z) h) L7 r
- Build Time Elapsed: 00:00:08
复制代码
9 m n0 f! ~* T, {6 u* E没有错误,没有警告,下载正常运行。$ ]' ? \4 y. M$ B7 h# e
4 ~# R n$ {$ F$ p
2,AXI SRAM区域作为主heap. p' N" C, u0 E) e! z% k9 W8 Z8 W
AXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快
+ {- `/ T9 W5 ]2 Z' S# a" D- y. T9 @6 W9 }
- ; *************************************************************
/ {+ [0 P& y4 W# N) ` - ; *** Scatter-Loading Description File generated by uVision ***, t# d! z4 D" r* ?- J) |, w
- ; *************************************************************# P+ t" x6 e* x7 L
- ]0 a) Z) v, ~( `- LR_IROM1 0x08000000 0x00200000 { ; load region size_region
# _* ?1 D$ H8 g: k% w/ S% ], x - ER_IROM1 0x08000000 0x00200000 { ; load address = execution address0 f) H0 r! j/ d% H$ E5 X" A" l
- *.o (RESET, +First)
8 o, w2 V, h* e - *(InRoot$Sections)) s! s9 i# D4 l, M$ D, t! r
- .ANY (+RO)' _! w+ Q+ R$ w$ R% Q8 r* G
- }$ O7 T" l3 \$ s9 ~$ ?
- RW_IRAM1 0x20000000 0x00020000 { ; RW data. e& D Y2 K3 z0 q3 }& L& b) T
- .ANY (+RW +ZI)
2 _6 U/ C# w4 i9 c- o" Y ] - }4 a, I+ B; q9 p3 }0 }9 O7 Y
- RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data
; \7 A+ A1 Q. ?3 g% o5 t/ H! _ - *(.RAM_HEAP)
( h5 h7 i, P1 {2 V - }
$ T. ]& m- C* e3 X - }
复制代码- #define STM32_SRAM_SIZE (128)
) b! o, \# J* U6 G& Q" z - #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)
/ n0 }- i6 Y2 L5 m' N3 G% @' W - 0 T5 Y: e6 a. o: k8 Y. t7 `
- #if defined(__CC_ARM) || defined(__CLANG_ARM)+ g0 X$ } F4 d/ W' p: B8 i8 ^
- extern int Image$RW_IRAM1$ZI$Limit;! Z F5 S( _6 C4 A! U; R% L
- #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
. c1 s! i% I. E1 C" p- H - #elif __ICCARM__
7 }0 W# u( r1 o7 P" g* z - #pragma section="CSTACK"
& c' M, N1 [6 l+ \ - #define HEAP_BEGIN (__segment_end("CSTACK"))
' i5 h" J: M% X+ Y3 a3 K* t* { - #else
8 I1 T% U+ n$ p$ P: ?: q2 e9 s - extern int __bss_end;* ~; M( O; h- A- V! ]0 U
- #define HEAP_BEGIN (&__bss_end)6 X* e0 R) R* D% m l/ ~
- #
复制代码- #define STM32_SRAM_SIZE (512)
# R# l% B" F* W; L7 ?! e - #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024)/ R- ^; t( n( A& T
0 }( j* @; P0 E% m+ ^' M- #if defined(__CC_ARM) || defined(__CLANG_ARM)5 m! Z: z- x1 C# B+ v. X
- //extern int Image$RW_IRAM2$ZI$Limit;
- w6 s. x$ g | - #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)0 `4 n0 ^* B5 }$ M8 ?) q
- #elif __ICCARM__
5 n0 v; }& d3 q7 k - #pragma section="CSTACK"
& j1 ^% ^' D9 f - #define HEAP_BEGIN (__segment_end("CSTACK"))
9 A$ z. n4 V( c8 T0 H$ f - #else; d( x1 P1 R8 l8 j" U+ a+ l* E% V
- extern int __bss_end;
/ W3 n* K5 ~; O3 _( U; q - #define HEAP_BEGIN (&__bss_end)
/ I& L3 ]3 g' F9 G7 j3 S: m7 x' ~ - #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。
1 r) |, B1 Y7 C" R$ l修改完毕看一下,来测试一下! u" L r- R% |/ M5 z! C- Q- y
! }- A! b; X# k3 @4 w2 T6 v7 e- #define LED0_PIN GET_PIN(B, 10)
. k) P' N! |& `# h: Z) w - uint8_t test_buff[1000]= {0};4 `" [7 {' G, |% p
- int main(void)
1 G$ A5 S) ? A# t' v - {
( x% _, _! t1 l% M, w- s9 T - int count = 1;& J/ m' j! S4 W' m
- /* set LED0 pin mode to output */
( s( E( x$ K; Y6 C3 a& P6 F) e - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
, h, G) |' F# K( a z3 ~) \
6 w7 |- |5 s2 b7 X4 s- char *test_ptr;
; j+ F$ d& Z$ _1 b$ n, B! P/ [ - test_buff[10] = 1;
: n+ s/ t* F& F9 c) D: X0 s1 P - while (count++)
$ g/ I& k) j, [' h# [ - {5 S, J- | U/ f9 k
- test_ptr = rt_malloc(100);
/ b$ J2 ?% }$ z* ]! m) ~ - rt_pin_write(LED0_PIN, PIN_HIGH);
& ?. N1 u8 J3 }3 w: O - rt_thread_mdelay(500);
1 D6 n9 ]7 b0 G u0 {7 h3 ] - rt_pin_write(LED0_PIN, PIN_LOW);
9 c7 v( Z- E* R6 j& |6 W" S - rt_thread_mdelay(500);: f' h7 K+ m4 M- i+ g
- rt_free(test_ptr);) N) P+ g( t4 |3 v2 o/ W) }) g" T4 W1 h
- }
- J/ Y( l' ~, o" X" o - return RT_EOK;+ i; `% W! q- b9 U9 f# F
- }
复制代码 6 O( O9 ~# u* l E9 Q( F7 g
编译一下' I. ]$ [! v" U1 i- m
- Build started: Project: project! }" X/ K4 Y! e! ]3 K. |( [
- *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'. u0 ^' g# g% E6 w7 ~& W6 O
- Build target 'rtthread'
! c9 _" I+ t \7 \3 T }' c3 F/ H - compiling main.c...0 @7 V6 @) ?9 F* {6 X1 W: i
- linking...7 A, [+ l, d, u; k! x
- .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).% [. T4 X' T& ~# |8 c' q
- Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964 . N0 l+ n, ]1 w/ E1 _
- Finished: 0 information, 1 warning and 0 error messages.
: _% f( U) D0 h& ~* l6 l7 C5 | - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
' y8 {8 L# u4 {- K - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).
, v! g' B& C8 b' `* @9 n - Build Time Elapsed: 00:00:02
复制代码 4 d$ H3 y4 m5 \( X' |
有一处警告 不要紧,查看一下map文件
3 n; X3 e% Z1 P, G- `, ^ ^2 G4 n$ P6 d0 e G0 u, W+ [
* ^- O& _, k% z: p' {% S5 \
' h7 Z8 M# B4 c2 B可以看到定义的test_buff是在地址0x20000898的位置。+ n8 g7 Z# E; J* n& Y) p* w
# m4 [) {- W4 M4 ?三 总结分析
( [' Y9 j5 V9 v* A# a! l实验成功
$ \: t& l M6 ]+ G. P, `6 q
* x2 h. c, V5 FTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。9 A7 u# c: d- c1 V0 G$ O" T
5 b* O x; L2 k6 X) r9 H3 y7 \
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。, h4 h; e# ^ l
! d$ V9 A- T1 Q
5 } E1 z& F9 p
0 N r8 \% f" n" s1 Q6 ~ |