嵌入式复习

嵌入式系统概述

  1. 定义:嵌入式系统是以应用为中心,以计算机技术为基础,采用可剪裁软硬件,适用于对功能、可靠性、成本、体积、功耗等有严格要求的专用计算机系统。

  2. 实时系统:指系统能够在限定的响应时间内提供所需水平的服务。

  3. 嵌入式操作系统:VxWorks、Windows CE、Android、iOS,Linux

  4. 区别:

    • 任务是专用而确定
    • 要求实时性
    • 使用实时操作系统
    • 高可靠性保障
    • 功耗约束
    • 资源少、需要专用工具和特殊方法
  5. 嵌入式系统一般由嵌入式微处理器、外围硬件设备、嵌入
    式操作系统(可选),以及用户的应用软件系统等四个部
    分组成

嵌入式系统硬件概述【重点】

1 嵌入式微处理器

  • 嵌入式微处理器(EMPU):有CPU, ROM, RAM总线等,尺寸更大
  • 嵌入式微控制器(MCU):单片机,尺寸小
  • DSP处理器,协处理器,可以看成外设
  • 片上系统SOC,全部外设集成到一个芯片上

2 ARM与Thumb

  • ARM32 按字排列,长度为32bit,ARM指令必须在ARM态下运行
  • Thumb 按半字排列,长度为16bit,Thumb指令必须在Thumb态下运行
  • 在CPSR T字段记录运行状态

ARM和Thumb状态切换使用bx指令
ARM=>Thumb:

LDR R0,=Label+1
BX R0

Thumb=>ARM:

LDR R0,=Label
BX R0

ARM寄存器:31(通用寄存器)+6(状态寄存器)

总线比较

USB

通用串行总线,无时序信号(异步),单主设备

I2C

主设备传输数据给从设备,
串行总线,需要时钟信号(同步),总线仲裁
多主设备

PCI/SPI

和I2C差不多, PCI使用集中仲裁

嵌入式软件编程技术【重点】

1 arm处理器模式(7种)

用户模式+特权模式
特权模式为除了系统模式(System)+异常模式(5种)
CPSR寄存器作为状态寄存器

2 arm指令

2.2 条件符
   条件符		含义
	GT/LT	符号数大于/小于
	GE/LE	符号数大于等于/小于等于
	HI/LO	无符号数大于/小于
	HS/LS	无符号数大于等于/小于等于
2.3 寻址方式

寄存器寻址

MOV R1, R2 ;R2->R1
SUB R0, R1,R2 ;R1-R2 -> R0

立即数寻址

SUBS R0,R0,#1 ;R0-1 -> R0
MOV R1,#0xFF00 ;0xFF00 -> R0

寄存器偏移寻址

ADD R1, R1, R2 , ROR #0x2
; R2循环右移两位后与R1相加,结果放入R1
MOV R1, R0, LSL R2
; R0逻辑左移R2位后放入R1中

寄存器间接寻址

STR R1, [R2]
; 将R1的值存入以R2内容为地址的存储器中 
SWP R1, R1, [R2]
; 交换以R2为地址的存储器内容和R1内容

基址变址寻址

op Rd, [Rn, R1] 
; 零偏移,Rn+R1是操作数地址
op Rd, [Rn, FlexOffset] 
; 前索引偏移,Rn+FlexOffset是地址
op Rd, [Rn, FlexOffset]!
; 带写回的前索引偏移,地址存入Rn寄存器
op Rd, [Rn], FlexOffset
; 后索引偏移,Rn是地址,Rn+FlexOffset写入Rn

多寄存器寻址

LDMIA R0, {R1, R2, R3, R4, R5} 
; R1<- R0, R2<- R0+4, …, R5<-R0+16
STMIA R0, {R2-R5, R7}
; R0<-R2, R0+4<-R3, … , R0+12<-R5, R0+16<-R7

堆栈寻址

 STMFD SP!, {R1-R7, LR} 
; 将R1-R7,LR存放到堆栈中,这条指令一般用来保护现场

相对寻址

BL Label
; 转跳到Label标签处

2.4 指令后缀

指令后缀含义
B(byte)功能不变,操作长度变为8位(依赖CPU位数,以下相同)
H(Halfword)功能不变,操作长度变为16位
S(signed)功能不变,操作数变为有符号数
S(S标识)影响CPSR里的NZCV标识位
2.5 条件代码
条件代码含义
N正负,N=1,结果为负,N=0,结果为正或0
Z零,Z=1结果为0,Z=0,结果非零
C进位,加法产生进位则C=1,不然为C=0;
借位,减法运算产生了借位则C=0,否则C=1
V溢出,V=1,有溢出,V=0,无溢出

2.3 数据传输指令

mov: 在两个寄存器之间或者立即数和寄存器之间传递数据,将后一个寄存器上的值或者立即数赋值给前一个寄存器

mvn:和mov用法一致,区别是mvn会把后一个寄存器的值或者立即数按位取反后赋值给前一个寄存器

mvn r0,#0xFF
; 后一个数取反后赋值给前一个数,r0的值为0xffffff00(32位数据)
2.4 算术指令

rsb:逆向减运算
adc:带进位的加法运算(ADC指令用于把两个操作数相加,再加上CPSR中的C条件标志位的值)
sbc:带进位的减法运算
rsc:带进位的反减指令

2.5 逻辑指令

and:与操作
orr:或操作
eor:异或操作
bic:位清除操作

BIC R0,R0,#%1011
;清除R0的0,1,3位,赋值给R0
2.5 比较指令

cmp:比较大小
cmn:取反比较
tst:按位与运算
teq:按位异或运算

2.6 乘法指令

mul:32位乘法
mla:32位乘加

MLA R0, R1, R2, R3
; R0 = R1*R2+R3

umull:64位无符号乘法
umlal:64位无符号乘加
smull:64位有符号乘法
smlal:64位有符号乘加

2.7 跳转指令

b指令:跳转
bl指令:跳转,保存返回地址
bx指令:跳转,切换到ARM/Thumb模式
blx指令:跳转,保存返回地址,切换到ARM/Thumb模式

BL Label
; 转跳到Label标签处
2.8 内存访问

ldr:加载指定内存地址的数据到寄存器,按照字节访问
str:加载指定寄存器数据到内存地址中,按照字节访问

STR R1, [R2]
; 将R1的值存入以R2内容为地址的存储器中

ldm: 和ldr功能一样,一次多字节多寄存器访问
stm:和str功能一样,一次多字节多寄存器访问

ldm/stm后缀含义
iaincrease after,后增加,表示每个操作时,先传输数据,后增加内存地址,
ibincrease before,先增加,表示在每个操作时,先增加内存地址,再进行数据传输
dadecrease after:和ia一样,差别在于减少地址
dbdecrease before:和ib一样,差别在于减少地址
fdfull decrease:满递减堆栈,指的是从高地址向下生长,sp指向装最后一个数据的位置
edempty decrease:空递减堆栈
fa满递增堆栈
ea空递增堆栈
STMIA R0, {R2-R5, R7}
; [R0]<-R2, [R0+4]<-R3, … , [R0+12]<-R5, [R0+16]<-R7
STMFD SP!, {R1-R7, LR} 
; 将R1-R7,LR存放到堆栈中,这条指令一般用来保护现场

SWP:内存和寄存器互换指令,一边读一边写

SWP R1, R1, [R2]
; 交换以R2为地址的存储器内容和R1内容
swp r1,r2,[r0]
; [r0] -> r1,r2 -> [r0](记忆方式:r1是目的寄存器,所以将值写入r1)
2.9 软中断指令

swi(software interrupt),在软件层模拟产生一个中断,这个
中断会传送给CPU,常用于实现系统调用

3 可重入

  • 如果某个函数可被多个任务并发调用而不会造成数据错误,则称该
    函数具有可重入性
  • 可重入函数可在任意时刻被中断,稍后继续运行时不会造成错误

不可重入性:

  • 不可重入函数不能被多个任务共享,除非采用信号量等机制确保函
    数的互斥调用,或者在代码的关键部分禁止中断

注意:可重入被多个任务并发调用,应该考虑为多个线程并发调用。因此代码中出现全局变量,或者是static的,多为不可重入函数。

4 中断

  • 中断:当中断产生的时候,CPU会中断当前正在运行的任务,来处理中断
  • 软中断:通常为正在执行的进程产生的IO请求
  • 硬中断:硬件产生的中断,比如键盘,网卡等

中断处理-硬件:

  • 复制CPSR到SPSR_<mode>
  • 设置正确的CPSR位
  • 切换到<mode>
  • 保存返回地址到LR_<mode>
  • 设置PC跳转到相应的异常向量表入口

中断处理-软件:

  • 把SPSR和LR压栈
  • 把中断服务程序的寄存器压栈
  • 开中断,允许嵌套中断
  • 中断服务程序执行完后,恢复寄存器
  • 弹出SPSR和PC,恢复执行

5 makefile

格式:

目标:[依赖模块] 
命令
命令

6 嵌入式汇编

寄存器别名含义
A1-A4R0-R3,用来传递参数
V1-V8R4-R11
IPR12,前一个栈指针
SPR13,栈指针
LRR14,返回地址
PCR15
  • text section
    代码段,只读
  • data section
    数据段,存放已初始化的全局变量、静态变量和常量等
  • bss section
    block started by symbol,存放未初始化全局和静态变量
    在这里插入图片描述

汇编mian函数编写:

.global _start 
.text
_start:
	; main函数主体
	;函数调用
	MOV		R0, 1
	LDR		R1,	[R1, 2]
	BL		fun
	;函数返回值在R0
.end

汇编函数编写:

fun:
	STMFD 	SP!, {R0-R4,R12,LR}	;保存现场
	
	;函数的参数通过R0-R3传递
	LDR 	R0, [R1, #0x4]	;获取数组的值,注意计算偏移量
	STR 	R0, [R1, #0x4]	;修改数组的值
	PUSH	{R0, R1}	;变量入栈
	POP		{R0, R1}	;变量出栈
	
	LDMFD 	SP!,{R0-R4,R12,LR}
	MOV		R0, R1; 返回值保存
	BX LR

实现阶乘20!,结果放入R9:R8

.global _start
.text
_start:
		Mov R8, #20 	@低32位初始化为20
		Mov R9,#0 		@高32位初始化为0
		Sub R0,R8,#1 	@初始化计数器
Loop:
		MOV R1,R9 			@暂存高位值
		UMULL R8,R9,R0,R8 	@[R9:R8]=R0*R8
		MLA R9,R1,R0,R9 	@R9=R1*R0+R9
		SUBS R0,R0,#1 		@计数器递减
		BNE Loop 			@计数器不为0时继续循环
.Stop:
		B Stop
.end 					@文件结束

注意点:

  1. 如果函数体内再次调用函数,则一定写push {lr},后面写 pop {lr}
  2. 尽量不要使用栈操作,为每个变量都分配一个寄存器
  3. 尽量使用R0-R3,如果使用超过R3,则必须入栈
  4. 返回时不要忘记把返回值赋值给R0

基本块

如果是简单的if语句:

if(r0 >= r1) r0 = r1 + r2;
CMP R0, R1
ADDGE R0, R1, R2

如果if块中有较多的语句

	CMP R0, R1
	BLT else 	;这里的条件是if取反 
	;条件满足时执行
else:
	;条件不满足时执行	 

如果是循环语句:

MOV R0, #20	;设置计数器	
LOOP:
	;循环体
	SUBS R0, R0, #1
	BNE LOOP
STOP:
	;循环结束

7 混合编程

arm调用C

C语言函数 int add(int a, int b);
在arm中:

IMPORT add;声明要调用的C函数

MOV r0, 1
MOV r1, 2
BL add ;调用C函数add
C调用arm

C语言:

extern int add (int x,int y); //声明add为外部函数
void main()
{
   int a=1,b=2,c;
   c=add(a,b); //调用add子程序
   ……
}

arm

EXPORT add ;声明add子程序将被外部函数调用

add:					;求和子程序add
	ADD r0,r0,r1
	MOV pc,lr
内嵌汇编
__asm(
	汇编语句模板: 
	输出部分: 
	输入部分: 
	修改部分
)
  1. 参数传递时无法指定寄存器,必须传递进入后使用MOV
  2. 输出部分: “=r” (result),result表示C语言的变量
  3. 输入部分:“r”(value),value表示输入的C语言变量,多个变量用逗号分隔
  4. 在模板中使用%0,%1的占位符,按顺序表示输出输入的变量
  5. 如果在汇编模板中用到了寄存器,则需要在最后注明(用逗号隔开)

例子:

#include <stdio.h>
int main(void)
{
	int result ,value;
	value=1;
	printf("old value is %x",value);
	__asm("mov %0,%1,ror #1": "=r"(result):"r"(value));
	printf("new result is %x\n",result) ;
	return 1;
}

嵌入式操作系统uCOS【重点】

1 调度

基于优先级,就绪态优先级最高的任务先运行

抢占式:如果中断服务中出现了高优先级任务就绪,则中断结束后直接返回高优先级任务
非抢占式:中断结束后总是返回原来的任务

临界区:执行时不允许中断

2 进程分配

  • 抢占式实时操作系统
  • 64个任务,8(系统保留)+56(应用程序)
  • 允许每个任务有不同的栈空间
  • 中断嵌套最多255层
  • 优先级越高,任务编号数字越小
  • 空闲任务(idle task) 当所有的任务都在等待事件发生时μC/OS-Ⅱ执行OSTaskIdle()函数
  • OS_TCB:堆栈指针,状态,优先级,任务表位置,任务链表指针等,OS_TCBs全部驻留在RAM中
  • uC/OS中不支持时间片轮转法
  • uC/OS任务调度所花的时间为常数,与应用程序中建立的任务数无关

3 优先级计算

OSRdyTbl是一个长度为8的数组,看成一个8*8的矩阵,第一行是7->0,如果一个元素为1,表示该优先级的任务就绪。
OSRdyGrp是一个8bit的数,看成OSRdyGrp[n]表示第n行是否有就绪队列
任务号高三位是矩阵的行(0开始),任务号低3位是矩阵的列(从右边开始数)
OSMapTbl[n]就是2的n次的值,把一个值n映射到了第n个bit是1的8位数

关键是计算行列地址。

任务就绪时
OSRdyGrp |=OSMapTbl[prio>>3];
OSRdyTbl[prio>>3] |=OSMapTbl[prio & 0x07];

如果没有给OSMapTbl,则直接改成2^i次即可,比如优先级为12
12=0x1100,地址为(1,4)

OSRdyTbl[1] |= 2^4
OSRdyGrp |= 2^1=2
脱离就绪态
OSRdyTbl[prio>>3] &= ~OSMapTbl[prio&0x07];
if(OSRdyTbl[prio>>3] == 0);
	OSRdyGrp &= ~OSMapTbl[prio>>3];

如果优先级12脱离就绪态,则在矩阵中的地址为(1,4)

OSRdyTbl[1] &= ~2^4;
if(OSRdyTbl[1] == 0) {
	OSRdyGrp &= ~2^4;
}
寻找优先级最高的任务

根据OSRdyGrp从右开始为1的最高位就是行地址x,
在OSRdyTbl中该行从右开始为1的就是列地址y。
优先级=x*8+y

比如OSRdyGrp=01101000B,则从右开始数第一个为1的位为3,
OSRdyTbl[3] = 11100100B,则从右开始为1的是2,优先级为3*8+2=26

High3 =OSUnMapTbl[OSRdyGrp];
Low3 =OSUnMapTbl[OSRdyTbl[High3]];
Prio =(Hign3<<3)+Low3;

嵌入式软件开发环境和调试技术【了解】

交叉编译:就是在一个平台上生成另一个平台上的可执行代码

远程调试:调试器运行于通用桌面操作系统的应用程序,被调试的程序则运行于基于特定硬件平台的嵌入式操作系统(目标操作系统)

Boot Loader程序设计【重点】

在操作系统内核运行之前运行的一段小程序,Boot Loader一般存储在0地址,系统加电后,CPU将首先执行 Boot Loader 程序
字符方式与用户进行交互

典型结构

stage1state2
硬件设备初始化
(屏蔽中断,设置CPU速度,RAM初始化,LED初始化,关闭CPU指令)
初始化本阶段要使用到的硬件设备
为加载 Boot Loader 的 stage2 准备 RAM 空间检测系统内存映射(memory map)
拷贝 Boot Loader 的 stage2 到 RAM 空间中将 kernel 映像和根文件系统映像从 flash 上读到 RAM 空间中
设置好堆栈为内核设置启动参数
跳转到 stage2 的 C 入口点调用内核

stage 1

  • 汇编
  • 简单的硬件初始化

stage 2

  • C语言
  • 不能使用 glibc 库中的任何支持函数
  • trampoline(弹簧床)编程方式:用汇编将state2的main函数包裹起来,可以处理传递进来的参数,对main函数返回值进行处理

嵌入式操作系统内核设计

内存管理

32位地址长度,4GB虚拟空间

  • 段映射:12位段表(段地址长12bit,端大小为1M)
  • 粗页表映射:64k或4k/页
  • 细页表映射:1k/页

模块机制

  • 微内核(Micro-kernel) Windows
    操作系统主要组件(内存管理器、进程管理器和I/O管理器)运行在独立进程

  • 单一内核(monolithic-kernel) Linux
    操作系统核心组件在同一进程实现

嵌入式文件系统设计

文件访问操作:

  1. 系统调用create, open, read, write, close操作
  2. 调用VFS层函数
  3. 通过file_opration指针调用具体的函数

基于Flash的文件系统

NOR Flash, NAND Flash不带Flash控制器,
SD, EMMC, SSD, USB 带Flash控制器

基于Block Device的文件系统

FAT、EXT2:逻辑块的大小是512B,写入和修改时单位为块

基于MTD的文件系统:

JFFS2:不适合NAND,NAND容量较大,导致日志文件太大,内存占用过多,挂载时扫描整个FLASH内容,简历日志节点,导致耗时较长
支持数据压缩
YAFFS2:不支持数据压缩,挂载时间短
UBIFS:更适合NAND,支持write-back,写入数据放入cache,
不需要扫描整个Flash,可以部分压缩

内存文件系统

Ramdisk:制度,不支持动态擦写,按顺序存放数据
Ramfs/tmpfs:随机页访问,只读

网络文件系统

Samba
NFS

嵌入式字符设备驱动程序设计【重点】

概念:

  • 对设备的初始化和释放
  • 把数据从内核传到硬件/从硬件读数据到内核
  • 读取应用程序传送给设备文件的数据和回送应用程序请求的数据。这需要在用户空间,内核空间,总线以及外设之间传输数据
  • 检测和处理设备出现的错误、

具体分类

  • 字符设备:无需缓冲直接读写
  • 块设备:通过buffer或cache进行读写,支持随机访问
  • 网络设备:通过BSD套接口访问

每个设备文件都对应有两个设备号

  • 主设备号,标识设备的种类,使用的驱动程序
  • 次设备号,标识使用同一设备驱动程序的不同硬件设备

字符设备在Linux内核中使用struct cdev结构来表示

file_operations

//用来从设备中读取数据
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 

//用来向设备写入数据
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

//用来打开设备
int (*open) (struct inode *, struct file *);

//用来关闭设备
int (*release) (struct inode *, struct file *);

file

file结构体在<linux/fs.h>中定义
f_mode: 文件读写模式
f_pos: 文件读写位置
f_flags: 文件标志
f_op: 文件关联操作
private_data: 系统调用信息

inode

是内核文件系统索引节点对象,包含内核在操作文件或目录时需要的全部信息

在内核中inode结构体用来表示文件,file是表示打开文件
的结构体

  • dev_t i_rdev:设备号
  • struct cdev *i_cdev:指向cdev结构的指针

最小内核模块:

#define CHRDEV_MAJOR 240  // 主设备号
#define CHRDEV_MAION 0    // 次设备号
#define CHRDEV_COUNT 1    // 次设备号个数
#define CHRDEV_NAME  "testchrdev"

struct led_cdev
{
	struct cdev chrdevcdev;
	int major;
	dev_t dev;
	struct class *led_dev_class;
	struct semaphore led_sem;// 定义信号量
};
static struct led_cdev leddev;



ssize_t chrdev_read (struct file *file, char __user *usr, size_t size, loff_t *loff)
{
	printk("%s\r\n",__func__);
	return 0;
}
int chrdev_open (struct inode *inode, struct file *file)
{
	if (down_trylock(&leddev.led_sem) != 0) {  // 当应用程序打开文件时会尝试申请信号量
		return -EBUSY;                         // 当信号量已经申请完时,就返回错误码
	}
	file->private_data = &leddev;
	return 0;
}
int chrdev_release (struct inode *inode, struct file *file)
{
	struct led_cdev  *led_private_data = (struct led_cdev  *)file->private_data;
	up(&led_private_data->led_sem);            // 当应用程序关闭文件时释放信号量
	return 0;
}
struct file_operations fops = 
{
	.open    = chrdev_open,
	.read    = chrdev_read,
	.release = chrdev_release,
};


static int __init chrdev_init(void)
{
	int ret = 0,error = 0;
	struct device *devices;
	//DEBUG_SFLR("%s\r\n",__func__);
	error = alloc_chrdev_region(&leddev.dev,CHRDEV_MAION,CHRDEV_COUNT,CHRDEV_NAME); // 注册设备号
	printk("MAJOR = %d MINOR = %d\r\n",MAJOR(leddev.dev),MINOR(leddev.dev));
	if(error < 0){
		printk("alloc_chrdev_region error\r\n");
		ret =  -EBUSY;
		goto fail;
	}
	leddev.major = MAJOR(leddev.dev);
	cdev_init(&leddev.chrdevcdev, &fops); // 绑定字符设备操作函数集
	error = cdev_add(&leddev.chrdevcdev,leddev.dev,CHRDEV_COUNT);   // 添加字符设备
	if(error < 0){
		printk("cdev_add error\r\n");
		ret =  -EBUSY;
		goto fail1;
	}
	
	// 创建类,类名为testledclass
	leddev.led_dev_class = class_create(THIS_MODULE, "testledclass");
	if (IS_ERR(leddev.led_dev_class)){
		printk("class_create error\r\n");
		ret =  -EBUSY;
		goto fail2;
	}
		
	// 创建设备
	devices = device_create(leddev.led_dev_class, NULL, MKDEV(leddev.major,0), NULL, "testled");
	if(NULL == devices){
		printk("device_create error\r\n");
		ret =  -EBUSY;
		goto fail3;
	}
	
	sema_init(&leddev.led_sem,2); // 初始化信号量
	
	return 0;
fail3:	
	class_destroy(leddev.led_dev_class);/*  删除类 */
	
fail2:	
	cdev_del(&leddev.chrdevcdev);/*  删除cdev */
fail1:
	unregister_chrdev_region(leddev.dev,CHRDEV_COUNT);
fail:
	return ret;
}


static void __exit chrdev_exit(void)
{
	//DEBUG_SFLR("%s\r\n",__func__);
	device_destroy(leddev.led_dev_class,MKDEV(leddev.major,0));/*  卸载设备 */
	class_destroy(leddev.led_dev_class);/*  删除类 */
	cdev_del(&leddev.chrdevcdev);/*  删除cdev */
	unregister_chrdev_region(leddev.dev,CHRDEV_COUNT);
}

module_init(chrdev_init);
module_exit(chrdev_exit);

MODULE_DESCRIPTION("xxxxxx");
MODULE_AUTHOR("xxxxxx");
MODULE_LICENSE("GPL");

内核编译:

make -C KERNER_DIR M=$shell(pwd) modules

内核装载和卸载:

lnsmod module.ko
rmmod module.ko

内核模块开发时需要的机制:了解进程间通信,

同步机制和通信

重点,几部分组成,每部分的作用、实验是重点

嵌入式块设备驱动程序设计

块设备数据存取的单位是块,块的大小通常为512字节到
32K字节不等;块设备每次能传输一个或多个块,支持随机
访问,并采用了缓存技术

字符设备以字节为单位进行读写,块设备则以块为单位
块设备还支持随机访问,而字符设备只能顺序访问

嵌入式网络设备驱动程序设计

网线=>变压器=>PHY芯片=>MAC芯片=>PCI总线

MAC芯片:实现MAC子层和LLC子层的功能,提供PCI界面
PHY芯片主要负责数据收发:CSMA/CD、模数转换、编解码、串并转换等

嵌入式数据库技术

概念

  • 安装在嵌入式设备中
  • 通常与操作系统和具体应用集成

特点

  • 占用存储空间小
  • 可靠性、可管理性和安全性
  • 互操作性和可移植性
  • 可剪裁性

关键技术

  • 数据库微型化:关键模式优化和数据压缩
  • 数据同步技术:同步冲突检测
  • 系统定制能力:和应用程序结合
  • 系统实时处理能力:实时应用需要数据库实时处理能力

例题

  1. bootloader两阶段的功能?

state1 硬件初始化、准备RAM空间,将state2代码拷贝到RAM中、设置堆栈、跳到C语言函数入口
state2 初始化本阶段硬件、检测内存映射、加载内核和根文件系统代码、设置内核启动参数、调用内核

  1. 解释交叉编译并举例:

在一个平台编译生成另一个平台的可执行代码
比如在arm64机器上编译生成arm32代码,在x86机器上编译生成arm32代码

  1. BSP,驱动程序,bootloader,HAL的含义?

BSP: ?
驱动程序:内核的一部分,提供设备的初始化和释放,设备和内核的数据交换,设备和应用软件的数据交换,出错控制
bootloader:在操作系统开始运行前运行的一小段代码
HAL: 硬件抽象层

  1. ucOS2的优先级任务算法具体是怎样的?以优先级12为例进行说明?

计算出12所在的行:12=0x001100,行=1,列=4,
设置就绪队列:OSRdyGrp | = 2^1, OSRdyTbl[1] |= 2^4
取消就绪队列:OSRdyTbl[1] &= ~16, if(OSRdyTbl[1]==0) OSRdyGrp &= ~2

  1. 以优先级21为例进行说明:

计算出21所在的行列:21=0x0001 0101,行=2,列=5
设置就绪队列:OSRdyGrp |= 2^2=4, OSRdyTbl[2] |= 2^5 = 32
取消就绪队列:OSRdyTbl[2] &= ~32, if(OSRdyTbl[2]==0) OSRdyGrp &= ~4

  1. 加入OSRdyGrp==100 100b, OSRdyTbl[2]=
    0x12,求最高优先级:

通过OSRdyGrp右侧第一个1确定行:2,通过OSRdyTbl[2]右侧第一个1确定列:0x12=0b0001 0010, 列=1,则优先级=2*8+1=17

  1. 写⼀条 ARM 指令,完成操作r1 = r2 * 3

注意是一条:MUL R1, R2, 3
或者是 ADD R1, R2, R2, LSL #1

  1. 初始值R1=23H,R2=0FH执⾏指令BIC R0,R1,R2,LSL #1后,寄存器R0,R1的值分别是多少?

R2 LSL 1后 R2=b1 1110, BIC指令将R2对应位为1的值在R1上清0,R1=0b0010 0011
BIC 后: 0010 0001 ,R0=0x21, R1=0x23

  1. 说明指令STMIA r12!, {r0-r11}的操作功能

R0-> [R12], R1->[R12+4], …, R11->[R12+44], i指的是地址增加,a指的是第一个地址不增

10.以下哪种⽅式不是uc/os操作系统中任务之间通信⽅式。
(A) 信号量
(B) 消息队列
(C) 邮件
(D) 邮箱

ucOS通信方式:信号量、邮箱、消息队列,事件标志

  1. nand 和 nor的区别:
nandnor
价格便宜
容量
擦写次数
擦写速度
读取速度
读取单位字节字节
写单位page字节
擦除blockblock
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值