本帖最后由 jf_1137202360 于 2022-5-13 11:14 编辑
前言
作为单片机,很多时候需要应用在实时性要求很高的场景,中断响应时间也是单片机的一项重要性能参数。 很多时候也是选型决定性关键参数,所以本文就实际测一测GD32VF103单片机的中断响应时间到底能到多少。
测试方案
使用PA0作为外部中断输入,上升沿触发中断。对应的是EXti线0。
PA1作为输出,默认输出低,进入中断回调函数时拉高。测量PA0的上升沿和PA1上升沿就可以间接测得中断的响应时间。由于拉高PA1的代码本来需要时间,所以还需要想办法测试拉高PA1代码的执行时间并减去。
为了尽可能精确,所有代码都使用汇编代码编写,主频配置为108MHz。
如下图:
T3示波器可以直接测出,
T2也可以重复执行PA1拉高代码(重复拉高拉低)来模拟测量。
则T1=T3-T2
file:///C:UsersqinyuAppDataLocalTempksohtml15540wps4.png
中断初始化
所有的端口都有外部中断能力,为了使用外部中断线,端口必须配置为输入模式
放在init.c中
- void _init()
- {
- SystemInit();
- //ECLIC init
- eclic_init(ECLIC_NUM_INTERRUPTS);
- eclic_mode_enable();
- //printf("After ECLIC mode enabled, the mtvec value is %x
- ", read_csr(mtvec));
- // // It must be NOTED:
- // // * In the RISC-V arch, if user mode and PMP supported, then by default if PMP is not configured
- // // with valid entries, then user mode cannot access any memory, and cannot execute any instructions.
- // // * So if switch to user-mode and still want to continue, then you must configure PMP first
- //pmp_open_all_space();
- //switch_m2u_mode();
-
- /* Before enter into main, add the cycle/instret disable by default to save power,
- only use them when needed to measure the cycle/instret */
- disable_mcycle_minstret();
- /* enable the clock */
- rcu_periph_clock_enable(RCU_GPIOA);
- /* PA0下降沿输入中断 */
- gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_0);
- GPIO_BC(GPIOA) = GPIO_PIN_1;
- /* PA1推挽高速输出 */
- gpio_init(GPIOA,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_1);
- /* enable the global interrupt */
- eclic_global_interrupt_enable();
- eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL3_PRIO1);
- /* enable and set key EXTI interrupt to the lowest priority */
- eclic_irq_enable(EXTI0_IRQn, 1, 1);
- /* connect key EXTI line to key GPIO pin */
- gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOA, GPIO_PIN_SOURCE_0);
- /* configure key EXTI line */
- exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_RISING);
- exti_interrupt_flag_clear(EXTI_0);
- }
T3:中断延迟时间+PA1拉高代码执行时间测量
中断回调函数编写如下,放在start.s中
- EXTI0_IRQHandler:
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,0(a3) # 0x40010810 - 0
- sw a5,-2028(a4)# 0x40010814 = 0x40011000 -2028
- lui a4,0x40010 # C
- li a5,1
- sw a5,1044(a4)# 0x40010414 = 0x40010000 +0x414
- ret
按键PA0产生上升沿,进入中断服务函数拉高PA1,测量PA0和PA1两个上升沿之间的时间为T3.
实际测得为406nS。
T2:PA1拉高代码执行时间测量
放在start.s中
- call _init
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,0(a3) # 0x40010810 - 0
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,-2028(a4)# 0x40010814 = 0x40011000 -2028
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,0(a3) # 0x40010810 - 0
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,-2028(a4)# 0x40010814 = 0x40011000 -2028
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,0(a3) # 0x40010810 - 0
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,-2028(a4)# 0x40010814 = 0x40011000 -2028
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,0(a3) # 0x40010810 - 0
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,-2028(a4)# 0x40010814 = 0x40011000 -2028
- /* argc = argv = 0 */
- li a0, 0
- li a1, 0
- call main
- tail exit
由于中断回调函数中拉高PA1的代码如下
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,0(a3) # 0x40010810 - 0
执行也需要时间所以需要测量这部分代码的执行时间。
重复执行以下拉高拉低代码使用示波器测量即可得到执行时间。
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,0(a3) # 0x40010810 - 0
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,-2028(a4)# 0x40010814 = 0x40011000 -2028
时间测得时间为T2=74/2=37nS。
T1:中断响应时间计算T1=T3-T1=406-37=369nS
直接使用指令最快IO翻转速率测量
放在start.s中
- call _init
- lui a4,0x40011 # C
- addi a3,a4,-2032 # 0x40010810 = 0x40011000-2032
- li a5,2
- sw a5,0(a3) # 0x40010810 - 0
- sw a5,-2028(a4)# 0x40010814 = 0x40010810 -2028
- sw a5,0(a3) # 0x40010810 - 0
- sw a5,-2028(a4)# 0x40010814 = 0x40010810 -2028
- sw a5,0(a3) # 0x40010810 - 0
- sw a5,-2028(a4)# 0x40010814 = 0x40010810 -2028
- sw a5,0(a3) # 0x40010810 - 0
- sw a5,-2028(a4)# 0x40010814 = 0x40010810 -2028
- sw a5,0(a3) # 0x40010810 - 0
- sw a5,-2028(a4)# 0x40010814 = 0x40010810 -2028
- sw a5,0(a3) # 0x40010810 - 0
- sw a5,-2028(a4)# 0x40010814 = 0x40010810 -2028
- /* argc = argv = 0 */
- li a0, 0
- li a1, 0
- call main
- tail exit
直接使用指令最快IO翻转速率是26.74MHZ
总结
中断延迟在369nS左右,属于nS级别,108MHz,1个CLK也就是9ns左右,大概40个CLK。
响应时间还是比较短的,在大部分实时性要求情况下应该都是满足需求的。