TinyThread源码分析之中断
转载请注明来源:cuixiaolei的技术博客
https://github.com/xhawk18/TinyThread
TinyThread 是基于Cortex-M0的小型的OS.
知识储备:
IPSR(中断程序状态寄存器),IPSR包含了当前正在执行的中断服务程序编号,用于识别当前中断。
Cortex-M0处理器内置中断控制器,并且支持最多32个中断请求(IRQ)和一个不可屏蔽中断(NMI).
PRIMASK置位(写1),开启屏蔽,屏蔽除了NMI和硬件错误(hardfault)外的所有中断。清除此位,关闭屏蔽。
TinyThread中断控制涉及到的文件主要有:tt_sys.h、tt_sys.c
TinyThread中断控制函数API主要有以下两个,它们分别是打开IPSR和关闭IPSR寄存器(中断屏蔽特殊寄存器).
- void tt_enable_irq (void) // 打开中断,PRIMASK清零
- void tt_disable_irq (void) // 关闭中断,PRIMASK置位
tt_sys.c
1 #include "../Inc/tt_thread.h" 2 3 volatile int g_iIRQ_disable_count = 0; 4 volatile bool g_bIRQ_real_disable = 0;
tt_sys.h
#ifndef INC_TT_SYS_H__ #define INC_TT_SYS_H__ #ifdef __cplusplus extern "C" { #endif extern volatile int g_iIRQ_disable_count; extern volatile bool g_bIRQ_real_disable; //#define TT_SYS_NO_PRINTF /* Implement in tt_syscall.s */ #if defined __CC_ARM # if __CM0_CMSIS_VERSION < 0x00020000 TT_INLINE bool tt_is_in_irq (void) //__get_IPSR()得到当前 中断程序状态寄存器 的值,此函数用来判断当前是否处在中断状态。 { register uint32_t __regIPSR __asm("ipsr"); return(__regIPSR); } # else TT_INLINE bool tt_is_in_irq (void) { return __get_IPSR (); } #endif #elif defined __GNUC__ __attribute__((always_inline )) TT_INLINE bool tt_is_in_irq (void) { uint32_t result; __asm__ volatile ("MRS %0, ipsr" : "=r" (result) ); return(result); } #elif defined __ICCARM__ # pragma diag_suppress=Pe940 TT_INLINE bool tt_is_in_irq (void) { __asm(" MRS R0, IPSR "); } #endif TT_INLINE bool tt_is_irq_disabled (void) //查看 中断屏蔽特殊寄存器的值 中断被屏蔽返回true,中断可用返回false { int primask = __get_PRIMASK (); if ((primask & 1) == 0) //中断程序状态寄存器第0位置1,表示中断被屏蔽 return false; else return true; } TT_INLINE void tt_enable_irq (void) { if (!tt_is_irq_disabled ()) //如果中断可以使用 { __set_PRIMASK(1); //PRIMASK写1,屏蔽中断 #if !defined TT_SYS_NO_PRINTF printf ("Not call tt_disable_irq before tt_enable_irq\n"); #endif while (1); //错误处理,用死循环提示,我个人认为作者这么处理的原因是程序死掉,开发人员会追到这里,就知道原因了(没有先执行tt_disable_irq函数). } g_iIRQ_disable_count--; if (g_iIRQ_disable_count == 0) { if (g_bIRQ_real_disable) { __set_PRIMASK(0); } } } TT_INLINE void tt_disable_irq (void) { if (tt_is_irq_disabled ()) //已经disbale过了 { if (g_iIRQ_disable_count == 0) g_bIRQ_real_disable = false; } else { __set_PRIMASK(1); if (g_iIRQ_disable_count == 0) g_bIRQ_real_disable = true; } g_iIRQ_disable_count++; }
在 void tt_enable_irq (void) 函数中,我们可以知道,在没有先disable irq的情况下,不允许执行此函数. 如果连续执行此函数,报错。
在 void tt_disable_irq (void) 函数中,我们可以知道,虽然可以连续执行tt_disable_irq函数,但是当连续执行此函数后, g_bIRQ_real_disable 的值为 false, 那么当enable irq时是没有其作用的。
所以使用这对函数,一定要成对出现,而且要先disable,然后enable.