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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 18:00
一,STM32H7 RAM介绍' q9 r) B. E, {, m5 M
使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示" k& h7 s* m% f$ m& E! k' i. `
2020021922201274.jpg
0 w+ E2 _: t, w

' p) V# D" q  D+ d! j
20200219221709559.jpg
# 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" O
20200219224822144.jpg
0 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
20200219230749268.jpg

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
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.       ; *************************************************************3 z' W5 g( x7 v) `0 d
  2. ; *** Scatter-Loading Description File generated by uVision **** m$ M8 G6 g1 C' r# @( y1 \$ |+ T2 B
  3. ; *************************************************************% J% K, d- P, h7 P
  4. 4 q  R) R& j3 D1 @, n8 P
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
    : x1 N) H$ E/ r6 M$ e3 s4 z4 J3 P
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address# n2 g3 i. g4 Q% z
  7.    *.o (RESET, +First)
    4 s/ ?; V5 e; n5 P3 h
  8.    *(InRoot$Sections)& j: [) S) W" ]. b) j' Z) z
  9.    .ANY (+RO)
    ! l  K& M0 u) {: @7 k- {
  10.   }
    8 m& N% I% o: `. Q/ Z" V
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data
    8 v0 F2 z* d* s) F' J- ?
  12.    .ANY (+RW +ZI)
    + b3 w1 M5 ]0 @% V8 m
  13.   }
    5 C9 v7 g8 q# V' E/ H% O7 h2 ?
  14. }
复制代码
  1. 第三步 写一个axi_sram.c
复制代码
  1. struct rt_memheap axi_sram_heap;0 V3 P) o, w! V
  2. void *axi_sram_malloc(unsigned long size)
    / t* @1 g+ S& D" W5 w# T* b
  3. {
    , C% i6 T8 h( t& B  [& d" O  ^
  4.     return rt_memheap_alloc(&axi_sram_heap,size);
    0 d# M/ R! w4 [' f1 {% G% m, Q4 u
  5. }# [+ q; y: _7 O7 ~; t

  6. 2 E/ b( C3 @: C" |
  7. void axi_sram_free(void *ptr)
    ! Z2 T3 _0 T) H, j
  8. {; `- L; J# P3 J# i/ G4 F$ x' a
  9.     rt_memheap_free(ptr);8 H$ W9 t; G! D: }  N
  10. }
    " @0 Y9 v4 r. |5 u
  11. 2 n" c* U! t- N* W, U9 R
  12. void *axi_sram_calloc(unsigned int n,unsigned int size)5 ?$ a1 @$ q( E$ L9 i3 ~$ w% H
  13. {
      L0 B  ~/ n) L
  14.     void* ptr = NULL;
    . I9 E4 [- H! n# I/ I
  15. : Q9 B1 Y+ g: Q) S
  16.     ptr = axi_sram_malloc(n * size);
    $ v7 Z/ j6 j/ l: P% ~
  17.     if(ptr)
    " r1 S& b/ ^+ E' P) F* J
  18.     {
    $ ^+ \- m, [$ T' F; C
  19.         memset(ptr, 0, n*size);- F7 `8 B) H  Z; a) y! F9 k  _# y
  20.     }6 Z; H1 p& t7 o! C0 C
  21. % ]% @0 I: x& T" |8 U
  22.     return ptr;: H4 d  c9 S* `' u/ u
  23. }
复制代码
  1. 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码
  1.   #if defined(RT_USING_HEAP), L5 ^8 ~) o0 N* H' D
  2.     rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);3 |: d. a8 L3 [! t& m5 k+ M
  3. #endif4 c1 s) u) Y. _: r- j3 C4 d8 U

  4. ) k" a! X) @! e, }1 {* K
  5.     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
  1. int main(void)5 U0 T4 M3 w! U5 B
  2. {
    9 D$ {# K6 Q: e: p0 s
  3.     int count = 1;
    8 C6 ~! p7 [( m5 P1 I/ y: A9 ?
  4.     /* set LED0 pin mode to output */
    , f: J( o' N9 J* I' {/ q- N
  5.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    & O" _$ H' l7 g+ ?0 R, e4 c

  6. 7 j! E) f9 ?/ R  L
  7.     char *test_ptr;" {) G! o( K5 I+ \7 @
  8. , p: p  ]% ~$ v
  9.     while (count++); _' D% {" M. U, R2 i
  10.     {
    ' v, m  Y- `  L/ U0 [% Y) \
  11.         test_ptr = axi_sram_malloc(100);
    3 n& c- g! @2 ]5 u' p6 U6 G
  12.         rt_pin_write(LED0_PIN, PIN_HIGH);
    % f3 C: R9 m& P' [/ ]
  13.         rt_thread_mdelay(500);  a- |3 l, v$ P: U1 q0 w5 I
  14.         rt_pin_write(LED0_PIN, PIN_LOW);
    1 H$ P! b* H, W# k& D  R
  15.         rt_thread_mdelay(500);
    ' q1 u6 N3 x- j: n
  16.         axi_sram_free(test_ptr);
    ( I8 y& q; }7 O) N
  17.     }
    " f  ^2 U( E1 G
  18.     return RT_EOK;; @" {  Q, Q: [8 a
  19. }
复制代码
( r! Q" z+ q. F; {. ]
编译一下
5 d$ o" q! z5 m4 S4 W+ T0 r" Z
  1. Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060  5 ]( ?5 T4 Y1 a$ y/ z( y6 G# {
  2. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
    7 _, f9 d& _/ \2 `9 O# u" ^5 ?
  3. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).
    7 ?/ y1 C4 b* `# \
  4. 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
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.   ; *************************************************************
    ' V+ Z# x$ c+ D0 m1 H; G
  2. ; *** Scatter-Loading Description File generated by uVision ***7 L! \; N, X; C3 m( w' o
  3. ; *************************************************************2 Q6 c0 P$ R- K. h# c3 W* x
  4. 3 D& G5 s% o" n& L4 B
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
    7 ?  \3 ~& q$ ]2 q
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
    ! z9 |' _/ [; O# {7 D' x$ P  j
  7.    *.o (RESET, +First)
    5 J! ?% N( M& g$ L. ^& t& W
  8.    *(InRoot$Sections)
    ' b! |' W$ V# c/ F; m
  9.    .ANY (+RO)+ D; c! C& d1 _8 N
  10.   }
    5 [, m* U" E6 b) r
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data
    . H- F* T8 s8 }# H1 }# w6 c% J& |
  12.    .ANY (+RW +ZI)
    1 A+ v# e( p+ Z' F
  13.   }4 @+ O! y% V3 t7 a4 B. C; K
  14.   RW_IRAM_HEAP 0x24000000 0x00080000  {  ; RW data; a: \- v% a. U+ K& A% r7 m
  15.    *(.RAM_HEAP)! V. ~: K" n" k  x+ {2 S
  16.   }/ Y8 N  C4 O# w
  17. }
复制代码
  1. 第二步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (128)" D: p( M6 V$ A) |. a  ?  M
  2. #define STM32_SRAM_END            (0x20000000 + STM32_SRAM_SIZE * 1024)  N* u5 d) z: P( N

  3. $ v% _, k, o$ |/ W: Q( \4 C4 H0 ]
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)7 R: v* Q; i' {8 n# M
  5. extern int Image$RW_IRAM1$ZI$Limit;
    - Z4 m2 b' A) X, N2 h8 h' a
  6. #define HEAP_BEGIN      (&Image$RW_IRAM1$ZI$Limit)
    % C7 u. F1 P. T0 ]2 g, k. `; O; x
  7. #elif __ICCARM__
    6 D8 ~4 k. T. n. V3 I
  8. #pragma section="CSTACK"
    , R. @  c& E; `: p5 e% N) ^
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))1 _* I3 W9 X6 t3 V& j3 T* u
  10. #else
    " @% ]" F; U+ k# _( ^
  11. extern int __bss_end;$ }( L8 q* U& `% k: n3 x: k
  12. #define HEAP_BEGIN      (&__bss_end)" N9 P+ o! H& @& o
  13. #
复制代码
  1. 第三步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (512)
    0 D! E' P) P9 ]# M3 _
  2. #define STM32_SRAM_END            (0x24000000 + STM32_SRAM_SIZE * 1024)
      \: b/ A, M. |" i+ O; o

  3. % I6 C/ P1 x: X5 k# j0 O3 v" V
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)
    - v* x  n9 b. W% G; x
  5. //extern int Image$RW_IRAM2$ZI$Limit;5 |5 o2 F: D* k- _8 Y* M( a
  6. #define HEAP_BEGIN      0x24000000//(&Image$RW_IRAM1$ZI$Limit)6 C" }% Z3 d- m( {; y1 a. e4 s% w
  7. #elif __ICCARM__
    0 f: H# O# V1 M9 T/ B7 Z# \  l
  8. #pragma section="CSTACK"8 k/ w$ @8 z$ i2 x" X. q' ]7 G
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))
    - X+ i0 k1 w0 |# ~/ ^) |( o  P
  10. #else
    6 q* M3 @9 |3 `( X7 X. g
  11. extern int __bss_end;
    6 \4 O. C/ E7 X
  12. #define HEAP_BEGIN      (&__bss_end)
    * d! M' d  W1 D# Z! B, t
  13. #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
  1. #define LED0_PIN    GET_PIN(B, 10)
    " w3 f, g# `- e! o5 X$ f
  2.     uint8_t test_buff[1000]= {0};1 |; u4 {$ ]+ k7 `' A/ d4 X0 I
  3. int main(void)
    " f! g0 X4 h9 ?! D4 G
  4. {   $ M. f8 n; n6 X  |# F1 U
  5.     int count = 1;
    , B' ]' M# l( c, p; I
  6.     /* set LED0 pin mode to output */
    ' a6 q/ b% Q' F. E* W
  7.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    2 ^& U5 u. V  N5 h4 u2 l

  8. & e+ h( }' T- H: A& m' K4 c
  9.     char *test_ptr;) \. W& s3 l' m0 Z* c$ J
  10.     test_buff[10] = 1;
    0 y3 M$ E5 y7 c3 E" ^
  11.     while (count++)
    # C. J2 h% Q5 V' |* X$ P& F
  12.     {5 n3 x' s$ `/ G7 r/ X& c
  13.         test_ptr = rt_malloc(100);
    6 D, o0 ~4 ^# h* ]9 j" K
  14.         rt_pin_write(LED0_PIN, PIN_HIGH);
    5 _! \& a3 x$ }+ j0 p/ t
  15.         rt_thread_mdelay(500);
    $ T- o; s) W+ u$ F# q
  16.         rt_pin_write(LED0_PIN, PIN_LOW);: S4 S( L( t% L' a9 ^, T/ D! d
  17.         rt_thread_mdelay(500);* c8 ?7 o, Y% w- R6 P
  18.         rt_free(test_ptr);
    # G" J9 g5 K9 K1 ^' A7 M
  19.     }
    1 s" ^# U/ g# h  ?
  20.     return RT_EOK;
    . T% U, I! o1 i; @
  21. }
复制代码

: H* ?- i; @/ A编译一下% j2 W3 A+ p- y4 y9 t! m% u; }9 s
  1. Build started: Project: project, O" D. u1 Q0 w. _/ Z. s% @" W4 t% n
  2. *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
    / Q# Y+ Y) u( h7 ?. }
  3. Build target 'rtthread'5 v5 p. t$ x; S* t  z
  4. compiling main.c...8 |9 c& f  C" I. F, Z2 |* e: k& p
  5. linking...) ?2 V1 n9 z! g, Q5 ^  A2 V
  6. .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).
    + K2 P. B7 L# u2 T
  7. Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964  
    . u* M5 [) s% i) Y. p4 Y
  8. Finished: 0 information, 1 warning and 0 error messages./ Y5 X+ X+ f  K
  9. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin( C, M6 N, p" s' Y
  10. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).: j. E1 Q" A, \# l( \
  11. Build Time Elapsed:  00:00:02
复制代码
- u" u! |' j  R0 l
有一处警告 不要紧,查看一下map文件, g5 I, Y& j* |& L: k/ ?  ]: Y
' @) l/ G4 e! r
20200219233304754.jpg
& 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
收藏 评论0 发布时间:2021-12-27 18:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版