368 lines
16 KiB
Markdown
368 lines
16 KiB
Markdown
# 中断机制
|
||
|
||
* [简介](#interrupt)
|
||
* [RISC-V架构的中断和异常](#riscv_interrupt)
|
||
* [概述](#riscv_intro)
|
||
* [异常处理机制](#riscv_exception)
|
||
* [中断类型](#riscv_int_type)
|
||
* [中断控制器](#riscv_int_controller)
|
||
* [ARM CORTEX-M架构的中断和异常](#arm_interrupt)
|
||
* [概述](#arm_interrupt_intro)
|
||
* [异常处理机制](#arm_interrupt_process_mechnism)
|
||
* [中断类型](#arm_int_type)
|
||
* [中断控制器](#arm_int_controller)
|
||
* [中断处理机制](#riscv_int_process)
|
||
* [中断服务程序](#riscv_int_service)
|
||
* [中断处理流程](#riscv_int_process2)
|
||
* [中断函数接口](#riscv_int_api)
|
||
* [中断响应性能测试](#time_test)
|
||
* [概述](#time_test_intro)
|
||
* [基于 ARM 处理器的中断响应性能测试](#time_test_arm)
|
||
* [基于 RISC-V 处理器的中断响应性能测试](#time_test_riscv)
|
||
* [中断响应性能测试对比](#comparison)
|
||
* [使用场景](#situation)
|
||
|
||
<span id="interrupt"></span>
|
||
|
||
## 简介
|
||
中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。
|
||
中断的触发一般是由外设或者CPU内部产生,由中断控制器进行处理再通知到CPU进行中断响应过程,其要点如下:
|
||
|
||
+ 外设或者CPU内部产生的这个中断来源称为中断源;
|
||
+ CPU响应中断转入到的新的处理程序称为中断服务程序;
|
||
+ 中断处理完成后,处理器需要恢复之前的现场,简称“恢复现场”;
|
||
+ 当多个中断源请求中断的时候,需要通过优先级区分中断,便于CPU进行中断的处理;
|
||
+ 低优先级可以被高优先级打断,这个过程称之为中断嵌套;
|
||
+ 中断可以被屏蔽;
|
||
+ 所有的中断源都有一个编号,称为“中断号”;
|
||
+ 每一个中断号通过中断向量表与中断服务程序一一对应,中断向量表保存的是所有的中断服务程序的入口地址,该入口地址被称之为中断向量;
|
||
|
||
<span id="riscv_interrupt"></span>
|
||
|
||
## RISC-V架构的中断和异常
|
||
|
||
<span id="riscv_intro"></span>
|
||
|
||
### 概述
|
||
从广义上来说,中断和异常属于一个概念;对于处理器而言,通常只区分为同步异常和异步异常。
|
||
+ 同步异常:同步异常是指由于执行程序或者试图执行指令而产生的异常;例如,非法指令访问;
|
||
+ 异步异常:最常见的异步异常是外部中断,例如外设触发一个外部中断。
|
||
|
||
<span id="riscv_exception"></span>
|
||
|
||
### 异常处理机制
|
||
+ 进入异常时,RISC-V架构规定(以机器模式为例):
|
||
+ 当前的程序执行流停止执行,直接跳转到CSR寄存器的mtvec定义的PC地址执行;
|
||
+ 硬件同时更新下列几个CSR寄存器(具体情况可参考RISC-V架构介绍):
|
||
+ mcause(Machine Cause Register):机器模式异常原因寄存
|
||
+ mepc(Machine Exception Program Register):机器模式异常PC寄存器
|
||
+ mtval(Machine Trap Value Register):机器模式异常值寄存器
|
||
+ mstatus(Machine Status Register):机器模式状态寄存器
|
||
|
||
mcause寄存器的Exception Code域标识是何种异常或者何种中断。定义如下图表格所示:
|
||
|
||
| Interrupt/Exception<br/> mcause[XLEN-1] | Exception Code<br/> mcause[XLEN-2:0] | Description |
|
||
| :---: | :---: | --- |
|
||
| 1<br/>1<br/>1<br/>1<br/>1<br/>1 | 1<br/>3<br/>5<br/>7<br/>9<br/>11 | Supervisor software interrupt<br/>Machine software interrupt<br/>Supervisor timer interrupt<br/>Machine timer interrupt<br/>Supervisor external interrupt<br/>Machine external interrupt |
|
||
| 0<br/>0<br/>0<br/>0<br/>0<br/>0<br/>0<br/>0<br/>0<br/>0<br/>0<br/>0<br/>0<br/>0 | 0<br/>1<br/>2<br/>3<br/>4<br/>5<br/>6<br/>7<br/>8<br/>9<br/>11<br/>12<br/>13<br/>15 | Intruction address misaligned<br/>Instruction access fault<br/>Illegal instruction<br/>Breakpoint<br/>Load address misaligned<br/>Load access fault<br/>store address misaligned<br/>Store access fault<br/>Environment call from U-mode<br/>Environment call from S-mode<br/>Environment call from M-mode<br/>Instruction page fault<br/>Load page fault<br/>Store page fault |
|
||
|
||
|
||
+ 退出异常时,需要从异常服务程序中退出,并返回主程序。RISC-V架构定义了一组专门的退出异常指令:MRET、SRET、URET,分别对应机器模式、监督模式、用户模式的退出。
|
||
以MRET为例,当处理器执行MRET指令后,硬件行为如下:
|
||
1、当前程序执行流程停止执行,跳转到mepc的地址运行;
|
||
2、更新mstatus状态寄存器(具体情况可参考RISC-V架构介绍);
|
||
|
||
<span id="riscv_int_type"></span>
|
||
|
||
### 中断类型
|
||
RISC-V 架构定义的中断类型分为 4 种。
|
||
+ 外部中断(External Interrupt) :指来自处理器核外部的中断,例如GPIO、UART等产生的中断。
|
||
+ 计时器中断(Timer Interrupt) :计时器中断是指来自计时器的中断。
|
||
+ 软件中断(Software Interrupt) :软件中断是指来自软件自己触发的中断。
|
||
+ 调试中断(Debug Interrupt):专用于实现调试器(Debugger)。
|
||
|
||
<span id="riscv_int_controller"></span>
|
||
|
||
### 中断控制器
|
||
+ CLINT 模块生成计时器中断和软件中断
|
||
CLINT 的全称为处理器核局部中断控制器(Core Local Interrupts Controller),主要用于产生计时器中断(Timer Interrupt)和软件中断(Software Interrupt)。
|
||
+ PLIC 管理多个外部中断
|
||
PLIC 全称为平台级别中断控制器(Platform Level Interrupt Controller),它是 RISC-V架构标准定义的系统中断控制器,主要用于多个外部中断源的优先级仲裁。
|
||
RISC-V中断控制器如下图所示:
|
||
|
||

|
||
|
||
|
||
|
||
<span id="arm_interrupt"></span>
|
||
|
||
## ARM-cortex-M架构的中断和异常
|
||
|
||
<span id="arm_interrupt_intro"></span>
|
||
|
||
### 概述
|
||
cortex-M提供了一个异常响应系统,支持为数众多的系统异常和外部中断。其中编号0-15对应系统异常,大于等于16位外部中断。
|
||
|
||
<span id="arm_interrupt_process_mechnism"></span>
|
||
|
||
### 异常处理机制
|
||
cortex-M支持的异常如下表所示:
|
||
|
||

|
||
|
||
表格中的SVCall异常属于系统服务调用,用于产生系统函数的调用请求,该异常必须得到响应,例如,操作系统不让用户程序直接操作硬件,通过一些系统服务函数发出SVC请求,触发一个SVC异常,然后通过SVC异常服务程序执行;
|
||
PendSV异常属于可悬挂系统调用,它可以像普通中断一样被悬起,典型应用是提供线程切换服务。
|
||
|
||

|
||
|
||
1. 任务 A 呼叫 SVC 来请求任务切换(例如,等待某些工作完成)
|
||
2. OS 接收到请求,做好上下文切换的准备,并且 pend 一个 PendSV 异常。
|
||
3. 当 CPU 退出 SVC 后,它立即进入 PendSV,从而执行上下文切换。
|
||
4. 当 PendSV 执行完毕后,将返回到任务 B,同时进入线程模式。
|
||
5. 发生了一个中断,并且中断服务程序开始执行
|
||
6. 在 ISR 执行过程中,发生 SysTick 异常,并且抢占了该 ISR。
|
||
7. OS 执行必要的操作,然后 pend 起 PendSV 异常以作好上下文切换的准备。
|
||
8. 当 SysTick 退出后,回到先前被抢占的 ISR 中,ISR 继续执行
|
||
9. ISR 执行完毕并退出后,PendSV 服务例程开始执行,并且在里面执行上下文切换
|
||
10. 当 PendSV 执行完毕后,回到任务 A,同时系统再次进入线程模式。
|
||
|
||
<span id="arm_int_type"></span>
|
||
|
||
### 中断类型
|
||
|
||

|
||
|
||
NVIC共支持1到240个外部中断输入(IRQs)。另外 ,NVIC还支持一个不可屏蔽输入中断,除了包含控制寄存器和中断控制逻辑外,还包含了MPU的控制寄存器、systick定时器以及调试控制。
|
||
|
||
<span id="arm_int_controller"></span>
|
||
|
||
### 中断控制器
|
||
cortex-M系列包含一个NVIC(嵌套中断向量控制器)提供硬件嵌套中断服务。在中断发生时,NVIC自动取出对应的服务例程入口地址,并且直接调用,无需软件判定中断源。另外M系列包含一个基本的systick定时器,配合NVIC工作,用于系统计数。NVIC控制器如下图所示:
|
||

|
||
|
||
<span id="riscv_int_process"></span>
|
||
|
||
### 中断处理机制
|
||
|
||
<span id="riscv_int_service"></span>
|
||
|
||
#### 中断服务程序
|
||
每一个中断源对应一个中断号,每一个中断号又通过中断向量表和中断服务程序进行关联。当中断产生后,通过中断向量表跳转到中断服务程序的入口地址进行执行。如下图所示:
|
||
|
||
<center>
|
||
|
||

|
||
|
||
</center>
|
||
|
||
<span id="riscv_int_process2"></span>
|
||
|
||
#### 中断处理流程
|
||
CPU响应中断并进行处理,通常经历以下过程:保存当前线程的栈信息、跳转中断服务程序运行、恢复被打断的线程栈继续运行。
|
||
如下图所示:
|
||
|
||
<center>
|
||
|
||

|
||
|
||
</center>
|
||
|
||
<span id="riscv_int_api"></span>
|
||
|
||
## 中断函数接口
|
||
|
||
```c
|
||
typedef void *xs_handler_x(int irq_num, void *arg)
|
||
xs_int32 xs_RegisterHwIrq(xs_uint32 irq_num, xs_handler_x handler, void *arg, const char *name);
|
||
```
|
||
该函数用于注册一个中断,当产生中断时,将调用该硬件中断号相应的回调函数进行执行 。
|
||
| 参数 | 描述 |
|
||
| --- | --- |
|
||
| irq_num | 硬件中断号 |
|
||
| handler | 中断处理回调函数 |
|
||
| arg | 中断处理回调函数的参数 |
|
||
| name | 中断名称 |
|
||
```c
|
||
xs_int32 xs_FreeHwIrq(xs_uint32 irq_num);
|
||
```
|
||
该函数用于释放一个中断。
|
||
| 参数 | 描述 |
|
||
| --- | --- |
|
||
| irq_num | 硬件中断号 |
|
||
|
||
```c
|
||
xs_int32 xs_DisableHwIrq(xs_uint32 irq_num);
|
||
```
|
||
该函数用于屏蔽一个中断。
|
||
| 参数 | 描述 |
|
||
| --- | --- |
|
||
| irq_num | 硬件中断号 |
|
||
```c
|
||
xs_int32 xs_EnableHwIrq(xs_uint32 irq_num);
|
||
```
|
||
该函数用于注使能一个中断。
|
||
| 参数 | 描述 |
|
||
| --- | --- |
|
||
| irq_num | 硬件中断号 |
|
||
|
||
<span id="time_test"></span>
|
||
|
||
## 中断响应性能测试
|
||
|
||
<span id="time_test_intro"></span>
|
||
|
||
### 概述
|
||
|
||
下面分别测试XiUOS系统运行在基于ARM和RISC-V不同处理器的开发板时,中断响应时间。
|
||
|
||
|
||
<span id="time_test_arm"></span>
|
||
|
||
### 基于 ARM 处理器的中断响应性能测试
|
||
|
||
#### 测试方法
|
||
为了测试系统的中断响应时间,考虑使用GPIO管脚进行中断测试,利用GPIO中断服务函数当中管脚波形输出配合输入源波形进行分析。使用Tektronix TB1202B示波器的1KHz方波输出作为中断触发源。
|
||
* 配置GPIO C2为输入模式,配置上升沿触发中断
|
||
* 配置C13管脚为输出模式,接示波器通道1
|
||
* 示波器的1KHz信号输出分别接C2管脚和示波器通道2
|
||
* 示波器GND和开发板GND共地对接
|
||
|
||
示波器的1KHz方波输出将在1s钟内触发1000个中断。接线图如下图所示。
|
||
|
||
<center>
|
||
|
||

|
||
|
||
</center>
|
||
1KHz的方波信号输出到GPIO C2上,将触发上升沿中断,在GPIO中断处理函数当中,将GPIO C13拉高,再将其置为低电平。触发源1KHz方波周期为1ms,因此不会影响到中断的响应。根据CMOS电路的电平特性,当电压值达到0.7*Vcc时,识别为高电平。
|
||
从波形上来看,当输入源触发信号给到GPIO C2的电平值达到3.3v * 0.7 = 2.31v(0.7*Vcc)时将触发中断,进入中断处理。因此,通道1的电平值高于2.31v到GPIO C13变为高电平这段时间即为中断响应时间。
|
||
|
||
#### 编程代码清单
|
||
|
||
<center>
|
||
|
||

|
||
|
||
</center>
|
||
|
||
#### 示波器测试选项设置
|
||
* 通道设置
|
||
* 耦合:直流
|
||
* 带宽限制:关闭
|
||
* 伏/格:粗调
|
||
* 探头:10X 电压
|
||
* 反相:关闭
|
||
* 触发设置
|
||
* 类型:边沿
|
||
* 信源: CH1
|
||
* 斜率:上升
|
||
* 模式:自动
|
||
* 触发电压:2.28v (略低于 2.31v即可)
|
||
|
||
* 测量设置
|
||
* 测量选通:开启
|
||
* 类型:时间
|
||
* 信源:CH1
|
||
* CH1:周期、频率、上升时间
|
||
* CH2:周期、频率、上升时间
|
||
* Scale:2.5us
|
||
|
||
#### 测试结果
|
||
|
||
<center>
|
||
|
||

|
||
|
||
</center>
|
||
|
||
从示波器测试结果上来看,从触发源电平达2.28v到C13管脚拉高,响应时间为11.9us。
|
||
|
||
<span id="time_test_riscv"></span>
|
||
|
||
### 基于 RISC-V 处理器的中断响应性能测试
|
||
|
||
#### 测试方法
|
||
|
||
为了测试系统的中断响应时间,考虑使用GPIO管脚进行中断测试,利用GPIO中断服务函数当中管脚波形输出配合输入源波形进行分析。使用Tektronix TB1202B示波器的1KHz方波输出作为中断触发源。
|
||
* 配置GPIO19为输入模式,配置上升沿触发中断
|
||
* 配置GPIO18管脚为输出模式,接示波器通道1
|
||
* 示波器的1KHz信号输出分别接GPIO19管脚和示波器通道2
|
||
* 示波器GND和开发板GND共地对接
|
||
|
||
示波器的1KHz方波输出将在1s钟内触发1000个中断,接线图如下图所示。
|
||
|
||
<center>
|
||
|
||

|
||
|
||
</center>
|
||
|
||
1KHz的方波信号输出到GPIO19上,将触发上升沿中断,在GPIO中断处理函数当中,将GPIO18拉高,延时100us,再将其置为低电平。触发源1KHz方波周期为1ms,因此不会影响到中断的响应。根据CMOS电路的电平特性,当电压值达到0.7*Vcc时,识别为高电平。
|
||
|
||
从波形上来看,当输入源触发信号给到GPIO19的电平值达到3.3v * 0.7 = 2.31v(0.7*Vcc)时将触发中断,进入中断处理。因此,通道1的电平值高于2.31v到GPIO18变为高电平这段时间即为中断响应时间。
|
||
#### 编程代码清单
|
||
|
||
<center>
|
||
|
||

|
||
|
||
</center>
|
||
|
||
#### 示波器测试选项设置
|
||
* 通道设置
|
||
* 耦合:直流
|
||
* 带宽限制:关闭
|
||
* 伏/格:粗调
|
||
* 探头:10X 电压
|
||
* 反相:关闭
|
||
* 触发设置
|
||
* 类型:边沿
|
||
* 信源: CH1
|
||
* 斜率:上升
|
||
* 模式:自动
|
||
* 触发电压:2.28v (略低于 2.31v即可)
|
||
|
||
* 测量设置
|
||
* 测量选通:开启
|
||
* 类型:时间
|
||
* 信源:CH1
|
||
* CH1:周期、频率、上升时间
|
||
* CH2:周期、频率、上升时间
|
||
* Scale:250us
|
||
#### 测试结果
|
||
|
||
<center>
|
||
|
||

|
||
|
||
</center>
|
||
|
||
从示波器测试结果上来看,从触发源电平达2.28v到GPIO18管脚拉高,响应时间为2.6us。
|
||
|
||
<span id="comparison"></span>
|
||
|
||
### 中断响应性能测试对比
|
||
对sylixos的中断响应性能测试结果,如下:
|
||
|
||
| 操作系统 | 测试开发板 | CPU | 中断响应时间 |
|
||
| --- | --- | --- | --- |
|
||
| sylixos | mini210s开发板 | ARM Cortex-A8 主频 1GHz | 3.612 us |
|
||
| XiUOS | KD233开发板 | RISC-V K210 主频 400MHz | 2.6 us |
|
||
| XiUOS | STM32F407G-DISC1开发板 | STM32f407 主频 168MHz | 11.9 us|
|
||
|
||
结果分析:
|
||
* XiUOS在RISC-V K210 400MHz CPU主频上中断响应时间为 2.6 us低于sylixos的 3.612 us
|
||
* 若进行同等1GHz主频换算,K210上的中断响应时间应为 1.016 us,XiUOS中断响应的效率比sylixos提高 71.87%
|
||
* 在ARM stm32f407 168MHz CPU主频中断响应时间 11.9 us高于1GHz主频测试的sylixos
|
||
* 若进行同等1GHz主频换算,STM32F407上的中断响应时间应为 1.952 us,XiUOS的中断响应的效率比sylixos提高 45.95%
|
||
|
||
由于XiUOS优化了中断响应的流程,减少了执行指令数量,因此,同等主频条件下,中断响应时间更短。
|
||
|
||
<span id="situation"></span>
|
||
|
||
## 使用场景
|
||
|
||
|
||
|
||
|