详细概括Linux内核中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指向一个特殊地址。这个地址放在存储器一个特殊的表中,称为向量表

【文章福利】小编推荐自己的Linux内核技术交流群: 【977878001】整理一些个人觉得比较好得学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!

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:
		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控制器和代码搬移

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值