ARM硬件原理

目标:了解常用硬件接口,并且编程控制
重点:对各个接口实现原理的掌握

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 缓存可以分为多片。指令,数据可能会分开放。这些有缓存控制器来实现/
在这里插入图片描述
line是缓存最小单元,指向主存的连续字单元
index是存储器地址的一部分,用来决定找到缓存的第几行
offset是偏移量

MMU 内存管理模块

1、虚拟存储器
作用:允许多道程序直接有效而安全的共享存储器。清除一个小而受限的主存容量对程序设计造成的影响。
MMU用来:1、保护存储空间和锁定解锁。2、分割.完成内存地址映射(虚拟地址到物理地址的映射)。

在这里插入图片描述

内存空间最小存储单位是页

页的存放与查找:页表,页表寄存器(用来存储页表)
页表类似哈希表,前面是虚拟地址,后面有对应的物理地址
如果不缺页直接读物理内存
如果缺页了,通过造作系统去磁盘中找。

集成虚拟存储器:TLB,CACHE
TLB:地址转换高速缓存。(页表的缓存)
处理TLB缺失:1页在主存中,只需创建缺失的TLB表项.2、页不再主存中,需要将控制权交给操作系统来解决缺页。

ARM异常中断

ARM体系结构中存在7种异常处理。异常发送时,处理器会把PC指向一个特殊地址。这个地址放在存储器一个特殊的表中,称为向量表
在这里插入图片描述
0X00000000是低地址向量吧,一般是裸板开发
0Xffff0000是高地址向量表,一般带有操作系统的要看这一块

异常发生时CPU处理步骤
1、保存当前执行位置。保存到R14 LR
2、保存当前的执行状态。CPSR
3、寻址中断入口。即向量表地址 (PC寄存器去找向量地址)
4、执行中断处理程序
5、中断返回,继续执行

ARM异常优先级
复位异常 highest
数据异常
FIQ
IRQ
预处理异常
软中断 未定义指令 lowest

未定义指令异常发生时伪指令
在这里插入图片描述
首先把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:
		LDR R0,=0XE0200280            //伪指令,把这个地址放到R0。否则就说把地址的值放到R0了
		MOV R1,#0X00001111
		STR R1,[R0]                             //把R1的值给R0   间接寻址
		MOV R1, #00
		STR R1,[R0]

loop:
	B loop

用C来实现

#indefine  GPJCON (*(volatile unsigned long*) 0xE0200280)
#indefine  GPJDAT (*(volatile unsigned long*) 0xE0200284)
int main()
{
	GPJCON=0x00001111;
	GPJDAT=0x00000000;
	return 0}
      然后汇编中直接BL main

makefile中%。o:%。s 把当前目录下所有点s文件生成。o文件

通过GPIO让蜂鸣器响起来
思路:
1.建立start.S启动代码,运行。c里面的main函数
2.检录main。c 执行代码。GPIO操作。buzzer蜂鸣器。看电路图,找到相应GPIO接口,以及状态设置及值设置
3.makefile编写

.text
.global _start
_start:
	BL main
_loop:
	B_loop
#indefine  GPD0CON (*(volatile unsigned long*) 0xE02000A0)
#indefine  GPD0DAT (*(volatile unsigned long*) 0xE02000A4)
int main()
{
	GPD0CON|=1<<0;
	while(1)
	{
		buzzer_on();
		delay(0x50000);
		buzzer_off();
		delay(0x50000);
		
	}
	return 0;
}
void buzer_on(void)
{
	GPD0AT|=1<<0;
}
void buzzer_off(void)
{
	GPD0DAT&=~(1<<0);
}
voide delay(unsigned long count)
{
	volatile unsigned ling i =count;
	while(i--);
}

makefile

buzzer.bin:start.0 main.0
	arm-linux-ld -Ttext 0x20000000 -o buzzer.elf $^          #连接
	arm-linux-objcopy   -o binary buzzer.elf buzzer.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) //按键控制引脚
int main()
{
	GPD0CON|=1<<0;//(这样比较安全不会影响其他为)
	GPH0CON=0x00while(1)
	{
		if(GPH0DAT&1<<0)//按键按下去引脚是低电平,当DAT与1与结果为1说明按键未按下
		buzzer_off();
		else
		buzzer_on();
		
		
	}
	return 0;
}
void buzer_on(void)
{
	GPD0AT|=1<<0;
}
void buzzer_off(void)
{
	GPD0DAT&=~(1<<0);
}
voide delay(unsigned long count)
{
	volatile unsigned ling i =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控制器和代码搬移

发布了33 篇原创文章 · 获赞 4 · 访问量 2600

猜你喜欢

转载自blog.csdn.net/CNMNMSL1/article/details/105121508
今日推荐