自己上个学期期末为了应付嵌入式考试而根据老师PPT总结的笔记,昨晚我看到Xiaomage也把自己的笔记发到博客上去了,所以我也把我这个发上来了,希望能帮到同道中人(喜)
KG yyds! KB yyds!
概论
微处理器结构
冯·诺依曼架构:程序和数据在同一个存储体中,共用一组地址和数据线。~ARM7
丹佛架构:程序和数据存储器分开组织和存储,分为两组的地址、指令/数据线。执行时可以预读下一段指令。ARM9至今
ARM架构版本
v5:提高ARM/Thumb切换效率;E:增强DSP指令集,全部算法操作和16位乘法;J:Java加速
v6:Thumb-2、SIMD、灵活的配置和裁剪
v7:A:高性能开放应用平台,支持大型OS;R:高性能硬实时;M:低成本低功耗快中断
ARM变种
Thumb (T):更高密度代码
长乘法 (M)、增强DSP指令 (E)、Java加速 (J)、ARM媒体功能扩展 (SIMD)
体系结构
处理器内核系统:
- 中断控制器NVIC(输入为外中断信号组)
- 取指单元、指令解码器、寄存器组、ALU、存储器接口
- NVIC让
PC
指针自动指向下一个位置,并把当前要执行的命令取到IR中放置;根据取到的指令解释后利用ALU、寄存器和内存完成该指令所规定的操作,并储存指令结果 - 取指、译码、执行、存结果
ARM控制器:14个输入、40个输出,分散控制:寄存器、ALU、Load/Store、乘法器、移位寄存器、协处理器和地址
寄存器
Cortex-M3有2种模式:处理器模式handler(异常处理例程代码,只有特权级模式)和线程模式thread(一般程序代码,有特权级和用户级)
异常:内/外中断源产生并引起CPU处理一个事件
想要控制特定的硬件时,它就会产生一个SVC异常,然后OS提供的SVC异常服务例程执行,它再调用相关的OS函数,后者完成用户程序请求的服务。提出要求-得到满足的模式。
好处:用户程序和硬件脱钩。
Cortex-M3的寄存器
通用寄存器
R0-R15
- 低组寄存器
R0-R7
,所有指令均可访问 - 高组寄存器
R8-R12
,所有32位指令和极少数16位Thumb指令能访问 R13
:分为主堆栈指针MSP
(缺省SP,由OS内核、异常服务例程等需要特权访问的程序使用。支持线程和处理器模式)和进程堆栈指针PSP
(只能用于常规代码和线程模式)R14
:连接寄存器LR
,调用子程序时存储返回地址。BL FUNC1 => PC=FUNC1并且LR=主程序MAIN的下一条指令地址
。BL
:分支并连接Branch & LinkR15
:程序计数器PC
,总是指向“正在取指”的指令,而不是指向“正在执行”的指令或正在“译码”的指令。M3有3级指令流水线,所以读PC
的返回值是当前指令地址+4。
- 低组寄存器
特殊功能寄存器,只能被专用MRS/MSR访问,没有存储器地址
MRS:状态寄存器传送到通用寄存器;MSR:通用到状态
状态寄存器组:
PSRs
或xPSR
(应用程序APSR
、中断号IPSR
、执行EPSR
)中断屏蔽寄存器组:
PRIMASK
(置1就屏蔽除NMI和硬Fault之外的其他中断)FAULTMASK
(置1就只响应NMI)BASEPRI
(最大9位,屏蔽所有数值上不小于它的优先级)控制寄存器
CONTROL
:[1]选堆栈指针,0选
MSP
(初始值),1选PSP
(handler下不能选1)[0]特权级和用户级的切换,0为特权1为用户
存储部件
支持的数据类型:8b有/无符号字节,16b有符号和无符号半字(以2字节的边界对齐),32位有/无符号字(以4字节边界对齐)
对于字对齐的地址A,地址空间规律为:
- 地址位于A的字由地址为A、A+1、A+2和A+3的字节组成
- 地址位于A的半字由地址为A和A+1的字节组成
- 地址位于A+2的半字由地址为A+2和A+3的字节组成
- 地址位于A的字由地址为A和A+2的半字组成
端序
- 复位时决定使用大端序还是小端序,运行时无法更改,指令预取始终是小端
- 配置控制存储空间的访问永远使用小端模式
- 地址0xE0000000至0xE00FFFFF永远使用小端模式
REV/REVH
指令完成端序转换
中断
执行过程:异常触发→查向量表→异常handler执行
特点:向量化中断。缩短了延迟,因为不需要软件判断中断源。进入异常handler时,自动压栈,结束时自动弹出
STM32的中断优先级分组:优先级越高,数值越低!抢占优先级相同的任务,响应优先级高的先响应,但不能互相抢占;抢占优先级不同的,可以抢占低优先级的CPU
总线
I-code是基于AHB-Lite协议的32位总线,用于取指,只读不写,一次取一个长字 (32bit),也就是一两个Thumb指令,或者是一个或一部分的ARM/Thumb-2指令。
D-code是基于AHB-Lite的32位总线,用于数据传输,可读写,能单个读写也能顺序读写。
系统总线是内核访问数据、指令、调试模块的接口。优先级是数据访问>指令>中断向量>调试模块接口。
总线架构:AMBA
外部接口I/O
内核没有I/O部件和模块,通过AMBA总线扩充
存储器单元能重复读多次且结果一致,I/O设备的多次读取结果可能不同
流水线
效率可能变低,因为存在相关性问题和程序转移问题。
相关性问题:用乱序执行解决
程序转移问题:用分支预测解决
3级流水线体现:M3有3级指令流水线,所以读PC的返回值是当前指令地址+4。例如当前是0x1000
,此时流水线上有0x1000 - 0x1002
,下一个要载入的是0x1003
,执行MOV之后PC后移到0x1004
。
MOV R0,PC ; 0x1000
R0 = 0x1004
指令集
汇编代码:分号注释、标号顶格写、要声明文件结束
指令集背景
处理器包括指令集、微结构、工具链
指令集架构 (ISA):指令和指令编码的列表。执行运算和处理功能、控制程序流、数据转移、辅助功能
指令分类和格式
是RISC,指令等长、内存管理简单、1周期执行、指令流水线化、硬连线控制、编译程序复杂度高
指令分类:数据处理(改变寄存器值)、数据传送(Load/Store)、子程序调用和跳转、饱和运算指令(多用于DSP)、隔离指令(主要是流水线和写缓冲)、标志位和条件转移
一般格式:opcode cond s Rd Rn operand2
指令操作符编码、执行条件编码、结果是否影响xPSR
、目的寄存器编码、第一操作数寄存器编码、第二操作数
ANDNES R0,R1,#0x0F
状态寄存器xPSR
:记录ALU 标志(0标志,进位标志,负数标志,溢出标志),执行状态,以及当前正服务的中断号。指令根据xPSR
中的条件位自动判断是否执行指令,在条件满足时,指令执行,否则指令被忽略。
指令能带后缀:
对条件后缀的使用有限制,只有转移指令(B 指令)才可随意使用。而对于其它指令,CM3 引入了 IF‐THEN
指令块,在这个块中才可以加后缀,且必须加以后缀。另外,S后缀可以和条件后缀在一起使用。共有 15 种不同的条件后缀。
第二操作数可以是立即数、寄存器、任意移位的寄存器。
操作数符号:立即数#
、二进制2_
和%
、十六进制0x
逻辑移位操作(带在第二个操作数前面):逻辑左移LSL
(低位填0)、算术左移ASL
(低位填0)、逻辑右移LSR
(高位填0)、算术右移ASR
(高位用第31位值填充)、循环右移ROR
、扩展循环右移RRX
(循环带C位)
指令关系:Thumb-2 (16/32位)>Cortex-M3>Thumb (16位)
ADD R0,R1 ; 使用传统的Thumb语法
ADD R0,R0,R1 ; UAL语法允许的等值写法R0=R0+R1
; 如果使用传统的Thumb语法,有些指令会默认地更新APSR,即使你没有加上S后缀。如果使用UAL语法,则必须指定S后缀才会更新。
ANDS R0,R0,R1 ; UAL下执行AND同时刷新APSR要加后缀S,而Thumb可能会默认的更新APSR
; Thumb-2下某些操作可以是16或32位操作,UAL下可以让汇编器选择用哪个,也可以手动确定
ADDS R0,#1 ; 汇编器为了省资源,自动选择16位
ADDS.N R0,#1 ; 强制16位(Narrow)
ADDS.W R0,#1 ; 强制32位(Wide)
寻址方式
处理器根据指令中的地址信息寻找物理地址的方式
立即寻址、寄存器间接寻址、堆栈寻址、相对寻址、寄存器寻址、基址加偏址寻址、块拷贝寻址
堆栈寻址:
- 满递增堆栈:堆栈指针指向最后压入的数据,且由低地址向高地址生成。
- 满递减堆栈:堆栈指针指向最后压入的数据,且由高地址向低地址生成。
- 空递增堆栈:堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成。
- 空递减堆栈:堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成。
用PUSH
和POP
指令控制堆栈,简略来讲,堆栈操作就是地址受SP
控制的内存读写操作
Cortex-M3使用的是“向下生长的满栈”模型。堆栈指针SP指向最后一个被压入堆栈的32位数值。在下一次压栈(PUSH
)时,SP先自减4,再存入新的数值
POP
操作刚好相反:先从SP
指针处读出上一次被压入的值,再把SP
指针自增4
带符号扩展指令
意义:在二进制补码表示法中,最高位是符号位,且所有负数的符号位都是1。但是负数还有另一个性质,就是不管在符号位的前面再添加多少个1,值都不变。于是,在把一个8位或16位负数扩展成32位时,欲使其数值不变,就必须把所有高位全填1。至于正数或无符号数,则只需简单地把高位清0。因此,必须给带符号数开小灶。
; 记R0=0x55aa8765,则
SXTB R1,R0 ; R1=0x00000065,65最高位是0,因此R1高位填0
SXTH R1,R0 ; R1=0xffff8765,8765最高位是1,因此R1高位填1
STM32基本原理
定时器
- 内核中的
SysTick
计时器:简单的周期定时器,一般在μC/OS下面用它做系统滴答服务。位于M3核心中的NVIC,定时结束时发SysTick
异常 (序号15) - 常规定时器
- 高级控制定时器
TIM1
、TIM8
:1. 测量输入信号的脉冲宽度;2. 产生输出波形;3. 与RCC(复位与时钟控制)配合,可以实现脉冲宽度和波形周期的精确调节 - 通用定时器
TIM2-TIM5
:与高级控制定时器类似,可同步操作。 - 基本定时器
TIM6
、TIM7
:主要用来触发DAC同步电路
- 高级控制定时器
区别:刹车信号管理,应该用高级
SPI
MISO
:主设备输入、从设备输出脚
MOSI
:主设备输出、从设备输入脚
SCK
:串口时钟,主机输出从机输入
NSS
:从设备选择 (可选),主要是用来片选
每个时钟周期内,MISO
和MOSI
各走1位数据
(写入)发送缓冲区→(MISO
& LSBFIRST
控制位)→移位寄存器→接收缓冲区(读出)
I2C
起始条件:SCL
为高电平时,SDA
线由高到低切换。
终止条件:SCL
为高电平时,SDA
线由低到高切换。
FSMC
FSMC扩展存储器:扩展存储器时FSMC可以把外存划分为256MB的4个连续存储块
开发环境
J-Link
Description: STM32F2xx Flash
Device Type: On-Chip Flash
Device Size: 1M
SPI
ADC
/* 电压转换函数 */
while(1)
{
adc_data = AD_read_data(0x8c00);
volat = (float)adc_data/4096*2.5;
sprintf(temp,"%4.1f",volat);
LCD_DisplayStringLargeFont(100,100,(uint8_t *)temp);
DelayMs(1000);
}
将得到的AD采样值转换为实际电压值:
GPIO
使用GPIO模拟I2C
void iic_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure. GPIO_Pin = iic_scl|iic_sda;
GPIO_InitStructure. GPIO_Mode=GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure. GPIO_Speed= GPIO_Speed_50MHz; //设置数据传输速率为50MHz
GPIO_Init(iic_gpio, &GPIO_InitStructure);
GPIO_SetBits(iic_gpio, iic_scl|iic_sda);
}
GPIO库函数
//清零指定端口的端口位GPIO_ResetBits:
GPIO_ResetBits(GPIOA, GPIO_Pin_10 | GPIO_Pin_15);
//向指定GPIO数据端口写入数据 GPIO_Write :
GPIO_Write (GPIOA, 0xAAAA);
//设置指定端口的端口位GPIO_SetBits :
GPIO_SetBits(GPIOA, GPIO_Pin_10 | GPIO_Pin_15);
μC/OS-II
可移植、可嵌入ROM、可裁剪、抢占式、实时多任务
只是个实时OS内核,只有任务调度、任务管理、时间管理、存储管理、任务间通信与同步等基本功能,没有I/O管理、文件管理、网络等附加功能
$ EOF.