Keil5链接脚本修改:定制SF32LB52内存分布

Keil5链接脚本修改:深入定制SF32LB52内存布局 🛠️

你有没有遇到过这样的情况?系统跑着跑着,突然某个中断响应慢了几个毫秒——就这短短一瞬间,电机控制失步、信号采样错位,整个应用差点“崩盘”。排查半天发现,并不是代码逻辑的问题,而是 Flash访问延迟在作祟 。

又或者,客户要求支持远程升级(OTA),但你一想:现在整个固件都从头开始执行,怎么留个“后门”让我安全跳转?这时候你就知道,不能再依赖默认的启动流程和内存映射了。必须动手改——改什么? 链接脚本(Linker Script) 。

今天我们就以赛腾微电子的车规级MCU SF32LB52 为例,带你彻底搞懂如何在Keil MDK(即Keil5)环境下,通过 .sct 文件实现对内存分布的精细掌控。这不是简单的复制粘贴教程,而是一次嵌入式底层开发的深度实战演练 💥。


为什么标准配置不够用?

SF32LB52基于ARM Cortex-M0+内核,拥有128KB Flash和32KB SRAM,集成了CAN FD、LIN、ADC等丰富外设,常用于车载传感器、智能电源管理等场景。听起来资源还算充裕?但在真实项目中,很快就会碰到瓶颈:

  • 要做OTA升级 → 得划分Bootloader区和App区;
  • 实时性要求高 → 关键ISR必须放进SRAM执行;
  • 需要保存校准参数或日志 → 常量数据不能随便放;
  • 多任务调度或堆栈隔离 → RAM得合理切分;

而这一切,Keil默认生成的 startup_sf32lb52.s 和隐式使用的链接规则根本无法满足。它只会把所有 .text 扔进Flash, .data 和 .bss 塞进SRAM,然后说:“好了,编译吧。”

可我们想要的是:
👉 让CAN中断函数在SRAM里飞起来;
👉 把主应用程序挪到0x8000以后,给Bootloader腾地方;
👉 确保某些关键变量永远待在特定地址,方便调试器追踪……

这些需求,全靠一个文件来实现—— .sct 散列加载脚本。


.sct文件到底是什么?🧠

很多人把它当成“配置文件”来看待,其实不然。 .sct 是一种 由开发者编写、被armlink解析的指令集 ,本质上是告诉链接器:“你应该这样组织我的程序。”

它采用的是ARM自家的 Scatter-Loading机制 ,允许我们将输出段(output sections)精确地分配到物理存储空间中,比如:

  • 哪些代码放在Flash起始处?
  • 哪些函数需要复制到SRAM运行?
  • 向量表是否要重定位?
  • 数据段是从哪里加载、在哪里执行?

它和传统ld脚本有什么不同?

如果你熟悉GCC + linker script(.ld),那你可能会觉得 .sct 有点“非主流”。确实,它是ARM工具链特有的格式,语法更简洁,但也更受限。不过对于MDK用户来说,这是唯一可控的方式。

更重要的是: Keil不直接暴露ld脚本接口 ,所以 .sct 就是你的终极武器 🔫。


一张图看懂工作流程 🧩

想象一下,你的工程里有十几个 .c 文件,每个都被编译成 .o 目标文件,里面包含各种段(section):

startup.o     → .text.reset, .vector_table
main.o        → .text, .rodata, .data
isr_handler.o → .text.CAN_IRQHandler
utils.o       → .text.fast_math_func

如果没有 .sct ,Keil会把这些段按类型合并,统一放入默认区域:

ROM1: 0x0000_0000 ~ 0x0002_0000 → 所有.text/.rodata
RAM1: 0x2000_0000 ~ 0x2000_8000 → 所有.data/.bss

但有了 .sct 之后,你可以告诉链接器:

“听着, .text.CAN_IRQHandler 这个函数我要放到SRAM高端去执行;
主程序代码只占前124KB Flash;
应用程序从0x8000开始……”

于是,链接器就会按照你的规划,构建出一个复杂的“加载-运行”视图,并自动生成一段初始化代码(scatter loading code),负责在启动时完成必要的数据搬移——比如将 .data 从Flash复制到SRAM,或将 .ramfunc 段复制到指定位置。

⚠️ 注意:如果你没调用 __main() ,那这段初始化是不会执行的!很多初学者在这里栽跟头。


如何写第一个自定义.sct?📝

我们先来看一个适用于常规单应用的 .sct 模板:

LR_IROM1 0x00000000 0x00020000 {    
    ER_IROM1 0x00000000 0x00020000 {  
        *.o (RESET, +First)          
        *(InRoot$$Sections)
        .ANY (+RO)                   
    }

    RW_IRAM1 0x20000000 0x00008000 { 
        .ANY (+RW +ZI)               
    }
}

别急,我们逐行拆解:

LR_IROM1 0x00000000 0x00020000

这是 加载域(Load Region) ,表示这个程序最终会被烧录到Flash的 0x0000_0000 开始的位置,总大小为128KB(0x20000)。名字可以自定义,但通常习惯叫 LR_IROM1 。

ER_IROM1 ...

这是 执行域(Execution Region) ,说明代码实际运行的位置。在这里,加载地址 == 运行地址,属于典型的XIP(eXecute In Place)模式。

注意:如果两者不同(比如函数要从Flash加载到SRAM执行),就需要分开定义。

*.o (RESET, +First)

确保 startup.o 中的复位处理函数排在最前面。这是硬性要求!因为CPU上电后第一件事就是读取向量表首地址作为MSP,第二条是PC入口。

加 +First 是为了防止链接器优化时打乱顺序。

*(InRoot$$Sections)

这是CMSIS标准的一部分,包含一些必须位于根区域的段,比如 __main 、 __scatterload 等初始化例程。漏掉它可能导致初始化失败。

.ANY (+RO) 和 .ANY (+RW +ZI)

  • +RO :所有只读段,包括代码( .text )、字符串常量( .rodata );
  • +RW :已初始化的全局变量( .data );
  • +ZI :未初始化或清零的变量( .bss );

.ANY 是个通配符,意思是“剩下的都给我塞进来”。但它有个问题: 没有优先级控制 ,容易导致关键段被挤到边缘。

所以我们后面会看到更精细的做法。


想让函数在SRAM里跑?没问题 ✅

假设你在做一个车窗防夹检测系统,PWM捕获中断每100μs触发一次,任何延迟都会导致误判。而Flash有等待周期(wait state),哪怕只有1~2个cycle,也可能成为瓶颈。

解决方案?把ISR搬到SRAM里执行!

第一步:标记函数进入指定段

// isr_handler.c
#include "sf32lb52.h"

__attribute__((section(".ramfunc")))
void PWM_Capture_IRQHandler(void) {
    uint32_t capture = TIM_GetCaptureValue();
    if (is_obstruction_detected(capture)) {
        motor_stop_immediately();
    }
    TIM_ClearFlag(TIM_SR_CC1IF);
}

这里用了GCC风格的 __attribute__ 语法,将该函数放入名为 .ramfunc 的自定义段中。Keil ARMCC/ArmClang都支持。

第二步:修改.sct,为.ramfunc单独开个区域

LR_IROM1 0x00000000 0x00020000 {
    ER_IROM1 0x00000000 0x0001F000 {      
        *.o (RESET, +First)
        *(InRoot$$Sections)
        .ANY (+RO)
        !(.ramfunc)                      
    }

    ER_IROM_RAMFUNC 0x0001F000 0x1000 {  
        *.o (.ramfunc)                   
    }

    RW_IRAM1 0x20000000 0x00008000 {
        .ANY (+RW +ZI)
    }
}

关键点来了:

  • 主代码区只占前124KB(0x1F000),留出4KB给 .ramfunc ;
  • 使用 !() 排除 .ramfunc 段进入主代码区;
  • 单独定义 ER_IROM_RAMFUNC 来接收该段;

你以为这就完了?No ❌。

此时 .ramfunc 仍然只是 存在于Flash中的一个段 。要想让它真正在SRAM中运行,必须完成两个动作:

  1. 在启动阶段,由scatter loader自动将其复制到SRAM;
  2. 链接器生成跳转桩(trampoline),使得对该函数的调用实际上跳向SRAM中的副本。

而这,依赖于你在.sct中正确设置运行域的属性。

等等……我们现在还是把 .ramfunc 放在Flash高端啊?那怎么复制到SRAM?

答案是:我们需要重新设计执行域。

正确做法:加载在Flash,运行在SRAM

LR_IROM1 0x00000000 0x00020000 {
    ER_IROM1 0x00000000 0x0001F000 {      
        *.o (RESET, +First)
        *(InRoot$$Sections)
        .ANY (+RO)
        !(.ramfunc)                      
    }

    ; 加载域仍在Flash
    LR_RAMFUNC 0x0001F000 0x1000 {
        ; 但运行域在SRAM
        ER_RAMFUNC 0x20007000 0x1000 {
            *.o (.ramfunc)
        }
    }

    RW_IRAM1 0x20000000 0x00008000 {
        .ANY (+RW +ZI)
    }
}

现在发生了什么?

  • .ramfunc 段的内容仍存储在Flash的 0x1F000 处(便于烧录);
  • 但在程序启动时,scatter loader会自动将其复制到SRAM的 0x20007000 ;
  • 所有对该函数的引用,都会被重定向到SRAM地址;
  • 函数执行时完全无Flash等待,速度拉满 ⚡;

💡 小技巧:你可以使用 __RAM_FUNC 宏简化书写:

```c

define RAM_FUNC __attribute ((section(“.ramfunc”)))

```

此外,记得确认项目设置中启用了“Use Memory Layout from Target Dialog”,否则.sct不会生效。


构建Bootloader + App双区架构 🔁

这才是真正的重头戏。

设想你要开发一款支持CAN总线OTA升级的车身控制器。出厂时预装一个Bootloader,平时静默运行;当收到升级指令时,接收新固件写入App区;下次重启,直接跳过去执行。

这就要求:

  • Bootloader占用低地址段(如0x0000~0x7FFF,共32KB);
  • App从0x8000开始,最多可用96KB;
  • 两者共用同一套SRAM;
  • 跳转时能正确切换堆栈和中断向量表;

Step 1:准备两个独立的.sct文件

Bootloader脚本:BL_Script.sct
LR_BOOT 0x00000000 0x00008000 {         
    ER_BOOT 0x00000000 0x00008000 {
        *.o (RESET, +First)
        *(InRoot$$Sections)
        .ANY (+RO)
    }
    RW_IRAM 0x20000000 0x00008000 {
        .ANY (+RW +ZI)
    }
}
Application脚本:APP_Script.sct
LR_APP 0x00008000 0x00018000 {           
    ER_APP 0x00008000 0x00018000 {
        *.o (RESET, +First)
        *(InRoot$$Sections)
        .ANY (+RO)
    }
    RW_IRAM 0x20000000 0x00008000 {
        .ANY (+RW +ZI)
    }
}

注意App的基地址偏移了32KB。你还需要调整以下内容:

  • 在App工程中,修改Target → IROM1起始地址为 0x8000 ,大小为 0x18000 ;
  • 修改中断向量表偏移: SCB->VTOR = 0x00008000;
  • 如果使用RTOS或动态内存,需确保heap/buffer不与Bootloader冲突;

Step 2:实现安全跳转逻辑

typedef void (*pFunc)(void);

#define APP_START_ADDR    0x00008000
#define MSP_VALUE         (*(uint32_t*)APP_START_ADDR)
#define RESET_HANDLER     (*(pFunc*)(APP_START_ADDR + 4))

void jump_to_application(void) {
    // 先检查栈顶是否在合法SRAM范围内
    if ((MSP_VALUE & 0xFFFE0000) != 0x20000000) {
        return; // 非法地址,拒绝跳转
    }

    // 关闭所有中断
    __disable_irq();
    __set_FAULTMASK(1); // 屏蔽所有异常(除NMI)

    // 设置主堆栈指针
    __set_MSP(MSP_VALUE);

    // 清除可能挂起的中断
    NVIC_ClearPendingIRQs();

    // 重新映射向量表(可选)
    SCB->VTOR = APP_START_ADDR;

    // 跳转!
    RESET_HANDLER();
}

几点关键说明:

  • __set_MSP() 是CMSIS提供的内联函数,用来更新主堆栈指针;
  • 必须在跳转前关闭中断,否则一旦发生中断,handler还在旧地址,会引发HardFault;
  • FAULTMASK = 1 可临时屏蔽除NMI外的所有异常,确保跳转原子性;
  • NVIC_ClearPendingIRQs() 清除所有待处理中断标志,避免跳转后立即触发;
  • VTOR 重定向可以让App有自己的中断向量表,不必复制一份;

🎯 实战建议:可以在Bootloader中加入CRC校验、数字签名验证、升级标志清除等逻辑,提升安全性。


实际工程中的那些坑 🕳️

你以为改完.sct就万事大吉?Too young.

❌ 问题1:JTAG下载覆盖Bootloader

最常见的悲剧:调试App的时候,Keil默认从 0x0000 开始下载,结果把Bootloader干掉了。

解决办法 :

  • 在App工程中,勾选“Don’t stop debugger on flash programming”;
  • 或者使用“Download to Specific Address”功能,仅烧录0x8000以后的内容;
  • 更高级的做法是使用外部脚本配合J-Link Commander进行选择性烧录;

❌ 问题2:向量表没重定向,中断进不去

App运行后,如果没设置 VTOR ,中断依然会跳回 0x0000 处的Bootloader向量表,造成崩溃。

务必在App启动初期加上 :

SCB->VTOR = 0x00008000;

前提是芯片支持向量表偏移(Cortex-M0+部分型号有限制,但SF32LB52支持)。

❌ 问题3:SRAM冲突导致数据错乱

Bootloader和App共用SRAM,若Bootloader在跳转前没有清空 .bss 或释放heap,App可能读到脏数据。

最佳实践 :

  • 跳转前调用 __deinitialize_user_heap_stack() (Keil提供);
  • 或手动清零相关区域;
  • 若使用RTX5或其他RT-Thread组件,注意内存池状态;

❌ 问题4:编译器优化导致段名丢失

有时你会发现 .ramfunc 没被识别,查map文件发现函数被内联或优化没了。

应对策略 :

  • 添加 __attribute__((noinline)) 禁止内联;
  • 使用 volatile 关键字阻止过度优化;
  • 在.sct中使用具体对象名而非通配符:

text my_isr.o (.ramfunc)


设计建议与最佳实践 🧭

✅ 内存规划要“留白”

不要把128KB Flash用得满满当当。建议:

  • Bootloader预留32KB(足够做通信协议+校验+基础驱动);
  • App最多用96KB,剩下留给未来扩展;
  • SRAM中为堆栈、heap、DMA缓冲区预留空间;

✅ 使用命名段而非地址硬编码

比起直接写 __attribute__((at(0x20007000))) ,推荐使用 section(".ramfunc") 方式:

  • 更易维护;
  • 支持链接器自动分配;
  • 避免地址冲突;

✅ 开启Map文件分析

每次构建后打开 .map 文件,查看各段分布:

  • 是否有段溢出?
  • .ramfunc 是否真的被复制到了SRAM?
  • 向量表位置是否正确?

这是排查链接问题的第一手资料。

✅ 利用IDE图形化辅助

Keil5的“Memory Layout”对话框虽然鸡肋,但至少能帮你快速设定IROM/IRAM基址。配合.sct使用,避免手动计算错误。


最后的思考:链接脚本的本质是什么?🤔

它不只是一个配置文件,而是你对 程序生命周期的理解表达 。

当你写下:

ER_RAMFUNC 0x20007000 0x1000 { *.o (.ramfunc) }

你其实在说:

“我知道这个函数很重要,它不能忍受哪怕一个Flash周期的延迟;
我愿意牺牲一点Flash空间,换来SRAM中的极速执行;
我接受启动时多花几微秒做复制操作;
因为我清楚系统的优先级——实时性高于一切。”

这就是嵌入式工程师的决策力。

而当你设计Bootloader跳转逻辑时,你在构建一种 信任传递机制 :从复位那一刻起,控制权如何一步步移交,直到系统真正“活”起来。


现在的你,还敢说“.sct文件不重要”吗?😎

下次再遇到性能瓶颈或OTA需求,别急着改算法、换芯片。先打开那个默默无闻的 .sct 文件,问问自己:

“我的内存,真的被充分利用了吗?” 💬

数据挖掘实战:决策树 + 聚类 + 关联规则,零 Key 离线可跑(Python 源码) 数据挖掘实战包。用 Python 标准库实现 CART 风格决策树、K-Means 聚类与 Apriori 关联规则,在虚构「星河便利店」会员表和购物篮上跑通分类、分群与购物篮分析,并给出准确率、轮廓系数、支持度/置信度/提升度。零第三方依赖、零 API Key 即可离线跑通。含 4 个样例、离线冒烟、中文 README(含「使用方法」)。均为作者原创可运行源码。MIT。作者 blog.csdn.net/mtl1994 立即下载

相关推荐

产业园区如何高效对接企业技术需求与高校科研成果?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

KEiL链接脚本解析

KEIL链接脚本

cat_milk的博客 1715

国央企创新负责人如何快速掌握本地科技资源分布与匹配情况?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

Keil5链接脚本定制ESP32-S3内存段分布方案

本文深入解析ESP32-S3在Keil5环境下的链接脚本配置,针对IRAM、DRAM、RTC内存等区域提出精准布局方案,解决中断延迟、DMA异常和深度睡眠数据丢失等问题,提升系统实时性与稳定性。

agile9scrum的博客 991

国央企创新负责人如何实现科技成果的精准识别与高效筛选?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

多视图学习 (Multi-View Learning)

多视角/多视图学习(Multi-view learning)是陶大成提出的一个研究方向。我们都知道,在机器学习中样本可以用不同的特征(如图片可以用LBP、SIFT等特征)来表示,或者从不同的角度进行观察(如从前后左右观察一个对象),甚至是采用不同的传感器来观测(如RGB摄像头,Depth摄像头),这些不同的观测手段、角度或特征在多视角学习中称为“视角”。多视角学习通过对不同的视角进行统一分析和研究,希望能够得到更好的分类或聚类等等的效果。

CarpeDiem 3万+

Linux淘金记(一):module_init——初始化就该这么写

Linux内核源码是一个巨大的宝库,总会发现属于你的宝物。阅读源码不是目的,为己所用才是答案。

baidu_23858427的博客 1461

PyCharm中Pyvips配置避坑指南:为什么pip安装后import还是报错?

本文详细解析了在PyCharm中配置Pyvips时,即使pip安装成功,import仍报错的根本原因。核心在于Pyvips依赖的libvips原生库未正确配置环境变量。文章提供了从下载libvips、配置Windows系统PATH到PyCharm项目级设置的完整避坑指南,并对比了三种配置策略,帮助开发者彻底解决DLL加载失败问题。

bush的博客 209

记录keil5下使用RAM调试过程

1.设置程序存放的地址,IROM1,这里设置从0x2000 0000开始,大小为0x8000; 2.设置程序RAM运行地址,IRAM1,由于前面的0x8000大小的RAM用于存放程序,所以这里得设置从0x2000 8000开始,大小为0x8000. 3.设置中断向量表存放位置的宏,VECT_TAB_SRAM表存放在SRAM中。 4.先去选Use Memory,在右边的R/O Base...

u010947832的博客 4277

TensorFlow实战:5步搞定因果推断模型TARNet(附完整代码)

本文提供了一份基于TensorFlow的TARNet因果推断模型实战指南。通过五个清晰步骤,从数据预处理、模型构建到训练评估,详细讲解了如何利用深度模型解决营销评估、疗效分析等场景中的因果效应估计问题,并附有完整代码解决样本不平衡等工程挑战。

python9snake的博客 416

射频功率放大器设计实战:从理论到Layout的全流程解析

本文以一款40W、960MHz LDMOS功率放大器为例,系统解析了从理论分析、仿真设计到版图实现的射频功率放大器设计全流程。内容涵盖AB类放大器选型、核心指标定义、稳定性分析、Load-Pull/源牵引仿真、史密斯圆图匹配、偏置网络设计,以及最终的谐波平衡仿真与版图电磁验证,为工程师提供了一套从理论到实践的完整设计方法论。

weixin_29266007的博客 249

如果完全不需要 xxxxFont.sct,可以改用 默认链接脚本(Keil 里不指定 scatter file),怎样改?

如果你确认 完全不需要 xxxxFont.sct 这个分散加载文件(scatter file),可以改用 Keil 的 默认链接脚本。某些芯片的启动文件(如 startup_xxx.s)可能依赖 scatter file,移除后需检查能否正常进入 main()。ROM (Flash):0x08000000,大小根据芯片调整(如 0x00080000 对应 512KB)。代码和常量(RO)被正确放入 Flash(如 0x08000000)。变量(RW/ZI)被放入 RAM(如 0x20000000)。

weixin_50882165的博客 733

波士顿咨询最新发布《2025年全球支付报告:未来不稳定》:到2029 年,支付收入将预计达到 2.4 万亿美元

波士顿咨询最新发布《2025年全球支付报告:未来不稳定》:到2029 年,支付收入将预计达到 2.4 万亿美元

face light~ 917

Keil5内存窗口查看:分析SF32LB52堆栈使用情况

本文介绍如何利用Keil uVision5内存窗口动态分析SF32LB52 MCU的堆栈使用情况,通过填充法观测实际栈消耗,定位溢出风险,结合调用深度与中断嵌套进行综合评估,提升系统稳定性。

uran的专栏 914

雷电模拟器安装面具环境并过软件检测系列(看这一篇就够了!)

雷电模拟器安装面具环境并过基本软件的环境检测

qq_45059975的博客 6万+

ElectrolyteGPT:首个电池电解液逆向设计的生成式 AI 系统 —— 算法原理与复现解析

数据驱动的重要性:1100 万→100 万的精心筛选,比单纯增大模型更有效领域适配:fLine 表示法、正则分词、化学感知的数据增强(SMILES randomization)都是关键小模型的力量:6M 参数在特定化学空间的表现,远超通用大模型在相同任务上的零样本能力条件生成的极限:10 维条件导致模型崩溃,提示我们需要更好的条件编码策略(如 diffusion guidance、RLHF-style 偏好优化)未来方向配方实验验证。

ASKCOS博客 123

JLink与Keil联合调试:定位SF32LB52运行异常

本文通过J-Link与Keil联合调试,深入分析国民技术SF32LB52芯片在Stop模式下唤醒失败的问题,揭示独立看门狗IWDG在低功耗模式中持续运行导致系统复位的根源,并提供完整的诊断流程、寄存器分析与解决方案,展示高阶调试工具在复杂嵌入式问题中的关键作用。

gold8的专栏 1259

109. SAP ABAP 应用程序中的锁机制和工作原理介绍

SAP ABAP 系统中的锁概念,是 SAP ABAP 为了保证`数据一致性`而引入的一种保护机制。 像 SAP 这种复杂的企业级应用,系统中同一时间段的同一份数据,可能会有多个 Transaction(终端用户或者 API )同时进行读写操作。为了防止出现数据不一致,SAP ABAP 引入了锁机制。 这种锁机制并非数据库服务器层面的锁,而是在 SAP ABAP 应用服务器层面上工作,加锁和解锁都由专门的 ABAP Function Module 来完成。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1468

keil代码连接地址修改

bootload拷贝APP代码到DRAM的某一地址,然后跳转运行APP. bootload部分代码如下:

u013216061的博客 2584

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

关于keil 自定义链接脚本 编译错误

为了在程序中实现printf 打印, 于是在keil Target 中勾选了 use MicroLib 选项, 编译时出现如下错误: L6218E: Undefined symbol __initial_sp (referred from entry2.o). 解决方法: 在链接脚本中(scat 文件,分散加载文件),指定堆栈指针的位置: ARM_LIB_HEAP  0x200047

may02的博客 4977

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Realview MDK中链接脚本详细解析

使用Realview MDK时不可避免的要涉及到链接脚本文件,特别是编译链接那些大的工程文件时更是如此。在链接脚本中可以指定代码的存储布局,可以将代码段、只读数据段、可读写的数据段分别存放,甚至可以精确地指定代码放置的位置,这一点是很关键的,譬如说启动代码就必须放在可知型文件的开始位置。由于链接脚本重要性,开发者必须掌握其编写的方法。 Realview MDK链接程序使用了两种方式控制程序的链接

非著名码农的专栏 2801

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

KEIL MDK链接脚本详解

在了解keil的链接脚本之前需要了解几个重要概念: RO(ReadOnly):表示程序中的指令和常量 RW(Read/Write):表示程序中已初始化的变量 ZI(Zero):表示程序中未初始化的变量 我们在编译keil中的工程项目时生成的目标文件时叫做镜像文件(Image)或bin文件,image文件中只包含RO,RW段,这是因为ZI数据段都是零,没有必要包含,只需要把ZI所在的区域清零即...

qq_40888343的博客 9653

STM32链接脚本详解

程序的编译分为四个步骤:预处理、汇编、编译、链接。在开发STM32时,我们只要在IDE中点击编译就能一次性完成这4个步骤,实际上IDE也是要经过这些步骤的,只不过IDE为我们屏蔽了很多细节。 首先我们需要了解一个image文件的构成。image即编译的产物,我们编译STM32生成的bin文件此处称之为image。一个image文件由RO段和RW段组成,RO段包含只读的代码段和常量,RW段包含可读...

Dokin 1万+

KEIL MDK链接脚本-分散加载文件sct

在了解keil的链接脚本之前需要了解几个重要概念: RO(ReadOnly):表示程序中的指令和常量 RW(Read/Write):表示程序中已初始化的变量 ZI(Zero):表示程序中未初始化的变量 我们在编译keil中的工程项目时生成的目标文件时叫做镜像文件(Image)或bin文件,image文件中只包含RO,RW段,这是因为ZI数据段都是零,没有必要包含,只需要把ZI所在的区域清零即可。而其他两个数据段是被赋值了的,所以image文件需要包含已初始化变量的初值。如果我们将image文件烧录到R

EmbeddedCoder 的优快云博客 9950

MDK5 keil 下动态内存分配以及使用事例

1.打开mdk的Operation选项,在target栏目里选中Use MicroLIB选项以便支持malloc-free函数原型                      2.打开stm32工程源码,找到start_stm32f10x_md.s文件修改:Heap_Size       EQU     0x00001000 /*********************************

长江不择细流,故能浩荡万里 6037

MDK链接脚本解析

文章目录序言一些基本概念的建立链接脚本的作用具体链接脚本分析 序言 我的上一篇文章程序是在FLASH中运行中介绍了单片机中的一种奇特现象:程序不需要加载到SRAM中,而是可以直接在FLASH中运行。在我们知道了这件事情之后,我们趁热打铁,继续探讨程序在FLASH中的静态布局与运行时动态布局。链接脚本文件对这两种布局有着重要影响。我们下面的主要探究对象就是这个链接脚本文件。 一些基本概念的建立 段...

Shijia Yin 2191
上一篇: 如何设计 PCB 天线避免 WiFi/蓝牙互相影响
下一篇: Multisim 做不了仿真?常见问题一篇搞定
docker8compose
博客等级 码龄1天 0粉丝 1102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值