# 从0到1点亮并深入理解 ARM 底层软件开发 **Repository Path**: Coding-years/hello_baremetal ## Basic Information - **Project Name**: 从0到1点亮并深入理解 ARM 底层软件开发 - **Description**: 基于i.MX6ULL (Cortex-A7)开发板的裸机(bare-metal)编程实践项目,配合DAPLink / JLINK调试器和OpenOCD + GDB + VSCode调试链路进行开发。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-15 - **Last Updated**: 2026-09-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # hello_baremetal **从 0 到 1 点亮并深入理解 ARM 底层软件开发** 基于 **i.MX6ULL (Cortex-A7)** 开发板的裸机(bare-metal)编程实践项目,配合 **DAPLink / JLINK** 调试器和 **OpenOCD + GDB + VSCode** 调试链路进行开发。 > **核心目标**:不依赖 SDK 和 bootloader,通过阅读芯片参考手册(Reference Manual)和官方数据手册,从汇编启动、时钟树配置、外设寄存器操作到 DDR 初始化,彻底搞懂 ARM 处理器系统架构的每个环节。 --- ## 目录 - [背景与动机](#背景与动机) - [开发环境](#开发环境) - [路线图](#路线图) - [第一阶:SRAM/OCRAM 裸机程序](#第一阶段-sramocram-裸机程序) - [第二阶段:DDR 裸机程序(规划中)](#第二阶段-ddr-裸机程序规划中) - [第三阶段:综合与进阶(规划中)](#第三阶段综合与进阶规划中) - [项目结构](#项目结构) - [快速开始](#快速开始) - [核心知识点清单](#核心知识点清单) - [参考资源](#参考资源) --- ## 背景与动机 ARM 嵌入式开发常见的路径是依赖厂商 SDK(如 NXP SDK、STM32 HAL)或 RTOS/ Linux。这种方式虽然上手快,但也容易把底层硬件细节隐藏起来——时钟树如何切换、PLL 如何锁定、DDR 为何需要训练参数、Cache 一致性如何处理——这些关键问题往往变成了"黑盒"。 本项目反其道而行: - **不跑 Linux,不挂 SDK 头文件**(但参考 SDK 中的寄存器定义) - **每一行代码都直接从参考手册中来** - **使用 DAPLink / JLINK 等 SWD 调试器,通过 OpenOCD + GDB 实现纯软件调试** 从点亮一颗 LED 开始,逐步深入到完整的存储系统和处理器微架构。 --- ## 开发环境 | 组件 | 方案 | |------|------| | **主控** | NXP i.MX6ULL (Cortex-A7, ARMv7-A) | | **调试器** | DAPLink (CMSIS-DAP) / SEGGER JLINK | | **调试服务器** | OpenOCD 0.12+ | | **IDE** | VSCode + Cortex-Debug 插件 | | **工具链** | `arm-none-eabi-gcc` (12.x+) | | **串口工具** | minicom / PuTTY / serial 等 (115200 8N1) | **调试链路架构**: ``` VSCode (Cortex-Debug) ↓ gdb GDB (arm-none-eabi-gdb) ↓ gdb-server OpenOCD (adapter + imx6ull target) ↓ SWD DAPLink / JLINK → i.MX6ULL ``` ### 关键配置 - `imx6ull_daplink.cfg` — OpenOCD 配置文件(DAPLink 版本),包含 `reset-deassert-post` 自定义初始化流程(关 I-Cache、halt 后 dbginit) - `.vscode/launch.json` — GDB 调试启动配置,`overrideLaunchCommands` 包含 `monitor reset halt → load → set $cpsr → set $pc` 全自动加载流程 - `target/imx6ull.cfg` — OpenOCD 目标芯片配置(TAP IDCODE、DAP 操作) - `interface/cmsis-dap.cfg` — DAPLink 适配器配置 > 详见 `uart/TECHNICAL_NOTES.md` 中记录的调试经验和问题定位过程。 --- ## 路线图 ### 第一阶段:SRAM/OCRAM 裸机程序 ✅ 在 i.MX6ULL 内部 **128KB OCRAM** (0x00900000) 中运行裸机程序。OCRAM 上电即用,不需要初始化 DDR 控制器,是"从 0 到 1"的最佳起点。 | 项目 | 功能 | 涉及核心技术 | 状态 | |------|------|-------------|------| | `led/` | GPIO 控制 LED 闪烁 | ARM 启动流程、I-Cache/MMU 关闭、栈指针设置、链接脚本、GPIO 寄存器操作 | ✅ | | `uart/` | UART1 回显驱动 | 时钟树(PLL 安全切换、Glitchless 两路选择器、两级同步)、UART 波特率精确匹配、字符 I/O | ✅ | | _(规划中)_ | GPT 定时器、按键中断、EPIT | 中断系统(GIC)、定时器精度校准 | ⏳ | | _(规划中)_ | printf 重定向 | 可变参数、格式控制 | ⏳ | **已完成的核心知识点**: 1. **ARM Cortex-A7 启动流程**:`_start` → 关 I-Cache → 关 MMU → 设 SP → 跳 main 2. **SCTLR 操作与 Cache 管理**:CP15 协处理器指令、ICIALLU、BPIALL 3. **PLL 安全切换**:切旁路 → 改 DIV → 等 LOCK → 切回(四步法) 4. **Glitchless 时钟 Mux 原理**:两级同步 + 双计数器,无毛刺切换 5. **UART 波特率精确匹配**:UBIR/UBMR 公式推导,实现 115200 零误差 6. **DAPLink + OpenOCD 调试链路搭建**:reset-deassert-post、gdb-attach 问题诊断 7. **链接脚本设计**:段布局、栈顶计算、内存区域划分 ### 第二阶段:DDR 裸机程序(规划中) 从 SRAM 跳转到 DDR 执行,涉及整个存储子系统的深度理解。 | 任务 | 内容 | |------|------| | DDR 控制器初始化 | 阅读 i.MX6ULL RM 中 DDR 控制器章节, 配置 MMDC 寄存器 | | DDR 训练参数 | 理解 write leveling、DQS gating、read/write calibration 原理 | | PCB 走线与高频信号 | 了解 DDR 信号完整性要求、等长走线、终端匹配(参考 i.MX6ULL 官方硬件设计指南) | | 从 SRAM 搬运到 DDR | 编写搬运代码(scatter-loading),实现"SRAM 小内核加载 DDR 大程序" | | MMU 与页表 | 初始化页表、开启 MMU、建立 DDR 区域映射 | | Cache 使能与管理 | I-Cache + D-Cache 使能、Cache 策略配置(write-back / write-through) | ### 第三阶段:综合与进阶(规划中) | 任务 | 内容 | |------|------| | 处理器流水线 | Cortex-A7 的 8 级流水线结构、分支预测、流水线 hazard 分析 | | 中断控制器 (GIC) | GIC-400 配置、中断优先级、FIQ/IRQ 处理流程 | | 编译与链接深入 | `arm-none-eabi-objdump` 反汇编分析、链接脚本高级语法(OVERLAY、AT>)、`nm/size` 分析 | | 链接地址与加载地址分离 | 理解 `LMA != VMA`、`AT>` 实现代码重定位 | --- ## 项目结构 ``` hello_baremetal/ ├── README.md ← 本文件 ├── .vscode/ │ └── launch.json ← VSCode 调试启动配置 │ ├── led/ ← 第一阶段:LED 闪烁 (SRAM) │ ├── main.c ← GPIO 驱动 + 主循环 │ ├── startup.s ← ARM 汇编启动 │ ├── linker.ld ← 链接脚本 (OCRAM 0x00900000) │ └── Makefile │ ├── uart/ ← 第一阶段:UART 回显 (SRAM) │ ├── main.c ← 主函数 (clkinit → uart_init → echo) │ ├── clk.c ← 时钟初始化 (PLL 切换 + 使能) │ ├── uart.c / uart.h ← UART 驱动 (寄存器操作) │ ├── startup.s ← ARM 汇编启动 │ ├── linker.ld ← 链接脚本 │ ├── uart.dis ← 反汇编文件 (调试参考) │ └── TECHNICAL_NOTES.md ← 技术总结与调试经验 │ ├── imx6ull_daplink.cfg ← OpenOCD 主配置 (DAPLink) ├── target/imx6ull.cfg ← i.MX6ULL 目标配置 ├── interface/cmsis-dap.cfg ← DAPLink 适配器配置 │ ├── test_uart.py ← 串口自动测试脚本 ├── analyze_jtag.py ← JTAG 信号分析工具 │ └── xunwei_imx6ull_baremetal/ ← 参考:讯为官方案例(对比/验证用) ``` --- ## 快速开始 ### 前置条件 ```bash # 工具链 sudo apt install gcc-arm-none-eabi gdb-arm-none-eabi openocd # 串口工具 sudo apt install minicom ``` ### 编译 ```bash # 编译 LED cd led && make # 编译 UART cd uart && make ``` ### 下载调试(DAPLink 示例) 1. 连接 DAPLink 到 i.MX6ULL SWD 接口 2. 连接 UART1 TX/RX 到串口转 USB 模块 3. 确认 DAPLink 在线: ```bash lsusb | grep 0d28:0204 ``` 4. 启动 OpenOCD: ```bash sudo openocd -f imx6ull_daplink.cfg ``` 5. 在 VSCode 中按 **F5** 启动调试(自动 load 并运行) > 详见 `uart/TECHNICAL_NOTES.md` 中的完整调试步骤和故障排除记录。 --- ## 核心知识点清单 ### 处理器架构 - [x] Cortex-A7 寄存器模型(R0-R15, CPSR, SPSR) - [x] ARM/Thumb 指令集切换与 CPSR T 位 - [x] CP15 协处理器与 SCTLR 系统控制寄存器 - [x] 异常向量表与处理器模式 ### 存储系统 - [x] I-Cache 失效与关闭(ICIALLU, BPIALL) - [x] MMU 关闭与页表跳过 - [ ] MMU 页表初始化与映射(规划中) - [ ] D-Cache 使能与策略配置(规划中) - [ ] DDR MMDC 控制器配置(规划中) - [ ] DDR 训练与校准(规划中) ### 时钟与电源 - [x] PLL 频率计算(DIV_SELECT 公式) - [x] Glitchless 时钟切换(两级同步原理) - [x] 四步安全切换流程 - [ ] 电源域与 LDO 配置(规划中) ### 外设驱动 - [x] GPIO 输入输出与复用配置(IOMUXC) - [x] UART 波特率生成与 FIFO 模式 - [x] 时钟门控寄存器(CCGR0-6) - [ ] GPT/EPIT 定时器(规划中) - [ ] GIC 中断控制器(规划中) ### 编译与链接 - [x] ARM 链接脚本语法(MEMORY, SECTION, ORIGIN/LENGTH) - [x] 栈顶与堆位置计算 - [x] `.text.boot` / `.text` / `.rodata` / `.data` / `.bss` 段布局 - [ ] LMA vs VMA 与代码重定位(规划中) --- ## 参考资源 - **NXP i.MX6ULL Reference Manual** (IMX6ULLRM) — 最核心的技术文档 - **NXP i.MX6ULL Data Sheet** — 电气特性、DDR 布局指南 - **ARM Cortex-A7 Technical Reference Manual** — 处理器微架构细节 - **ARM Architecture Reference Manual ARMv7-A/ARMv7-R** — CP15、指令集规范 - **讯为 i.MX6ULL 裸机教程 & 源码** — 本项目最初的学习参考 - **OpenOCD 用户指南** — `cmsis-dap` 驱动与 `cortex_a` target 配置