你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7在RT-Thread上的多内存使用方法

[复制链接]
STMCU小助手 发布时间:2021-12-27 18:00
一,STM32H7 RAM介绍
/ [4 C% Z* l# r; o( \! ~! y9 e) X使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
9 I8 T  V: q  ^$ J& S8 i( F; x
2020021922201274.jpg
! J( w+ |1 g+ L5 r% A/ K) w

1 x! p0 @0 t" |$ C0 m# O
20200219221709559.jpg
0 c- m- c/ q8 D3 Q$ ~2 a) D
9 C( {4 a: Z5 F0 e7 |
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。0 \- g: [: A* F: j

8 U& Z1 t" G  N
20200219224822144.jpg
( z1 a8 I+ C  H  x

: [$ n; w) O# c* E  K8 {1 T: E" J既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
; y! P5 k# _' n$ O" X% [0 \( d1 g" T7 m: M( a8 r9 X9 ~6 s6 W2 s8 C& @/ G
二 多RAM管理办法) p( t7 x( f1 P  a6 Z( u
STM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。
; G/ n% M' J) n首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap/ a4 Y; z8 A9 N& f9 [  ~& `5 F
% `# x: D* W% n9 A! o, `
20200219230749268.jpg

0 I) V  S/ f, E& x3 B- h8 l8 k1 L# a; d# @9 f, X9 S$ R2 z
之后重新生成工程。1 y- b& U" j1 s1 f- n* j

& c* l3 j, }$ q1,TCM区域做为主heap
- V5 Z( J. f2 s! r! z5 w3 X! jTCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问
1 L' N7 ]1 O- S8 K5 T5 Z2 B# M4 k  C+ G) @
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.       ; *************************************************************. D! j. `5 z6 z3 H. `
  2. ; *** Scatter-Loading Description File generated by uVision ***
    * l0 \- W0 c1 c" t5 d. }
  3. ; *************************************************************
    : g) i6 H8 |7 l& T, P) d' F0 o% _

  4. ! M# a* `8 y! R( t6 }" ?
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
    * e- p3 u- A; K8 i& B3 b
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
    9 X. |3 S3 o1 e5 i6 v# \; O
  7.    *.o (RESET, +First)
    9 {; D+ C) ]) R1 I0 X1 {
  8.    *(InRoot$Sections)9 h# B& V$ z1 D
  9.    .ANY (+RO)
    - k2 S2 B! c9 g4 t4 Q" F7 l* y
  10.   }
    2 _& }' B+ y0 F
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data0 x/ L8 u( \, C
  12.    .ANY (+RW +ZI)) x3 J. {6 a3 J/ S# `
  13.   }
    & i$ z( L% d2 C2 f: p
  14. }
复制代码
  1. 第三步 写一个axi_sram.c
复制代码
  1. struct rt_memheap axi_sram_heap;: s2 U  B9 g" C6 k/ y+ }7 ?
  2. void *axi_sram_malloc(unsigned long size)$ g$ ^# l' d3 ?) j
  3. {
    - Q1 ~3 w2 d6 E8 }; f& |8 O8 p
  4.     return rt_memheap_alloc(&axi_sram_heap,size);
    , }% b& u- u; ?9 n4 N
  5. }2 x5 {  a/ d" W1 B( g6 l( ?

  6. $ v' d* e9 D% \* h# p' f+ t4 s
  7. void axi_sram_free(void *ptr)3 z3 e& i% x+ M+ N6 l3 D
  8. {9 k+ b) [2 }1 l) s  W- e6 t( U
  9.     rt_memheap_free(ptr);8 \% A" |) ^9 D7 u3 L( G: P
  10. }7 q; u8 Q, H/ G8 s' C- ?0 h

  11. ) f1 L0 k) c, `/ {" V& Q
  12. void *axi_sram_calloc(unsigned int n,unsigned int size)
    9 [0 e- N0 {( i6 O: D
  13. {; [# g; P( V' B  |' L
  14.     void* ptr = NULL;
    9 s1 ]: ]5 R, L+ u* _

  15. - }8 l% n1 D- ]& R- J6 m6 c
  16.     ptr = axi_sram_malloc(n * size);
    7 \+ y) T' N' s' q
  17.     if(ptr)
    2 x0 a" [3 b4 Q8 |: ^1 v6 G: B
  18.     {- f* j0 m3 z# {
  19.         memset(ptr, 0, n*size);
    ) ?5 P2 k) F% S, A* X* T) W
  20.     }$ S9 W, a& T+ k; a" S! Z/ k

  21. 7 N' W$ I9 y) m: N
  22.     return ptr;
    2 M# n% q0 n0 O. }6 L3 {
  23. }
复制代码
  1. 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码
  1.   #if defined(RT_USING_HEAP)& h  o- M; a  }3 s
  2.     rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
    $ c4 z# w4 A* u; v% V6 t5 C( }' z- d! U, U
  3. #endif
    6 u9 J3 Z7 ?& u: h" d2 C

  4. & Q5 o2 u1 X+ c. g. J
  5.     rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);   
复制代码
编写一个测试代码+ W7 \7 ~8 g' n9 }' n' J

5 W: `1 S1 M) Z; Z* y3 Z
  1. int main(void)
    0 J9 n* [# S1 }$ Y
  2. {
    " V: g7 J' B6 J+ j  c
  3.     int count = 1;
    ( M( n4 R) @1 V' ~: X- S2 r# `
  4.     /* set LED0 pin mode to output */9 I7 [4 U: E) z
  5.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    ) g' Y( a( R3 d4 D' K2 W

  6. ; K! `" i' F, l( e) f
  7.     char *test_ptr;) N. p' W. I1 k

  8. 8 u6 l( F9 `, e+ h6 ]6 x  @( ]
  9.     while (count++)2 n& {' \3 `! {3 ^" e7 s4 O
  10.     {
    3 K) h* s8 o1 c( h! ^
  11.         test_ptr = axi_sram_malloc(100);( @  i3 ^7 L4 d( `0 k
  12.         rt_pin_write(LED0_PIN, PIN_HIGH);8 o. M( x' q; }( t/ h* q4 ^2 b
  13.         rt_thread_mdelay(500);8 z/ Q) B2 A6 m5 l, `  c
  14.         rt_pin_write(LED0_PIN, PIN_LOW);
    / u( W, G  m+ f  U0 _
  15.         rt_thread_mdelay(500);! {) f4 z5 X- ~2 d$ P
  16.         axi_sram_free(test_ptr);
    " C  W+ g; S9 L  N* L$ |3 h; {
  17.     }
    9 O$ j5 B+ @- }& B' s8 h+ [1 ~
  18.     return RT_EOK;6 Y( V+ ?$ I4 c2 ~- B( y
  19. }
复制代码
/ ]. N( M% r# Q* P! ?& @
编译一下
& g' q+ y* D- P
  1. Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060  
    7 F8 }" a) ~8 I, f
  2. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
    1 V2 e0 _. a- p8 S% D9 @+ [) `3 e
  3. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).! C! {' g$ C  Q& y8 l4 _
  4. Build Time Elapsed:  00:00:08
复制代码
# b8 \* O$ H/ q8 }( M$ `
没有错误,没有警告,下载正常运行。
8 T+ r7 i# S# R* V, G* Y5 y1 O) K" O1 _# ^& I8 |8 @4 p
2,AXI SRAM区域作为主heap
) c' ~5 ^/ h, r. j! U9 OAXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快
+ [9 \+ V* X8 x  N: G5 R2 u" C/ d1 W, M; w  n" r( d0 o
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.   ; *************************************************************5 D6 X7 s& c3 H+ b5 j
  2. ; *** Scatter-Loading Description File generated by uVision ***
    0 H) D8 h# K- b8 ^! f0 H  t
  3. ; *************************************************************
    + W5 D; h, B2 V% S+ T

  4. 5 E" R5 F$ T! [3 v! r9 t7 i
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region* L5 N* V3 m2 G
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
      Z2 R0 k3 X& {8 A& i2 \4 M+ Z5 B
  7.    *.o (RESET, +First)
    8 U' R! C" e' o2 B# S  y( q7 @- }
  8.    *(InRoot$Sections)
    $ O% R: Y' g5 k- a( B6 ^# f
  9.    .ANY (+RO)
    ' ]6 a! }: z  ?$ v) H- s
  10.   }) G  f, h+ J5 z, \
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data
    9 ?3 _4 M( x" i# ^* W+ V# Z% u
  12.    .ANY (+RW +ZI)
    + F9 ~, O; F" z4 ?( D
  13.   }  @! f6 h  S- n
  14.   RW_IRAM_HEAP 0x24000000 0x00080000  {  ; RW data$ ^: D- j0 N* `, P+ R' P0 U
  15.    *(.RAM_HEAP)
    , a. I3 g2 v6 n9 n$ P4 K4 A& n$ L# a; g
  16.   }" c0 T; n: T$ r
  17. }
复制代码
  1. 第二步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (128)9 k3 K$ f9 b' s' l0 a( J( C% D
  2. #define STM32_SRAM_END            (0x20000000 + STM32_SRAM_SIZE * 1024)
    9 H0 S/ P  e) W7 j. [9 O
  3. % h) h8 B2 a& D, N* r
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)
    & Z! f' }2 K8 S: z( s
  5. extern int Image$RW_IRAM1$ZI$Limit;
    5 }) r1 }$ u4 n+ C0 L- `% C( A6 G4 o
  6. #define HEAP_BEGIN      (&Image$RW_IRAM1$ZI$Limit)
    9 o0 z7 Z0 \- c2 Q9 r' v. S! R
  7. #elif __ICCARM__
    4 g7 B& q( [7 Z5 E
  8. #pragma section="CSTACK"
    * P  M7 a- y, D' d
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))# [- T3 K; z9 s
  10. #else6 j) H3 O7 `# S2 W, ~
  11. extern int __bss_end;  {+ u+ G. X. X3 k6 \+ Z
  12. #define HEAP_BEGIN      (&__bss_end)
    7 ^! @; D, @# [9 G
  13. #
复制代码
  1. 第三步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (512): k& m) R! Q% u3 _) m3 @
  2. #define STM32_SRAM_END            (0x24000000 + STM32_SRAM_SIZE * 1024)
    + L* R7 n% W  l* D
  3. . ]5 I3 J" S& O( `  A& J
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)
    ) u0 F+ h4 r  p" O7 x  P" a; K
  5. //extern int Image$RW_IRAM2$ZI$Limit;
    8 b" w1 E/ `4 b
  6. #define HEAP_BEGIN      0x24000000//(&Image$RW_IRAM1$ZI$Limit)
    5 m" ^% f- F  B4 I0 @/ j
  7. #elif __ICCARM__
    3 g# P6 ^+ I2 x2 S- J5 T
  8. #pragma section="CSTACK"  P! y, Y# V6 }' l. ^
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))
    , e) A9 F3 m8 m" @% S& k4 t
  10. #else& e! o& Y4 s2 Q
  11. extern int __bss_end;; e0 T8 K( s4 j, F
  12. #define HEAP_BEGIN      (&__bss_end)
    ' `, y6 d* r* m$ K, {
  13. #endif
复制代码
设置heap的起始区域是0x24000000区域的512k大小。& m( |6 [. }2 t5 X* Y1 _
修改完毕看一下,来测试一下8 D% V+ }9 w" I$ X2 E

6 ^2 }  S2 h6 j' b5 @( |. r# K) @
  1. #define LED0_PIN    GET_PIN(B, 10): N% l% G2 X9 S/ q+ C
  2.     uint8_t test_buff[1000]= {0};; J8 ~9 Z0 i3 F6 A
  3. int main(void)
    $ ^. D3 u  C1 f6 `
  4. {   
    ; k  y6 `6 x5 K! t7 p! N' G  m1 @' P
  5.     int count = 1;
    9 {$ A6 q" v9 V9 c
  6.     /* set LED0 pin mode to output */
    6 n; s6 m* ], z, h/ g9 F
  7.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    , U0 _0 s) @# y4 B8 k
  8. 1 p. g9 z2 B2 e% [
  9.     char *test_ptr;9 T) o1 o0 ~  ~$ K
  10.     test_buff[10] = 1;
    " ]( ^  |5 D5 T
  11.     while (count++)
      _% p/ |/ q, w& M0 {5 n
  12.     {2 K' ~# [/ k& ]  y& H7 ]
  13.         test_ptr = rt_malloc(100);$ v8 N! ?! ]0 `: B% n7 g
  14.         rt_pin_write(LED0_PIN, PIN_HIGH);/ e4 [* Q8 p8 B6 k% [% n* Y
  15.         rt_thread_mdelay(500);) F$ M8 _6 @! \) Z% L/ Z: ^
  16.         rt_pin_write(LED0_PIN, PIN_LOW);- h) k& X) ~2 h9 Y) [
  17.         rt_thread_mdelay(500);
    0 v% i0 A" E( P9 w0 L/ Y
  18.         rt_free(test_ptr);
    3 e  V* s6 s' A0 F6 A
  19.     }
    , l! f6 p  |  t
  20.     return RT_EOK;
    7 j. @% r9 p  p2 Z
  21. }
复制代码
/ C2 M' F1 k+ Y; j0 R
编译一下. L# w2 M1 l4 l8 B2 m( e& x
  1. Build started: Project: project( H% b( Q; B3 {. i9 S2 a- ?
  2. *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'2 Q4 D9 @1 ?. P0 t7 n  M
  3. Build target 'rtthread'+ l+ o3 ], h& E( X% c6 L
  4. compiling main.c...
    : S3 A, T% p& U
  5. linking...9 k4 A( v; l+ t2 Y2 |9 X0 g
  6. .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).1 Z2 i8 s8 [4 @. x! [- y
  7. Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964  . u& G. [6 y# q; k5 C
  8. Finished: 0 information, 1 warning and 0 error messages.1 x9 {2 p4 t$ B+ A  q
  9. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin& [" ^6 w9 @8 {5 S5 d/ R
  10. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).- s# a1 [2 r2 a$ S. L1 {
  11. Build Time Elapsed:  00:00:02
复制代码

, ?$ G7 ~  w1 \+ G6 ^9 {% h7 U有一处警告 不要紧,查看一下map文件: a0 D% U) ]: S/ D, F, b9 h& u
5 m) B7 ~3 w2 k1 E2 z
20200219233304754.jpg

+ ^9 n7 b  c& f& ]: F/ v% g
$ |( V* m  _. B( e可以看到定义的test_buff是在地址0x20000898的位置。
+ W# l- j) y* A, l( a
+ N6 n4 C: b$ ^, V: s三 总结分析
# H5 m6 \/ d4 m- M2 K实验成功
  h) O3 k8 ~; a, [% S$ p) L* y2 a
6 w5 [% _5 X: Y, H* V  O) V3 YTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
" l! j$ I$ f7 J+ U7 q
5 \2 N# `4 p# r0 f' b& m' r1 c- uAXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
4 ~! i# D2 g1 x4 s
- _3 Y( a6 u% {: o; n7 }6 P/ }. R; t' c- |4 Q

* K( G9 q7 {) k9 Q+ ^
收藏 评论0 发布时间:2021-12-27 18:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版