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

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

[复制链接]
STMCU小助手 发布时间:2021-12-27 18:00
一,STM32H7 RAM介绍
9 E) D0 h  f' L0 e使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示6 s2 w- h- c- {, R" \& P# p
2020021922201274.jpg

! D  M# b& p, y, L% `7 L/ n
: e  p" {  q- l: d6 \2 w
20200219221709559.jpg

# `, }4 A; }2 c2 a' ~: W  S; H+ u( D# _% i9 H7 c+ g) B' U2 L
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。
! {3 ~6 y- k9 ^% v: U3 ?6 ]+ \) r7 t" U) R0 r
20200219224822144.jpg

4 ]# @4 u( Y* R" M0 {2 i2 A! _9 J# s5 K: x' g7 k$ ]
既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。
# `. O8 M" I5 Z" W: b
7 D* y" m- ^" R# B! a2 w二 多RAM管理办法8 Z8 Q$ Z- [, |. z/ @  |; t
STM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。' N0 g: l# y. O
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap, {. A4 ~( S$ A2 G
% U% u2 ]( l2 M# Z6 s
20200219230749268.jpg
9 J+ C! b1 d, Y) j$ e+ V3 I

8 V; [' ?* w  |2 b" \/ T) r" H之后重新生成工程。
6 B0 l8 g. \6 \) J7 A% s5 N& m
; U7 S3 o) ~2 ]2 a8 k# g1,TCM区域做为主heap
! t0 S+ p- G1 o7 I/ W0 F" {TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问
0 Z% O# z9 k  v0 S
- K, S: M/ b% n2 h; p# t
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.       ; *************************************************************
    , e. @* w* i) S) L! \; J
  2. ; *** Scatter-Loading Description File generated by uVision ***+ ~5 W, H% J0 }; [9 J
  3. ; *************************************************************
    3 N" e7 G/ \  A9 x3 T+ X! h/ H

  4. 0 m" B7 L: i$ {" w. I* I
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region4 z( P% N* b6 r$ \
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
    % g6 l- v$ _( d& F
  7.    *.o (RESET, +First); C) M% y# `/ H/ J3 G
  8.    *(InRoot$Sections)# y8 c. b0 K: \0 J4 E' z0 s3 `
  9.    .ANY (+RO)) _: Q( b* N9 H9 A  o$ K# ~3 q, J$ ]
  10.   }1 X5 ]# `0 u+ }1 @1 p3 s
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data
    $ T0 E$ S$ o* u  a9 O" C8 S8 ^  a
  12.    .ANY (+RW +ZI)5 }1 z' e0 Q+ ]# p) o  j
  13.   }5 b1 v& h9 R2 A. p& w
  14. }
复制代码
  1. 第三步 写一个axi_sram.c
复制代码
  1. struct rt_memheap axi_sram_heap;3 q* P8 K6 S( J  t/ E
  2. void *axi_sram_malloc(unsigned long size)/ W, [: {* [) ~. G8 j! P9 Q
  3. {/ ~8 e% T; j6 r1 F3 T
  4.     return rt_memheap_alloc(&axi_sram_heap,size);/ a( ]+ A! a! y1 a5 s9 g- F' q4 T
  5. }- k( y6 ?# H) d' X9 j4 @, L
  6. % A) ?5 y6 o$ l3 J
  7. void axi_sram_free(void *ptr)
    " M9 S/ j# _* @- Z2 q
  8. {
    0 e/ k/ S" K. m1 ~+ J* J
  9.     rt_memheap_free(ptr);
    9 M6 ], U- e5 j0 `3 _8 B# F+ ^
  10. }! U! ^" h, j% e# v1 D; A! ]

  11. & Z0 y/ [) s3 Q; a/ {8 H3 K
  12. void *axi_sram_calloc(unsigned int n,unsigned int size)
    $ n( Y+ h3 R! Q, R% z/ C# u" G. P& F
  13. {; u0 e: p5 }& k
  14.     void* ptr = NULL;) H2 E  c7 u/ H" |$ ~4 J4 F0 a
  15. / y- v9 o9 G. O5 d9 J! w
  16.     ptr = axi_sram_malloc(n * size);+ G/ g: r7 W7 i2 {% T' U
  17.     if(ptr)
    : N4 m" R; m0 i2 \# r
  18.     {
    5 X2 A* f3 c) N0 T
  19.         memset(ptr, 0, n*size);
    ! J3 i9 [: `% G& H
  20.     }% a. @. M; S5 y, U; ?

  21. ( _  i) U! @; U1 ^( c+ v, Y3 Z, T
  22.     return ptr;
    6 v: V' z- K8 F: U
  23. }
复制代码
  1. 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
复制代码
  1.   #if defined(RT_USING_HEAP)
    9 f4 |! i: F; ?9 i
  2.     rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);/ O2 _' }7 e" |' N/ r1 k1 j
  3. #endif; a. A: j, i. Q4 @9 _$ |) l
  4. " K+ I! f( z/ N6 B5 _+ j
  5.     rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);   
复制代码
编写一个测试代码% K' K& O7 E! i7 ~

, Q8 Z) H2 M8 M) |! P" Q+ X
  1. int main(void)
    8 G* H. o9 J* M8 M9 G, M# o
  2. {
    3 p% p( _" p, P
  3.     int count = 1;- v/ [$ i- Y1 l2 V0 q2 A. R. g1 s$ _
  4.     /* set LED0 pin mode to output */. c" Z- H2 L. o) U, V
  5.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);% S0 ?. h/ B) ]! _% k$ n

  6. % A- i2 L9 X7 b; q1 I9 u/ ~& f6 r
  7.     char *test_ptr;
    . p; C7 W$ _5 D' }

  8. 3 E2 S. W: h- ~# k2 z
  9.     while (count++)
    - x5 U2 F: o6 e- @. Z4 `: |
  10.     {( @4 y( V2 x0 u3 r1 Q
  11.         test_ptr = axi_sram_malloc(100);5 e5 p0 `6 n, t
  12.         rt_pin_write(LED0_PIN, PIN_HIGH);4 t+ H- K0 a5 e* x& c- F8 _
  13.         rt_thread_mdelay(500);
    ' d! K' t) L- _% Q% p" ^
  14.         rt_pin_write(LED0_PIN, PIN_LOW);$ x4 S" V$ E3 X* t2 H" j* t
  15.         rt_thread_mdelay(500);- k$ f* R) U' p: d) h
  16.         axi_sram_free(test_ptr);
    , m$ f( q. _( `4 M$ a. r
  17.     }# N# h. A$ U8 Q! s: f# c4 ^, X
  18.     return RT_EOK;
    . l/ j; j7 q; H( J
  19. }
复制代码

; |0 I( ?& w' z+ y" \编译一下3 t. i5 y$ N, r4 J
  1. Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060  
    8 ^1 L% H  {4 X( J
  2. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
    5 B" J. {2 e" a6 v
  3. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).* d8 }) v! ?5 d. X
  4. Build Time Elapsed:  00:00:08
复制代码
4 f! _' H! o$ `5 r: u- Y- A1 u
没有错误,没有警告,下载正常运行。
7 y( Z8 g8 Y' ?4 z! ]
# i, m# ]% T( ~2,AXI SRAM区域作为主heap8 A$ i- u4 m2 e7 G0 e  |: p9 D
AXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快
) W: |3 v% G' V/ p8 v4 \3 X/ i* `0 P, Q& h: z: s$ B
  1.   第一步 修改keil连接文件link.sct  
复制代码
  1.   ; *************************************************************
    - X# d+ @; [4 c+ k0 p, H9 a# \
  2. ; *** Scatter-Loading Description File generated by uVision ***' u2 n+ R( H4 r' K7 y
  3. ; *************************************************************9 }4 `, n" Y1 t4 A! F

  4. ; \. o+ N# s  S5 j3 G
  5. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region" f) l' M) X9 Y
  6.   ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
    : L% J+ [+ x/ H8 m
  7.    *.o (RESET, +First)  W1 X& W1 a) E. i9 n9 ~
  8.    *(InRoot$Sections)
    : ]1 p) f# r- O; J8 w( @
  9.    .ANY (+RO)
    6 R  P1 P4 z+ n- x6 ?
  10.   }
    - y6 i" M; T' g2 h/ }6 r
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data; F" O; Z, l- R, P* Y  Q. |& q
  12.    .ANY (+RW +ZI)( J" R) |, b& Z2 O$ q0 t/ W) s
  13.   }
    0 h3 ~' y# `" w7 t
  14.   RW_IRAM_HEAP 0x24000000 0x00080000  {  ; RW data# R/ N, h! y( n% {4 C7 U
  15.    *(.RAM_HEAP)
    $ i1 [3 n9 Z) Q2 C
  16.   }
    1 _( r) k0 v. e4 S: W5 M
  17. }
复制代码
  1. 第二步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (128)" ~+ h. b; J& u# @( |% t- m
  2. #define STM32_SRAM_END            (0x20000000 + STM32_SRAM_SIZE * 1024)# P8 D* r% S3 V

  3. - p9 b! W7 a' k1 @) G/ Q9 `
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)
    : i0 B, u: N3 q" f1 O
  5. extern int Image$RW_IRAM1$ZI$Limit;0 b' I& k0 D' V! T! Y. F" Z
  6. #define HEAP_BEGIN      (&Image$RW_IRAM1$ZI$Limit)
    ; x0 ]& N$ D, K7 B+ G. C2 k! x/ V9 j
  7. #elif __ICCARM__/ {) ^$ T$ n8 F8 x6 {# K2 u
  8. #pragma section="CSTACK"
    ) ~6 V* l) {; w5 [+ E5 T) z/ j
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))
    " d! l4 G3 r9 G2 \) A  ?! G1 X
  10. #else
    . b% w4 W$ O, g  r0 D/ H9 u. }: `
  11. extern int __bss_end;( Z0 V1 g8 W9 g9 w
  12. #define HEAP_BEGIN      (&__bss_end)
    7 r" \5 x& X. k) V- J' ~4 ~
  13. #
复制代码
  1. 第三步 修改board.h
复制代码
  1. #define STM32_SRAM_SIZE           (512)/ R+ X' _8 u  Q( n$ M1 N6 ?$ N
  2. #define STM32_SRAM_END            (0x24000000 + STM32_SRAM_SIZE * 1024): ]1 D! j' L; J# k0 v8 a9 Y# t
  3. 5 F% q* `* O5 f8 x5 `2 X
  4. #if defined(__CC_ARM) || defined(__CLANG_ARM)( H; ~% F1 m# \2 {
  5. //extern int Image$RW_IRAM2$ZI$Limit;
    ; c0 r& z, D6 @  V9 r# B
  6. #define HEAP_BEGIN      0x24000000//(&Image$RW_IRAM1$ZI$Limit)5 Z- Z. h  S" ~5 ]
  7. #elif __ICCARM__
    / X* h' E  I  Q5 Y1 \  {6 s3 ]
  8. #pragma section="CSTACK"
    9 M' s. ]) o! ^. c6 E
  9. #define HEAP_BEGIN      (__segment_end("CSTACK"))- w! T6 ~; ~: e2 R3 `
  10. #else
    0 V( b& B1 H  R; K+ `7 ]' f
  11. extern int __bss_end;
    3 ?" t! s7 Z4 V% Q# U1 h' l, z5 |& b0 S5 t
  12. #define HEAP_BEGIN      (&__bss_end)
      Y" |: o9 u2 b2 Q8 A, {5 a% }
  13. #endif
复制代码
设置heap的起始区域是0x24000000区域的512k大小。
7 l' m* n* |# ]" _, P1 p- x修改完毕看一下,来测试一下
3 R( U! l$ s# k$ V: r1 R; R- y7 v" |  C
  1. #define LED0_PIN    GET_PIN(B, 10)
    3 g& ^- O1 v5 r' ?% n7 H) V
  2.     uint8_t test_buff[1000]= {0};
    ' Q' [5 J. Q- n
  3. int main(void)
    . U; N" e% L$ ]* Z0 x
  4. {   
    , O) w- f2 L" V9 \" Q  N
  5.     int count = 1;
    $ F$ i5 P' b/ L( ]! _! I
  6.     /* set LED0 pin mode to output */
    ! e/ k0 l: t/ Z% g- B+ ?' M
  7.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    ; o8 S0 T  Z1 p$ Z5 p
  8. ' A! Y& P' D5 L' U1 d
  9.     char *test_ptr;
    # I9 T" o3 j0 J9 }7 g
  10.     test_buff[10] = 1; ' Z8 }' e8 V: `* D+ ~3 @# H, c
  11.     while (count++)$ [4 A, Z/ L) Q1 R# z. d
  12.     {
    & T* J* f6 u# j0 ^( y- \( I
  13.         test_ptr = rt_malloc(100);
    ' T9 w. l4 w& c4 X' L
  14.         rt_pin_write(LED0_PIN, PIN_HIGH);
    ( y) {) J0 r& |. w6 x( @) o8 o
  15.         rt_thread_mdelay(500);
    : y9 K- O& k; ]" {
  16.         rt_pin_write(LED0_PIN, PIN_LOW);) k3 n1 O8 p! I4 q3 n
  17.         rt_thread_mdelay(500);
    - h9 y$ y+ B' v& u
  18.         rt_free(test_ptr);
    + e, f% A' E8 J/ F+ v2 W: f5 a
  19.     }
    1 Y% T/ ]: `7 Q5 q- N
  20.     return RT_EOK;
    4 S+ g6 P3 [! z9 m6 w7 J0 g
  21. }
复制代码

% x$ Q2 p( ]8 a' d! ~编译一下+ u' n# M' L' V$ A  [% f. x
  1. Build started: Project: project
    5 b4 q$ q8 @% p5 i
  2. *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
    , g0 K, s& X# [3 \. L- i9 T1 Z$ K
  3. Build target 'rtthread'
    $ b9 T9 `5 w) Q" z  Y, O
  4. compiling main.c...
    3 a  [# G  n' P
  5. linking...- ?& R/ F! t& P. ]1 C1 K
  6. .\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).$ X* U- y4 V  m! P/ f2 g2 w: x
  7. Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964  
    . Z* i8 y1 M1 S- m. L
  8. Finished: 0 information, 1 warning and 0 error messages.7 n( q; k/ x9 e! u. Q
  9. After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin6 i; M# F4 b& m. |" f/ [
  10. ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).' N9 p5 f$ @; Y6 W* C5 a$ P" P& K2 n
  11. Build Time Elapsed:  00:00:02
复制代码
- P7 b) @- D9 f) Q
有一处警告 不要紧,查看一下map文件) J5 q2 s: I& _) b/ {3 Z# j" `

. @* `, B# s8 I* q
20200219233304754.jpg

: Z) U$ x& ]6 L% |# R
& [; D/ I$ J" J* W( c# j& F8 k# R可以看到定义的test_buff是在地址0x20000898的位置。5 h, Q/ s4 ?% [% [$ K
: E9 E$ Y9 Y" v8 F- Q$ h
三 总结分析, ?: r% {4 S- p% M
实验成功
7 s9 L$ n3 u: T3 h( \4 P% R& r' g9 W( B3 i8 J
TCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。
2 F" @* W0 H: Y( `7 {2 ]; Z' A& u! O7 S7 @- }9 {6 l
AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。
1 y# w, A! K4 H) j+ g
2 k. P# R: }; V0 Y2 F7 s- B% L9 \$ y) b( W# V4 [
6 g5 n2 |' j4 o6 s$ ~4 i+ |; \3 B4 m
收藏 评论0 发布时间:2021-12-27 18:00

举报

0个回答

所属标签

相似分享

官网相关资源

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