原创 Kinetis L系列的启动过程及其实现(一)

2013-8-5 14:49 2310 19 25 分类: 消费电子

Kinetis L系列的启动过程及其实现(一)

 

[前提]

众所周知, Kinetis L 的 MCU 不存在 bootloader, 这与 NXP 的 ARM 系列有明显的不同.

在 NXP 的 LPC 系列(ARM7)中, 存在 bootloader, 这个 bootloader 将执行一系列的初始化, 也会将 flash 中断向量表 copyto ram, 同时也包括定义的 ram function. 而且, 在 bootloader 的启动中, 还会比较 ISP PIN(一般这个 PIN 是 P0.14), 如果 P0.14 被拉低, 那么 LPC MCU 将进入 ISP 状态, 也就是初始化 uart, 并可以通过 uart 直接下载 firmware.

而 Freescale 的 Kinetis L serials(CORTEX MO+) 是没有类似的 bootloader 的存在. 这可能带来两个方面的不同效果的影响:
作为项目设计者, 我们不得不自行设计系统 startup 的过程, 一手操办 system reset 中初始化的代码, 比如说, 数据初始化过程, 中断向量表与 ram function 向 RAM 的 copyto 等等. 没有经过设计者包办的启动过程, 我们甚至无法正确的运行 main() 函数. 一方面, 这带来了我们工作量的增加; 但是另一方面讲, 这也确实是一个机会, 使得项目设计者, 清晰了解 KL MCU 中的 RESET 过程, 并必须尊重 MCU 的 startup 的规则.

 

[参考]

网络上, 至少有两种中文开发者参考资源, 描述了 Kinetis L serial 的 startup 的过程, 但是都未曾明确指出, 这个 startup process 描述的出处 -- 实际上, 它来源于官方的 Freescale 的可下载帮助文档, 文档名为:
Kinetis L Peripheral Module Quick Reference 之中第一章: Chapter 1: General System Setup(Software Considerations)

 

[BOOT过程]

我们使用 IAR 6.50.3, 并借鉴 IAR 自带的 FREEDOM KL25Z 的 SAMPLE(FOR KL25Z128) 来说明 BOOT 过程, 不意外地, 通过对 BOOT 过程的理解, 以及 startup 规则的要求, 我们将跟随完成 startup 实际代码, 建立一个成功 BOOT 过程:

(1) START POINT:


FLASH 的起始地址被定义为: 0x00000000, 初始 stack pointer(SP) 位于向量表的首地址, 而 4-byte offsets 位置也就是向量表的第二个量是 Program counter(PC).


设备支持从 internal flash 做 boot, 也就是从地址 0x00000000 开始, 获得 SP 与 PC(VECTOR_001) 后, 并跳转于 PC address 开始执行指令.


当然设备也只从从 RAM 启动, 比方说, 如果在默认从 flash 启动后, 我们在 startup 中完成, 将 flash 中的异常向量表 copyto 到 ram, 那么我们将能实现从 RAM 启动的过程. 另外要提到的是, 我们记得曾经了解过, 将异常向量表在 startup 中 copy头 ram, 不仅仅可以 do ram boot, 也可以加速 interrput 的过程.


那么不意外的, 从向量表的 3rd 量开始, 这将是 interrupt isr 的入口地址(图例1中, 我们见到3rd 的值为 VECTOR_002, 实际上是不可屏蔽中断 NMI 对应的地址, 而之后的 VECTOR_003 开始, 是我们 interrupt 例程中使用到的地址. 在之后的图例中, 我们将看到对应的注释).

[图例1: 来自 freedom sample 中的 vectors.c 中, 对异常向量表的定义]

1.jpg
 
 
(2) 异常向量表的ADDRESS:

让我们检查 IAR complier 的 linker 安排, 无疑的, 异常向量表的初始地址是: 0x00000000

[图例2: 来自 IAR Linker 脚本文件, sample 中为, 128KB_Pflash.icf]
 
2.jpg



在 IDE 中, 我们使用 config options - > linker 的 config TAB 中, 对 ICF file 的 edit 按钮也可以读到:

[图例3: 来自 IAR IDE 中操作的 ICF FILE 编辑框]

3.jpg



准确的, Linker 脚本文件, 定义异常向量表的起始地址, 就是 FLASH 的起始地址:0x00000000

[图例4: 来自 IAR Linker 脚本文件, sample 中为, 128KB_Pflash.icf]

4.jpg
 
(3) RESET 过程与 MCU 状态

在 RESET 过程中, MCU 的 digital I/O PIN 将进入 disable state, 也就是高阻态(内部上拉下拉禁止). analog PIN 将进入默认的 analog function. 而一旦 RESET 完成后, digital I/O PIN 继续保持 disable state, 中断被禁止, 并且大部分的 modules 被关闭. 时钟模式进入 FEI 模式. 且 watchdog 被激活.

对于 kinetis L serial, 上述 RESET 执行后的 device state, 则暗示着我们, 我们需要在 startup 中主动设计: core clock, system clock 以及 flash clock (事实上, 默认 flash 与 bus 的 clock 相同). 这是 kinetis L serial 赋予我们设计者的神圣使命(其实, 如果不完成这些任务, 我们事实上无法正常启动这颗 MCU). ;P
 

(4) low-level 的汇编(启动)代码的实现


通过图例1, 我们已知, 设备(默认)从 FLASH 执行后, 从起始地址 0x00000000 处开始, 载入了 4-byte 的 SP 值后, 并将位于 0x00000004 的 PC 值读取后, 跳转到 PC 值指向的指令执行地址, 进行指令执行. 向量表中, PC 对应的定义 VECTOR_001.

[图例5: 来自 freedom sample 中的 vectors.h 文件]

5.jpg


上面的图例清楚说明了, 我们需要实现 __startup 对应于 (VECTOR_001), 也就是 PC 的执行地址. 我们需要实现 __startup 函数, 以实现 MCU 的正确 BOOT.

[图例6: 来自 freedom sample 中的 crt0.s 文件]

6.jpg
 

在上面的图例中, 我们见到了 __startup 的建立, 简单来说, 内容如代码注释, 通用寄存器被清零, 启用中断后, 跳转到了 C 代码形式的 start() 函数. 当然, 对于任何一个 IAR 构建的 NULL KINETIS L project, 这可能意味着, 我们不得不遵守完成 __startup 这个事实上的程序入口点.(题外话, 此时要想编译正常通过, 我们也需要定义 start()函数, 当然在函数内部我们需要 call main() ).

 

(5) REBUILL ALL 得到 OUTOUT FILE


这样, 我们在 IAR IDE 中, 通过正确设定 target mcu 后, 即可 rebuild all, 并生成输出文件格式(设为二进制文件 .bin).  在 IAR 下, 也就是设定:

[图例7: IAR IDE 中的 out file format 的设定]

7-1.jpg
 

(6) 为何 CODE 的起始地址是: 0x000000C0


默认从 FLASH 启动的 .bin 文件, 将异常向量表放在最前, 即从 0x00000000 的地址开始. 跟随着异常向量表, 才是 CODE 的放置区. 异常向量表的 size 有多大?

[图例8: NVIC 的定义, 来自于: Kinetis L Peripheral Module Quick Reference 之 NVIC 章节]

8.jpg

在 kinetis sample 中, 我们也找到下面的证明:

[图例9: NVIC 的定义, 来自 freedom sample 中的 vectors.c 文件]

9.jpg

[图例10: NVIC 的定义, 来自 IAR Linker 脚本文件, sample 中为, 128KB_Pflash.icf]

10.jpg

这里, 48*4 = 0xC0.

 

 
 

文章评论6条评论)

登录后参与讨论

用户468110 2014-1-16 17:19

感谢辛勤分享~~

allen_zhan_752827529 2013-8-27 10:32

"对于 kinetis L serial, 上述 RESET 执行后的 device state, 则暗示着我们, 我们需要在 startup 中主动设计: core clock, system clock 以及 flash clock (事实上, 默认 flash 与 bus 的 clock 相同). 这是 kinetis L serial 赋予我们设计者的神圣使命(其实, 如果不完成这些任务, 我们事实上无法正常启动这颗 MCU). ;P" -- 我们回顾3周前的这段内容时, 应该做的一个小的订正就是: 只有顺利完成全部的 startup, 我们则可以正常启动这颗 MCU. 而建立 core clock, system clock 等, 不具有启动必要性. 因为, MCU 在未有建立自定义时钟之前, 首先进入了 FEI 状态, 也就是内部的 IRC, 使其"心跳脉动". 其实我们都知道, 事实上, IRC 功能的 uController, 往往来自晶振的烦恼会更小些. 因为晶振相关的问题, 是大凡系统开发中, 都会常常遇到的现象.

allen_zhan_752827529 2013-8-15 12:35

谢谢, 我的努力, 也是对上次贵同事抬爱邀请在下欣赏宝华兄之精彩讲座的一份回报, 无功不受禄呀. 哈哈.

用户1277994 2013-8-15 09:25

代表所有电粉们向博主表示感谢先。

用户1602177 2013-8-5 15:01

感谢辛勤分享~~

用户1610239 2013-8-5 09:05

拜读学习啊 。谢谢allen的分享 啊
相关推荐阅读
allen_zhan 2023-02-27 19:08
对"三极管"译名由来的探讨
想讨论一个有意思的话题:今天中国大陆的电子业界, 为何将 BJT 称呼为 "三极管"? 或因其象形, 前辈自行进行随意的不严谨定义么? 带着疑问我们做了一下延伸查阅, 或得出这样的结论, 即中译名"三...
allen_zhan 2023-02-19 18:15
对知乎提问"为何三极管的一个PN结工作在反偏"的回复
将这个回复, 也发表在博文中, 作为自己的一个学习笔记叭.知乎问题: "三极管里面的PN结相当于二极管,为什么里面PN结加反向电压也能导通?"我的回复:首先, 二极管的"反向"概念, 容易给初学者某种...
allen_zhan 2023-02-18 10:17
从肖特基二极管到PN结与三极管
最近数个工作日的兴趣是回顾电子基础器件的发明/发展历史, 期待夯实技术基础的底蕴. 在学习与搜索资料的过程中, 顺便对知乎的一个同学的基础问题, 进行了回复. 不小心回复一下就成了千字文, 觉得挺有趣...
allen_zhan 2023-01-28 11:53
微功率 ISM 频率探讨相关文档组总结
不知不觉, 自开启关于微功率频率的话题起, 即从第一份文章写就到今天总结之日, 已经接近 10 个工作日左右. 早先的想法是对工程界未来的微功率设备相关项目, 从项目规划开始, 对选择系统, 频率, ...
allen_zhan 2023-01-27 22:50
关于 LoRa 应用场景的讨论
说明: 本文中斜体部分表示来自公告文件的部分内容剪贴或合并整理.1. "第52号文" 对 470MHz 的约束引自 如下:(四)民用计量仪表限在建筑楼宇、住宅小区及村庄等小范围内组网应用,任意时刻限...
allen_zhan 2023-01-25 13:24
ISM 频段中 2.4G 与 5.8GHz 设备的使用与限制
说明: 本文中斜体部分表示来自公告文件的部分内容剪贴或合并整理.1. ISM 频段定义中的 2.4G 与 5.8GHz正如同 文中确定的, 2.4G, 5.8GHz 属于中国大陆 ISM 频段的定义...
我要评论
6
19
关闭 站长推荐上一条 /2 下一条