Page 1 of 1

Signaling binsem from interrupt doesn't seem to work

PostPosted: Mon Feb 06, 2017 3:44 pm
by ben.phillips
When I use OS_WaitBinSem with OSNO_TIMEOUT in a task, and then try to signal the binsem from within an interrupt, my task will never resume even though the binsem has been signaled.

I'm trying to read in some bytes over uart using an interrupt. What I'd like to do is in my task payloadTest turn on the uart1 interrupt and then wait on a binary semaphore. When the interrupt has received enough bytes it will signal the binary semaphore, my payloadTest task should resume, and the task will disable the interrupt. If I wait the binsem with a timeout it will return to my task after the timeout. If I wait with no timeout it will never return to my task. I verified that the interrupt is hitting the line that signals the binsem. In the main loop where ossched() is called I've read the binsem using OSReadBinSem after my interrupt has run enough times and it says that the binsem is 1, but my task payloadTest never resumes.

As a sanity check I tried setting up two test tasks one called Test and the other Temp. Test will wait on a binsem with no timeout, Temp will delay for 5 seconds and then signal the binsem. I've verified that this behaves as expected: Test will wait on the binsem, then Temp will start executing and delay for 5 seconds. Since both are in a waiting state neither does anything in that 5 second period, after the 5 seconds is up Temp will signal the binsem, and the next time ossched() is called Test resumes execution. So it appears that I can wait with no timeout and signal a binsem between two tasks, but for some reason when I try to do the same with a task and an interrupt it doesn't work.

I'm not sure what could be causing this behavior and would appreciate any input.

Here is some of the relevant code:
Code: Select all
uint8 m_serialBuffDataLen;
uint8 m_aSerialBuff[255];
uint8 m_numBytesToRead;

void payloadTest(void)
{
    static uint8 bytesToRead = 200;

    // BulkReadStart and Stop enable and disable the interrupt respectively
    bulkReadStart(bytesToRead);
    OS_WaitBinSem(PAYLOAD_BYTE_RX, OSNO_TIMEOUT);
    bulkReadStop();
}

// UART PAYLOAD receive ISR
void __attribute__((__auto_psv__, __interrupt__)) _U1RXInterrupt(void)
{
  //Clear the interrupt flag
  IFS0bits.U1RXIF = 0;
 
  // If overflow error has occurred reset the error flag and reset flow control
  if (U1STAbits.OERR)
  {
    while(U1STAbits.URXDA && m_serialBuffDataLen < m_numBytesToRead)
    {
      m_aSerialBuff[m_serialBuffDataLen] = U1RXREG;
      m_serialBuffDataLen++;
    }
   
    if(m_serialBuffDataLen == m_numBytesToRead)
    {
      if(OSReadBinSem(PAYLOAD_BYTE_RX) == 0)
      {
        OSSignalBinSem(PAYLOAD_BYTE_RX);
        char* msg = "Signaled flag\r";
        usb_print(msg, strlen(msg));
      }
    }
    U1STAbits.OERR = 0;
    U1MODEbits.UEN = 1;
    return;
  }
 
  if(m_serialBuffDataLen >= m_numBytesToRead)
  {
    uint8 flag;
    flag = OSReadBinSem(PAYLOAD_BYTE_RX);
    if(!flag)
    {
      OSSignalBinSem(PAYLOAD_BYTE_RX);
      usb_print_int(m_serialBuffDataLen);
      char* msg = "Signaled flag\r";
      usb_print(msg, strlen(msg));
    }
    return;
  }
 
  m_aSerialBuff[m_serialBuffDataLen] = U1RXREG;
  usb_print((char*)&m_aSerialBuff[m_serialBuffDataLen], 1);
  m_serialBuffDataLen++;
}

// - Salvocfg.h
#define OSEVENTS               20
#define OSENABLE_EVENT_TRYING       TRUE
#define OSENABLE_EVENT_READING      TRUE
#define OSENABLE_EVENT_FLAGS        TRUE
#define OSTASKS                     9
#define OSENABLE_MESSAGES           TRUE
#define OSENABLE_TIMEOUTS           TRUE
#define OSENABLE_MESSAGE_QUEUES     TRUE
#define OSENABLE_BINARY_SEMAPHORES    TRUE
#define OSENABLE_DELAYS             TRUE
#define OSBYTES_OF_DELAYS           4  //32-byte delays
#define OSBYTES_OF_TICKS            4  //32-byte OStimerTicks
#define OSENABLE_BOUNDS_CHECKING    TRUE
#define OSMCC30_LARGE_CM

Re: Signaling binsem from interrupt doesn't seem to work

PostPosted: Thu Feb 09, 2017 12:04 pm
by aek
I don't see the ECB handle, the creation of the BinSem, and some other code required ...

What happens if you simplify your code substantially -- just signal binSem when the interrupt occurs? Should work fine.

Keep in mind that if you are hammering on the ISR, it may be better to use a Sem than a binSem.

Also, I don't recall if OSReadXyz() is properly callable at the ISR level.

Re: Signaling binsem from interrupt doesn't seem to work

PostPosted: Thu Feb 09, 2017 3:28 pm
by ben.phillips
According to the salvo documentation OSReadBinSem is callable from anywhere.
I can't test it today, but I'll try simplifying the code tomorrow like you said and see what happens.

I initialized the task and binSem elsewhere in code, here's that code if you think my initialization might be wrong:
Code: Select all
// Task initialization
#define P_PAYLOAD_TEST      OSTCBP(1)
// binSem initialization
#define PAYLOAD_BYTE_RX    OSECBP(1)

//Task and binsem creation
OSCreateTask(payloadTest, P_PAYLOAD_TEST, 0);
OSCreateBinSem(PAYLOAD_BYTE_RX, 0);


Why would it be better to use a semaphore vs a binSem in the ISR?

Re: Signaling binsem from interrupt doesn't seem to work

PostPosted: Thu Feb 09, 2017 3:33 pm
by aek
Why would it be better to use a semaphore vs a binSem in the ISR?


Because when you have a "rapid-fire" ISR where the ISR may occur (and thereby signal the binSem) faster than the task can successfully wait the binSem, then you will "lose count" (because the binSem pegs to a value of 1), if there is supposed to be a one-to-one relationship between the ISR and the data that it pushes to the task (e.g., individual, incoming Rx chars).

binSem: 20 rapid Rx char ISRs, but only 13 of them are immediately followed by the task successfully waiting the binSem: 7 chars are "lost", in the sense that you are now "behind" emptying your Rx buffer by 7 chars.

Sem: 20 rapid Rx char ISRs, but only 13 of them are immediately followed by the task successfully waiting the Sem: 7 chars will be picked up when the task can run / the ISRs settle, because the "remaining" value of the Sem (in those 7 cases) after being successfully waited is (still) non-zero.

Re: Signaling binsem from interrupt doesn't seem to work

PostPosted: Tue Feb 14, 2017 12:30 pm
by ben.phillips
After some testing I found out that it wasn't hanging because the binsem wasn't getting signaled, it was hanging because I had some bad structure in my interrupt and wasn't grabbing the last byte I was waiting for. You're advice helped eliminate some possibilities of what could be wrong, thanks for your help aek! And I'll keep in mind your advice about using a sem instead of a binsem.

Re: Signaling binsem from interrupt doesn't seem to work

PostPosted: Tue Feb 14, 2017 12:59 pm
by aek
Good!