diff --git a/docs/doc/kernel/imagesrc/arm_exception_table.png b/docs/doc/kernel/imagesrc/arm_exception_table.png deleted file mode 100644 index 7da1a82..0000000 Binary files a/docs/doc/kernel/imagesrc/arm_exception_table.png and /dev/null differ diff --git a/docs/doc/kernel/imagesrc/arm_int_type.png b/docs/doc/kernel/imagesrc/arm_int_type.png deleted file mode 100644 index d407dfe..0000000 Binary files a/docs/doc/kernel/imagesrc/arm_int_type.png and /dev/null differ diff --git a/docs/doc/kernel/imagesrc/int_arm_test_code.png b/docs/doc/kernel/imagesrc/int_arm_test_code.png deleted file mode 100644 index 8f85608..0000000 Binary files a/docs/doc/kernel/imagesrc/int_arm_test_code.png and /dev/null differ diff --git a/docs/doc/kernel/imagesrc/int_riscv_test_code.png b/docs/doc/kernel/imagesrc/int_riscv_test_code.png deleted file mode 100644 index 5cc908c..0000000 Binary files a/docs/doc/kernel/imagesrc/int_riscv_test_code.png and /dev/null differ diff --git a/docs/doc/kernel/int.md b/docs/doc/kernel/int.md index 8193531..d53306b 100644 --- a/docs/doc/kernel/int.md +++ b/docs/doc/kernel/int.md @@ -25,41 +25,40 @@ ## 简介 -中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。 -中断的触发一般是由外设或者CPU内部产生,由中断控制器进行处理再通知到CPU进行中断响应过程,其要点如下: - -+ 外设或者CPU内部产生的这个中断来源称为中断源; -+ CPU响应中断转入到的新的处理程序称为中断服务程序; -+ 中断处理完成后,处理器需要恢复之前的现场,简称“恢复现场”; -+ 当多个中断源请求中断的时候,需要通过优先级区分中断,便于CPU进行中断的处理; -+ 低优先级可以被高优先级打断,这个过程称之为中断嵌套; -+ 中断可以被屏蔽; -+ 所有的中断源都有一个编号,称为“中断号”; -+ 每一个中断号通过中断向量表与中断服务程序一一对应,中断向量表保存的是所有的中断服务程序的入口地址,该入口地址被称之为中断向量; +中断是指计算机运行过程中,出现某些意外情况需要主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。 +中断的触发一般是由外设或者 CPU 内部产生,由中断控制器进行处理再通知到 CPU 进行中断响应过程,其要点如下: ++ 外设或者 CPU 内部产生的这个中断来源称为中断源 ++ CPU 响应中断转入到的新的处理程序称为中断服务程序 ++ 中断处理完成后,处理器需要恢复之前的现场,简称“恢复现场” ++ 当多个中断源请求中断的时候,需要通过优先级区分中断,便于 CPU 进行中断的处理 ++ 低优先级可以被高优先级打断,这个过程称之为中断嵌套 ++ 中断可以被屏蔽 ++ 所有的中断源都有一个编号,称为“中断号” ++ 每一个中断号通过中断向量表与中断服务程序一一对应,中断向量表保存的是所有的中断服务程序的入口地址,该入口地址被称之为中断向量 -## RISC-V架构的中断和异常 +## RISC-V 架构的中断和异常 ### 概述 -从广义上来说,中断和异常属于一个概念;对于处理器而言,通常只区分为同步异常和异步异常。 -+ 同步异常:同步异常是指由于执行程序或者试图执行指令而产生的异常;例如,非法指令访问; -+ 异步异常:最常见的异步异常是外部中断,例如外设触发一个外部中断。 +从广义上来说,中断和异常属于一个概念。对于处理器而言,通常只区分为同步异常和异步异常。 ++ 同步异常,是指由于执行程序或者试图执行指令而产生的异常,例如,非法指令访问; ++ 异步异常,最常见的异步异常是外部中断,例如外设触发一个外部中断。 ### 异常处理机制 + 进入异常时,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):机器模式状态寄存器 + + 当前的程序执行流停止执行,直接跳转到 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域标识是何种异常或者何种中断。定义如下图表格所示: +mcause 寄存器的 Exception Code 域标识是何种异常或者何种中断。定义如下图表格所示: | Interrupt/Exception
mcause[XLEN-1] | Exception Code
mcause[XLEN-2:0] | Description | | :---: | :---: | --- | @@ -67,19 +66,18 @@ mcause寄存器的Exception Code域标识是何种异常或者何种中断。定 | 0
0
0
0
0
0
0
0
0
0
0
0
0
0 | 0
1
2
3
4
5
6
7
8
9
11
12
13
15 | Intruction address misaligned
Instruction access fault
Illegal instruction
Breakpoint
Load address misaligned
Load access fault
store address misaligned
Store access fault
Environment call from U-mode
Environment call from S-mode
Environment call from M-mode
Instruction page fault
Load page fault
Store page fault | -+ 退出异常时,需要从异常服务程序中退出,并返回主程序。RISC-V架构定义了一组专门的退出异常指令:MRET、SRET、URET,分别对应机器模式、监督模式、用户模式的退出。 -以MRET为例,当处理器执行MRET指令后,硬件行为如下: - 1、当前程序执行流程停止执行,跳转到mepc的地址运行; - 2、更新mstatus状态寄存器(具体情况可参考RISC-V架构介绍); - ++ 退出异常时,需要从异常服务程序中退出,并返回主程序。RISC-V 架构定义了一组专门的退出异常指令:MRET、SRET、URET,分别对应机器模式、监督模式、用户模式的退出。 +以 MRET 为例,当处理器执行 MRET 指令后,硬件行为如下: + 1. 当前程序执行流程停止执行,跳转到 mepc 的地址运行 + 2. 更新 mstatus 状态寄存器(具体情况可参考 RISC-V 架构介绍) ### 中断类型 RISC-V 架构定义的中断类型分为 4 种。 -+ 外部中断(External Interrupt) :指来自处理器核外部的中断,例如GPIO、UART等产生的中断。 -+ 计时器中断(Timer Interrupt) :计时器中断是指来自计时器的中断。 -+ 软件中断(Software Interrupt) :软件中断是指来自软件自己触发的中断。 -+ 调试中断(Debug Interrupt):专用于实现调试器(Debugger)。 ++ 外部中断(External Interrupt),指来自处理器核外部的中断,例如 GPIO、UART 等产生的中断 ++ 计时器中断(Timer Interrupt) ,指来自计时器的中断 ++ 软件中断(Software Interrupt) ,指来自软件自己触发的中断 ++ 调试中断(Debug Interrupt),专用于实现调试器(Debugger) @@ -87,12 +85,10 @@ RISC-V 架构定义的中断类型分为 4 种。 + CLINT 模块生成计时器中断和软件中断 CLINT 的全称为处理器核局部中断控制器(Core Local Interrupts Controller),主要用于产生计时器中断(Timer Interrupt)和软件中断(Software Interrupt)。 + PLIC 管理多个外部中断 -PLIC 全称为平台级别中断控制器(Platform Level Interrupt Controller),它是 RISC-V架构标准定义的系统中断控制器,主要用于多个外部中断源的优先级仲裁。 +PLIC 全称为平台级别中断控制器(Platform Level Interrupt Controller),它是 RISC-V 架构标准定义的系统中断控制器,主要用于多个外部中断源的优先级仲裁。 RISC-V中断控制器如下图所示: ![XiUOS RISC-V CONTROLLER](./imagesrc/int_riscv_controller.png) - - @@ -101,45 +97,68 @@ RISC-V中断控制器如下图所示: ### 概述 -cortex-M提供了一个异常响应系统,支持为数众多的系统异常和外部中断。其中编号0-15对应系统异常,大于等于16位外部中断。 +Cortex-M 提供了一个异常响应系统,支持为数众多的系统异常和外部中断。其中编号0-15对应系统异常,编号大于等于16的为外部中断。 ### 异常处理机制 -cortex-M支持的异常如下表所示: +Cortex-M支持的异常如下表所示: -![ARM CORTEX-M EXCEPTION](./imagesrc/arm_exception_table.png) +| 编号 | 类型 | 优先级 | 简介 | +| --- | --- | --- | --- | +| 0 | N/A | N/A | 没有异常在运行 | +| 1 | 复位 | -3(最高) | 复位 | +| 2 | NMI | -2 | 不可屏蔽中断(来自外部 NMI 输入脚) | +| 3 | 硬(hard)fault | -1 | 所有被除能的 fault,都将“上访”(escalation)成硬 fault。只要FAULTMASK没有置位,硬 fault 服务例程就被强制执行。Fault 被除能的原因包括被禁用,或者 FAULTMASK 被置位。 | +| 4 | MemManage fault | 可编程 | 存储器管理 fault,MPU 访问犯规以及访问非法位置均可引发。企图在“非执行区”取指也会引发此 fault。 | +| 5 | 总线 fault | 可编程 | 从总线系统收到了错误响应,原因可以是预取流产(Abort)或数据流产,或者企图访问协处理器 | +| 6 | 用法(usage)Fault | 可编程 | 由于程序错误导致的异常。通常是使用了一条无效指令,或者是非法的状态转换,例如尝试切换到ARM状态 | +| 7-10 | 保留 | N/A | N/A | +| 11 | SVCall | 可编程 | 执行系统服务调用指令(SVC)引发的异常 | +| 12 | 调试监视器 | 可编程 | 调试监视器(断点,数据 观察点,或者是外部调试请求) | +| 13 | 保留 | N/A | N/A | +| 14 | PendSV | 可编程 | 为系统设备而设的“可悬挂请求”(pendable request) | +| 15 | SysTick | 可编程 | 系统滴答定时器(也就是周期性溢出的时基定时器----译注) | -表格中的SVCall异常属于系统服务调用,用于产生系统函数的调用请求,该异常必须得到响应,例如,操作系统不让用户程序直接操作硬件,通过一些系统服务函数发出SVC请求,触发一个SVC异常,然后通过SVC异常服务程序执行; -PendSV异常属于可悬挂系统调用,它可以像普通中断一样被悬起,典型应用是提供线程切换服务。 +表格中的SVCall异常属于系统服务调用,用于产生系统函数的调用请求,该异常必须得到响应,例如,操作系统不让用户程序直接操作硬件,通过一些系统服务函数发出SVC请求,触发一个SVC异常,然后通过SVC异常服务程序执行。PendSV异常属于可悬挂系统调用,它可以像普通中断一样被悬起,典型应用是提供线程切换服务。 ![ARM PENSV EXAMPLE](./imagesrc/arm_pensv_example.png) 1. 任务 A 呼叫 SVC 来请求任务切换(例如,等待某些工作完成) -2. OS 接收到请求,做好上下文切换的准备,并且 pend 一个 PendSV 异常。 -3. 当 CPU 退出 SVC 后,它立即进入 PendSV,从而执行上下文切换。 -4. 当 PendSV 执行完毕后,将返回到任务 B,同时进入线程模式。 +2. OS 接收到请求,做好上下文切换的准备,并且 pend 一个 PendSV 异常 +3. 当 CPU 退出 SVC 后,它立即进入 PendSV,执行上下文切换 +4. 当 PendSV 执行完毕后,将返回到任务 B,同时进入线程模式 5. 发生了一个中断,并且中断服务程序开始执行 -6. 在 ISR 执行过程中,发生 SysTick 异常,并且抢占了该 ISR。 -7. OS 执行必要的操作,然后 pend 起 PendSV 异常以作好上下文切换的准备。 +6. 在 ISR 执行过程中,发生 SysTick 异常,并且抢占了该 ISR +7. OS 执行必要的操作,然后 pend 起 PendSV 异常以作好上下文切换的准备 8. 当 SysTick 退出后,回到先前被抢占的 ISR 中,ISR 继续执行 9. ISR 执行完毕并退出后,PendSV 服务例程开始执行,并且在里面执行上下文切换 -10. 当 PendSV 执行完毕后,回到任务 A,同时系统再次进入线程模式。 +10. 当 PendSV 执行完毕后,回到任务 A,同时系统再次进入线程模式 ### 中断类型 -![ARM INT TYPE](./imagesrc/arm_int_type.png) +| 编号 | 类型 | 优先级 | 简介 | +| --- | --- | --- | --- | +| 16 | IRQ #0 | 可编程 | 外中断 #0 | +| 17 | IRQ #1 | 可编程 | 外中断 #1 | +| ... | ... | ... | ... | +| 255 | IRQ #239 | 可编程 | 外中断 #239 | -NVIC共支持1到240个外部中断输入(IRQs)。另外 ,NVIC还支持一个不可屏蔽输入中断,除了包含控制寄存器和中断控制逻辑外,还包含了MPU的控制寄存器、systick定时器以及调试控制。 +NVIC共支持1到240个外部中断输入(IRQs)。另外,NVIC 还支持一个不可屏蔽输入中断,除了包含控制寄存器和中断控制逻辑外,还包含了 MPU 的控制寄存器、systick 定时器以及调试控制。 ### 中断控制器 -cortex-M系列包含一个NVIC(嵌套中断向量控制器)提供硬件嵌套中断服务。在中断发生时,NVIC自动取出对应的服务例程入口地址,并且直接调用,无需软件判定中断源。另外M系列包含一个基本的systick定时器,配合NVIC工作,用于系统计数。NVIC控制器如下图所示: +Cortex-M 系列包含一个 NVIC(嵌套中断向量控制器)提供硬件嵌套中断服务。在中断发生时,NVIC 自动取出对应的服务例程入口地址,并且直接调用,无需软件判定中断源。另外 M 系列包含一个基本的 systick 定时器,配合 NVIC 工作,用于系统计数。NVIC 控制器如下图所示: + +
+ ![NVIC CONTROLLER](./imagesrc/arm_nvic_controller.jpg) +
+ ### 中断处理机制 @@ -158,7 +177,7 @@ cortex-M系列包含一个NVIC(嵌套中断向量控制器)提供硬件嵌 #### 中断处理流程 -CPU响应中断并进行处理,通常经历以下过程:保存当前线程的栈信息、跳转中断服务程序运行、恢复被打断的线程栈继续运行。 +CPU 响应中断并进行处理,通常经历以下过程:保存当前线程的栈信息、跳转中断服务程序运行、恢复被打断的线程栈继续运行。 如下图所示:
@@ -172,7 +191,7 @@ CPU响应中断并进行处理,通常经历以下过程:保存当前线程 ## 中断函数接口 ```c -typedef void *xs_handler_x(int irq_num, void *arg) +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); ``` 该函数用于注册一个中断,当产生中断时,将调用该硬件中断号相应的回调函数进行执行 。 @@ -213,7 +232,7 @@ xs_int32 xs_EnableHwIrq(xs_uint32 irq_num); ### 概述 -下面分别测试XiUOS系统运行在基于ARM和RISC-V不同处理器的开发板时,中断响应时间。 +下面分别测试 XiUOS 系统运行在基于 ARM 和 RISC-V 不同处理器的开发板上时,中断响应时间。 @@ -221,29 +240,54 @@ xs_int32 xs_EnableHwIrq(xs_uint32 irq_num); ### 基于 ARM 处理器的中断响应性能测试 #### 测试方法 -为了测试系统的中断响应时间,考虑使用GPIO管脚进行中断测试,利用GPIO中断服务函数当中管脚波形输出配合输入源波形进行分析。使用Tektronix TB1202B示波器的1KHz方波输出作为中断触发源。 -* 配置GPIO C2为输入模式,配置上升沿触发中断 -* 配置C13管脚为输出模式,接示波器通道1 -* 示波器的1KHz信号输出分别接C2管脚和示波器通道2 -* 示波器GND和开发板GND共地对接 +为了测试系统的中断响应时间,考虑使用 GPIO 管脚进行中断测试,利用 GPIO 中断服务函数当中管脚波形输出配合输入源波形进行分析。使用 Tektronix TB1202B 示波器的 1KHz 方波输出作为中断触发源。 +* 配置 GPIO C2 为输入模式,配置上升沿触发中断 +* 配置 C13 管脚为输出模式,接示波器通道1 +* 示波器的 1KHz 信号输出分别接 C2 管脚和示波器通道2 +* 示波器 GND 和开发板 GND 共地对接 -示波器的1KHz方波输出将在1s钟内触发1000个中断。接线图如下图所示。 +示波器的 1KHz 方波输出将在1s钟内触发1000个中断,接线图如下图所示。
![XiUOS PROCESS](./imagesrc/int_arm_test_connect.png)
-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变为高电平这段时间即为中断响应时间。 +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 变为高电平这段时间即为中断响应时间。 #### 编程代码清单 -
+```c +#include +#include +#include +#include +#include -![XiUOS PROCESS](./imagesrc/int_arm_test_code.png) +#define GPIO_C2 17 +#define GPIO_C13 7 -
+void pin_irqisr(void *args){ + *(volatile *)0x40020818 = 0x2000; /////< GPIO_C13 set high + + *(volatile *)0x4002081a = 0x2000; /////< GPIO_C13 set low +} +int realtime_irq_test() +{ + int val = 0; + + xs_PinMode(GPIO_C13, PIN_MODE_OUTPUT); + xs_PinMode(GPIO_C2, PIN_MODE_INPUT); + + xs_PinWrite(GPIO_C13, PIN_LOW); + + xs_PinAttachIrq(GPIO_C2, PIN_IRQ_MODE_RISING, pin_irqisr, XS_NULL); + xs_PinIrqEnable(GPIO_C2, PIN_IRQ_ENABLE); + + return 0; +} +``` #### 示波器测试选项设置 * 通道设置 @@ -254,7 +298,7 @@ xs_int32 xs_EnableHwIrq(xs_uint32 irq_num); * 反相:关闭 * 触发设置 * 类型:边沿 - * 信源: CH1 + * 信源: CH1 * 斜率:上升 * 模式:自动 * 触发电压:2.28v (略低于 2.31v即可) @@ -275,7 +319,7 @@ xs_int32 xs_EnableHwIrq(xs_uint32 irq_num);
-从示波器测试结果上来看,从触发源电平达2.28v到C13管脚拉高,响应时间为11.9us。 +从示波器测试结果上来看,从触发源电平达2.28v到C13管脚拉高,响应时间为 11.9us。 @@ -284,12 +328,12 @@ xs_int32 xs_EnableHwIrq(xs_uint32 irq_num); #### 测试方法 为了测试系统的中断响应时间,考虑使用GPIO管脚进行中断测试,利用GPIO中断服务函数当中管脚波形输出配合输入源波形进行分析。使用Tektronix TB1202B示波器的1KHz方波输出作为中断触发源。 -* 配置GPIO19为输入模式,配置上升沿触发中断 -* 配置GPIO18管脚为输出模式,接示波器通道1 -* 示波器的1KHz信号输出分别接GPIO19管脚和示波器通道2 -* 示波器GND和开发板GND共地对接 +* 配置 GPIO19 为输入模式,配置上升沿触发中断 +* 配置 GPIO18 管脚为输出模式,接示波器通道1 +* 示波器的1KHz信号输出分别接 GPIO19 管脚和示波器通道2 +* 示波器 GND 和开发板 GND 共地对接 -示波器的1KHz方波输出将在1s钟内触发1000个中断,接线图如下图所示。 +示波器的 1KHz 方波输出将在1s钟内触发1000个中断,接线图如下图所示。
@@ -297,16 +341,39 @@ xs_int32 xs_EnableHwIrq(xs_uint32 irq_num);
-1KHz的方波信号输出到GPIO19上,将触发上升沿中断,在GPIO中断处理函数当中,将GPIO18拉高,延时100us,再将其置为低电平。触发源1KHz方波周期为1ms,因此不会影响到中断的响应。根据CMOS电路的电平特性,当电压值达到0.7*Vcc时,识别为高电平。 +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变为高电平这段时间即为中断响应时间。 +从波形上来看,当输入源触发信号给到 GPIO19 的电平值达到 3.3v * 0.7 = 2.31v(0.7 * Vcc)时将触发中断,进入中断处理。因此,通道1的电平值高于 2.31v 到 GPIO18 变为高电平这段时间即为中断响应时间。 #### 编程代码清单 -
+```c +#define GPIO_18 18 +#define GPIO_19 19 -![RISC-V INT TIME TEST](./imagesrc/int_riscv_test_code.png) +void pin_irqisr(void *args){ + *(volatile *)0x3800100c |= 0x5; + usleep(100); + *(volatile *)0x3800100c &= ~0x5; +} +int realtime_irq_test() +{ + xs_PinMode(GPIO_18, PIN_MODE_OUTPUT); + xs_PinMode(GPIO_19, PIN_MODE_INPUT); + xs_PinWrite(GPIO_18, PIN_LOW); + xs_PinAttachIrq(GPIO_19, PIN_MODE_RISING, pin_irqisr, XS_NULL); + xs_PinIrqEnable(GPIO_19, PIN_IRQ_ENABLE); + return 0; +} -
+void realtime_taskswitch_test() +{ + xs_PinMode(GPIO_18, PIN_MODE_OUTPUT); + xs_PinWrite(GPIO_18, PIN_LOW); + while(1){ + xs_DelayKThread(1); + } +} +``` #### 示波器测试选项设置 * 通道设置 @@ -317,7 +384,7 @@ xs_int32 xs_EnableHwIrq(xs_uint32 irq_num); * 反相:关闭 * 触发设置 * 类型:边沿 - * 信源: CH1 + * 信源: CH1 * 斜率:上升 * 模式:自动 * 触发电压:2.28v (略低于 2.31v即可) @@ -337,7 +404,7 @@ xs_int32 xs_EnableHwIrq(xs_uint32 irq_num); -从示波器测试结果上来看,从触发源电平达2.28v到GPIO18管脚拉高,响应时间为2.6us。 +从示波器测试结果上来看,从触发源电平达 2.28v 到 GPIO18 管脚拉高,响应时间为2.6us。