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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 18:00
一,STM32H7 RAM介绍' n- h5 M3 ^& W
使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
3 I' T; V/ j4 h" g! ^# W
2020021922201274.jpg

% b. u4 ^  e4 h3 p  O/ h$ H1 o: r7 V& S# S  s3 w$ I
20200219221709559.jpg
: ^* A' G( T$ P# v1 ~% @
/ }2 m) N3 {% U9 R  W
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。5 |& T' L4 N6 f, B) Z
1 x  ?9 \7 [& K6 L* G
20200219224822144.jpg

0 @$ t5 M2 |0 R8 Z: Q. S) X7 R, z9 x( u& X+ l2 K) {3 }
既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
; W9 T- e7 w8 C' e. b1 o4 f. i, G$ D
二 多RAM管理办法
0 [' u2 L. I/ q; |1 pSTM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。
" ~5 v* Q) b. ~. n  \首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap% E) Q: w* \) n4 J& ]  e
: t6 e* u0 ?: u0 F
20200219230749268.jpg
3 Q6 ]: {* R, @8 V0 Z  {
+ T) F* n$ v3 I1 j1 ~7 q# @8 J
之后重新生成工程。; C$ W# u5 |% l0 G8 Y- [
* f2 d) X+ n/ `* k/ E
1,TCM区域做为主heap
2 v. ]) J% @2 @TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问, ]( q6 ~& R6 I% t/ f4 B7 g

3 N/ N+ P/ B$ Z+ A: f  U- o/ [
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.       ; *************************************************************; u6 k* C$ e2 ^7 L$ R1 X
  2. ; *** Scatter-Loading Description File generated by uVision ***
    & e2 `: l$ u( F# C
  3. ; *************************************************************
    ( x) h7 }8 I5 D) Y' R, P2 Q
  4.   i0 F& ~. @0 q% R3 O
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region9 l! P0 f0 G1 w* |
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
    . [& R# |5 P/ `1 P$ z4 d
  7.    *.o (RESET, +First)1 {$ T% w8 E0 m1 B
  8.    *(InRoot$Sections)" U: o" [$ z! b: O  W( C
  9.    .ANY (+RO)
    1 y! i1 C, ?6 x4 K" u/ j
  10.   }
    , A. a1 u- }5 y% Z* a; o, w( C; U
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data
    8 r+ ^) L8 `- W( Y! \
  12.    .ANY (+RW +ZI)+ ~/ w) W  x& I
  13.   }
    * X$ x5 Q) O* E
  14. }
复制代码
  1. 第三步 写一个axi_sram.c
复制代码
  1. struct rt_memheap axi_sram_heap;
    # b" d1 S* p& f8 s- K* m( N
  2. void *axi_sram_malloc(unsigned long size)) ]! t; e8 E8 o$ e0 t1 ?  u
  3. {
    6 `9 Q  U" U( H+ b
  4.     return rt_memheap_alloc(&axi_sram_heap,size);
    0 Q/ J1 _1 e/ x( a
  5. }5 N- p# i$ i/ e& v9 U3 z* }% }6 P6 z3 c

  6. ' O/ h% S$ C  J* x  P7 a
  7. void axi_sram_free(void *ptr)& X3 z% x( k# l4 [
  8. {# c& b* {* _" G
  9.     rt_memheap_free(ptr);
    ' K3 ]6 A# I7 k9 ]) Z& t, J5 w
  10. }) }, U# U9 E; ]4 p  y! Q  `  e
  11. 4 F; ^2 F6 i% c" y
  12. void *axi_sram_calloc(unsigned int n,unsigned int size)
    1 `0 K3 b/ _8 |5 T' g" |, ~
  13. {
    % W8 ?7 E! U8 v' j  M
  14.     void* ptr = NULL;% p, t: n1 w/ e6 B( d

  15. , O5 h* t& Z6 U2 {7 a' y
  16.     ptr = axi_sram_malloc(n * size);4 N4 {- ?* N3 G( b
  17.     if(ptr)3 ?$ w& b8 F) B. L0 ?
  18.     {
    . H" G" ]3 L, n
  19.         memset(ptr, 0, n*size);' |/ L& O: r" M, G) _- Q
  20.     }" Z! S1 I5 a1 D; f3 W+ r! P

  21. 3 P8 M" C+ D+ v2 X5 }$ j
  22.     return ptr;2 A! f( X1 R" n; H$ A5 ?
  23. }
复制代码
  1. 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码
  1.   #if defined(RT_USING_HEAP)
    2 S3 w: l( V3 }# n, P1 ]
  2.     rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
    . G+ n' X8 Y7 @$ B. [& @
  3. #endif
    ( b7 q( K9 b; r" O  A7 q

  4. & Q$ o* x& d* ]8 d& i
  5.     rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);   
复制代码
编写一个测试代码
$ B% z# m; z* G9 _( u$ L
3 G  e/ i+ ?1 F5 ]
  1. int main(void)& v+ h1 |! Y2 Q0 s6 Y8 E  V, F
  2. {
    9 t+ F! |* k) f6 P  i& l
  3.     int count = 1;+ U& C2 M/ a$ V! {: I+ S
  4.     /* set LED0 pin mode to output */& `* w3 ], ~3 z
  5.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    0 F! x" N: ]" `
  6.   M3 W* k2 y1 y% @" v
  7.     char *test_ptr;
    - w+ s8 I$ H; N6 E3 r( ]

  8. 5 H& Y8 m1 V+ a3 }3 e# N9 k
  9.     while (count++)0 z$ C+ y0 I# l( }5 I
  10.     {
    2 ~# P% _+ n: _0 H; f$ @: C! o
  11.         test_ptr = axi_sram_malloc(100);
    ) ]8 c0 M' M# ]* [0 D0 [3 a
  12.         rt_pin_write(LED0_PIN, PIN_HIGH);
    + F3 R' x7 |& d- y. R; @2 t
  13.         rt_thread_mdelay(500);' Y- {3 S) D/ v
  14.         rt_pin_write(LED0_PIN, PIN_LOW);- s- j& {- T/ I! w  r
  15.         rt_thread_mdelay(500);
    # c- {7 z' c- u- e; u# h5 ]& Y
  16.         axi_sram_free(test_ptr);$ Y3 V2 v- F/ i; s  N4 c$ v
  17.     }
    4 C1 `+ \1 ^( o8 C  ]( u
  18.     return RT_EOK;2 A9 y3 j" I. L" ?- S4 d  d
  19. }
复制代码
+ m  z  V% l' q7 o% G2 Z& q+ F, r
编译一下
" n! }; R2 _# ]% |  G2 L2 S
  1. Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060  
    9 ^, g0 A% D7 I* u( M8 O" a* p/ h
  2. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
    0 k+ K7 `, G& @  [
  3. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).
    ( K) O  }/ T6 N5 r
  4. Build Time Elapsed:  00:00:08
复制代码

* \/ F' M% r9 z没有错误,没有警告,下载正常运行。7 A8 T1 n6 O% a0 B1 d
# v8 G2 i1 S8 b& a! n
2,AXI SRAM区域作为主heap
8 |5 r7 ~# l' I: eAXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快! s- R2 `4 h9 O7 }6 ?7 q5 h

* q; l3 F$ o/ m* J5 V
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.   ; *************************************************************
    # \- u, Q/ v" a3 E& v
  2. ; *** Scatter-Loading Description File generated by uVision ***/ O8 E+ q7 z% c6 `) S
  3. ; *************************************************************
    & J+ M3 d0 f! m( S" Y1 D- w) f

  4. ; \, U, H$ u& q" n: z
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region/ M! O% a7 P& S& b3 F0 K9 a+ O
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address3 O2 I( R  |+ e
  7.    *.o (RESET, +First)# H8 z7 \6 {* c4 F( A
  8.    *(InRoot$Sections)* o, }( X/ B5 U- Y7 f
  9.    .ANY (+RO)
    5 H" E/ [; j: y& |* K- b
  10.   }3 Z& B! l; e( f9 J# [
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data
    + G  r1 V8 B6 O) u0 n- R
  12.    .ANY (+RW +ZI)9 p, j/ D8 S. Z+ W4 L
  13.   }: U4 |5 w3 Y% v" U
  14.   RW_IRAM_HEAP 0x24000000 0x00080000  {  ; RW data- |  ?+ X$ s3 _0 V2 B6 p
  15.    *(.RAM_HEAP)% X4 Z1 t; b& _+ ~8 y8 D+ W
  16.   }
    , {/ y7 A& G  \5 N! ]# Y; |+ A
  17. }
复制代码
  1. 第二步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (128)
    2 h" g1 h: Z8 Y. {
  2. #define STM32_SRAM_END            (0x20000000 + STM32_SRAM_SIZE * 1024)
    $ T4 g  B( G, ]: d  I9 H; m1 _

  3. ! Q: \$ e6 u0 Q9 b
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)4 w* y6 b+ |: k$ h7 p" g$ r
  5. extern int Image$RW_IRAM1$ZI$Limit;% k; l4 ~1 @, S: ~5 R& R: z0 w
  6. #define HEAP_BEGIN      (&Image$RW_IRAM1$ZI$Limit)
    % w+ l) q2 `+ B
  7. #elif __ICCARM__/ |) z* Y1 j4 N8 ]% N
  8. #pragma section="CSTACK"
    3 h  D' m$ Q. f$ m& p9 F+ V2 ]% v
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))
    0 `. K' O5 ~3 [* f
  10. #else
    $ i6 x) u, O( p; L
  11. extern int __bss_end;
    : Z' u. d! P  r/ |( p1 z  F$ R
  12. #define HEAP_BEGIN      (&__bss_end)
    ' {& h1 `6 }4 A+ E
  13. #
复制代码
  1. 第三步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (512)
    1 K6 P1 {( L8 H7 n2 o* z! l/ h
  2. #define STM32_SRAM_END            (0x24000000 + STM32_SRAM_SIZE * 1024)  X" J8 A* ^: D  ~

  3. % Z9 q& Q- z' X! G! S
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)/ b6 i/ S' B/ T' \0 B: F
  5. //extern int Image$RW_IRAM2$ZI$Limit;
    : |7 A& D5 W( A; \) u
  6. #define HEAP_BEGIN      0x24000000//(&Image$RW_IRAM1$ZI$Limit)
    . C4 s! K$ d; H; E6 a0 w6 n* j
  7. #elif __ICCARM__
    ' I  o* k$ h4 {. U2 ]
  8. #pragma section="CSTACK"8 O: O; q6 W$ X9 d3 O
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))6 k  [/ P9 E. Y1 R8 z
  10. #else- p; E0 J' n1 u* [* x- j1 C. Z
  11. extern int __bss_end;
    1 o4 @) v- M2 r- F
  12. #define HEAP_BEGIN      (&__bss_end). U% k/ o- \& q5 Y) q" D3 I
  13. #endif
复制代码
设置heap的起始区域是0x24000000区域的512k大小。
. q! O* Y4 S1 c8 {; {. L7 G4 Y修改完毕看一下,来测试一下
" A3 T0 [' d! A7 N0 ^! P( \- g  P8 P, ^  ?7 N
  1. #define LED0_PIN    GET_PIN(B, 10)* J% c+ K; g8 {5 l) R( ]
  2.     uint8_t test_buff[1000]= {0};! l# L1 b- H  D8 _
  3. int main(void)
    ! c) i: W9 O/ k) ^' K) h' j
  4. {   0 s4 ]" ]9 K7 X: W4 q( c8 p5 h, I
  5.     int count = 1;/ [0 }! W  o$ Z7 L  Z4 D4 |7 I
  6.     /* set LED0 pin mode to output */3 k' H/ Y) o0 l( m8 S& j! N
  7.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
      E7 \4 j0 R8 {4 O  E) W
  8. 1 [/ k4 b) @5 ]$ L
  9.     char *test_ptr;: d# E3 M+ T6 F! M- W
  10.     test_buff[10] = 1;
    8 C0 \! Q' d* m  V
  11.     while (count++), ^, C1 ^5 @2 W1 F# S" H
  12.     {2 u) d; ~9 c* w; y/ u7 e2 `/ q8 ~( H
  13.         test_ptr = rt_malloc(100);
    % l% c2 i/ s. ^( A. g" K8 c
  14.         rt_pin_write(LED0_PIN, PIN_HIGH);5 O7 b  H. G1 B1 y  a
  15.         rt_thread_mdelay(500);
    . N. N7 c6 g, s  p
  16.         rt_pin_write(LED0_PIN, PIN_LOW);
    9 s8 m* k3 B+ C: F
  17.         rt_thread_mdelay(500);: R: k; ~" |$ O! N: @0 k- A- X( c
  18.         rt_free(test_ptr);
    , n% e% J/ O' y# h/ [& F- @3 b6 A" ~
  19.     }5 R9 i+ y4 O- M  P
  20.     return RT_EOK;* T$ J% ?  V! B* {. P! `
  21. }
复制代码
- C8 J1 S* C3 K! u4 ~
编译一下
$ o# @, t5 p+ R$ M4 r3 C
  1. Build started: Project: project. g4 G8 Z0 n. U# |- `5 V# C: y/ X. J
  2. *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
    : u( I8 L- y6 F: W+ ?
  3. Build target 'rtthread'
    - V6 q6 M' [5 h) [& Z4 G+ U( Q
  4. compiling main.c...0 g6 p  t! A: a5 g# v
  5. linking...
      R' Z* s4 f! x/ p9 V2 f- [6 F
  6. .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).5 o3 S4 U; J5 z" |
  7. Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964  1 F: j7 _  D3 i( u+ K
  8. Finished: 0 information, 1 warning and 0 error messages.
    ) d6 S  g) S5 q/ @; a% q+ H7 c2 }
  9. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
    6 k4 r9 n2 {( m# N& Y
  10. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).
    3 r2 C; R  P# Q
  11. Build Time Elapsed:  00:00:02
复制代码

. k8 t5 R, y* t+ Q9 l) F% c: T& g" [有一处警告 不要紧,查看一下map文件  r$ F: h4 w1 b( `
  W: o- Z  x' J
20200219233304754.jpg
8 k9 g+ z( q" q/ {- b5 ?' ~7 u
1 R% r9 j7 e5 q9 O1 Q+ w
可以看到定义的test_buff是在地址0x20000898的位置。
/ Q0 y  Z7 Y& [  q# V4 M- m- _2 S& ~2 o
三 总结分析
' {, q9 Z! u$ H& ~8 \: }实验成功
+ f' x2 ]1 Z& O. n0 r
9 Z) J' x: [. N& ?, h& PTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
4 i1 D5 Y. e& R1 j5 N7 n' u. w' M5 d$ q5 k
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
' j8 f$ O$ U* i6 X1 G
* A- Q, R! T: F
" V" S. m! Q. f$ `( X+ M  G5 p3 a* P3 Z
赞 收藏 评论0 发布时间:2021-12-27 18:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版