keil分散加载表与ide的ld文件
在 Keil MDK 使用的 分散加载文件 (.sct) 中,没有 (NOLOAD) 这个关键字。它的等价替代者是 UNINIT。
在你提供的 .sct 修改建议中,我使用的 RW_SHARED 0x38000000 UNINIT 0x00002000 里的 UNINIT,其作用与 GCC 链接脚本(.ld)中的 (NOLOAD) 完全一致。
1. 为什么在 Keil 中要用 UNINIT?
在 C 语言程序启动时,执行单元(C Lib)会进行“清场”:
-
RW 段:从 Flash 拷贝初始值到 RAM。
-
ZI 段:把 RAM 区域全部清零。
如果你不加 UNINIT: 当 M7 启动并初始化好了电机参数(MotorObject),随后 M4 启动。M4 的启动代码发现自己也有一个 RW_SHARED 段,于是它会按照惯例把这块内存再次清零。结果就是 M7 刚写好的数据瞬间被 M4 抹掉了。
加上 UNINIT 后: 链接器(Armlink)会标记这块内存为“不初始化”。这样 M4 启动时,它的 __main 函数会跳过这块地址,保持内存里原有的数据(即 M7 写好的数据)不动。
2. 检查你的 .sct 文件位置
请确保你的 .sct 文件里是这样写的:
; M7 的 sct 文件
RW_SHARED 0x38000000 UNINIT 0x00002000 {
*(SHARED_DATA_SECTION)
}
; M4 的 sct 文件(同样要加 UNINIT)
RW_SHARED 0x38000000 UNINIT 0x00002000 {
*(SHARED_DATA_SECTION)
}
3. 特别注意:手动初始化
由于使用了 UNINIT,这块内存里的数据在冷上电(刚插电)时是随机的垃圾值。
因为 M4 不负责初始化,M7 也不自动清零,你必须在 M7 的代码中手动调用你的初始化函数:
// 在 M7 的 main.c 中
void main(void) {
// 1. 先进行硬件初始化
// 2. 手动对共享结构体进行一次性赋值
Task_Motor_Init();
// 3. 此时才唤醒 M4 核心
HAL_RCCEx_EnableBootCore(RCC_BOOT_C2);
}
4. 补充:C 代码里的“双保险”
如果你想在代码层面也强调这一点(虽然 .sct 已经决定了结果),在 Keil 下你还可以给变量增加这个特殊的属性:
// 在 M7 中定义时,显式指定不初始化
MotorStruct MotorObject[MaxMotorNum] __attribute__((section("SHARED_DATA_SECTION"), zero_init));
注意:在 Keil 中,如果你想让变量绝对不被清零,除了 sct 里的 UNINIT,有时还需要配合编译器指令,但最稳妥、最直观的方法就是通过刚才改好的 .sct 文件。
总结
-
GCC (.ld) 使用
(NOLOAD)。 -
Keil (.sct) 使用
UNINIT。
ld例子
MEMORY { /* 必须和 M7 的地址完全一致! */ SHARED_RAM (xrw) : ORIGIN = 0x38000000, LENGTH = 64K } SECTIONS { /* M4 这边也映射到同一个物理位置 */ .shared_section (NOLOAD) : { . = ALIGN(32); KEEP(*(.shared_data)) . = ALIGN(32); } > SHARED_RAM }
MEMORY { /* 假设我们使用 SRAM4 作为共享区 */ SHARED_RAM (xrw) : ORIGIN = 0x38000000, LENGTH = 64K ... } SECTIONS { /* 将名为 .shared_data 的输入段放入 SHARED_RAM 区域 */ .shared_section (NOLOAD) : { . = ALIGN(32); KEEP(*(.shared_data)) /* 匹配代码中的 section(".shared_data") */ . = ALIGN(32); } > SHARED_RAM }
浙公网安备 33010602011771号