一、温故知新
1、搭建开发环境
1)查询当前环境的编译器
gcc -v 发现我们当前Ubuntu环境下使用的gcc编译器是X86的架构,所以我们需要使用交叉编译工具链进行编译程序。
2)搭建交叉编译工具链
【1】获取交叉编译工具链
下载官网:Downloads | GNU-A Downloads – Arm Developer
【2】配置环境
vim ~/.bashrc
export PATH=$PATH:/opt/toolchains/arm-cortex_a9-eabi-4.7-eglibc-2.18/bin
【3】验证交叉编译工具是否搭建完成
在终端输入arm- + tab键,看是否可以自动补齐
3)保证下位机可以ping通上位机
可以通过网线让上位机和下位机交互数据
注意:保证下位机可以ping通上位机
【1】修改虚拟机的IP
将虚拟机IP改为静态IP(192.168.1.27)
【2】配置虚拟机
选择为桥接模式
【3】设置开发板Uboot的IP地址
printenv、print、pr:查看环境变量
setenv:设置环境变量
re:重启Uboot
【4】验证下位机可以ping通上位机
ping 192.168.1.27
4)安装tftpd服务
【1】保证上位机可以连接外网
ping www.baidu.com -c3
【2】安装tftpd
sudo apt install tftpd(客户端)
sudo apt install tftpd-hpa(服务端)
【3】创建tftp下载目录
sudo mkdir /tftpboot
sudo chmod 777 /tftpboot
【4】配置tftp服务器
【5】重启tftpd服务
sudo service tftpd-hpa restart
或
sudo /etc/init.d/tftpd-hpa restart
5)验证tftp服务
查看是否可以在下位机通过tftp服务从上位机中下载ubootpak.bin
【1】把ubootpak.bin文件拷贝到/tftpboot目录中
cp ubootpak.bin /tftpboot
【2】保证下位机可以ping通上位机
ping 192.168.1.27
【3】通过tftp下载文件
tftp 0x48000000 ubootpak.bin
【4】把内存中的ubootpak.bin写入到EMMC
update_mmc 2 2ndboot 0x48000000 0x200 0x53ba8
【5】重启
re
2、S5P6818的裸板驱动
从表象到里象的方式进行研究
S5P6818上有537个管脚
GPIO有160个管脚
一共有5组GPIO:GPIOA、GPIOB、GPIOC、GPIOD、GPIOE
每组有32个管脚
【1】从外观入手
【2】阅读开发板原理图
【3】阅读数据手册
【4】写代码
【5】编译程序
【6】烧写程序
二、uboot的操作
1、Uboot的简介
uboot就是universal bootloader(通用的启动代码),具有移植性
uboot是由一个德国工程师发起的开源项目,然后网络上众多的用户共同维护的一个bootloader
uboot经过很多年的发展,现在大部分的嵌入式电子产品都会选择uboot作为设备的bootloader
uboot的核心功能
【1】负责初始化硬件
【2】负责加载引导操作系统的启动
2、Uboot的初始化
uboot的核心功能是初始化各种硬件,但设备在上电初期,内存还没有被初始化,所以我们不能使用C语言初始化硬件,我们使用汇编语言对CPU和cache进行初始化。
----------------------------------------------
C语言是依靠内存进行执行的,它的正常运行离不开内存的参与
----------------------------------------------
三、ARM体系结构与编程
1、多数指令单周期完成
对于S5P6818芯片来说执行一个指令的周期是:1/1.4GHz
2、ARM指令集
大多数ARM核都执行两种指令集
【1】arm指令集 32bit
【2】Thumb指令集 16bit
3、ARM支持的数据类型
ARM支持 Halfword and signed Halfword / byte
数据类型和C/C++有很大区别
byte 8bit
Halfword 16bit(2bytes)
Word 32bit(4bytes)
Doubleword 64bit(8bytes)<ARM-CORTEX-A系列处理器>
4、ARM流水线
1)三级流水线(CPU在处理这条指令时,需要3个步骤)
【1】取指:CPU先把指令拿到CPU寄存器中
----------------------------------------------
CPU的本质就是一堆寄存器,这些寄存器都是32bit的
----------------------------------------------
【2】解码:把指令解释成0和1
【3】执行:执行指令
注意 | |
---|---|
ALU操作 | 进行算术运算的操作,如:加、减、与、或、非 |
PC | 寄存器的别名,永远保存当前正在执行的指令地址 |
PC-4 | 对于ARM指令集来说,寄存器是32bit,一个寄存器占4bytes PC-4是解码指令的地址,PC-8是执行指令的地址 |
PC-2 | 对于Thumb指令集来说,寄存器是16bit,一个寄存器占2bytes PC-2是解码指令的地址,PC-4是执行指令的地址 |
2)通用寄存器和特殊功能寄存器
通用寄存器:CPU内部的寄存器(32bit)
如:PC寄存器
特殊功能寄存器:外设中的寄存器(具有特定功能的寄存器-32bit)
如:GPIOCALTFN0 GPIOCOUT GPIOCOUTENB
3)流水线的不同情况
![]() | 一个周期执行一条指令 指令周期数(CPI) = 1 现实生活中不存在, 这是一种理想状态下的流水线 |
![]() | LDR指令在一个周期内执行不完,需要占用3个周期 要从内存中取出数据到寄存器,处理完成之后,在下一个周期,需要把寄存器中的数据写回到内存中 所以在第4 5个周期没有执行AND指令,而是Stall停顿 虽然第4 5个周期浪费了,但这是有必要的浪费 综上,在第六个周期中实际执行了4条语句 指令周期数(CPI) = 6 / 4 = 1.5 |
![]() | 当执行第一条BL指令时,打断了第2 3条指令(SUB ORR) 跳到0x8FEC执行AND指令 但是ARM没有取指,所以第二个周期先取指 第三个周期进行解码,第四个周期才可以执行 |
![]() | 在第2个周期执行中断,中断打断流水线 在第5个周期执行跳转语句,跳到0xAF00 在第8个周期才开始执行新的语句 所以从2个周期到第8个周期 IRQ中断反应时间最小是7个周期 |
5、ARM的工作模式
1)介绍
ARM有7种工作模式:
【1】SVC(管理模式)
处理器复位后会进入到该模式
执行软中断指令(SWI)后会进入到该模式(按下复位键)
【2】FIQ(快速中断)
发生高优先级中断会进入该模式
【3】IRQ(中断)
发生低优先级中断会进入该模式
【4】undef(未定义)
用于处理未定义指令
当产生未定义的异常时会进入该模式(在decode解指令时解析错误)
【5】abort(终止)
用于处理非正常访问寄存器
(访问不存在的地址、直接访问4byte以内的数据)
-----------------------------------
内存器是按照4bytes方式对齐,无法直接访问4bytes以内的数据
-----------------------------------
【6】system(系统)
与用户模式共用寄存器的特权模式
【3】user(用户)
多数应用程序和系统任务运行在该模式下
2)第一种分类方式(异常/非异常)
前5种模式称为异常模式
SVC、FIQ、IRQ、UNDEF、ABORT
后2种模式称为非异常模式
SYSTEM、USER
3)第二种分类方式(特权/非特权)
前6种模式称为特权模式
SVC、FIQ、IRQ、UNDEF、ABORT、SYSTEM
后1种模式称为非特权模式
USER
6、ARM的工作状态
ARM有2种工作状态:
【1】ARM工作状态 4bytes 32bit对齐
【2】Thumb工作状态 2bytes 16bit对齐
当执行ARM指令时就处在ARM工作状态
当执行Thumb指令时就处在Thumb工作状态
7、ARM的通用寄存器的组织结构
1)组织结构
37个32bit的寄存器(属于普通寄存器,包括以下两个分类)
【1】31个通用寄存器
【2】6个状态寄存器(包括以下两个分类)
【a】1个CPSR(当前程序状态寄存器)
【b】5个SPSR(程序状态存储寄存器)
USER和SYSTEM模式共用一套寄存器R0-R15 | 16个 |
SVC模式共用R0-R12,但有自己的R13、R14 | 2个 |
ABORT模式共用R0-R12,但是有自己的R13、R14 | 2个 |
UNDEF模式共用R0-R12,但是有自己的R13、R14 | 2个 |
IRQ模式共用R0-R12,但是有自己的R13、R14 | 2个 |
FIQ模式共用R0-R12,但是有自己的R8-R14 | 7个 |
所有模式共用CPSR | 1个 |
异常模式分别有自己的SPSR | 5个 |
2)CPSR/SPSR寄存器
CPSR和SPSR寄存器都是32bit的而且内部的组织结构是一模一样的
【1】CPSR寄存器
其可以在任何处理器模式下被访问,它包含以下内容
【a】ALU(算术逻辑单元)状态标志
【b】当前的工作模式
【c】中断使能标志
【d】设置端序
【2】SPSR寄存器
当特定的异常中断发生时,它负责存储CPSR寄存器的内容,当异常处理程序返回时,再把SPSR寄存器中的内容恢复到CPSR寄存器中。
bit31 | N(negative) | 如果指令的结果为负数,则N=1 否则,N=0 |
bit30 | Z(zero) | 如果指令的结果为零(一般表示比较的结果),则Z=1 否则,Z=0 |
bit29 | C(carry) | [1]对于add,如果产生进位,则C=1,否则C=0 [2]对于sub,如果产生借位,则C=0,否则C=1 [3]对于包含移位操作的非add/sub,C为移出的最后一位 [4]对于其他非add/sub,C通常保持不变 |
bit28 | V(overflow) | [1]对于add/sub,如果有符号溢出,则V=1,否则V=0 [2]对于非add/sub,V通常保持不变 |
注意:C是用于判断进位 / 借位,V是用于判断溢出 | ||
bit27 | Q(Qflag) | 在ARMV5架构及以上版本,bit27用于指示在一些面向DSP的指令是否发生了异常或饱和 |
bit26~25 | Reserved | 保留字段 |
bit24 | J(Java) | arm中对Java的编程模型 |
bit23~20 | Reserved | 保留字段 |
bit19~16 | GE[3:0](Greater than or Equal) | 大于或等于标志位,主要被SIMD指令使用 SIMD指令允许处理器用一条指令同时对多个数据项执行相同的操作 当SIMD指令执行时,它会对多个数据项进行比较操作(如比较大小),然后将每个比较的结果存储在GE[3:0]中。每个位对应一个数据组的比较结果,如果对应的数据组大于或等于另一个数据组,则相应的GE位被设置为1,否则为0。 |
bit15~10 | Reserved | 保留字段 |
bit9 | E(Endianness) | 端序标志位,E=0表示小端运算,E=1表示大端运算 大端模式(Big-Endian):在这种模式下,数据的高位字节存放在内存的低地址端,而数据的低位字节存放在内存的高地址端。 小端模式(Little-Endian):与大端模式相反,小端模式下数据的低位字节存放在内存的低地址端,而数据的高位字节存放在内存的高地址端。 |
bit8 | A | 用于控制是否屏蔽特定的异步异常,即是否屏蔽异步中止(Abort)。 A=1表示屏蔽异步终止 A=0表示打开异步终止 |
bit7 | I | 用于控制是否屏蔽IRQ(普通中断请求) I=1表示屏蔽普通中断 I=0表示打开普通中断 |
bit6 | F | 用于控制是否屏蔽FIQ(快速中断请求) F=1表示屏蔽快速中断 F=0表示打开快速中断 |
bit5 | T | 判断处理器是否处于Thumb状态 J和T标志共同决定处理器使用的指令集 J=0 T=0 ARM指令集 J=0 T=1 Thumb指令集 J=1 T=0 Java指令集 J=1 T=1 Thumb-2指令集 |
bit4~0 | M[4:0](Mode) | 表示处理器的模式 10000 User 用户模式 10001 FIQ 快速中断模式 10010 IRQ 中断模式 10011 Supervisor 管理模式 10100 Abort 中止模式 11011 Undefined 未定义模式 11111 System 系统模式 (新版的V8架构中bit4保留,默认是1,bit3~0表示模式) |
3)通用寄存器
【1】不分组寄存器R0-R7
不分组寄存器R0-R7是真正的通用寄存器,所有模式共用的寄存器,没有特殊含义
【2】分组寄存器R8-R14
分组寄存器R8-R14取决于当前的处理器模式,每种模式都有自己专用的分组寄存器
寄存器R8-R14可分为两组寄存器
【a】一组用于FIQ模式,该组寄存器允许快速中断处理
【b】一组用于除FIQ以外的其他模式
分组寄存器R13 R14在异常模式中都是独立的
【3】寄存器R13 SP(stack pointer)
【a】处理器使用sp作为指向栈的指针
【b】在Thumb指令集中,大多数指令不能访问sp
【c】每种模式都有自己的栈,使用前初始化栈,模式切换时,公公寄存器的内容保存到SP指向的栈中,用来保护上下文,恢复时可以从栈中恢复
【b】汇编代码里可以直接写SP代替R13
【4】寄存器R14 LR(link register)
【a】链接寄存器是一个特殊的存起,可以保存返回链接的信息
【b】执行BL跳转指令前,将寄存器R15的内容保存到LR中,然后可以执行跳转,如果子程序执行完成后需要返回,就将LR的内容恢复到R15寄存器中
【c】当软件不需要LR进行链接时,LR寄存器也可以存储其他的内容
【d】汇编代码里可以直接写LR代替R14
【5】寄存器R15 PC(program counter)
【a】寄存器PC并不是指向当前正在运行的地址,而是指向正在取指的地址,每次完成取指操作后,PC会自动偏移4个字节,指向下一条指令。
【b】执行ARM指令时,PC的值是当前指令的地址偏移8字节(三级流水线)
【c】执行Thumb指令时,PC的值是当前指令的地址偏移4字节(三级流水线)
【d】如果将地址写入到PC寄存器中,会跳转到该地址
【e】汇编代码里可以直接写PC代替R15
8、异常向量表
异常向量表存放的是异常处理函数(中断处理函数)的函数名(入口地址)
这个异常向量表是ARM公司提供的
当正常的程序执行流程发生暂时的停止时,该现象称之为异常,例如我们在处理一个外部的中断请求时,在处理异常之前,当前处理器的状态必须保存,这样当异常处理完成之后,当前程序可以继续执行,处理器允许多个异常同时发生,在处理异常时,会按照固定的优先级进行处理
1)异常类型
【1】复位 | 产生复位异常时,程序跳转到复位处理的程序执行 |
【2】未定义指令 | 遇到不能处理的指令时,产生未定义指令异常 |
【3】软件中断 | 执行SWI指令时产生,用于用户模式下的程序调用特权操作指令 |
【4】指令预取终止 | 处理器预取指令的地址不存在,或该地址不允许当前指令访问,会产生指令预取中止 |
【5】数据中止 | 处理器数据访问指令的地址不存在,或该地址不允许当前指令访问,会产生数据中止 |
【6】IRQ | 外部中断请求有效,并且CPSR中的 I 位为0时,产生IRQ异常 |
【7】FIQ | 快速中断请求有效,并且CPSR中的 F 位为0时,产生FIQ异常 |
2)当异常发生时的操作
当异常发生时,ARM核将完成
【1】复制CPSR到SPSR
【2】何止CPSR合适的bit
【a】切换到ARM状态
【b】切换到异常模式
【c】禁止中断(当切换模式时,不允许打开中断)
【3】存储返回地址到LR
【4】设置PC为相应的异常处理函数的入口
3)从异常中返回
【1】把SPSR中的内容恢复到CPSR
【2】把LR寄存器中的内容恢复到PC
4)中断
中断是CPU CORE感知外部事件变化的一种方式
轮询、中断、DMA
中断分为三级:
中断源级
中断控制器级
arm core级