avatar nyne
Open App

嵌入式

概论

  1. 世界上第一台现代电子计算机“埃尼阿克”(ENIAC),诞生于1946年2月14日的美国宾夕法尼亚大学
  2. 嵌入式系统: 以应用为中心,以计算机技术为基础,软件硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、重量、功耗严格要求的专用计算机系统. 简而言之,是含有处理器的专用软硬件系统, 具有自主的信息处理能力.
  3. 嵌入式系统是以嵌入式应用为目的的计算机系统,可分为系统级、模块级、芯片级
  1. 嵌入式系统的体系结构 image
  2. 特点

ARM体系

ARM简介

  1. 特点
  1. 多核
  1. 体系架构分类
  1. 流水线技术

ARM处理器的运行

  1. 工作模式

    • 用户模式(usr):ARM处理器正常的程序执行状态。
    • 系统模式(sys):运行具有特权的操作系统任务。
    • 快速中断模式(fiq):用于高速数据传输或通道处理。
    • 外部中断模式(irq):用于通用的中断处理。
    • 管理模式(svc):操作系统使用的保护模式。
    • 数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护。
    • 未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真。
  2. 寄存器 image

    • 寄存器R8~R12有两个分组的物理寄存器。一个用于除FIQ模式之外的所有寄存器模式,另一个用于FIQ模式。这样在发生FIQ中断后,可以加速FIQ的处理速度
    • 寄存器R13、R14分别有6个分组的物理寄存器。一个用于用户和系统模式,其余5个分别用于5种异常模式。
    • R13常作为堆栈指针
    • R14为链接寄存器: 在每种模式下,模式自身的R14版本用于保存子程序返回地址;当发生异常时,将R14对应的异常模式版本设置为异常返回地址(有些异常有一个小的固定偏移量)
    • 寄存器R15为程序计数器(PC),它指向正在取指的地址。
    • 寄存器R16(CPSR)用作当前程序状态寄存器, 它包括条件标志位、中断禁止位、当前处理器模式标志位,以及其他一些相关的控制和状态位。
  3. 程序状态寄存器

  1. 异常: 当一个异常出现以后,ARM微处理器会执行以下几步操作

    • 将下一条指令的地址存入相应链接寄存器LR,以便程序在处理异常返回时能从正确的位置重新开始执行
    • 将CPSR复制到相应的SPSR中
    • 根据异常类型,强制设置CPSR的运行模式位
    • 强制PC从相关的异常向量地址取下一条指令执行,从而跳转到相应的异常处理程序处。还可以设置中断禁止位,以禁止中断发生。如果异常发生时,处理器处于Thumb状态,则当异常向量地址加载入PC时,处理器自动切换到ARM状态
    • 异常处理完毕之后,ARM微处理器会执行以下几步操作从异常返回: 将连接寄存器LR的值减去相应的偏移量后送到PC中, 将SPSR复制回CPSR中, 若在进入异常处理时设置了中断禁止位,要在此清除
  2. 异常优先级 image

  3. 储存系统

    • 地址空间: ARM体系结构将存储器看做是从零地址开始的字节的线性组合。作为32位的微处理器,ARM体系结构所支持的最大寻址空间为4GB。当程序正常执行时,每执行一条ARM指令,当前指令计数器加4个字节;每执行一条Thumb指令,当前指令计数器加2个字节。
    • 存储器格式: ARM体系结构可以用两种方法存储字数据,称之为大端格式和小端格式。在小端存储格式中,低地址中存放的是字数据的低字节,高地址存放的是字数据的高字节。

指令系统

  1. 指令格式: {cond} {S} , {,operand2}
  1. 寻址方式
  1. 常用指令

加载和存储:

分支指令:

数据处理:

运算:

状态寄存器访问:

ARM程序设计

伪操作

  1. .section伪操作: 自定义一个段
  2. .text .data .bss: 将汇编系统预定义的段名编译到相应的代码段、数据段和bss段
  3. .end: 表明源文件的结束
  4. .include: 将指定的文件在使用位置处展开
  5. .incbin: 将原封不动的一个二进制文件编译到当前文件中
  6. .if .else .endif: 条件表达式
.if 条件表达式     
    代码段1 
.else     
    代码段2 
.endif
  1. .macro: 定义宏 .endm: 宏结束
  2. .string "abcd","hello" 定义字符串
  3. .set: 为程序中标号定义名称
  4. .global .extern
  5. .ltorg.pool用于声明一个数据缓冲池的开始,它可以分配很大的空间

伪指令

LDR r1,=0xff 将0xff读取到r1中

循环

LOOP:   
  ADD   R0,R0,R1	    @ R0=R0+R1
  CMP   R0,#3	        @ 比较R0和#3 
  BLS     LOOP          @if R0<3 then 跳转到LOOP循环

子程序

BL 子程序名

该指令在执行时完成如下操作:将子程序的返回地址存放在连接寄存器LR中,同时将程序计数器PC指向子程序的入口点,当子程序执行完毕需要返回调用处时,只需要将存放在LR中的返回地址重新复制给程序计数器PC即可

寄存器的使用

C语言与汇编相互调用

  1. C语言, 使用extern声明汇编函数
  2. 汇编, 使用.extern声明c函数

裸机开发接口

GPIO

代码示例:

<a href="/tag/define" class="tag" target="_blank">#define</a> GPBCON (*(volatile unsigned int *) 0xE0200040)
<a href="/tag/define" class="tag" target="_blank">#define</a> GPBDAT (*(volatile unsigned int *) 0xE0200044)

void delay() 
{ 
    int i = 0x100000; 
    while (i--); 
} 

int main(void) 
{ 
    int i = 0;

    GPBCON &= ~0xfff0000;
    GPBCON |= 0x1110000;              

    while (1) 
    { 
        GPC0DAT &= ~(7 << 5);
        GPC0DAT |= 1 << (i + 5);                
        i++; 
        if (i == 4) 
            i = 0;
        delay();                                         
    } 
    return 0;
}

Linux系统

嵌入式交叉编译环境

Bootloader

Bootloader是在操作系统运行之前执行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射表,从而建立适当的系统软硬件环境,为最终调用操作系统内核做好准备。 对于嵌入式系统,Bootloader是基于特定硬件平台来实现的。因此,几乎不可能为所有的嵌入式系统建立一个通用的Bootloader,不同的处理器架构都有不同的Bootloader。

U-Boot: 通用引导程序

设备驱动编程

应用程序调用库函数, 库函数通过系统调用执行软件陷阱指令进入内核, 内核中通过系统调用的异常处理与驱动程序交互, 驱动程序调用硬件设备

代码示例

<a href="/tag/include" class="tag" target="_blank">#include</a> <unistd.h>
<a href="/tag/include" class="tag" target="_blank">#include</a> <stdio.h>
<a href="/tag/include" class="tag" target="_blank">#include</a> <fcntl.h>
static int fd = -1;
int main()
{
    int i=0;
    fd=open("/dev/gpioled ",O_RDWR);
    if(fd<0){
		printf("Can't open\n");
		return -1;
	} else {
		printf("open OK 11%x\n", fd);
	}
    while(1) {
	    for(i=0;i<8;i++) {
	        ioctl(fd, LED_ON, 1<<i);
	        sleep(1);
	    }
	}
	
   	close(fd);
  	return 0;
}