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,我手头有对应的官方开发板,动手前,应该试一下的, 要有验证和怀疑的精神。这年头,值得信任的人不多.

当然了,如果时间紧,或没有条件验证第三方的工程,那只能直接上了。发现有坑时,再想办法解决。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部