STM32H7系列MCU分散加载方式管理多块内存

前面一篇文章简单介绍了 STM32H7 系列 MCU 的内存管理办法,稍微提了一下分散加载内存,这篇文章就以 Keil 为例注重分析一下 STM32H7 系列 MCU 分散加载方式管理多块内存。

在 Keil 默认设置下编译工程完成后,会在本工程的路径下自动生成一个后缀为.sct 的文件,如图 1 所示。

STM32H7系列MCU分散加载方式管理多块内存
图 1 Keil 生成的内存加载文件的名字和位置

打开自动生成的.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 所示。

STM32H7系列MCU分散加载方式管理多块内存
图 2 STM32H7 的程序加载过程

第 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 所示。

STM32H7系列MCU分散加载方式管理多块内存
图 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

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2021年3月18日 15:19
下一篇 2021年3月23日 09:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注