一、arm32位通用寄存器
R0到R12是通用寄存器
R13:是栈指针也就是SP
R14:是链接寄存器,用来保存返回地址LR
R15:程序计数器PC
还有一个CPSR程序状态寄存器。

二、armv7架构的几种模式
Cortex-A7 处理器基于 ARMv7-A 架构,支持几种不同的工作模式。以下是 Cortex-A7 处理器的主要模式:
- User Mode (用户模式)
这是最基本的模式,程序在此模式下运行时,无法访问某些特权资源和指令,保证系统的安全性和稳定性。程序只能访问用户空间内存,无法直接控制硬件或修改控制寄存器。 - FIQ Mode (快速中断模式)
用于处理中断请求中的高速中断(Fast Interrupt Request, FIQ)。FIQ模式具有比IRQ更高的优先级,并且可以使用更多的专用寄存器,提高中断响应速度。 - IRQ Mode (中断请求模式)
用于处理常规的中断请求(Interrupt Request, IRQ)。IRQ模式的优先级低于FIQ模式,但仍然可以响应外部硬件或系统的中断信号。 - Supervisor Mode (管理模式)
管理模式通常在操作系统内核运行时使用,允许执行特权指令,访问硬件资源,如设置内存管理单元(MMU)和访问特权寄存器。操作系统核心(Kernel)通常在此模式下执行。 - Abort Mode (异常模式)
当发生数据访问异常或预取异常时,处理器会切换到Abort模式。该模式用于处理页面故障、地址错误等异常情况。 - Undefined Mode (未定义模式)
当处理器遇到未定义的指令或非法指令时,它会切换到未定义模式。此模式用于捕获和处理无法识别的指令。 - System Mode (系统模式)
系统模式与用户模式类似,但它具有更高的权限,可以访问更多的特权资源。操作系统的内核通常在此模式下运行。与管理模式(Supervisor Mode)不同,系统模式允许更直接的系统操作。 - Monitor Mode (监控模式)
Monitor Mode 是 ARMv7-A架构的特性,但它在 Cortex-A7 中不是常规使用模式。它与 ARMv7-M架构中的调试模式不同,主要用于监控和调试,通常由虚拟化和系统监控软件使用。
三、常用指令
1、内存指令
内存访问指令
str <源>, [目标地址]:从寄存器 写入 内存。
ldr <目标>, [源地址]:从内存 读取 到寄存器。
间接寻址[]代表取内容
ldr r0,=0x2000 //将0x2000的地址赋给r0
ldr r1,=0x12345678//将0下2345678赋给r1
strb r1,[r0]//将r1的1字节写给r0所指向的内存
ldrb r3,[r0]//将r3的1字节写给r0所指向的内存
Strh 两字节
Ldrh 两字节
Str 四字节
Ldr 四字节
2、运算指令
ADD、SUB、AND、AND、ORR
3、跳转指令
常用的BL、B
使用跳转指令跳转
BL DELAY
MOV R4,#5
DELAY
MOV R0,#5
LOOP
SUBS R0,R0,#1
BNE LOOP
MOV PC,LR
使用跳转指令跳转
BL DELAY
MOV R4,#5
DELAY
MOV R0,#5
LOOP
SUBS R0,R0,#1
BNE LOOP
MOV PC,LR
;直接给pc赋值跳转指令
ADR LR,RET
ADR PC,DELAY
RET
MOV R1,#5
DELAY
MOV R0,#5
LOOP
SUBS R0,R0,#1
BNE LOOP
MOV PC,LR
3.1 怎么给函数传参
四、分析imx6ull的汇编点灯
.text //.text 是一个 段指令,告诉汇编器接下来的代码将放在代码段
.global _start //用于标识全局的函数入口
_start: //程序的入口
/* 将gpio5_3设置为输出模式 */
LDR R0,=(0x02290000 + 0x14) // 加载GPIO寄存器的地址(GPIO5的控制寄存器地址)
LDR R1,[R0] // 读取该地址的值(即GPIO寄存器的当前配置)
ORR R1,R1,#0x5 // 使用OR运算设置相关位(将GPIO5_3设置为输出模式)
STR R1,[R0] // 将新的值写回GPIO寄存器,生效设置
/* 设置引脚为输出 */
LDR R0,=0x020AC004 // 加载GPIO控制寄存器地址(假设为GPIO输出引脚控制寄存器的地址)
LDR R1,[R0] // 读取该寄存器的当前值
ORR R1,R1,#(1<<3) // 设置GPIO引脚3(即GPIO的某个具体引脚)为输出模式
STR R1,[R0] // 写回控制寄存器,使设置生效
/* DATA out寄存器 */
LDR R2,=(0x020AC000) // 加载GPIO数据寄存器的地址(控制输出值的寄存器)
Loop:
LDR R1,[R2] // 读取GPIO数据寄存器的值
ORR R1,R1,#(1<<3) // 将GPIO引脚3的值设置为1(即输出高电平)
STR R1,[R2] // 写回GPIO数据寄存器,生效
LDR R3,=10000 // 加载延迟计数值
BL Delay // 调用延迟子程序,产生延迟效果
LDR R1,[R2] // 重新读取GPIO数据寄存器的值
BTC R1,R1,#(1<<3) // 清除GPIO引脚3的值(即输出低电平)
STR R1,[R2] // 写回GPIO数据寄存器,生效
LDR R3,=10000 // 再次加载延迟计数值
BL Delay // 调用延迟子程序,产生延迟效果
B Loop // 跳回到Loop标签,继续执行循环
Delay:
SUBS R3,R3,#1 // 延迟计数:R3减1
CME R3,#0 // 比较R3与0,如果R3为0,标志位设置
BNE Delay // 如果R3不为0,跳回Delay继续延迟
MOV PC,LR // 延迟结束,返回调用处(退出延迟子程序)
五、怎么驱动IMX6ULL串口控制器
每一个控制器大致初始化结构大致是这样的
① 使能时钟
② 选择iomux复用
③ 控制器内部寄存器的操控
这些寄存器的控制要从哪里得到?去查看芯片手册
5.1使能时钟
通过查看芯片手册获得使能串口时钟的寄存器
CCGR5:为使能串口1寄存器的时钟。
5.2复用iomux
上面这两个寄存器分别是串口的接收和发射引脚的复用。
5.3 串口控制器的内部
根据上图时钟树我们可以看到串口的波特率分频寄存器是CCM_CSCDR1这个寄存器的第6位为0就是80MHZ给串口的波特率生成。
typedef struct
{
volatile unsigned int URXD; // 接收数据寄存器(UART Receive Data Register),用于存储接收到的数据
char reserve1[64]; // 保留字段,用于对齐或占位
volatile unsigned int UTXD; // 发送数据寄存器(UART Transmit Data Register),用于发送数据
char reserve2[64]; // 保留字段,用于对齐或占位
volatile unsigned int UCR1; // 控制寄存器1(UART Control Register 1),配置UART的基本功能
volatile unsigned int UCR2; // 控制寄存器2(UART Control Register 2),配置UART运行模式(如校验位、数据位)
volatile unsigned int UCR3; // 控制寄存器3(UART Control Register 3),设置额外功能(如流控)
volatile unsigned int UCR4; // 控制寄存器4(UART Control Register 4),配置特定功能(如中断)
volatile unsigned int UFCR; // FIFO控制寄存器(UART FIFO Control Register),配置FIFO队列
volatile unsigned int USR1; // 状态寄存器1(UART Status Register 1),存储模块的中断和状态信息
volatile unsigned int USR2; // 状态寄存器2(UART Status Register 2),存储错误和状态标志
volatile unsigned int UESC; // 转义字符寄存器(UART Escape Character Register),定义特殊转义字符
volatile unsigned int UTIM; // 超时寄存器(UART Timeout Register),设置接收超时时间
volatile unsigned int UBIR; // 波特率增量寄存器(UART Baud Rate Increment Register),用于波特率生成
volatile unsigned int UBMR; // 波特率调制寄存器(UART Baud Rate Modulation Register),用于波特率生成
volatile unsigned int UBRC; // 波特率计数寄存器(UART Baud Rate Count Register),实时显示波特率计数
volatile unsigned int ONEMS; // 每毫秒计数寄存器(One Millisecond Register),用于时间或波特率计算
volatile unsigned int UTS; // 测试寄存器(UART Test Register),测试UART模块的功能
volatile unsigned int UMCR; // 模式控制寄存器(UART Mode Control Register),配置UART的特殊模式(如环回模式)
} uart_type;
用一个结构体描述串口寄存器,里面包括用于生成串口协议的寄存器操作等,
下面是在IMX6ULL裸机上面进行开发和控制
//头文件uart1.h
#ifndef __UART_H__
#define __UART_H__
#define CCM_CCGR5 (0x0020407C) //bit[24:25]为1使能串口1时钟
#define CCM_CSCDR1 (0x20C4024)
#define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA (0x20E0084)//bit[0:3]为0为串口1
#define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA (0x20E0088)//bit[0:3]为0为串口1
#define IOMUXC_UART1_RX_DATA_SELECT_INPUT (0x20E0624)//bit[0:1]为11为串口1
#define UART1_BASE (0x2020000)
typedef struct
{
volatile unsigned int URXD;
char reserve1[64];
volatile unsigned int UTXD;
char reserve2[64];
volatile unsigned int UCR1;
volatile unsigned int UCR2 ;
volatile unsigned int UCR3 ;
volatile unsigned int UCR4 ;
volatile unsigned int UFCR ;
volatile unsigned int USR1 ;
volatile unsigned int USR2 ;
volatile unsigned int UESC ;
volatile unsigned int UTIM ;
volatile unsigned int UBIR ;
volatile unsigned int UBMR ;
volatile unsigned int UBRC ;
volatile unsigned int ONEMS;
volatile unsigned int UTS ;
volatile unsigned int UMCR;
}uart_type;
void uart1_clk_enable(void);
void iomux_select_uart1(void);
void uart1_init(void);
char recv_char(void);
void transfer_char(char c);
void transfer_string(char *str);
#endif
//C文件uart.c
#include "uart.h"
#include <stdio.h>
uart_type *uart1 = (uart_type *)(UART1_BASE);
void uart1_clk_enable(void)
{
volatile unsigned int *CCM_CCGR5_PTR = (unsigned int *)CCM_CCGR5;
volatile unsigned int *CCM_CSCDR1_PTR = (unsigned int *)CCM_CSCDR1;
*CCM_CSCDR1_PTR &= ~((1 << 6) | (0x3f));
*CCM_CCGR5_PTR |= (1 << 24) | (1 << 25);
}
void iomux_select_uart1(void)
{
volatile unsigned int *IOMUXC_UART1_TX_DATA_PTR = (unsigned int *)IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA;
*IOMUXC_UART1_TX_DATA_PTR &= ~(0xf);
volatile unsigned int *IOMUXC_UART1_RX_DATA_PTR = (unsigned int *)IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA;
*IOMUXC_UART1_RX_DATA_PTR &= ~(0xf);
volatile unsigned int *IOMUXC_UART1_RX_INPUT_PTR = (unsigned int *)IOMUXC_UART1_RX_DATA_SELECT_INPUT;
*IOMUXC_UART1_RX_INPUT_PTR |= 0x3;
}
void uart1_init(void)
{
// 使能串口
uart1->UCR1 |= (1 << 0);
// 设置数据格式//波特率为115200
uart1->UBIR = 694;
uart1->UBMR = 15;
uart1->UCR2 |= (1 << 2) | (1 << 1) | (1 << 14) | (1 << 5);
uart1->UCR2 &= ~((1 << 6) | (1 << 8));
uart1->UCR3 |= (1 << 2);
}
char recv_char(void)
{
while ((uart1->USR2 & (1 << 0)) == 0)
;
return uart1->URXD;
}
void transfer_char(char c)
{
while ((uart1->USR2 & (1 << 3)) == 0)
;
uart1->UTXD = c;
}
void transfer_string(char *str)
{
while (str != NULL)
{
transfer_char(*str);
str++;
}
}