一,STM32H7 RAM介绍
9 E) D0 h f' L0 e使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示6 s2 w- h- c- {, R" \& P# p
! D M# b& p, y, L% `7 L/ n
: e p" { q- l: d6 \2 w
# `, }4 A; }2 c2 a' ~: W S; H+ u( D# _% i9 H7 c+ g) B' U2 L
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。
! {3 ~6 y- k9 ^% v: U3 ?6 ]+ \) r7 t" U) R0 r
4 ]# @4 u( Y* R" M0 {2 i2 A! _9 J# s5 K: x' g7 k$ ]
既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
# `. O8 M" I5 Z" W: b
7 D* y" m- ^" R# B! a2 w二 多RAM管理办法8 Z8 Q$ Z- [, |. z/ @ |; t
STM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。' N0 g: l# y. O
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap, {. A4 ~( S$ A2 G
% U% u2 ]( l2 M# Z6 s
9 J+ C! b1 d, Y) j$ e+ V3 I
8 V; [' ?* w |2 b" \/ T) r" H之后重新生成工程。
6 B0 l8 g. \6 \) J7 A% s5 N& m
; U7 S3 o) ~2 ]2 a8 k# g1,TCM区域做为主heap
! t0 S+ p- G1 o7 I/ W0 F" {TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问
0 Z% O# z9 k v0 S
- K, S: M/ b% n2 h; p# t- ; *************************************************************
, e. @* w* i) S) L! \; J - ; *** Scatter-Loading Description File generated by uVision ***+ ~5 W, H% J0 }; [9 J
- ; *************************************************************
3 N" e7 G/ \ A9 x3 T+ X! h/ H
0 m" B7 L: i$ {" w. I* I- LR_IROM1 0x08000000 0x00200000 { ; load region size_region4 z( P% N* b6 r$ \
- ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
% g6 l- v$ _( d& F - *.o (RESET, +First); C) M% y# `/ H/ J3 G
- *(InRoot$Sections)# y8 c. b0 K: \0 J4 E' z0 s3 `
- .ANY (+RO)) _: Q( b* N9 H9 A o$ K# ~3 q, J$ ]
- }1 X5 ]# `0 u+ }1 @1 p3 s
- RW_IRAM1 0x20000000 0x00020000 { ; RW data
$ T0 E$ S$ o* u a9 O" C8 S8 ^ a - .ANY (+RW +ZI)5 }1 z' e0 Q+ ]# p) o j
- }5 b1 v& h9 R2 A. p& w
- }
复制代码- struct rt_memheap axi_sram_heap;3 q* P8 K6 S( J t/ E
- void *axi_sram_malloc(unsigned long size)/ W, [: {* [) ~. G8 j! P9 Q
- {/ ~8 e% T; j6 r1 F3 T
- return rt_memheap_alloc(&axi_sram_heap,size);/ a( ]+ A! a! y1 a5 s9 g- F' q4 T
- }- k( y6 ?# H) d' X9 j4 @, L
- % A) ?5 y6 o$ l3 J
- void axi_sram_free(void *ptr)
" M9 S/ j# _* @- Z2 q - {
0 e/ k/ S" K. m1 ~+ J* J - rt_memheap_free(ptr);
9 M6 ], U- e5 j0 `3 _8 B# F+ ^ - }! U! ^" h, j% e# v1 D; A! ]
& Z0 y/ [) s3 Q; a/ {8 H3 K- void *axi_sram_calloc(unsigned int n,unsigned int size)
$ n( Y+ h3 R! Q, R% z/ C# u" G. P& F - {; u0 e: p5 }& k
- void* ptr = NULL;) H2 E c7 u/ H" |$ ~4 J4 F0 a
- / y- v9 o9 G. O5 d9 J! w
- ptr = axi_sram_malloc(n * size);+ G/ g: r7 W7 i2 {% T' U
- if(ptr)
: N4 m" R; m0 i2 \# r - {
5 X2 A* f3 c) N0 T - memset(ptr, 0, n*size);
! J3 i9 [: `% G& H - }% a. @. M; S5 y, U; ?
( _ i) U! @; U1 ^( c+ v, Y3 Z, T- return ptr;
6 v: V' z- K8 F: U - }
复制代码- 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码- #if defined(RT_USING_HEAP)
9 f4 |! i: F; ?9 i - rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);/ O2 _' }7 e" |' N/ r1 k1 j
- #endif; a. A: j, i. Q4 @9 _$ |) l
- " K+ I! f( z/ N6 B5 _+ j
- rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);
复制代码 编写一个测试代码% K' K& O7 E! i7 ~
, Q8 Z) H2 M8 M) |! P" Q+ X- int main(void)
8 G* H. o9 J* M8 M9 G, M# o - {
3 p% p( _" p, P - int count = 1;- v/ [$ i- Y1 l2 V0 q2 A. R. g1 s$ _
- /* set LED0 pin mode to output */. c" Z- H2 L. o) U, V
- rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);% S0 ?. h/ B) ]! _% k$ n
% A- i2 L9 X7 b; q1 I9 u/ ~& f6 r- char *test_ptr;
. p; C7 W$ _5 D' }
3 E2 S. W: h- ~# k2 z- while (count++)
- x5 U2 F: o6 e- @. Z4 `: | - {( @4 y( V2 x0 u3 r1 Q
- test_ptr = axi_sram_malloc(100);5 e5 p0 `6 n, t
- rt_pin_write(LED0_PIN, PIN_HIGH);4 t+ H- K0 a5 e* x& c- F8 _
- rt_thread_mdelay(500);
' d! K' t) L- _% Q% p" ^ - rt_pin_write(LED0_PIN, PIN_LOW);$ x4 S" V$ E3 X* t2 H" j* t
- rt_thread_mdelay(500);- k$ f* R) U' p: d) h
- axi_sram_free(test_ptr);
, m$ f( q. _( `4 M$ a. r - }# N# h. A$ U8 Q! s: f# c4 ^, X
- return RT_EOK;
. l/ j; j7 q; H( J - }
复制代码
; |0 I( ?& w' z+ y" \编译一下3 t. i5 y$ N, r4 J
- Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060
8 ^1 L% H {4 X( J - After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
5 B" J. {2 e" a6 v - ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).* d8 }) v! ?5 d. X
- Build Time Elapsed: 00:00:08
复制代码 4 f! _' H! o$ `5 r: u- Y- A1 u
没有错误,没有警告,下载正常运行。
7 y( Z8 g8 Y' ?4 z! ]
# i, m# ]% T( ~2,AXI SRAM区域作为主heap8 A$ i- u4 m2 e7 G0 e |: p9 D
AXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快
) W: |3 v% G' V/ p8 v4 \3 X/ i* `0 P, Q& h: z: s$ B
- ; *************************************************************
- X# d+ @; [4 c+ k0 p, H9 a# \ - ; *** Scatter-Loading Description File generated by uVision ***' u2 n+ R( H4 r' K7 y
- ; *************************************************************9 }4 `, n" Y1 t4 A! F
; \. o+ N# s S5 j3 G- LR_IROM1 0x08000000 0x00200000 { ; load region size_region" f) l' M) X9 Y
- ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
: L% J+ [+ x/ H8 m - *.o (RESET, +First) W1 X& W1 a) E. i9 n9 ~
- *(InRoot$Sections)
: ]1 p) f# r- O; J8 w( @ - .ANY (+RO)
6 R P1 P4 z+ n- x6 ? - }
- y6 i" M; T' g2 h/ }6 r - RW_IRAM1 0x20000000 0x00020000 { ; RW data; F" O; Z, l- R, P* Y Q. |& q
- .ANY (+RW +ZI)( J" R) |, b& Z2 O$ q0 t/ W) s
- }
0 h3 ~' y# `" w7 t - RW_IRAM_HEAP 0x24000000 0x00080000 { ; RW data# R/ N, h! y( n% {4 C7 U
- *(.RAM_HEAP)
$ i1 [3 n9 Z) Q2 C - }
1 _( r) k0 v. e4 S: W5 M - }
复制代码- #define STM32_SRAM_SIZE (128)" ~+ h. b; J& u# @( |% t- m
- #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)# P8 D* r% S3 V
- p9 b! W7 a' k1 @) G/ Q9 `- #if defined(__CC_ARM) || defined(__CLANG_ARM)
: i0 B, u: N3 q" f1 O - extern int Image$RW_IRAM1$ZI$Limit;0 b' I& k0 D' V! T! Y. F" Z
- #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
; x0 ]& N$ D, K7 B+ G. C2 k! x/ V9 j - #elif __ICCARM__/ {) ^$ T$ n8 F8 x6 {# K2 u
- #pragma section="CSTACK"
) ~6 V* l) {; w5 [+ E5 T) z/ j - #define HEAP_BEGIN (__segment_end("CSTACK"))
" d! l4 G3 r9 G2 \) A ?! G1 X - #else
. b% w4 W$ O, g r0 D/ H9 u. }: ` - extern int __bss_end;( Z0 V1 g8 W9 g9 w
- #define HEAP_BEGIN (&__bss_end)
7 r" \5 x& X. k) V- J' ~4 ~ - #
复制代码- #define STM32_SRAM_SIZE (512)/ R+ X' _8 u Q( n$ M1 N6 ?$ N
- #define STM32_SRAM_END (0x24000000 + STM32_SRAM_SIZE * 1024): ]1 D! j' L; J# k0 v8 a9 Y# t
- 5 F% q* `* O5 f8 x5 `2 X
- #if defined(__CC_ARM) || defined(__CLANG_ARM)( H; ~% F1 m# \2 {
- //extern int Image$RW_IRAM2$ZI$Limit;
; c0 r& z, D6 @ V9 r# B - #define HEAP_BEGIN 0x24000000//(&Image$RW_IRAM1$ZI$Limit)5 Z- Z. h S" ~5 ]
- #elif __ICCARM__
/ X* h' E I Q5 Y1 \ {6 s3 ] - #pragma section="CSTACK"
9 M' s. ]) o! ^. c6 E - #define HEAP_BEGIN (__segment_end("CSTACK"))- w! T6 ~; ~: e2 R3 `
- #else
0 V( b& B1 H R; K+ `7 ]' f - extern int __bss_end;
3 ?" t! s7 Z4 V% Q# U1 h' l, z5 |& b0 S5 t - #define HEAP_BEGIN (&__bss_end)
Y" |: o9 u2 b2 Q8 A, {5 a% } - #endif
复制代码 设置heap的起始区域是0x24000000区域的512k大小。
7 l' m* n* |# ]" _, P1 p- x修改完毕看一下,来测试一下
3 R( U! l$ s# k$ V: r1 R; R- y7 v" | C
- #define LED0_PIN GET_PIN(B, 10)
3 g& ^- O1 v5 r' ?% n7 H) V - uint8_t test_buff[1000]= {0};
' Q' [5 J. Q- n - int main(void)
. U; N" e% L$ ]* Z0 x - {
, O) w- f2 L" V9 \" Q N - int count = 1;
$ F$ i5 P' b/ L( ]! _! I - /* set LED0 pin mode to output */
! e/ k0 l: t/ Z% g- B+ ?' M - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
; o8 S0 T Z1 p$ Z5 p - ' A! Y& P' D5 L' U1 d
- char *test_ptr;
# I9 T" o3 j0 J9 }7 g - test_buff[10] = 1; ' Z8 }' e8 V: `* D+ ~3 @# H, c
- while (count++)$ [4 A, Z/ L) Q1 R# z. d
- {
& T* J* f6 u# j0 ^( y- \( I - test_ptr = rt_malloc(100);
' T9 w. l4 w& c4 X' L - rt_pin_write(LED0_PIN, PIN_HIGH);
( y) {) J0 r& |. w6 x( @) o8 o - rt_thread_mdelay(500);
: y9 K- O& k; ]" { - rt_pin_write(LED0_PIN, PIN_LOW);) k3 n1 O8 p! I4 q3 n
- rt_thread_mdelay(500);
- h9 y$ y+ B' v& u - rt_free(test_ptr);
+ e, f% A' E8 J/ F+ v2 W: f5 a - }
1 Y% T/ ]: `7 Q5 q- N - return RT_EOK;
4 S+ g6 P3 [! z9 m6 w7 J0 g - }
复制代码
% x$ Q2 p( ]8 a' d! ~编译一下+ u' n# M' L' V$ A [% f. x
- Build started: Project: project
5 b4 q$ q8 @% p5 i - *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
, g0 K, s& X# [3 \. L- i9 T1 Z$ K - Build target 'rtthread'
$ b9 T9 `5 w) Q" z Y, O - compiling main.c...
3 a [# G n' P - linking...- ?& R/ F! t& P. ]1 C1 K
- .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).$ X* U- y4 V m! P/ f2 g2 w: x
- Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964
. Z* i8 y1 M1 S- m. L - Finished: 0 information, 1 warning and 0 error messages.7 n( q; k/ x9 e! u. Q
- After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin6 i; M# F4 b& m. |" f/ [
- ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).' N9 p5 f$ @; Y6 W* C5 a$ P" P& K2 n
- Build Time Elapsed: 00:00:02
复制代码 - P7 b) @- D9 f) Q
有一处警告 不要紧,查看一下map文件) J5 q2 s: I& _) b/ {3 Z# j" `
. @* `, B# s8 I* q
: Z) U$ x& ]6 L% |# R
& [; D/ I$ J" J* W( c# j& F8 k# R可以看到定义的test_buff是在地址0x20000898的位置。5 h, Q/ s4 ?% [% [$ K
: E9 E$ Y9 Y" v8 F- Q$ h
三 总结分析, ?: r% {4 S- p% M
实验成功
7 s9 L$ n3 u: T3 h( \4 P% R& r' g9 W( B3 i8 J
TCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
2 F" @* W0 H: Y( `7 {2 ]; Z' A& u! O7 S7 @- }9 {6 l
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
1 y# w, A! K4 H) j+ g
2 k. P# R: }; V0 Y2 F7 s- B% L9 \$ y) b( W# V4 [
6 g5 n2 |' j4 o6 s$ ~4 i+ |; \3 B4 m
|