ARM裸机笔记
ARM启动代码中做的事
Cortex‑A7裸机,上电首先执行启动汇编,完成硬件、内核模式、栈、缓存初始化,最后跳转C语言main函数。
- 设置异常向量表
将复位、未定义指令、软中断、预取中止、数据中止、IRQ、FIQ异常的跳转指令放在内存起始处,发生异常CPU自动跳转到对应偏移地址执行。 - 异常向量表地址重映射
把异常向量表重映射到程序链接地址0x87800000,告诉Cortex‑A7内核从此处读取异常向量。 - 为不同处理器工作模式分配栈指针SP
ARM7/A7有多种工作模式:管理模式、IRQ中断模式、FIQ模式、系统模式。
每种模式拥有独立SP栈寄存器;在汇编里给IRQ模式、System模式设置栈空间,中断发生才能正常入栈保存寄存器。
ARM默认是满减栈,STMFD入栈、LDMFD出栈。
- 使能IRQ内核总中断
修改CPSR程序状态寄存器,打开内核层面IRQ中断开关;注意:GIC外设中断还需要单独使能,此处只是内核允许接收IRQ。 - 清零BSS段
BSS段存放初始化为0/未初始化的全局、静态变量;BSS段在bin文件中不占空间,汇编需要手动把BSS内存区域全部置0,防止随机脏数据。 - 打开I‑CACHE指令缓存,关闭D‑CACHE数据缓存
CP15协处理器控制Cache:
- I‑Cache:指令高速缓存,打开,CPU取指令速度大幅提升;
- D‑Cache:数据高速缓存,裸机下关闭,避免IO寄存器访问被缓存优化出现异常。
- 跳转到C语言main函数执行
使用bl main,把返回地址存入LR,正式进入C语言裸机业务代码。
关键指令补充:
MRS:读取CPSR特殊寄存器到通用寄存器;MSR:把通用寄存器写回CPSR,用来切换工作模式、开关中断。stmfd sp!,{r0‑r12,lr}:中断入栈保护现场;ldmfd sp!,{r0‑r12,lr}:中断出栈恢复现场。
中断系统(GIC V2,IMX6ULL)
GIC是ARM提供的通用中断控制器,Cortex‑A7使用GIC V2,IMX6ULL硬件支持160路中断源。
GIC中断三大类
- SPI共享外设中断:各类外设产生(GPIO、EPIT、GPT、UART、I2C),多核之间可以共享处理。
- PPI私有中断:属于单个CPU内核,用于核间通信,和外部外设无关。
- SGI软件中断:SVC/swi指令软件触发,多用于操作系统。
IMX6ULL外部中断完整流程(以GPIO按键为例)
- 外设侧寄存器配置(GPIO模块)
GPIOx_ICR:配置中断触发方式:上升沿 / 下降沿 / 高电平 / 低电平;GPIOx_IMR:中断掩码,使能该引脚中断;GPIOx_ISR:中断状态标志位,写1清除中断标志。
- GIC中断控制器配置
- 设置该中断源优先级;
- GIC Distributor层使能对应中断;
- 内核响应中断
外设产生中断信号送给GIC;GIC转发给Cortex‑A7内核。CPU进入IRQ异常模式,跳转到异常向量表IRQ入口。 - 中断服务处理
- 读
C_IAR寄存器,获取发生中断的中断号; - 根据中断号调用对应外设中断处理函数;
- 处理完成,将中断号写入
C_EOIR,通知GIC本次中断处理完毕; - 恢复寄存器现场,返回被打断的程序。
中断优先级:IMX6ULL共32级优先级0~31,数字越小优先级越高。
定时器(EPIT / GPT)
EPIT定时器
32位自减计数器,两种工作模式:
- Free‑Running 自由运行模式:计数器到0后自动重装载最大值0xFFFFFFFF;
- Set‑and‑Forget 设置遗忘模式:计数到0,只重装载一次加载寄存器的值。
GPT定时器
32位自增计数器:
- 输出比较:可以输出PWM方波;
- 输入捕获:测量外部脉冲高/低电平时间,测脉冲宽度。
按键软件消抖:利用定时器延时,跳过机械按键抖动时间段再读取IO电平,代替硬件RC电容消抖。
时钟系统
IMX6ULL外部输入晶振:24M无源晶振
- PLL锁相环:实现倍频,把低频外部晶振提升到高频内核时钟;
- PFD相位分数分频器:进一步做倍频、分频;
- Prescale预分频器:对时钟做整数分频。
IMX6ULL核心时钟配置目标
- ARM内核时钟:528MHz
- AHB_CLK_ROOT:132MHz 高速总线时钟(AHB总线,高速外设:DDR、USB)
- IPG_CLK_ROOT:66MHz
- PERCLK_CLK_ROOT:66MHz
总线划分:
- AHB高速总线:高速外设 DDR、网卡、USB;
- APB外设总线:低速外设 GPIO、UART、定时器、I2C。
每个外设都有CCGR时钟门控寄存器,使用外设前必须打开时钟,否则外设不工作。
UART 通用异步收发器
UART:全双工、串行、异步通信 。
信号线:
- TXD:发送;RXD:接收;
- RTS_B 请求发送、CTS_B清除发送:硬件流控,防止接收缓冲区溢出丢数据,裸机一般不用。
UART通信帧格式
空闲状态:总线高电平
1bit起始位(低电平) → 8bit数据位 → 可选校验位 → 1bit停止位(高电平)
常用配置:
115200‑8‑N‑1:波特率115200,8数据位,无校验,1停止位。
电气标准对比
| 项目 | TTL | RS232 | RS485 |
|---|---|---|---|
| 信号 | 单端 | 单端 | 差分A/B |
| 电平 | 0~3.3V / 0~5V | ±3~±15V | A‑B压差 |
| 最大距离 | <5m | 15m | 1200m |
| 双工 | 全双工 | 全双工 | 半双工 |
| 节点 | 点对点 | 点对点 | 总线多节点 |
| 抗干扰 | 弱 | 一般 | 强工业环境 |
| 芯片 | IO口 | MAX232 | MAX485 |
UART编程要点
- CCM打开UART外设时钟;
- IOMUXC引脚复用,把IO配置成TXD/RXD功能,配置电气属性;
- 设置波特率寄存器(分频、采样因子);
- 设置帧格式:数据位、停止位、校验;
- 使能发送器、接收器;
- 两种收发方式:
- 轮询模式:不断查询发送/接收状态标志寄存器,判断是否可以发送、是否收到数据;简单,CPU占用高;
- 中断模式:收到数据/发送缓冲区空触发中断,在中断服务函数处理收发,CPU效率更高。
UART异步含义:收发双方没有公共时钟信号线,依靠预先约定的波特率来采样数据;波特率误差不能太大,否则乱码。