arm体系结构

一、arm32位通用寄存器
R0到R12是通用寄存器
R13:是栈指针也就是SP
R14:是链接寄存器,用来保存返回地址LR
R15:程序计数器PC
还有一个CPSR程序状态寄存器。
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fc07751在这里插入图片描述
ef3ea40afbd6e0e98bad31442.png)
二、armv7架构的几种模式
Cortex-A7 处理器基于 ARMv7-A 架构,支持几种不同的工作模式。以下是 Cortex-A7 处理器的主要模式:

  1. User Mode (用户模式)
    这是最基本的模式,程序在此模式下运行时,无法访问某些特权资源和指令,保证系统的安全性和稳定性。程序只能访问用户空间内存,无法直接控制硬件或修改控制寄存器。
  2. FIQ Mode (快速中断模式)
    用于处理中断请求中的高速中断(Fast Interrupt Request, FIQ)。FIQ模式具有比IRQ更高的优先级,并且可以使用更多的专用寄存器,提高中断响应速度。
  3. IRQ Mode (中断请求模式)
    用于处理常规的中断请求(Interrupt Request, IRQ)。IRQ模式的优先级低于FIQ模式,但仍然可以响应外部硬件或系统的中断信号。
  4. Supervisor Mode (管理模式)
    管理模式通常在操作系统内核运行时使用,允许执行特权指令,访问硬件资源,如设置内存管理单元(MMU)和访问特权寄存器。操作系统核心(Kernel)通常在此模式下执行。
  5. Abort Mode (异常模式)
    当发生数据访问异常或预取异常时,处理器会切换到Abort模式。该模式用于处理页面故障、地址错误等异常情况。
  6. Undefined Mode (未定义模式)
    当处理器遇到未定义的指令或非法指令时,它会切换到未定义模式。此模式用于捕获和处理无法识别的指令。
  7. System Mode (系统模式)
    系统模式与用户模式类似,但它具有更高的权限,可以访问更多的特权资源。操作系统的内核通常在此模式下运行。与管理模式(Supervisor Mode)不同,系统模式允许更直接的系统操作。
  8. 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++;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值