前面一篇文章简单介绍了 STM32H7 系列 MCU 的内存管理办法,稍微提了一下分散加载内存,这篇文章就以 Keil 为例注重分析一下 STM32H7 系列 MCU 分散加载方式管理多块内存。
在 Keil 默认设置下编译工程完成后,会在本工程的路径下自动生成一个后缀为.sct 的文件,如图 1 所示。

打开自动生成的.sct 文件:
; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* LR_IROM1 0x08000000 0x00200000 { ; load region size_region ER_IROM1 0x08000000 0x00200000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) .ANY (+XO) } RW_IRAM1 0x20000000 0x00020000 { ; RW data .ANY (+RW +ZI) } }
通过更改此.sct 文件内容,使得 MDK 能够分散加载方式管理多块内存。更改后的代码:
; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* LR_IROM1 0x08000000 0x00200000 { ; load region size_region ER_IROM1 0x08000000 0x00200000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00020000 { ; RW data - 128KB DTCM .ANY (+RW +ZI) } RW_IRAM2 0x24000000 0x00080000 { ; RW data - 512KB AXI SRAM *(.RAM_D1) } RW_IRAM3 0x30000000 0x00048000 { ; RW data - 128KB SRAM1(0x30000000) + 128KB SRAM2(0x3002 0000) + 32KB SRAM3(0x30040000) *(.RAM_D2) } RW_IRAM4 0x38000000 0x00010000 { ; RW data - 64KB SRAM4(0x38000000) *(.RAM_D3) } }
更改后的代码增加了 3 个供调用的 RAM 区域,逐行注解如下:
第 5 行至第 6 行:LR_IROM1 是 Load Region(加载域),ER_IROM1 是 Execution Region(执行域)。首地址都是 0x0800 0000,大小都是 0x0020 0000,即 STM32H7 的 Flash 地址和对应大小。加载域是程序在 Flash 中的实际存储,执行域是芯片上电后的运行状态,如图 2 所示。

第 7 行:在启动文件 startup_stm32h743xx.s 有个段名为 RESET 的代码段,主要存储了中断向量表。这里是将其存放在 Flash 的首地址。
第 8 行:这里是将 MDK 的一些库文件全部放在根域,比如 __main.o, _scatter.o, _dc.o。
第 9 行:将目标文件中所有具有 RO 只读属性的数据放在这里,即 ER_IROM1。
第 12 至 13 行:RW_IRAM1 是执行域,配置的是 DTCM,首地址 0x2000 0000,大小 128KB。将目标文件中所有具有 RW 和 ZI 数据放在这里。
第 16 至 17 行:RW_IRAM2 是执行域,配置的是 D1 域的 AXI SRAM,首地址 0x24000000,大小 512KB。给这个域取名为.RAM_D1。这样通过 attribute((section(“name”)))将其分配到这个 RAM 域。
第 20 至 21 行:RW_IRAM3 是执行域,配置的是 D2 域的 SRAM1,SRAM2 和 SRAM3,首地址 0x30000000,共计大小 288KB。 给这个域取名为.RAM_D2。这样通过 attribute((section(“name”)))将其分配到这个 RAM 域。
第 24 至 25 行:RW_IRAM3 是执行域,配置的是 D3 域的 SRAM4,首地址 0x38000000,共计大小 64KB。给这个域取名为.RAM_D3。这样通过 attribute((section(“name”))) 将其分配到这个 RAM 域。
注:关于 XO、RO、RW、ZI 术语解释摘自 MDK 帮助文档
- One execute-only (XO) section if the execution region contains only XO sections.
- One RO section if the execution region contains read-only code or data.
- One RW section if the execution region contains read-write code or data.
- One ZI section if the execution region contains zero-initialized data.
至此,.sct 文件制作完毕。工程引用.sct 文件如图 3 所示。

至此,已经配置完毕,编写应用程序进行验证:
// mian 函数前声明 /* 定义在 512KB AXI SRAM 里面的变量 */ __attribute__((section (".RAM_D1"))) uint32_t AXISRAMBuf[10]; __attribute__((section (".RAM_D1"))) uint16_t AXISRAMCount; /* 定义在 128KB SRAM1(0x30000000) + 128KB SRAM2(0x30020000) + 32KB SRAM3(0x30040000)里面的变量 */ __attribute__((section (".RAM_D2"))) uint32_t D2SRAMBuf[10]; __attribute__((section (".RAM_D2"))) uint16_t D2SRAMount; /* 定义在 64KB SRAM4(0x38000000)里面的变量 */ __attribute__((section (".RAM_D3"))) uint32_t D3SRAMBuf[10]; __attribute__((section (".RAM_D3"))) uint16_t D3SRAMCount; // main 函数中调用 switch (ucKeyCode) { case KEY_DOWN_K1: /* K1 键按下,操作 AXI SRAM */ AXISRAMBuf[0] = AXISRAMCount++; AXISRAMBuf[5] = AXISRAMCount++; AXISRAMBuf[9] = AXISRAMCount++; printf("K1 键按下, AXISRAMBuf[0] = %d, AXISRAMBuf[5] = %d, AXISRAMBuf[9] = %d\r\n", AXISRAMBuf[0], AXISRAMBuf[5], AXISRAMBuf[9]); break; case KEY_DOWN_K2: /* K2 键按下,操作 D2 域的 SRAM1,SRAM2 和 SRAM3 */ D2SRAMBuf[0] = D2SRAMount++; D2SRAMBuf[5] = D2SRAMount++; D2SRAMBuf[9] = D2SRAMount++; printf("K2 键按下, D2SRAMBuf[0] = %d, D2SRAMBuf[5] = %d, D2SRAMBuf[9] = %d\r\n", D2SRAMBuf[0], D2SRAMBuf[5], D2SRAMBuf[9]); break; case KEY_DOWN_K3: /* K3 键按下,操作 D3 域的 SRAM4 */ D3SRAMBuf[0] = D3SRAMCount++; D3SRAMBuf[5] = D3SRAMCount++; D3SRAMBuf[9] = D3SRAMCount++; printf("K3 键按下, D3SRAMBuf[0] = %d, D3SRAMBuf[5] = %d, D3SRAMBuf[9] = %d\r\n", D3SRAMBuf[0], D3SRAMBuf[5], D3SRAMBuf[9]); break; default: /* 其它的键值不处理 */ break;
至此,可以看到程序正常运行,以上就是 STM32H7 系列 MCU 分散加载方式管理多块内存。
扫码关注尚为网微信公众号

原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/933.html