【STM32】在链接脚本中指定DMA Buffer的地址

发布于:2025-09-03 ⋅ 阅读:(24) ⋅ 点赞:(0)

简介

在使用ARM Keil工具链的项目中,分散加载文件是编译过程中必不可少的一个文件,它在代码编译的链接期间起作用,链接器根据sct文件的配置分配各个节区地址,生成分散加载代码。就是.sct文件(Scatter-Loading File)。

其实在Linux环境下用gcc编译时也需要用到类似的文件,叫做链接脚本文件,就是.ld文件,例如在使用STM32CubeIDE工具的项目中。

如何查看和生成链接脚本

Keil项目为例,我们使用的是STM32F407ZGT6的MCU。STM32F407ZGT6 的存储器资源是分析链接脚本的基础:

  • Flash (ROM): 1 MB,起始地址 0x0800 0000
  • SRAM (RAM): 192 KB,分为:
    • 112KB SRAM1 + 16KB SRAM2,起始地址 0x2000 0000 (CPU和DMA均可访问)
    • 64KB CCMRAM,起始地址 0x1000 0000 (仅CPU可访问,DMA不能访问)

在魔术棒的target页中,我们已经配置了Flash和SRAM的地址和大小。(这里ROM的起始地址修改了,是因为我们的项目中有bootloader,并不影响本篇文章的介绍内容)

在这里插入图片描述
在这里插入图片描述

在Linker页中,有一个选项Use Memory Layout from Target Dialog,这个如果勾选后,就不允许点击Edit按钮了。也就是说.sct文件是根据target dialog中的配置自动生成的,我们可以到.\Haptic\Haptic.sct查看该文件。

LR_IROM1 0x08020000 0x00100000  {   ; 加载区域(Load Region),名为 LR_IROM1
  ER_IROM1 0x08020000 0x00100000  { ; 第一个执行区域(Execution Region),名为 ER_IROM1
   *.o (RESET, +First)              ; 向量表必须放在最开头
   *(InRoot$$Sections)              ; 特殊的库段(如 __main.o, __scatter*.o)
   .ANY (+RO)                       ; 所有只读数据(代码和常量)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  { ; 第二个执行区域,名为 RW_IRAM1
   .ANY (+RW +ZI)                   ; 所有可读写数据(全局/静态变量)和未初始化数据
  }
  RW_IRAM2 0x10000000 0x00010000  { ; 第二个执行区域,名为 RW_IRAM2
   .ANY (+RW +ZI)                   ; 所有可读写数据(全局/静态变量)和未初始化数据
  }
}
  • LR_IROM1 定义了加载区域(Load Region)位于 Flash(起始地址 0x08020000,大小 0x00100000)。

  • ER_IROM1 定义了执行区域(Execution Region)位于 Flash,并指定了哪些代码段放置在此区域。

  • RW_IRAM1 定义了可读写区域(Read-Write Region)位于 SRAM(起始地址 0x20000000,大小 0x00020000),用于存放数据。

  • RW_IRAM2 定义了可读写区域(Read-Write Region)位于 SRAM(起始地址 0x10000000,大小 0x00010000),用于存放数据。

修改SCT文件

一般我们修改.sct文件是为了把函数放到SRAM中运行,或者把变量放在指定位置。我们使用自己修改的.sct文件,就需要这样配置:

在这里插入图片描述

这样配置后不再根据target dialog中的配置自动生成的.sct文件,并且我们可以直接Edit

将变量指定到某一块RAM中

在代码中定义数组时,使用 __attribute__((section("your_section_name"))) 来指定一个自定义的段名。例如在F407MCU中,DMA不能访问CCMRAM中的内存,但是可以访问其他地方的RAM。

/* 将数组放置在 SRAM1 的区域 */
uint8_t my_array_sram1[1024] __attribute__((section(".sram1_section")));

然后修改.sct文件

LR_IROM1 0x08020000 0x00100000  {   ; 加载区域(Load Region),名为 LR_IROM1
  ER_IROM1 0x08020000 0x00100000  { ; 第一个执行区域(Execution Region),名为 ER_IROM1
   *.o (RESET, +First)              ; 向量表必须放在最开头
   *(InRoot$$Sections)              ; 特殊的库段(如 __main.o, __scatter*.o)
   .ANY (+RO)                       ; 所有只读数据(代码和常量)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  { ; 第二个执行区域,名为 RW_IRAM1
   .ANY (+RW +ZI)                   ; 所有可读写数据(全局/静态变量)和未初始化数据
   *(.sram1_section)                ; 将自定义的 sram1_section 段也放在这里
  }
  RW_IRAM2 0x10000000 0x00010000  { ; 第二个执行区域,名为 RW_IRAM2
   .ANY (+RW +ZI)                   ; 所有可读写数据(全局/静态变量)和未初始化数据
  }
}

网站公告

今日签到

点亮在社区的每一天
去签到