cpu核心
NEON/SIMD(单指令多数据流)
一个指令取出多个数据给CPU(原来是一个指令取出一个数据交给CPU在用下个指令去取)
NEON技术可加速多媒体和信号处理算法(如视频编码/解码,2D/3D图形等多媒体)性能会提升很多倍
cache(缓存机制)
系统外围
RTC实时时钟(real time clock)
PLL锁相回路或锁相环。用来统一正合时脉讯号,使内存能正确地存取信号。(一般不去控制它)
PWM 脉冲宽度调制,做蜂鸣器或者稳压等
watchdog Timer 看门狗,由于电磁脉冲干扰,程序达不到预期成果,导致程序死锁等。一旦接收不到程序来的信号就会把程序reset,重新执行
DMA(direct memory access )
直接内存访问。内存和外部设备进行数据迁移的时候不需要去访问CPU
keypad 按钮
ADC模数转换器
连接
USB/OTG
UART 通用异步收发接口。是一种通用串行数据总线,用于异步通信(并行入,串行出)
I2C基层电路总线(串行)
SPI 串行外围接口 用在EEPROM FLASH 实时时钟,AD转换器,数字信号处理器和数字信号解码器之间
Modem IF 通讯的调制解调器
GPIO 通用输入输出引脚
Audio IF 音频
storage IF 存储器的interface
多媒体
camera IF /MIPI CSI
coder/decoder
2D/3D graphic engine
TV out/HDMI
JPEG CODEC
LCD
存储接口
SRAM/SROM 静态RAMROM
OneNand 升级的nandflsh
SLC/MLC Nand 标准nandflsh
DDR
电源管理
clock gating
power gating
frequency scaling(频率定标)
片内理解就可
主要学习目标:片外硬件,接口型的如GPIO、各种总线协议(I2C,SPI)、存储设备(DDR 网卡)
cache
我们现在采用的存储器结构称为多体交叉存储器体系
I/O向主存请求的级别高于CPU访存
贮存速度跟不上CPU的发展
主存一般都是片外,频繁进出速度慢,能耗高
cache一般使用sram
缓存控制器cache controller 控制从内存中取数据到cache
直接映射缓存direct mapped cache 效率不高,直接将主存中的地址,每块按比例来映射
映射时有专门的target记录地址,还记录偏移量
联合应用缓存set associative cache 缓存可以分为多片。指令,数据可能会分开放。这些有缓存控制器来实现/
![](https://i-blog.csdnimg.cn/blog_migrate/452a631142120dc82af0ee4362cf2de0.png)
line是缓存最小单元,指向主存的连续字单元
index是存储器地址的一部分,用来决定找到缓存的第几行
offset是偏移量
MMU 内存管理模块
1、虚拟存储器
作用:允许多道程序直接有效而安全的共享存储器。清除一个小而受限的主存容量对程序设计造成的影响。
MMU用来:1、保护存储空间和锁定解锁。2、分割.完成内存地址映射(虚拟地址到物理地址的映射)。
![](https://i-blog.csdnimg.cn/blog_migrate/26d88a6f76594d37af4fc7711201be8c.png)
内存空间最小存储单位是页
页的存放与查找:页表,页表寄存器(用来存储页表)
页表类似哈希表,前面是虚拟地址,后面有对应的物理地址
如果不缺页直接读物理内存
如果缺页了,通过造作系统去磁盘中找。
集成虚拟存储器:TLB,CACHE
TLB:地址转换高速缓存。(页表的缓存)
处理TLB缺失:1页在主存中,只需创建缺失的TLB表项.2、页不再主存中,需要将控制权交给操作系统来解决缺页。
ARM异常中断
ARM体系结构中存在7种异常处理。异常发送时,处理器会把PC指向一个特殊地址。这个地址放在存储器一个特殊的表中,称为向量表
![](https://i-blog.csdnimg.cn/blog_migrate/d704fe38d249a1b026826fb74dfd5ec9.png)
【文章福利】小编推荐自己的Linux内核技术交流群: 【977878001】整理一些个人觉得比较好得学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!
![](https://i-blog.csdnimg.cn/blog_migrate/19728cecee61ef3e06c022aca2b6a0a7.jpeg)
0X00000000是低地址向量吧,一般是裸板开发
0Xffff0000是高地址向量表,一般带有操作系统的要看这一块
异常发生时CPU处理步骤
1、保存当前执行位置。保存到R14 LR
2、保存当前的执行状态。CPSR
3、寻址中断入口。即向量表地址 (PC寄存器去找向量地址)
4、执行中断处理程序
5、中断返回,继续执行
ARM异常优先级
复位异常 highest
数据异常
FIQ
IRQ
预处理异常
软中断 未定义指令 lowest
未定义指令异常发生时伪指令
![](https://i-blog.csdnimg.cn/blog_migrate/a888dce012b626a9e8426b0ae64de67e.png)
首先把R14置到指向下一个指令的地址
用SPSR进行保存,把当前程序状态保存到SPSR中
然后CPSR改变模式,禁用IRQ等
然后寻找向量表,给PC赋地址
启动原理
CPU中集成的iROM和iRAM,先启动IROM中的code。然后把bootloader第一段程序从SD卡或nand flash’中搬到IRAM中运行,先进行校验。然后在搬第二段运行。运行成功后把操作系统OS搬到DRAM中运行。需要查询手册知道iROM,iRAM和DRAM的地址。
0x00是iRAM的地址
iROM的作用:
初始化系统时钟,设置看门狗,初始化栈和堆
加载BL1
BL1的作用:
初始化RAM,关闭Cache,设置栈
加载BL2
BL2的作用:
初始化其他外设
加载OS内核
GPIO
当去写寄存器的时候是输出,要去读寄存器状态的时候是输入
SFRS特殊功能寄存器,GPIO寄存器放在这里面
GPJ2CON的地址是0xE0200280
GPJ DAT地址为0xE0200284
.text.global_start_start:
LDRR0,=0XE0200280//伪指令,把这个地址放到R0。否则就说把地址的值放到R0了
MOVR1,#0X00001111
STRR1,[R0]//把R1的值给R0 间接寻址
MOVR1,#00
STRR1,[R0]loop:
Bloop
用C来实现
#indefine GPJCON (*(volatile unsigned long*) 0xE0200280)
#indefine GPJDAT (*(volatile unsigned long*) 0xE0200284)
intmain(){
GPJCON=0x00001111;
GPJDAT=0x00000000;
return0;}
然后汇编中直接BLmain
makefile中%。o:%。s 把当前目录下所有点s文件生成。o文件
通过GPIO让蜂鸣器响起来
思路:
1.建立start.S启动代码,运行。c里面的main函数
2.检录main。c 执行代码。GPIO操作。buzzer蜂鸣器。看电路图,找到相应GPIO接口,以及状态设置及值设置
3.makefile编写
.text.global_start_start:
BLmain_loop:
B_loop
#indefine GPD0CON (*(volatile unsigned long*) 0xE02000A0)
#indefine GPD0DAT (*(volatile unsigned long*) 0xE02000A4)
intmain(){
GPD0CON|=1<<0;
while(1)
{
buzzer_on();
delay(0x50000);
buzzer_off();
delay(0x50000);
}
return0;}voidbuzer_on(void){
GPD0AT|=1<<0;}voidbuzzer_off(void){
GPD0DAT&=~(1<<0);}voidedelay(unsignedlongcount){
volatileunsignedlingi=count;
while(i--);}
makefile
buzzer.bin:start.0main.0
arm-linux-ld-Ttext0x20000000-obuzzer.elf$^#连接
arm-linux-objcopy-obinarybuzzer.elfbuzzer.bin#生成bin%.s:%.o
arm-linux-gcc-c-o$@$<%.c:%.o
arm-linux-gcc-c-o$@$<clean:
rm-f*.o*.elf*.bin
利用按键控制蜂鸣器
#indefine GPD0CON (*(volatile unsigned long*) 0xE02000A0)//蜂鸣器引脚控制地址
#indefine GPD0DAT (*(volatile unsigned long*) 0xE02000A4)//蜂鸣器电平地址
#indefine GPH0CON (*(volatile unsigned long*) 0xE0200C40) //按键控制引脚
#indefine GPH0DAT (*(volatile unsigned long*) 0xE0200C44) //按键数据位
intmain(){
GPD0CON|=1<<0;//(这样比较安全不会影响其他为)
GPH0CON=0x00;
while(1)
{
if(GPH0DAT&1<<0)//按键按下去引脚是低电平,当DAT与1与结果为1说明按键未按下
buzzer_off();
else
buzzer_on();
}
return0;}voidbuzer_on(void){
GPD0AT|=1<<0;}voidbuzzer_off(void){
GPD0DAT&=~(1<<0);}voidedelay(unsignedlongcount){
volatileunsignedlongi=count;
while(i--);}
了解开发板资源
1、找CPU,用什么样的CPU架构。为了找到系统上电之后,第一条执行的代码,我们应该放到哪里。
ARM:异常向量表(reset)0x0
中断是外界导致的,比如CPU使用时间到了程序停止
异常是主动发出的。例如在程序中调用OPEN等系统调用函数。
2、0x0接的是什么芯片(可读芯片)
soc 片上系统,CPU集成了各种核心器件
3.地址都被芯片公司重定义了。去芯片公司的datasheet中寻找memory map这样的章节
主要看
片内资源地址确定sfrs 特殊功能寄存器
片外资源地址确定 DRAM SRAM 分块,程序访问的地址落在哪个分块区间上,CPU中 控制器)就自动的的把该分块的片选信号置为有效
找到对应芯片,找该芯片的类似于CS/ENABLE这样的引脚,看该引脚接到CPU的哪个片选信号上
找异常向量表总reset向量地址对应的是 什么东西
4.boot程序设计
设置时钟
5、接口开发(boot+interface)
如果一个块没有接到总线上,则去片内的控制器找(sfrs)
bootloader
boot 的最终目的是跳到C语音中,
关闭看门狗,中断,cache
配置系统工作时钟
配置SDRAM的控制器()
让sp指向可读可写的设备区间中。满足递减的规则
代码搬移,只能初始化16K代码,一般搬移到DRAM上。因为执行速度问题,从速度慢的存储器(nand flash)送到更快的内存
有的CPU是只把存储器一部分代码执行出来,把存储在其他位置上的代码搬移到内存,对应存储器的控制器的初始化(如果SD卡启动要写SD卡控制器的驱动,nand启动要写nand的控制器驱动)
loader的目的:执行应用逻辑
写boot loader难点是配置SDRAM控制器和代码搬移