OS_ERR_TASK_CREATE_ISR
试验原因
刚移植完STM32F103 + ucosii_v2.92.07 + lwip2.1.2
准备先起个ucos任务试试移植效果,看看能不能跑。
就随手写个空任务,居然在OSTaskCreate()后返回错误码 : OS_ERR_TASK_CREATE_ISR.
因为在固件库移植完后,做了测试, 固件库没问题。
移植ucosiiI_v2.92.07是从ucos官方工程中迁移过来的,刚移植完的时候,没写个简单任务测试一下. 官方的工程一定靠谱的。
现在移植完lwip后, 才测试。看到这个错误,有点后悔。应该在迁移完ucosii_v2.92.07后,就先测试一下,看看ucosii能不能正常跑起来。
现在要解决这个问题,有以下2个方法:
-
本工程开发过程都已经svn归档过,退到ucosii刚迁移完的版本,看看是否正常. 如果不正常,就地修正。如果正常,将svn时间线向当前时间推,推到错误点修正。这样简单,花的时间可能稍多些。
-
就在当前完全迁移完的版本上, 将这个bug五花大绑, 就地正法。根据错误码,顺藤摸瓜,找到bug原因。这样快,但是过程可能就需要绕些弯子。可能要调试几次。
试验
写测试任务时,特意的将错误码不正确的情况用ITM打印出来。
如果不打印出来,因为任务创建失败,进不去任务,任务中的测试代码执行不了(LED流水, ITM). 估计要楞30秒。所以,将可能的错误情况都返回,都指示出来,对开发过程是有帮助的,都是随手的事情。
测试ucosii的代码没几句,如下
int main(void)
{OS_CPU_SR cpu_sr = 0; // for OS_ENTER_CRITICAL()/OS_EXIT_CRITICAL()INT8U rc = 0;RCC_Configuration(); // 设置时钟频率和tick节拍printf(">> main\n");OSInit();OS_ENTER_CRITICAL(); // os_cpu.h// for OS_ERR_TASK_CREATE_ISRrc = OSTaskCreate(task1_proc, (void*)0, (OS_STK*)&TASK1_STK[TASK1_STK_SIZE-1], TASK1_TASK_PRIO);if (OS_ERR_NONE != rc) {printf("err : OSTaskCreate(task1_proc), rc = %d\n", rc);}OS_EXIT_CRITICAL();OSStart();return 0;
}
配置了系统时钟后,有了tick.
调用OSInit(), 进行ucosii的初始化。
然后就建立一个测试任务。
当发现OSTaskCreate()返回错误码 OS_ERR_TASK_CREATE_ISR 后,单步跟OSTaskCreate()
#if OS_TASK_CREATE_EN > 0u
INT8U OSTaskCreate (void (*task)(void *p_arg),void *p_arg,OS_STK *ptos,INT8U prio)
{OS_STK *psp;INT8U err;
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */OS_CPU_SR cpu_sr = 0u;
#endif#ifdef OS_SAFETY_CRITICAL_IEC61508if (OSSafetyCriticalStartFlag == OS_TRUE) {OS_SAFETY_CRITICAL_EXCEPTION();return (OS_ERR_ILLEGAL_CREATE_RUN_TIME);}
#endif#if OS_ARG_CHK_EN > 0uif (prio > OS_LOWEST_PRIO) { /* Make sure priority is within allowable range */return (OS_ERR_PRIO_INVALID);}
#endifOS_ENTER_CRITICAL();if (OSIntNesting > 0u) { /* Make sure we don't create the task from within an ISR */OS_EXIT_CRITICAL();return (OS_ERR_TASK_CREATE_ISR); // 在这错误返回了}
返回 OS_ERR_TASK_CREATE_ISR 的原因是 OSIntNesting > 0.
在工程中找 OSIntNesting, 看到这个变量是用来指示中断嵌套级别的。
OS_EXT INT8U OSIntNesting; /* Interrupt nesting level */
只要进了一个中断,就OSIntNesting++。
只要出了一个中断,就OSIntNesting–。
这样,只要不是在中断内 OSIntNesting 就必然为0.
那么OSIntNesting为0,就可以作为不在中断中的标志判断。
建立任务不能在中断中进行,是ucos的一个要求,必须满足。
通过单步,看OSIntNesting的值为6或0x3C。 中断嵌套层数这么多么?…
在工程中找OSIntNesting的变化点。
OSIntNesting初始化
static void OS_InitMisc (void)
{
#if OS_TIME_GET_SET_EN > 0uOSTime = 0uL; /* Clear the 32-bit system clock */
#endifOSIntNesting = 0u; /* Clear the interrupt nesting counter */
中断进入的函数 自增
void OSIntEnter (void)
{if (OSRunning == OS_TRUE) {if (OSIntNesting < 255u) {OSIntNesting++; /* Increment ISR nesting level */}}
}
离开中断的函数自减
void OSIntExit (void)
{
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */OS_CPU_SR cpu_sr = 0u;
#endifif (OSRunning == OS_TRUE) {OS_ENTER_CRITICAL();if (OSIntNesting > 0u) { /* Prevent OSIntNesting from wrapping */OSIntNesting--;}
ucos中的时钟tick重载函数中自增
void OS_CPU_SysTickHandler (void)
{OS_CPU_SR cpu_sr;OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR */OSIntNesting++;OS_EXIT_CRITICAL();OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */
}
这3处,我都是直接迁移过来的,官方代码,哪有不靠谱的。
但是确实只有这3处动了OSIntNesting.
仔细看3个函数。
OSIntEnter()和OSIntExit()没问题。这2个函数也是接口,要是这有问题了,ucosii根本拿不到证书。
OS_CPU_SysTickHandler()在迁移时,实际上是用户要实现的。不是ucos该提供的。
看着OS_CPU_SysTickHandler(),有点疑问。明明有进中断的函数,为啥自己写呢?
尝试将官方自己写的函数换成进中断的API, 如下, 好使了…
void OS_CPU_SysTickHandler (void)
{
// OS_CPU_SR cpu_sr;// OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR */
// OSIntNesting++;
// OS_EXIT_CRITICAL();OSIntEnter();OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */
}
再去看OSIntEnter()的实现
void OSIntEnter (void)
{if (OSRunning == OS_TRUE) {if (OSIntNesting < 255u) {OSIntNesting++; /* Increment ISR nesting level */}}
}
这里的OSIntNesting自增是由条件的(必须ucosii跑起来,才会自增中断嵌套级别), 而不是像官方demo那样,上来就强制自增。OSIntExit()的自减也是有条件的。所以导致,进了ucos tick中断,手写的强制自增,但是在OSIntExit()中不满足条件(此时还没运行 OSStart()呢, 所以中断级别不会自减,导致中断嵌套级别越来越大)
总结
-
代码有了进度,就抓紧测试一下,靠谱了,才往下走,这样保险些。要是真是代码堆多了,有了bug不好直接找出来,用svn回溯法,时间比直接找bug要多一些。
-
找到第三方的工程, 有条件的时候,先试试效果,先简单浏览分析一下自己关心的部分(e.g. 如何用好第三方的实现)。再作迁移。虽然会多用一些时间。
ucos官方的这个工程 Micrium_uC-Eval-STM32F107_uCOS-II_V2_92_07,我手头有对应的官方开发板,动手前,应该试一下的, 要有验证和怀疑的精神。这年头,值得信任的人不多.
当然了,如果时间紧,或没有条件验证第三方的工程,那只能直接上了。发现有坑时,再想办法解决。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
