I.MX6U 裸机开发2. 芯片简介、汇编基础及GPIO操作准备工作
- 一、I.MX6U 芯片介绍
- 1. 基本介绍
- 2. 架构图如下:
- 3. I.MX6U 管脚定义规则 :
- 二、GPIO资源介绍
- 1. 原理图
- 2. 寄存器控制
- (1) 使能时钟,CCGR0~CCGR7
- (2) 设置引脚复用
- (3) 设置电气属性
- (4) 配置GPIO功能 ,设置输入输出
- 三、汇编介绍
- 1. GNU 汇编语法介绍
- 2. ARM Context-A7 常用的通用寄存器
- CPSR介绍
- 3. Context-A处理器运行模式
- 4. Cortext-A7常用汇编指令
- (1) 数据处理指令
- (2) 数据传输指令(存储器访问)
- (3) 分支指令
- (4) 逻辑运算指令
- (5) 移位指令
- (6) 条件执行
- (7) 出栈和入栈
一、I.MX6U 芯片介绍
1. 基本介绍
官网地址:
https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/i-mx-applications-processors:IMX_HOME
点击:
根据其官网介绍:
i.MX 6ULL 是一个高能效且成本优化的应用处理器系列,采用单个 Arm Cortex-A7 内核的高级实现,运行速度高达 900 MHz。i.MX 6ULL 应用处理器包括一个集成的电源管理模块,可降低外部电源的复杂性并简化电源排序。该系列中的每个处理器都提供各种内存接口,包括 16 位 LPDDR2、DDR3、DDR3L、原始和托管 NAND 闪存、NOR 闪存、eMMC、Quad SPI 以及用于连接外围设备(如 WLAN、蓝牙、GPS、显示器和摄像头传感器)的各种其他接口。
2. 架构图如下:
基本情况如下:
- CPU采用ARM A7架构
- 一级缓存的ICache(Instruction Cache指令缓存):32K
- 一级缓存的DCache(Data Cache数据缓存):32K
- 二级缓存:128K
- NEON模块,用于ARM处理器的高级SIMD扩展,提供了加速多媒体和信号处理应用的能力
- 多媒体能力,如摄像头、可编程的处理单元等
- 24位并行CSI能力
- 24位并行LCD能力
- 扩展存储,支持NOR Flash,4线SPI Flash,16位的LP-DDR2/DDR3/DDR3L
- 外设支持eMMC,NAND,UART8,SPI4,PC4,88 Keypad,GPIO,I2S,FlexCAN*2,S/PDIF Tx/Rx,USB2 OTG w/PHY *2,网口,ESAI
- JTAG,PLL.OSC,RTC,Smart DMA, IOMUX,Timer4, PWM8,Watch Dog2,LDO,ADC2
- 内部存储 96KROM, 128KRAM
数据手册可以在官网下载,已放在本系列博文能应开源仓库。
比较重要的是应用参考手册,由于官网下载时需要填写一些资料,为防止版权问题,开源仓库没有放这个文档,可从官网自行下载 。
3. I.MX6U 管脚定义规则 :
管脚定义示例:
IOMUXC_SNVS_SW_MUX_CTL_PAD_BOOT_MODE0
其名称为 PAD_BOOT_MODE0,MUX表示复用,可以在文档找到下图所示部分:
找到:IOMUXC_SNVS_SW_MUX_CTL_PAD_BOOT_MODE0章节里的复用功能说明。
在 IOMUXC_SNVS_SW_PAD_CTL_PAD_BOOT_MODE0 查看管脚的电气属性。
二、GPIO资源介绍
本章节为操作LED作一些准备工作。
1. 原理图
2. 寄存器控制
GPIO功能图:
开发板的LED0 接的GPIO3引脚,要对IO引脚初始化,需要以下步骤:
(1) 使能时钟,CCGR0~CCGR7
(2) 设置引脚复用
即将 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 bit3~0设置为0x0101。
(3) 设置电气属性
其中:
- bit0:SRE,压摆率(电平跳变速率),0是低压摆率,1是高压摆率。
- bit5~3:DSE,IO口作为输出时的驱动能力,驱动能力通常使用等效电阻来表示,在3.3V下,R0是260欧,1.8V下R0是150欧,接DDR时是240欧。
等效电阻表示了IO口在输出高电平或低电平时的驱动能力,较低的等效电阻意味着更强的驱动能力,可以提供更大的电流。
- bit7~6:SPEED速度
- bit11: ODE,1是开漏输出
- bit12:PKE,上拉保持 ,在输入引脚上连接一个上拉电阻。
- bit13:PUE,上拉使能
- bit15~14:PUS 上拉/下拉配置,可以选择上拉电阻的强度和配置
- bit16:Hyst. Enable,迟滞使能,滞后现象常见于比较器和施密特触发器等器件中。通过引入滞后,可以确保输出信号在输入信号达到一定阈值后才发生变化,并且在输入信号回到另一阈值之前不会恢复,从而避免输出信号的抖动。
(4) 配置GPIO功能 ,设置输入输出
相关的寄存器:
- GPIOx_DR(Data Register):用于读写 GPIO 引脚的电平状态。
- GPIOx_GDIR(Direction Register):用于设置 GPIO 引脚的方向(输入或输出)。
- GPIOx_PSR(Pad Status Register):用于读取 GPIO 引脚的当前状态。
- GPIOx_ICR1/ICR2(Interrupt Configuration Registers):用于配置 GPIO 引脚的中断触发方式。
- GPIOx_IMR(Interrupt Mask Register):用于使能或屏蔽 GPIO 引脚的中断。
- GPIOx_ISR(Interrupt Status Register):用于读取和清除 GPIO 引脚的中断状态。
- GPIOx_EDGE_SEL(Edge Select Register):用于选择 GPIO 引脚的边沿触发方式。
具体设置步骤:
- GPIO1_DR的bit3设置为1,即输出模式;
- GPIO1_DR的bit3设置为1,输出高电平;
三、汇编介绍
大部分Cortext-A芯片,上电时C语言的运行环境未准备好,需要使用汇编进行一些初始化工作。
1. GNU 汇编语法介绍
GNU 汇编(GAS,GNU Assembler)是 GNU 工具链的一部分,使用 AT&T 语法。以下是一些基本的 GNU 汇编语法介绍:
-
指令格式:
- 操作码在前,操作数在后。
- 操作数用逗号分隔,源操作数在前,目标操作数在后。
-
寄存器:
- 寄存器名称以
%
开头,例如?x
、?x
。
- 寄存器名称以
-
立即数:
- 立即数以
$
开头,例如$5
、$0x10
。
- 立即数以
-
内存操作:
- 内存地址用
()
表示,例如(?x)
表示寄存器?x
指向的内存地址。
- 内存地址用
-
注释:
- 单行注释以
#
开头。
- 单行注释以
以下是一个简单的示例,展示了基本的 GNU 汇编语法:
.section .text
.global _start # 声明一个全局标号
_start:
# 初始化堆栈指针
ldr sp, =_stack_top
# 初始化中断向量表
ldr r0, =_vector_table
ldr r1, =0x00000000
str r0, [r1]
# 清除 BSS 段
ldr r0, =_bss_start
ldr r1, =_bss_end
mov r2, #0
clear_bss:
cmp r0, r1
strlo r2, [r0], #4
blo clear_bss
# 初始化数据段
ldr r0, =_data_load
ldr r1, =_data_start
ldr r2, =_data_end
copy_data:
cmp r1, r2
ldrlo r3, [r0], #4
strlo r3, [r1], #4
blo copy_data
# 跳转到 C 语言的 main 函数
bl main
# 死循环,防止返回
hang:
b hang
.section .bss
_bss_start:
.space 1024
_bss_end:
.section .data
_data_load:
.word 0x12345678
_data_start:
.space 4
_data_end:
.section .stack
_stack_top:
.space 1024
.section .vector_table
_vector_table:
.word _start
这个示例展示了如何使用 GNU 汇编语法编写一个简单的程序,该程序将 “Hello, World!” 消息写入标准输出并退出。
2. ARM Context-A7 常用的通用寄存器
- R0-R12:这些是通用寄存器,可以用于任意数据操作。
- R13 (SP):堆栈指针寄存器,用于指向当前堆栈的顶部。
- R14 (LR):链接寄存器,用于存储子程序调用的返回地址。
- R15 (PC):程序计数器寄存器,用于存储当前指令的地址。
- CPSR:用于存储当前程序的状态信息。
- SPSR:用于保存异常处理时的程序状态(备份程序状态寄存器)。
CPSR介绍
CPSR(Current Program Status Register)是 ARM 处理器中的一个重要寄存器,用于存储当前程序的状态信息。CPSR 包含以下几个主要字段:
- N(Negative flag): 表示上一次运算结果为负。
- Z(Zero flag): 表示上一次运算结果为零。
- C(Carry flag): 表示上一次运算产生了进位或借位。
- V(Overflow flag): 表示上一次运算产生了溢出。
- Q(Saturation flag): 表示饱和运算的状态。
- I(IRQ disable bit): 用于屏蔽 IRQ 中断。
- F(FIQ disable bit): 用于屏蔽 FIQ 中断。
- T(Thumb state bit): 表示处理器是否在 Thumb 状态下运行。
- M[4:0](Mode bits): 表示当前处理器模式。
下面是使用 ARM 汇编指令读取和修改 CPSR的示例:
# 读取 CPSR 到通用寄存器 r0
MRS r0, CPSR
# 修改 CPSR 的模式位,将处理器切换到 Supervisor 模式
BIC r0, r0, #0x1F # 清除模式位
ORR r0, r0, #0x13 # 设置模式位为 Supervisor 模式
MSR CPSR_c, r0 # 写回 CPSR
3. Context-A处理器运行模式
- Cortex-A 处理器支持多种处理器模式,每种模式用于不同的操作场景:
- User mode: 普通程序运行的模式。
- FIQ mode: 快速中断请求模式,用于处理高优先级中断。
- IRQ mode: 普通中断请求模式,用于处理一般中断。
- Supervisor mode: 操作系统内核运行的模式。
- Abort mode: 数据或指令访问失败时进入的模式。
- Undefined mode: 未定义指令异常时进入的模式。
- System mode: 特权模式,通常用于操作系统。
不同运行模式下使用的寄存器有所不同,如下表所示:
4. Cortext-A7常用汇编指令
(1) 数据处理指令
MOV r0, r1 # 将寄存器 r1 中的数据传递到寄存器 r0
MOV r0, #1 # 将立即数 1 移动到寄存器 r0
ADD r1, r0, r2 # 将 r0 和 r2 相加,结果存储在 r1 中
SUB r3, r1, #4 # 将 r1 减去立即数 4,结果存储在 r3 中
MUL r4, r2, r3 # 将 r2 和 r3 相乘,结果存储在 r4 中
MRS r0, CPSR # 将当前程序状态寄存器 (CPSR) 的值移动到通用寄存器 r0
MSR CPSR, r1 # 将通用寄存器 r1 的值移动到当前程序状态寄存器 (CPSR)
(2) 数据传输指令(存储器访问)
LDR r5, [r6] # 从内存地址 r6 处加载数据到 r5
STR r7, [r8] # 将 r7 中的数据存储到内存地址 r8 处
LDMIA r9!, {r0-r3} # 从内存地址 r9 开始加载多个寄存器,地址递增
STMIA r10!, {r4-r7} # 将多个寄存器存储到内存地址 r10 开始,地址递增
LDR和STR按字操作(32bit),指令后面加B是按字节操作,加H是按半字操作。
(3) 分支指令
B label # 无条件跳转到 label
BL subroutine # 跳转到子程序 subroutine,并保存返回地址到链接寄存器 (LR)
BX lr # 跳转到链接寄存器 (LR) 中的地址,通常用于从子程序返回
BEQ label # 如果上一次操作结果为零,则跳转到 label
BNE label # 如果上一次操作结果不为零,则跳转到 label
(4) 逻辑运算指令
AND r0, r1, r2 # 将 r1 和 r2 进行按位与操作,结果存储在 r0 中
ORR r3, r4, r5 # 将 r4 和 r5 进行按位或操作,结果存储在 r3 中
EOR r6, r7, r8 # 将 r7 和 r8 进行按位异或操作,结果存储在 r6 中
BIC r9, r10, r11 # 将 r10 和 r11 进行按位与非操作,结果存储在 r9 中
(5) 移位指令
LSL r0, r1, #2 # 将 r1 左移 2 位,结果存储在 r0 中
LSR r2, r3, #3 # 将 r3 右移 3 位,结果存储在 r2 中
ASR r4, r5, #1 # 将 r5 算术右移 1 位,结果存储在 r4 中
ROR r6, r7, #4 # 将 r7 循环右移 4 位,结果存储在 r6 中
(6) 条件执行
ADDEQ r0, r1, r2 # 如果上一次操作结果为零,则将 r1 和 r2 相加,结果存储在 r0 中
SUBNE r3, r4, r5 # 如果上一次操作结果不为零,则将 r4 和 r5 相减,结果存储在 r3 中
(7) 出栈和入栈
PUSH {r0, r1, r2} # 将寄存器 r0, r1 和 r2 的内容保存到堆栈中
POP {r0, r1, r2} # 从堆栈中恢复寄存器 r0, r1 和 r2 的内容