硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3328|回复: 6
收起左侧

总结一下关于FreeRTOS中开关中断的注意事项

[复制链接]

36

主题

1445

回帖

1553

积分

至尊会员

积分
1553
发表于 2018-6-8 15:18:42 | 显示全部楼层 |阅读模式
1.首先说明:本工程是使用FreeRTOS V8.2.3。

2.问题起源:在bsp_Init();硬件初始化里面初始化外设,并且使用printf函数打印,导致死机。

3.问题描述:
在启动任务之前,我工程使用printf函数(串口FIFO使用串口发送中断了)
测试发现在操作系统启动之前,如果调用开关中断,会导致中断关闭,之后无法打开。无法进入串口发送中断;


4.因为本工程是使用FreeRTOS操作系统,使用
#define DISABLE_INT()    taskENTER_CRITICAL()
#define ENABLE_INT()     taskEXIT_CRITICAL()
完成开关中断操作的。这一点要跟裸机下使用  __set_PRIMASK(0) __set_PRIMASK(1)是不一样的;


5.对于上述问题归根到底是因为:
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;【port.c 157行】
中断嵌套默认是0xaaaaaaaa,而开中断函数:
void vPortExitCritical( void )
{
        configASSERT( uxCriticalNesting );
        uxCriticalNesting--;
        if( uxCriticalNesting == 0 )
        {
                portENABLE_INTERRUPTS();
        }
}

这里判断 uxCriticalNesting 等于0 的时候 才会执行portENABLE_INTERRUPTS();进行开中断。
所以简而言之就是系统启动之前,只能关闭中断,而无法打开中断;
我尝试把static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;更改为
static UBaseType_t uxCriticalNesting = 0x00000000;,这样哪怕在操作系统启动之前,开关中断都没有什么问题;


6.为什么说操作系统启动之后,开关中断就没问题了呢,需要进一步看:
void vTaskStartScheduler( void )【task.c  1543行】是启动操作系统的,这里面调用
BaseType_t xPortStartScheduler( void )【port.c 332行】,这个函数有初始化uxCriticalNesting = 0;
所以说,必须启动操作系统,操作开关中断才会都有效,否则只能关闭中断,无法打开中断。

/***********************************************************/
我还遇见另外一个问题,一起记录下:
还有一个问题:测试发现在操作系统启动之前,如果前面有大量printf打印函数,会死机,比如:
for(u8 i = 0;i<100;i++)         循环100次
        printf("11112554645235695659+\r\n");
一点打印函数就不会死机;比如:
for(u8 i = 0;i<10;i++)          循环10次
        printf("11112554645235695659+\r\n");

分析:
1.经过仿真发现是大量打印函数会导致串口FIFO缓冲区满,而串口里面有检测:如果缓冲区满,会等待缓冲区不满;而中断由被屏蔽了,导致死等,那么就死机;
仔细想一下,串口FIFO不是边填充,边串口发送中断里面发送吗?归根到底还是串口中断被屏蔽了导致的。
2.那么小量打印,缓冲区不会满,但是串口在操作系统启动之前不会打印东西的,也是因为串口中断被屏蔽了。这种情况下,当系统启动之后,会立即进行发送。因为启动操作系统后,在函数prvStartFirstTask();【port.c  410行】里面会打开所有中断。



/***********************************************************/
注意:
FreeRTOS操作系统使用 basepri 进行开关中断,而一般裸机使用 primask 开关中断。区别如下:
名字                                                         功能描述
primask         这是个只有 1 个 bit 的寄存器。 在它被置 1 后,就关掉所有可屏蔽的异常,只剩下
                    NMI 和硬 fault 可以响应。它的缺省值是 0,表示没有关中断。
faultmask     这是个只有 1 个 bit 的寄存器。当它置 1 时,只有 NMI 才能响应,所有其它的异
                    常,甚至是硬 fault,也通通闭嘴。它的缺省值也是 0,表示没有关异常。
basepri        这个寄存器最多有 9 位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。
                   当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优
                   先级越低)。但若被设成 0,则不关闭任何中断, 0 也是缺省值。
                                                               
使用basepri屏蔽中断之后,就算使用primask开启所有中断,也是无效的。


可以这样理解 primask 和 basepri的关系:学过51的人都知道,51有个总中断开关EA,这个EA就相当于primask,是总开关;
而 basepri 可以理解为是串口,定时器1中断开关;如ES、ET1这些分开关。
所以:
就算总开关开了,  但是外设中断被屏蔽了,还是进不去中断;
就算外设开关开了,但是总中断关了,      还是进不去中断;


/***********************************************************/
进一步深入:
prvStartFirstTask();【port.c  410行】中打开了总开关primask,并且开异常faultmask。没有发现操作basepri的。
进一步看里面有一句:svc 0 这会导致进入SVC中断,
__asm void vPortSVCHandler( void )函数是SVC中断函数,这里面有:
        mov r0, #0
        msr        basepri, r0
所以总得来说,函数prvStartFirstTask();里面对中断而言,对primask faultmask basepri都有操作,操作结果是:
primask   为 0,开中断;
faultmask 为 0,开异常;
basepri   为 0,不关闭任何中断;

/**************************************************************/       
附录:
在汇编代码中,CPSID   CPSIE  用于快速的开关中断。
CPSID   I; PRIMASK=1,  ;关中断
CPSIE   I; PRIMASK=0,  ;开中断
CPSID   F; FAULTMASK=1,;关异常
CPSIE   F; FAULTMASK=0,;开异常


好了,大概就这么多,不进去不知道,一进去就出不来了。
分享一下,防止大家遇到跟我一样的问题。




评分

参与人数 1金币 +100 收起 理由
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106918
QQ
发表于 2018-6-8 15:24:12 | 显示全部楼层
非常感谢楼主分享。
ps:另外补充下FreeRTOS教程里面的中断章节,比重要,第12章
http://www.armbbs.cn/forum.ph ... 7658&extra=page%3D1


QQ截图20180608152405.png
回复

使用道具 举报

18

主题

285

回帖

339

积分

高级会员

积分
339
发表于 2018-6-10 11:25:24 | 显示全部楼层
分析的很透彻,谢谢分享
回复

使用道具 举报

6

主题

17

回帖

35

积分

新手上路

积分
35
发表于 2018-7-2 14:02:51 | 显示全部楼层
嗯,谢谢楼主分享,虽然只明白了大概的意思,随后文档里会系统了解
回复

使用道具 举报

0

主题

6

回帖

6

积分

新手上路

积分
6
发表于 2018-7-14 21:40:05 | 显示全部楼层
谢谢 分享,很受启发
回复

使用道具 举报

36

主题

1445

回帖

1553

积分

至尊会员

积分
1553
 楼主| 发表于 2018-7-14 21:52:32 | 显示全部楼层
loodao 发表于 2018-7-14 21:40
谢谢 分享,很受启发

再看一下老大的教程就基本明白了
回复

使用道具 举报

36

主题

1445

回帖

1553

积分

至尊会员

积分
1553
 楼主| 发表于 2018-7-14 21:52:54 | 显示全部楼层
木兰花 发表于 2018-6-10 11:25
分析的很透彻,谢谢分享

共同学习
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-10 08:46 , Processed in 0.303335 second(s), 32 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表