[应用相关] stm32管理内存分配以及CCM的使用方法

[复制链接]
 楼主| 木木guainv 发表于 2025-7-9 22:12 | 显示全部楼层 |阅读模式
前言
本文以stm32f407VGT6为例描述,查阅该芯片的手册,可以知道其内存一共192K,但是在MDK编译项目时,有时候发现内存总量只有128k,原因在于,192k中有64k是CCM内存,剩下的128K才是正常的内存,所谓的CCM内存是cpu直接访问的空间,读写速度比其它内存快,但是不支持DMA,所以DMA对应的内存空间不能放在CCM中。

一、使用CCM
打开mdk项目options,target选项卡,右下角可以配置使用的内存空间,注意新版的cube自动生成的mdk项目,默认是不使用ccm的,所以默认配置下IRAM1和IRAM2都是128k的地址空间,首地址是0x20000000,只不过将128k划分为两段。

31497686c8d85a88e3.png

我们得手动修改才能激活使用CCM,首先将IRAM1大小改为0x20000,即整个128k空间,然后将IRAM2改为CCM的首地址0x10000000,大小为0x10000。

25561686c8d8b8575c.png

这样配置后,如果程序没有用到DMA,已经可以正常使用了。系统会自动将整个项目程序的data、bss等内容分配到IRAM1和IRAM2中。
但是如果程序中用到了DMA,就存在风险了,一旦DMA对应的内存被自动分配到了IRAM2 ccm中,运行就会出错。

二、手动管理内存分配
为了解决这个问题,我们需要手动分配内存块,首先,去掉linker里面的 use memory layout from Target Dialog,那么就取消了自动内存分配,我们需要手动加载自定义的sct文件,手动配置的sct文件可以放在任意路径下,linker里面 scatter file可以指定sct文件的路径。这里我自己的sct文件叫my.sct还是放在原来的sct文件目录下,即MDK-ARM\项目名称\my.sct。

60573686c8d944359c.png

sct文件功能很强大,能够以多种方法进行内存的配置,比如,直接指定某个c文件使用的内存地址空间,另外,在代码中申请内存空间的时候,还可以用__attribute__((at(内存地址)))或__attribute__((section(”段别名“)))这个后缀来直接指定内存地址或内存段别名,二者配合使用可以很方便的分配使用的内存。
打开my.sct,修改内容如下:


; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
   .ANY (ORIRAM)
  }
  RW_IRAM2 0x10000000 0x00010000  {
   startup_stm32f407xx.o(Heap)
   heap_4.o(+RW +ZI)
   .ANY(CCMRAM)
  }
}



这个配置的目标是分别将 startup_stm32f407xx.s中的Heap和 heap_4.c包含的所有数据放在了CCM IRAM2中,另外设置了一个段别名CCMRAM,凡是定义时指定了这个别名的数据,也会放入IRAM2中。同时在IRAM1中也设置了一个段别名ORIRAM,用来放置DMA使用的内存空间。其它data和bss数据都默认保存在IRAM1中( .ANY (+RW +ZI) )。

在程序main.c中,分别定义两个数组:

__align(32) uint8_t DmaMenBase[DMA_BUF_SIZE] __attribute__((section("ORIRAM")));
__align(32) uint8_t RapidMemBase[1024] __attribute__((section("CCMRAM")));


第一个DmaMenBase是串口接收DMA内存,指定放在ORIRAM section中,也就是IRAM1中避免读写错误,第二个RapidMemBase数组则指定放在CCMRAM section中,也就是IRAM2。设置完后编译程序,如果配置正确不会报错。

三、结果验证
编译完成后,打开map文件(和sct在同一个目录,即MDK-ARM\项目名称\XX.map),搜索 RW_IRAM2,可以看到如下内容:


Execution Region RW_IRAM2 (Exec base: 0x10000000, Load base: 0x0800396c, Size: 0x00004220, Max: 0x00010000, ABSOLUTE, COMPRESSED[0x0000000c])
Exec Addr    Load Addr    Size         Type   Attr      Idx    E Section Name        Object
0x10000000   COMPRESSED   0x00000020   Data   RW         4603    .data               heap_4.o
0x10000020   COMPRESSED   0x00000400   Data   RW           17    CCMRAM              main.o
0x10000420        -       0x00003c00   Zero   RW         4602    .bss                heap_4.o
0x10004020        -       0x00000200   Zero   RW            2    HEAP                startup_stm32f407xx.o
Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x0800395c, Size: 0x000013a0, Max: 0x00020000, ABSOLUTE, COMPRESSED[0x00000010])
Exec Addr    Load Addr    Size         Type   Attr      Idx    E Section Name        Object
0x20000000   COMPRESSED   0x00000004   Data   RW          227    .data               freertos.o
0x20000004   COMPRESSED   0x0000000c   Data   RW         1372    .data               stm32f4xx_hal.o
0x20000010   COMPRESSED   0x00000004   Data   RW         2937    .data               system_stm32f4xx.o
0x20000014   COMPRESSED   0x0000003c   Data   RW         3601    .data               tasks.o
0x20000050   COMPRESSED   0x00000014   Data   RW         3932    .data               timers.o
0x20000064   COMPRESSED   0x00000004   Data   RW         4157    .data               cmsis_os2.o
0x20000068   COMPRESSED   0x0000000c   Data   RW         4659    .data               port.o
0x20000074   COMPRESSED   0x0000000c   PAD
0x20000080   COMPRESSED   0x00000100   Data   RW           18    ORIRAM              main.o
0x20000180        -       0x000000a4   Zero   RW          293    .bss                usart.o
0x20000224        -       0x00000048   Zero   RW          435    .bss                stm32f4xx_hal_timebase_tim.o
0x2000026c        -       0x00000040   Zero   RW         3176    .bss                queue.o
0x200002ac        -       0x000004c4   Zero   RW         3600    .bss                tasks.o
0x20000770        -       0x00000118   Zero   RW         3931    .bss                timers.o
0x20000888        -       0x000006b8   Zero   RW         4156    .bss                cmsis_os2.o
0x20000f40        -       0x00000060   Zero   RW         4783    .bss                c_w.l(libspace.o)
0x20000fa0        -       0x00000400   Zero   RW            1    STACK               startup_stm32f407xx.o



可以看到 heap_4.o 的data和bss 以及 startup_stm32f407xx.o 的Heap都放在了IRAM2里,IRAM2还包含main.o的CCMRAM段,大小为0x400,即1024字节,对应mian.c中定义的RapidMemBase。而IRAM1则包含了main.o的ORIRAM段,大小为0x100,即256字节,对应mian.c中定义的DmaMenBase。证明自定义配置已经生效。

注意,在程序代码中定义的数组,需要在代码段中确实使用到,否则可能会被编译器优化掉,那么在map中就看不到了。
————————————————
版权声明:本文为CSDN博主「小贝的奶爸」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chubbykkk/article/details/125389016
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/hbaizj/article/details/149104680

LOVEEVER 发表于 2025-7-29 23:36 | 显示全部楼层
很不错了解一下方法
您需要登录后才可以回帖 登录 | 注册

本版积分规则

188

主题

4322

帖子

5

粉丝
快速回复 在线客服 返回列表 返回顶部