Mini2440是一块非常经典的入门开发板。本文将讲透这张启动图背后的概念。

上电启动

一切始于电平。在 S3C2440 芯片上,有两个特殊的引脚:OM0 和 OM1。当然一般都是用的开关就实现了(图右下角)。

当系统复位(Reset)信号失效的瞬间,芯片内部逻辑会采样这两个引脚的电平状态,从而决定 CPU 的第一条指令从哪里读取。

OM1 OM0 启动模式 解释
0 0 NAND Flash 启动 Mini2440 最常用的模式。此时片内 SRAM 被映射到 0 地址。
0 1 16-bit ROM 启动 通常指 NOR Flash 启动。NOR Flash 被映射到 0 地址。
1 0 32-bit ROM 启动 同上,只是总线宽度不同。
1 1 Test Mode 测试模式,一般不用。

核心差异

  • NOR Flash 启动:NOR Flash 像内存一样,支持随机访问,支持片上执行(XIP, eXecute In Place)。CPU 可以直接读取 NOR Flash 里的指令执行。

  • NAND Flash 启动:NAND Flash 像硬盘,只能按块访问,不支持 XIP。CPU 无法直接去 NAND 里取指令。这就引出了 S3C2440 最精妙的设计——Steppingstone

什么是 Steppingstone?

S3C2440 SOC芯片内部集成了一块容量极小的 SRAM (Static RAM),大小只有 4KB

在官方数据手册中,这块 SRAM 被称为 "Steppingstone"。它的作用正如其名——它是系统启动的一块垫脚石。因为 4KB 太小,跑不了操作系统,甚至跑不下完整的 u-boot,但它足够用来完成最基本的硬件初始化和代码搬运。

当你点击“编译”时,工具链(gcc/ld)做了一件至关重要的事情:排座位

通过链接脚本(.lds),start.s 被安排在了最前面,main.c 紧随其后。假如最终生成的.bin 二进制文件结构如下:

  • 0x0000 - 0x0020: start.s 的机器码(关看门狗、设栈、跳转)。

  • 0x0020 - 0x0xxx: main.c 的机器码(配置寄存器、循环)。

Steppingstone 里的内容就是你通过Makefile或者keil编译生成的 bin (axf、hex)文件的前 4KB 数据,说白了就是start.s的内容。

内存映射

这是初学者最容易混淆的地方。ARM CPU 启动时永远只认地址 0x00000000。但是,物理上的存储器连接位置是固定的,如何让 CPU 在不同模式下看到不同的东西?答案是地址重映射

场景 A:NOR Flash 启动

  • Bank 0 (nGCS0):连接着外部的 NOR Flash。

  • 映射结果:硬件直接把 NOR Flash 映射到 0x00000000

  • 执行流:CPU 直接从 NOR Flash 读取指令运行。

场景 B:NAND Flash 启动

  • Bank 0 (nGCS0):虽然原理图上可能还连着 NOR Flash(如果有的话),但在逻辑上被断开了。

  • Steppingstone (SRAM):原本只能通过特定内部地址访问,现在被硬件强制映射到了 0x00000000

  • 自动拷贝机制

    • 上电复位瞬间,NAND Flash 控制器自动启动。

    • 它自动将 NAND Flash 中的前 4KB 数据拷贝到这块 Steppingstone (SRAM) 中。

    • 在这个拷贝过程中,CPU 处于复位保持状态(不运行)。

    • 拷贝完成后,CPU 复位释放,开始从 0x00000000(也就是 Steppingstone 的起始位置)执行代码。

Bootloader 第一阶段:SRAM

SRAM既然只有 4KB,代码必须极度精简(通常由汇编语言编写,比如keil提供的 S3C2440.s)。这 4KB 代码需要在几毫秒内完成以下“规定动作”:

4.1. 关看门狗 (Disable Watchdog)

  • 原因:看门狗默认开启,如果不在规定时间内“喂狗”,它会复位 CPU。启动初期我们没空喂狗,所以必须先把它关掉。

  • 代码:向 WTCON 寄存器写 0。

4.2. 关中断 (Disable Interrupts)

  • 原因:此时系统刚启动,中断向量表还没建立,堆栈也没准备好。如果来了中断,CPU 跳到乱七八糟的地方就挂了。

  • 代码:操作 CPSR 寄存器屏蔽 IRQ 和 FIQ。

4.3. 初始化系统时钟 (Clock Setup)

  • 原因:外部晶振通常只有 12MHz,CPU 跑得太慢。

  • 动作:配置 PLL (MPLL),将系统主频 (FCLK) 提升到 400MHz(或其他频率),并设置分频系数给外设使用。

4.4. 初始化 SDRAM

  • 这是最关键的一步!

  • Steppingstone 只有 4KB,跑不完后续代码。我们需要启用板载的大容量内存(SDRAM,例如 64MB)。

  • 动作:配置存储管理器(Bank 6 对应的寄存器),设定行/列地址宽度、刷新频率等,让 SDRAM 准备好接收数据。

4.5. 设置栈 (Stack Setup)

  • 原因:后续如果要调用 C 语言函数(或者进行复杂的逻辑跳转),必须有栈空间来保存现场。

  • 动作:将栈指针 SP (r13) 指向 SRAM 的顶端或者刚刚初始化好的 SDRAM 的某块区域。

4.6. 代码搬运

  • 核心逻辑:这 4KB 代码要把自己(完整的 Bootloader)或者操作系统内核,从 NAND Flash 中读出来,搬运到 SDRAM 中。

  • 为什么? 因为 NAND Flash 不能直接运行代码,而 4KB SRAM 又太小。

  • 实现:通过读写 NAND Flash 控制器的寄存器(NFCONF, NFCMD, NFADDR, NFDATA),循环读取数据并写入 SDRAM 地址(通常是 0x30000000 以后)。

4.7. 跳转 (Jump to RAM)

  • 动作:搬运完成后,修改 PC 指针,跳到 SDRAM 中去执行。

  • 指令ldr pc, =0x3000xxxx (使用绝对跳转指令)。

  • 结果:至此,Steppingstone 完成了历史使命,CPU 开始在宽阔的 SDRAM 中通过 u-boot 的第二阶段(C语言部分)继续狂奔。

总结图解

如果你再看一遍 Mini2440 的启动图,脑海中应该有这样一个动态过程:

  1. 上电 -> 硬件检测 (NAND模式)。

  2. 硬件动作 -> NAND Flash 前 4KB 自动 复制到内部 SRAM。

  3. 地址映射 -> 内部 SRAM 变身为 地址 0

  4. CPU 运行 -> 运行 SRAM 里的 S3C2440.s

  5. 初始化 -> S3C2440.s 初始化外部 SDRAM。

  6. 搬运 -> S3C2440.s 读取 NAND 中剩余的几百 KB 代码到 SDRAM。

  7. 跳转 -> PC 指针跳入 SDRAM,Linux 启动之路正式开始。

这就是为什么这块小小的 4KB 区域被称为 "Steppingstone" —— 它虽然小,却是连接静态存储(NAND)与动态运行环境(SDRAM)的唯一桥梁。

JLINK 调试

很多开发者使用 JLINK(配合 J-Flash 或 IDE)进行裸机程序调试。你可能会遇到这样的情况:为什么我用 JLINK 直接下载程序到 SDRAM (0x30000000) 会失败?

这需要结合我们上面讲的启动原理来看。

6.1 初始化 SDRAM

回顾第 4.4 节,SDRAM 并不是上电就能用的,它需要配置存储控制器寄存器(设置列地址、刷新率等)之后才能被读写。

  • 正常启动时:Steppingstone 里的 S3C2440.s 帮我们完成了初始化 SDRAM 的工作。

  • JLINK 调试时:通过 JTAG 连接板子时,CPU 通常处于复位或暂停状态,S3C2440.s 还没来得及运行(或者被跳过了)。此时 SDRAM 控制器处于未配置状态,SDRAM 就是一片荒原,根本无法写入数据。

6.2 调试脚本 (Init Script) 的作用

为了解决这个问题,在使用 JLINK调试 S3C2440 时,我们必须挂载一个初始化脚本(keil里是.ini)。

这个脚本的作用就是代替 Steppingstone,通过 JTAG 指令直接操作 CPU 寄存器:

  1. 关看门狗:防止调试一半重启。

  2. 配置时钟:让 CPU 跑快点。

  3. 初始化存储控制器这是最关键的一步! 脚本会向 Memory Controller 寄存器写入正确的值,瞬间“点亮” SDRAM。

6.3 调试的标准流程

有了初始化脚本,调试流程就变成了:

  1. 连接 JLINK:CPU 暂停。

  2. 运行初始化脚本:此时 SDRAM 变为可读写状态。

  3. Download:将编译好的程序(.bin.elf)直接下载到 SDRAM(例如 0x30000000)。

  4. Set PC:手动将 PC 指针修改为 0x30000000

  5. Run:程序开始直接在内存中狂奔。

总结:JLINK 调试其实就是绕过了“NAND -> SRAM”的搬运过程,利用上帝视角(JTAG)手动初始化内存并注入代码。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐