1 rtthread开关中断函数(cortex-m)
/*
* rt_base_t rt_hw_interrupt_disable();
*/
.global rt_hw_interrupt_disable
.type rt_hw_interrupt_disable, %function
rt_hw_interrupt_disable:
MRS r0, PRIMASK
CPSID I
BX LR
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
.global rt_hw_interrupt_enable
.type rt_hw_interrupt_enable, %function
rt_hw_interrupt_enable:
MSR PRIMASK, r0
BX LR
2 中断嵌套
我能看到rtthread中很多地方都会使用,开关中断。但是开关中断是否支持嵌套呢?
int global1;
int global2;
void foo(void)
{
rt_base_t level = rt_hw_interrupt_disable();
global1++;
rt_hw_interrupt_enable(level); //在这个地方开中断,调用后中断一定打开吗?
}
void bar(void)
{
rt_base_t level = rt_hw_interrupt_disable();
foo(); //执行后中断会被打开吗?
global2++; //这段代码安全吗?
rt_hw_interrupt_enable(level);
}
2.1 rt_hw_interrupt_disable
rt_hw_interrupt_disable:
MRS r0, PRIMASK ;保存PRIMASK到r0中
CPSID I ;关闭中断
BX LR ;返回调用
rt_hw_interrupt_disable() 是通过汇编语言实现的。首先将PRIMASK值保存到r0中,然后是关闭中断。最后执行调用返回。根据ARM的调用规范,函数返回后,返回值保存在r0寄存器中。所以rt_hw_interrupt_disable()的返回值就是当前函数调用前的PRIMASK值。那么PRIMASK值跟什么有关系呢?下面是Arm?v7-M Architecture Reference Manual 的描述: 也就是说PRIMASK代表着可屏蔽中断的状态。如果是1代表当前中断禁止,如果是0代表当前中断使能。由此可以看出,rt_hw_interrupt_disable() 的返回值代表当前的函数调用前的中断状态 。之后调用CPSID I 来关闭中断,所以rt_hw_interrupt_disable() 调用后当前中断一定是关闭的,同时PRIMASK的值也一定是1。接下来继续分析rt_hw_interrupt_enable() 函数。
2.2 rt_hw_interrupt_enable
//void rt_hw_interrupt_enable(rt_base_t level);
rt_hw_interrupt_enable:
MSR PRIMASK, r0 ;将level的值保存到PRIMASK寄存器
BX LR ;调用返回
根据ARM调用规范, 函数的第一个参数由r0寄存器传递,所以r0中保存的是level的值,rt_hw_interrupt_enable() 的功能就是将level 值写入到PRIMASK 寄存器中。所以rt_hw_interrupt_enable() 执行后,开不开中断取决于level 的值,开关中断是成对使用的,因为level 是rt_hw_interrupt_disable() 的返回值。所以这样就实现了中断的嵌套。继续阅读下面示例,来理解嵌套。
3 示例
3.1 test()调用前中断状态是使能的情况
int global_level1;
int global_level2;
int global_level3;
void test(void)
{
rt_base_t level1 = rt_hw_interrupt_disable(); //此函数执行前中断为使能,所以level1 = 0
rt_base_t level2 = rt_hw_interrupt_disable(); //此函数执行前中断已经被关闭了,所以level2 = 1
rt_base_t level3 = rt_hw_interrupt_disable(); //此函数执行前中断已经被关闭了,所以level3 = 1
global_level3++;
rt_hw_interrupt_enable(level3);//把level3赋值给PRIMASK后,PRIMASK=1,中断仍然关闭
global_level2++;
rt_hw_interrupt_enable(level2);//把level2赋值给PRIMASK后,PRIMASK=1,中断仍然关闭
global_level1++;
rt_hw_interrupt_enable(level1);//把level1赋值给PRIMASK后,PRIMASK=0,中断打开
}
3.2 test()调用前中断状态是关闭的情况
int global_level1;
int global_level2;
int global_level3;
void test(void)
{
rt_base_t level1 = rt_hw_interrupt_disable(); //此函数执行前中断已经被关闭了,所以level1 = 1
rt_base_t level2 = rt_hw_interrupt_disable(); //此函数执行前中断已经被关闭了,所以level2 = 1
rt_base_t level3 = rt_hw_interrupt_disable(); //此函数执行前中断已经被关闭了,所以level3 = 1
global_level3++;
rt_hw_interrupt_enable(level3);//把level3赋值给PRIMASK后,PRIMASK=1,中断仍然关闭
global_level2++;
rt_hw_interrupt_enable(level2);//把level2赋值给PRIMASK后,PRIMASK=1,中断仍然关闭
global_level1++;
rt_hw_interrupt_enable(level1);//把level1赋值给PRIMASK后,PRIMASK=1,中断仍然关闭
}
以上就把rtthread中断嵌套分析清楚了。
|