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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 18:00
一,STM32H7 RAM介绍
& p" S- N- b& A' C9 V# ~使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
7 g  ]! U+ E& |/ R! f. Y7 k
2020021922201274.jpg
/ N- a# _  W0 D% Z6 b5 _# Z/ U
2 v" E$ W5 R8 e$ f+ O- W% k
20200219221709559.jpg
  X  J! c/ G0 o5 M% N0 r
2 {& P: S4 y- @* e
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。0 F4 R/ B, `* X9 s8 q; \
% r3 \' n& W! O1 r
20200219224822144.jpg
$ T1 N  f- w' ]4 C- B

' P. K+ A" h1 _& ^4 U既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。2 _% `  n. W9 |, _+ D
, K& \. B$ X% g3 p
二 多RAM管理办法! t# H; a: c# ]1 O! G3 F/ w
STM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。4 Z  Z8 c8 R; J6 g
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap
6 W0 ~7 I" w1 Z! G: a" \" N' F, \; v# |6 p, T; K0 s! D+ N4 w  L, M1 t
20200219230749268.jpg
4 h) c. @7 y0 K+ [

( {. m$ C* P/ T" J! ?1 I2 w3 L之后重新生成工程。+ B/ N  L. i. \

7 P) B7 e2 j( r4 \2 E1,TCM区域做为主heap
) Z' J+ ^+ z* ]( l6 _TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问' h( |: z- W! U- g3 J. [! S; v
0 t/ n) s) h. v  @6 F1 r+ }- ^! E
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.       ; *************************************************************
    8 n  C4 I0 z& [0 ]7 ~
  2. ; *** Scatter-Loading Description File generated by uVision ***+ {' _/ T$ N& z% t& s7 ~
  3. ; *************************************************************
    . Y% q% D4 v* B' b' G, g
  4. : h/ A# N, M# C- k/ G9 Q$ \
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
      Z. u$ J7 |  T. M3 B
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
    3 @0 S5 I( J, S2 t  W9 s; J0 c6 ^
  7.    *.o (RESET, +First)! K5 g( G0 f8 e
  8.    *(InRoot$Sections)
    " ]) Q% P' O/ m2 u+ l$ J, q
  9.    .ANY (+RO)
    3 n) Y. Q% ?1 l
  10.   }
    8 Z6 J; {4 ?  C1 U. d
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data* }4 l( O% Q* {
  12.    .ANY (+RW +ZI)3 ]& o# K; E/ r- {( G
  13.   }
    & e, m7 ~& V+ s3 i8 W
  14. }
复制代码
  1. 第三步 写一个axi_sram.c
复制代码
  1. struct rt_memheap axi_sram_heap;
    6 \3 m- l" }, y/ |
  2. void *axi_sram_malloc(unsigned long size), j7 U5 j/ v/ [$ ?  U  c! [/ B
  3. {
    0 e, G! r7 t7 q6 P7 s  y
  4.     return rt_memheap_alloc(&axi_sram_heap,size);* b  A" y1 |- X4 z( |/ b$ B. l
  5. }1 o2 Y9 `* h* z( l0 t
  6. ! [9 d, s& I1 o* W6 _: Z, Z! i
  7. void axi_sram_free(void *ptr): C5 ]' |& j+ p( [( ]
  8. {7 l5 z- d: b" G. t4 _! R
  9.     rt_memheap_free(ptr);
    ) I6 d1 c4 O& H  W$ h9 C* n
  10. }0 U, T& ~: [* W) H

  11. . P  {9 J' I7 g$ i6 x
  12. void *axi_sram_calloc(unsigned int n,unsigned int size)8 d+ Q7 x) A, U) R) w; M8 A
  13. {: y4 P4 G/ k% g
  14.     void* ptr = NULL;
    , G5 T: L5 @/ `& x

  15. # X# v/ n+ A  T+ H# V% i
  16.     ptr = axi_sram_malloc(n * size);- q8 @" m9 H) a3 E* \
  17.     if(ptr)6 v2 o7 o! [$ I/ E
  18.     {
    8 S% W; J' @* h; s5 }$ a, N
  19.         memset(ptr, 0, n*size);. f6 Q: M3 x& @% w, B
  20.     }4 J8 M* X- s/ Z' d* ]) O
  21. 6 y: O% x* H: O% P5 S
  22.     return ptr;
    8 l- I; p2 h9 l% m' u. T* W
  23. }
复制代码
  1. 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码
  1.   #if defined(RT_USING_HEAP)
    ' o8 t5 ?% O1 F2 Y
  2.     rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
    . M. O' i. D# ~8 m/ h
  3. #endif
    8 {8 y. }$ e$ F$ u
  4. ' d3 M: t/ \4 f1 z
  5.     rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);   
复制代码
编写一个测试代码
4 S  d% a6 }7 K. ^* v" r
( m5 u- C7 Y: U7 \
  1. int main(void)! ^9 J+ w& [  ?3 F8 y
  2. {
    + B4 T, q! S; t8 r- W. F( c" m
  3.     int count = 1;- L1 p7 i3 x5 d, H
  4.     /* set LED0 pin mode to output */
    6 G; v: j4 _" M
  5.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    # d- ~" n3 O; P, x: h* ~; P
  6. : u% g1 e2 u/ t: R. ?" \% a! g: T, n
  7.     char *test_ptr;3 \: h& B3 u" f0 t% t  X0 n% A
  8. # q! d% y" k8 U+ J  P3 q* c
  9.     while (count++)
      @9 u5 h! P* Q; w( ], P( u
  10.     {
    " X& V6 G; H2 T
  11.         test_ptr = axi_sram_malloc(100);" O9 F1 R; y& B1 Q+ E8 C
  12.         rt_pin_write(LED0_PIN, PIN_HIGH);
    1 p( C/ M4 q0 g; B4 v9 e' ~0 ~- o* c
  13.         rt_thread_mdelay(500);3 P7 W; i+ ~! b
  14.         rt_pin_write(LED0_PIN, PIN_LOW);6 d$ R0 G1 B6 f4 ~. A; }
  15.         rt_thread_mdelay(500);
    * Q) y' }: M9 I9 k  R
  16.         axi_sram_free(test_ptr);
    8 h: \" |9 k1 l# ^, ^! D( w
  17.     }# R5 u- Y+ M& x7 ^0 k
  18.     return RT_EOK;  ^* k0 K0 F: ?4 g3 o7 P+ d2 @
  19. }
复制代码
% Q" N% A* S6 _0 f' \
编译一下  t) |' V1 X1 Y6 [
  1. Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060  8 j9 U" m+ s: }! A7 Q) y1 l
  2. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin) e$ t: z2 y- F( J
  3. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).7 T) k  C( Q2 ~. F! h( s+ [% n
  4. Build Time Elapsed:  00:00:08
复制代码
# \) V1 r* l8 n
没有错误,没有警告,下载正常运行。
& q; u8 ]/ o, s
$ k9 y3 q9 p& t4 ?2 p4 X7 J2,AXI SRAM区域作为主heap
8 n8 o9 t  K4 U* p. bAXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快
! y; ^4 q  T; r6 ^5 W4 Q7 g, A, ?1 P6 P7 I
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.   ; *************************************************************0 S7 [. U5 v6 Q3 q' b& Z, ]. X
  2. ; *** Scatter-Loading Description File generated by uVision ***/ z# l0 |. S4 X5 |1 o
  3. ; *************************************************************% A* C) m; @1 K7 G4 z0 v

  4. 0 s/ E/ `# ]" y) x6 X- k4 k
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
    ) a( O, B2 f: k6 j- c& w
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address& b5 @$ d* _: n$ p' x
  7.    *.o (RESET, +First)+ r9 ?; z0 s% X3 v2 y6 y
  8.    *(InRoot$Sections)
    % b) a4 ~) R# |+ F
  9.    .ANY (+RO)
    % }% |4 c% {) D, Q
  10.   }0 w! K1 ?0 T" R4 e
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data1 g; t" e5 S. I4 @  G9 M% x
  12.    .ANY (+RW +ZI)( ?8 \1 O8 h6 f
  13.   }7 Y# V! ]5 N; M& E6 \6 p" f( ?9 W0 H
  14.   RW_IRAM_HEAP 0x24000000 0x00080000  {  ; RW data- f! d$ Q. s& V( ~! n3 M
  15.    *(.RAM_HEAP)+ v7 x. ^6 Q! p4 C4 m: S. q
  16.   }
    $ P) E- n  q1 l# ?
  17. }
复制代码
  1. 第二步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (128)
    1 x+ M% O* N; P
  2. #define STM32_SRAM_END            (0x20000000 + STM32_SRAM_SIZE * 1024)& L4 G) Q( |& s! Y1 ?4 q
  3. 4 Z- n# y3 l% G% `
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM), @0 s( A. Y1 s
  5. extern int Image$RW_IRAM1$ZI$Limit;
    8 C) K9 u  g" N& d  o  K5 U8 v
  6. #define HEAP_BEGIN      (&Image$RW_IRAM1$ZI$Limit)
    / u+ {2 A/ Y/ Z
  7. #elif __ICCARM__
    9 O, n5 I2 ]; \1 T: B8 [( J* h6 E
  8. #pragma section="CSTACK"
    ; V7 j1 r. d7 o# x- n' @
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))6 N/ ]1 c$ T/ r( O" O
  10. #else: G4 N9 y: B' H* G
  11. extern int __bss_end;2 a5 D& {* c& v1 d( l# ?$ ~
  12. #define HEAP_BEGIN      (&__bss_end)- y: ^& s! s" H6 f5 M. [  g- t: q
  13. #
复制代码
  1. 第三步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (512): D* i0 e$ @# F- m) J' ]
  2. #define STM32_SRAM_END            (0x24000000 + STM32_SRAM_SIZE * 1024)
    9 W4 ]- Y, P% V8 D9 f
  3. 3 H" E6 F) z" [! h. ?
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)/ ~2 k5 R2 ~9 c* }- O5 X  q2 M
  5. //extern int Image$RW_IRAM2$ZI$Limit;
    $ m8 @: O8 ~1 ^) R9 d
  6. #define HEAP_BEGIN      0x24000000//(&Image$RW_IRAM1$ZI$Limit)
    5 }. |! `# I, L8 b7 H) Q5 C6 P
  7. #elif __ICCARM__: n# s5 u2 g$ W6 J4 M* w0 t9 x
  8. #pragma section="CSTACK"9 _/ A( v  M7 \3 F* h$ q# O
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))! S) e. S1 d; [
  10. #else# n6 G2 u6 Z! A  j
  11. extern int __bss_end;
    4 S( @( B* q, i( r
  12. #define HEAP_BEGIN      (&__bss_end)
    7 P7 @0 L& e8 E3 A" G
  13. #endif
复制代码
设置heap的起始区域是0x24000000区域的512k大小。
/ S9 o1 N& K6 g修改完毕看一下,来测试一下8 e" C/ g. }1 F
0 s" C5 }' N# W7 x' b$ G3 w
  1. #define LED0_PIN    GET_PIN(B, 10)$ L4 b; y0 }- f+ j9 `. C8 {
  2.     uint8_t test_buff[1000]= {0};7 K# p5 V! a2 H2 r1 _
  3. int main(void)
      m) S  [5 _. E& q% y6 C4 S6 T) o
  4. {   
    7 v/ r# z# l; G6 v* I+ ?
  5.     int count = 1;
    - i% Q3 o' c: N& L7 ?4 x
  6.     /* set LED0 pin mode to output */
    ' r" q; J( H2 T' T. J
  7.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);$ X1 G- T2 r" [+ i
  8. ! L, [- t& o# V; d% y! h: ?
  9.     char *test_ptr;
    ) h1 h; m" H, Y) |4 O6 `' t" q
  10.     test_buff[10] = 1;
    0 P9 x% o* g' J; ^
  11.     while (count++)
    . o  r9 Y/ B  v/ F1 V
  12.     {
    9 D7 T8 ~6 h- L3 {8 K) U
  13.         test_ptr = rt_malloc(100);
    / G; g. g8 I. n! t& M: k" R
  14.         rt_pin_write(LED0_PIN, PIN_HIGH);
    * p' I& y3 d7 S% B
  15.         rt_thread_mdelay(500);# A2 I0 j/ @2 d8 \+ b4 d8 q
  16.         rt_pin_write(LED0_PIN, PIN_LOW);
    9 L: K& P8 p  k3 r, p
  17.         rt_thread_mdelay(500);- g/ X& X7 n  ]# y
  18.         rt_free(test_ptr);
    , Z  [2 _  a, X! C) @: p2 v4 \
  19.     }5 I; f6 t- k* h  N
  20.     return RT_EOK;
    0 Y# o( U9 d% I3 z
  21. }
复制代码
+ y2 h2 l' f' G7 V/ }
编译一下
" N4 B' ~6 n! J
  1. Build started: Project: project" t" @( V* Z0 P. `6 T+ y; t
  2. *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
    " A8 P  {$ R- Z6 w" U) L
  3. Build target 'rtthread'
    , {# d; }* _4 U$ d9 w- n. b3 @% ?
  4. compiling main.c...! J* g4 n" U9 _* ~% v
  5. linking...: @! i! I" l: x) r; G  M
  6. .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).1 _8 R" _7 x$ X& F- B' O" G
  7. Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964  % P, _- J9 A  L# L: q% X+ Q: W. x) W8 g
  8. Finished: 0 information, 1 warning and 0 error messages.( i  v2 V$ @7 V& d
  9. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin8 N: W# v8 y. q1 S; M; N
  10. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).
    : k# K" n% {- u1 O" V1 U- j
  11. Build Time Elapsed:  00:00:02
复制代码
/ B$ F/ |' p% [9 p% X
有一处警告 不要紧,查看一下map文件/ B& I1 N# i+ a; Q$ H1 c

. s) y" D3 e3 @2 {: G' J( `
20200219233304754.jpg

0 i) B; w' Y5 G) o1 C) `
) Y( E: z/ X( A5 `, o/ z  Y, E4 E可以看到定义的test_buff是在地址0x20000898的位置。
+ a* D% L' ^+ \, n/ M
7 H  ^- g7 p2 o" w) h. c3 i三 总结分析
1 {- Q7 ^* [( A& c实验成功
  h% s* V& C( J4 {$ M
: {2 `5 k& V* O- W! jTCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
0 i5 L, r. {5 e2 \: s; d7 p) x$ W! f8 {& f: O/ i- i
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
/ i. i0 v9 Y2 A
9 ]3 j9 ?0 w, V6 E
; y- G" j( R& v6 ~# ]) [. N! V6 L  x
1 o3 \, i5 w" f. y/ }; V
收藏 评论0 发布时间:2021-12-27 18:00

举报

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