UC/OS III semaphore inside ISR sometimes does not work

1k Views Asked by At

I have a problem with a semaphore, it seems that sometime the SemPost called inside the ISR is not effective.

My application is base on Micrimum UCOS III and the target platform is based on Microsemi Smartfusion2 SoC (Cortex-M3). My application consists of two tasks (A and B) but only one is active when the problem occurs (the other one is stuck on a semaphore).

The problem occurs when the active task (let's call it Task A) does the following actions:

  1. write in some register to start an operation after wich an interrupt will be triggered
  2. awaits for operation completion making an OSSemPend on a semafore (let's call it Sem A), setting a timemout of 100msec.
  3. checks if the OSSemPend call ended normally or if i timeout occurred

When the interrupt is triggered, the related ISR makes a SemPost on Sem A in order to unlock the semaphore before the timeout.

When the problem occurs the OSSemPend returns OS_ERR_TIMEOUT. I can see this problem very very very rarely.

I'm sure that:

  • the start operation (see point one) is given and the operation starts.
  • the interrupt is triggered and the OSSemPost on Sem A is carried out.
  • the interrupt is triggered after less then 500 usec (i.e. < 1msec) from the start

Is the code properly written? Is there any restriction in the use of semaphores inside the ISR? Can someone help me? Thank you

I enclose a simplified version of the code

/*
 * the interrupt handler, triggered at the end of the operation
 */
void FabricIrq2_IRQHandler(void)
{
    OS_ERR os_err;
    CPU_SR_ALLOC();
    CPU_CRITICAL_ENTER();
    /*
     * write in a register of the ip core generating the interrupt in order 
     * to reset the interrupt
     */
    OSSemPost(&Sem_A, OS_OPT_POST_ALL, &os_err); 
    OSSemSet(&Sem_Tx, 0, &os_err); /* not relevant for this problem */
    CPU_CRITICAL_EXIT();
}

void startOp()
{
    CPU_SR_ALLOC();
    CPU_CRITICAL_ENTER();
    /*
     * write in an ip core register in order to start operation
     */
    CPU_CRITICAL_EXIT();
}


/*
 * task a **partial**
 */
uint8_t task_a(void)
{
    uint8_t ret;
    OS_ERR   os_err;
    startOp();
    OSSemPend(&Sem_A, (OS_TICK)10, OS_OPT_PEND_BLOCKING, NULL, &os_err);
    switch (os_err){
    /* manage errors*/
    }
    return ret;
}
1

There are 1 best solutions below

0
On
  1. You don't need to disable interrupts when calling OSSemPost(). OSSemPost() is considered an atomic operation w/r to your application.

  2. An ISR should look like this for a Cortex-M3 core which is what's in the Microsemi part:

    void MyISR (void)
    {
       CPU_SR_ALLOC();
    
       CPU_CRITICAL_ENTER();
       OSIntEnter();
       CPU_CRITICAL_EXIT();
       OSSemPost(...);
       OSIntExit();
    }
    

This allows you to tell uC/OS-III that you are starting an ISR. This is necessary to allow the kernel to schedule the posted task if it's the highest priority ready to run.