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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 18:00
一,STM32H7 RAM介绍
3 r6 g0 ]. q2 }使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
! `  u7 |$ x8 F3 d$ A, Y
2020021922201274.jpg

5 `+ v5 q) A% s) n: _3 t, z* C9 I' ~  K) o
20200219221709559.jpg

" k- e0 r$ `: ]/ D$ @# ?& ~% g3 S5 T6 P! V* `$ c( b4 \
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。2 T% o/ l9 M" [8 r1 r, P/ h

6 S6 s1 d  G5 J7 q2 w$ y
20200219224822144.jpg
0 z$ U' ?: l, {7 a& B2 ]- Q0 {+ o
1 a& x; \$ E* j
既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
1 y- k3 i) T0 F8 A' L0 x: ~$ F* o+ @) Y& i& g6 A4 g" d
二 多RAM管理办法
1 H% T: r* B+ t6 xSTM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。: O6 M9 v# `4 R& }. s$ y. ?
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap  W8 ]8 V) h) V) p/ P( p# v

- B7 r: D( x2 x) e% N
20200219230749268.jpg
! M0 h! f. m" `# X

, q9 a% m* y0 b0 H. r之后重新生成工程。
5 d! L0 e* \8 d) F) A. f$ Y7 \" ?
1,TCM区域做为主heap
" f$ ?2 x  ^* J: V) F$ B& C) jTCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问
) I* }# ]- U# j" k
/ {* I! U5 n# f9 j" d% ?" j5 E  j' G
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.       ; *************************************************************$ t6 r# v. c6 B" @' l9 M- N
  2. ; *** Scatter-Loading Description File generated by uVision ***
    5 L: B( f9 q; Y5 K; G" K
  3. ; *************************************************************5 i- {7 s5 ?8 s8 ^; h  I! ^

  4. 3 Y& @: |) ]( A# W
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region, v" B6 O' I! W
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
    % C* G; t1 _+ @+ U# p  I/ T  v! \
  7.    *.o (RESET, +First)
    & w( d8 w3 v6 E' ^
  8.    *(InRoot$Sections)# w1 l) R0 e3 r2 f1 `+ d
  9.    .ANY (+RO)- B' a& \& e2 D1 I6 S% L7 V1 A; s
  10.   }0 G6 v$ A6 u9 h+ x( k& r
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data
    , b, O  K9 C# C
  12.    .ANY (+RW +ZI)
    : f7 t' A5 x# i9 Y! _. @
  13.   }
    4 x4 q1 V9 y# }7 ]$ r
  14. }
复制代码
  1. 第三步 写一个axi_sram.c
复制代码
  1. struct rt_memheap axi_sram_heap;( x2 j$ X$ \7 p, N) m' `
  2. void *axi_sram_malloc(unsigned long size)( f1 Q- t# w, b+ w0 l0 |
  3. {
    ' b1 k6 Q! O5 s) C
  4.     return rt_memheap_alloc(&axi_sram_heap,size);# P; q' @, N! d2 n' `7 U
  5. }
    & [; {2 z) f2 K+ C

  6. " @' q( q. m) Z- m2 r
  7. void axi_sram_free(void *ptr)& c: t7 B! U8 T  {
  8. {
    7 s4 [) H$ [! x1 P% N' @
  9.     rt_memheap_free(ptr);
    # g( [5 |7 \1 z- O* H* U
  10. }
    " n5 w' }$ S3 }5 B9 e( n5 Z7 t+ D

  11. / I1 Y) c/ N9 W0 Y1 o$ V9 U
  12. void *axi_sram_calloc(unsigned int n,unsigned int size). a7 l& v0 C6 W# C7 p
  13. {
    ' u& t  A3 j* ^% D% V- U# Y; n( X# h
  14.     void* ptr = NULL;6 e- R$ d4 \) J/ _  C2 _

  15. 0 s/ b' P0 l8 l2 ^
  16.     ptr = axi_sram_malloc(n * size);
    1 ?( @% ?% {! W. M# \3 q  H
  17.     if(ptr)
    / o) g8 I$ k3 [7 y
  18.     {& v" _% f. i5 V* w7 U. k% l+ J
  19.         memset(ptr, 0, n*size);: H1 V. E! s. g! z1 n; a1 j
  20.     }
    ( h# Q# X* S, e" \7 C" ?
  21. 3 M0 C' l) V5 L  s# T4 J. p
  22.     return ptr;- W' \+ j' _' ~* p
  23. }
复制代码
  1. 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码
  1.   #if defined(RT_USING_HEAP)0 _6 R3 E( g4 E9 A
  2.     rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
    6 O2 T& N6 b* m
  3. #endif
    ( }0 B' ]8 ^+ ~! g. {
  4. * c9 Z& R1 A! e1 r3 z9 t
  5.     rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);   
复制代码
编写一个测试代码$ C) @# P4 y; ?2 f/ y6 Z1 r
1 _4 B4 n$ x6 ?2 K, P: }0 x9 {4 ]- {
  1. int main(void)% G$ `+ L! S( ^! e
  2. {  r( H* y4 L) i# |
  3.     int count = 1;& s# ~9 Q7 ^, d  k2 k  w* c
  4.     /* set LED0 pin mode to output */
    5 Y+ n5 J3 P' @% [2 c4 C- ~
  5.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    8 A. j7 b# w& n3 {' ^5 b4 l
  6. " Y- C$ }& s- c
  7.     char *test_ptr;
    , y+ T8 a; B  K( m9 p4 C
  8. ) y' f4 @: Y/ R5 s
  9.     while (count++)2 b( O7 i, C& G# L" ~
  10.     {
    8 y6 i/ ?4 V; K0 d/ V
  11.         test_ptr = axi_sram_malloc(100);
    + T3 m$ Y' x1 x8 c. _! s, }
  12.         rt_pin_write(LED0_PIN, PIN_HIGH);
    + [/ j' `/ I+ ?0 M; I7 n3 i
  13.         rt_thread_mdelay(500);
    , c+ y- g/ |4 ]5 R
  14.         rt_pin_write(LED0_PIN, PIN_LOW);
    ( r9 l& h, m) ]+ W
  15.         rt_thread_mdelay(500);! {" f( x  L9 _) [9 V8 p
  16.         axi_sram_free(test_ptr);9 g1 [9 O" B+ G$ k4 D6 M$ O
  17.     }* k6 A$ |$ s9 c0 {, n+ T- @) K
  18.     return RT_EOK;) \2 {; [- v5 p( g2 V
  19. }
复制代码
9 v% U( d" \# l! U3 c4 [2 Z1 T
编译一下
( }4 y4 ^2 v2 x
  1. Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060  
    , Y$ {1 c' y. B5 H# u8 P$ H
  2. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin. c1 a7 Q/ ]; l  @
  3. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).0 D  D  J5 ~$ c$ [5 `: |6 T
  4. Build Time Elapsed:  00:00:08
复制代码

3 j/ |+ m2 }, H, l没有错误,没有警告,下载正常运行。) f$ x- B) l* j" N0 M8 _) o

, a+ r* ^3 R9 g9 e3 @$ ^1 I0 M" e2,AXI SRAM区域作为主heap
  f! }- T8 M% m5 o0 w+ ^4 EAXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快5 }7 D7 K) U) \; w

& y( S& Y# y" y/ L. g- D
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.   ; *************************************************************
    8 Z' q* z* W! ?$ q
  2. ; *** Scatter-Loading Description File generated by uVision ***
    + c. Y2 a& Z2 d( h5 A9 c1 r8 T4 u% |
  3. ; *************************************************************, e! d' e5 v8 [+ `, G- [

  4. 8 O$ H* n- R0 @7 U+ }9 P
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
    ' ~. W' `" z/ q8 T
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
    / |" a/ F9 d- U' p1 D, f( X
  7.    *.o (RESET, +First)
    - j  r5 y, t. }8 Q4 D. E
  8.    *(InRoot$Sections)* t" `7 d4 i( V
  9.    .ANY (+RO), @/ C1 W. Z9 K9 t; `& d
  10.   }
    " D" P( G+ |& ^2 @' p+ T
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data( {/ L. ~8 i, D# e4 \
  12.    .ANY (+RW +ZI)2 H# p) m! |8 R+ y' O$ N
  13.   }
    / M! X1 @% V3 J
  14.   RW_IRAM_HEAP 0x24000000 0x00080000  {  ; RW data
    5 _5 I, [6 t0 k( i. A# B
  15.    *(.RAM_HEAP)# X; L3 L! m6 p" _
  16.   }5 q# G* }% m. R
  17. }
复制代码
  1. 第二步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (128)  I7 a  |6 L" B* N
  2. #define STM32_SRAM_END            (0x20000000 + STM32_SRAM_SIZE * 1024): w* \6 U( r, t" c" ~0 ^/ k

  3. : }9 m* m7 t/ m  b- A' K! i
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)
    , k6 p" U% Q8 _( U6 ]5 f" ]
  5. extern int Image$RW_IRAM1$ZI$Limit;
    - Z0 Z+ _! v" G; U7 Z6 G1 u
  6. #define HEAP_BEGIN      (&Image$RW_IRAM1$ZI$Limit)
    ! J) g+ Q" Y- f- N; x5 Q, l6 I
  7. #elif __ICCARM__
    9 |9 r$ T* {+ i+ j. @7 j. C
  8. #pragma section="CSTACK"
    $ k) ?$ v% \8 [
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))# ~% C9 q9 r) @8 c; @2 K) n
  10. #else; l- R: E/ p6 C! P0 ^
  11. extern int __bss_end;
    4 q; ]/ x* U$ H% d
  12. #define HEAP_BEGIN      (&__bss_end)
    ' h6 ^' p, l: {/ i/ ^5 D
  13. #
复制代码
  1. 第三步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (512)1 h3 q; J& X) B4 u1 O
  2. #define STM32_SRAM_END            (0x24000000 + STM32_SRAM_SIZE * 1024)
    1 E- ]; Q7 k! }1 N0 e! Q1 O) ~

  3. * v/ _/ p  n6 L$ g! K/ L3 O" v
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)
    + ]% D/ `" I; B8 k6 E8 G
  5. //extern int Image$RW_IRAM2$ZI$Limit;
    : _9 Z( _/ g) t7 k" T4 x
  6. #define HEAP_BEGIN      0x24000000//(&Image$RW_IRAM1$ZI$Limit)
    4 G' Q, C" i7 ?
  7. #elif __ICCARM__6 U, N; a0 Z- c- \  l; u' M' E7 P8 Z" I
  8. #pragma section="CSTACK"
    7 k  ~% Q6 K1 J% U4 ?0 \) o! D
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))9 D+ h5 B, i8 G4 k
  10. #else7 K- h0 _$ G& a7 @
  11. extern int __bss_end;( V: R5 i" ~$ J& B. L
  12. #define HEAP_BEGIN      (&__bss_end)8 B9 N, W+ R& c8 F! B
  13. #endif
复制代码
设置heap的起始区域是0x24000000区域的512k大小。
: V5 T2 v' {) g* p' {修改完毕看一下,来测试一下) L2 ?& i; _; }* Q) F4 T

& I7 ?' ^" O) ^1 w. `0 y9 R; T
  1. #define LED0_PIN    GET_PIN(B, 10)8 |: B6 u+ p) b. r
  2.     uint8_t test_buff[1000]= {0};2 b/ G# r0 h/ `) F4 v- c
  3. int main(void)2 _8 f5 \/ w! n, w2 l5 P, l
  4. {   9 v( F+ a: v* x9 I! Y* h
  5.     int count = 1;6 m* e' K) B& u( j8 F% W3 u# I
  6.     /* set LED0 pin mode to output */
    3 i8 Z; R  q1 d3 g* ~  D& e& ~. a
  7.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);* ?; Y8 r% s; _
  8. ( }, E' U' ^* B) F& I. o/ |6 \5 y
  9.     char *test_ptr;
    , ]. Z; W/ l. J* B
  10.     test_buff[10] = 1;
    . @, R# J' d- g
  11.     while (count++)
    + U% Z# B* F& I. N5 d" M
  12.     {
    1 s  J1 A' y2 K3 X! r+ |, Q# Z
  13.         test_ptr = rt_malloc(100);
    : ]# ~- y5 b4 [7 A7 G) h  ^: \  p
  14.         rt_pin_write(LED0_PIN, PIN_HIGH);, |- l0 h3 J8 X# z, k8 Z
  15.         rt_thread_mdelay(500);' T4 ^) k) H* u+ j" w  \
  16.         rt_pin_write(LED0_PIN, PIN_LOW);, d4 \1 V; Q) S( i% f4 A
  17.         rt_thread_mdelay(500);
    ; O: \! M4 W( w! U: c
  18.         rt_free(test_ptr);
    ! }$ L' h7 w0 h
  19.     }$ L" {8 T; Z  u2 M8 Q
  20.     return RT_EOK;
    ' B5 Q. S5 y+ J% m
  21. }
复制代码
* z+ S' b% g! l" {1 Y4 r" o% g$ z
编译一下/ r& b4 T( S7 L6 _. U6 J4 t7 r
  1. Build started: Project: project
    ) D  Q( q! Y: L8 {8 b
  2. *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'+ M* K' ~# t- R4 A9 v
  3. Build target 'rtthread'( A& N( m0 B& G: N) p9 \' u+ p
  4. compiling main.c...3 U! y8 C8 v- {! c2 V5 s5 b
  5. linking...
    3 n# w0 \" f+ m
  6. .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).7 S! c1 }9 @  q. n
  7. Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964  
    : O5 o6 X  _& @. t
  8. Finished: 0 information, 1 warning and 0 error messages.
    ) S/ p% r- _6 l4 i3 w# K
  9. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
    : O1 J' N/ J4 I4 O; c+ ^3 I/ n" g
  10. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).  H: G# N( B; R& @/ o
  11. Build Time Elapsed:  00:00:02
复制代码
4 k$ D7 M5 L7 t2 F
有一处警告 不要紧,查看一下map文件
0 ]+ g: S: y) M5 o( p$ i6 k" Y2 f
20200219233304754.jpg

5 o) E9 n: l0 z& w, b9 Y6 |6 z
! l' X3 L) N  N7 M2 F. |9 J9 N9 x可以看到定义的test_buff是在地址0x20000898的位置。
4 ]- c3 {7 ~0 g- |1 N
" m9 S. V9 L, d: M# c5 E% g' X: E三 总结分析3 E9 Q, W  m$ \  ?7 i( L4 P- H+ k1 F
实验成功
% @7 b$ a2 D" q
( @8 Q) O1 O2 M7 YTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
) |0 j# I' c2 N7 E, G7 Y! y8 k7 u( m
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
0 L8 [# o! `* M9 M6 ~  W
# _: X3 Y  P' v" @5 S; G* L4 E6 Y0 w. B% B+ }9 x5 {- \/ h, q
7 u9 ~; ?: {. z( z. {- M% h* |
收藏 评论0 发布时间:2021-12-27 18:00

举报

0个回答

所属标签

相似分享

官网相关资源

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