This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Using SEM_post and SEM_pend

Expert 2370 points

Hi,

I am using uPP to capture data from A/D converter, when buffer is filled, EOW interrupt is fired which executes ISR to disable the interrupt and post a semaphore to TASK which process the buffer and fills new buffer as well. In my application, time to capture the data using uPP is faster than processing it so I thought semaphore can be best use to synchronize the capturing and post-processing. Is it corect approach to deal with this kind of problem ?

How can I check if SEM_post and SEM_pend are working properly ? I mean making sure that it is not posting another semaphore untill previous processing is done? I tried ROV option, semaphore pends only once after that it never pend, I wonder if they are being used correctly ?

Following are the code snippet which shows SEM_post and SEM_pend:

void isrUPP(void)
{
  
  UPISR_t interrupt_status;
  interrupt_status.value = UPP->UPIER;
   
  while (interrupt_status.value != 0)
  {
      
    if (interrupt_status.bits.EOWI)
    {
        UPP->UPIER |= ~(0x08);                      
        // Handle EOWI
        SEM_post (&ProcBuf);    
     }
   
    interrupt_status.value = UPP->UPIER;
  }
   
}

void TSK_process(void)
{
    while(1)
    {
       SEM_pend(&ProcBuf, SYS_FOREVER);

      further processing...

}

}

Thanks for your help.

BAS

  • Hi,

    This approach should be fine (and is very typical). When are you re-enabling the peripheral? You should not enable it again, until the data is processed by the task. Otherwise, while you're processing the buffer in the Task, the peripheral could be over-writing it...not good.

    You can enable LOG data and see if the correct actions are going on.

    Todd

  • Todd,

    Thanks for your response.

    Do you mean when I am writing to UPIDX register to get new data ? I am writing them in TASK just after processing the buffer. If this is wrong way, please tell me where should I use semaphore.

    void TSK_process(void)
    {
        while(1)
        {
           SEM_pend(&ProcBuf, SYS_FOREVER);

          further processing...

          // Capture new data

          UPP->UPID0 = (uint32_t)&recv_buffer;  
          UPP->UPID1 = 0x00010800;                
          UPP->UPID2 = 0x00000800;

        }

    }

    Attached is the snapshot of Raw Logs. I don't see SEM_pend anywhere, it's just SEM_post..

    I don't know how to make sure if semaphore is not posted again untill buffer is processed properly.

    I would greatly appreciate all your help.

    Thanks.

  • There are many ways to write a driver, but two common ways are as follows. It's in pseudo code and no error checking for brevity.

    1.Single buffer. Assumes rxBuffer[BUFSIZE] is a global variable and peripheral will write into it

    ISR
        SEM_post(driverSem);
        //do not re-enable interrupts for this peripheral

    Task
        while (TRUE) {
            SEM_pend(driverSem);
            //process data in rxBuffer
            //re-enable peripheral interrupts
        }
    The semaphore can be counting or binary since, by design, the ISR only calls SEM_post after the data is processed in the Task.   

    2. Multiple buffers. Assumes rxBuffer[NUMBUFS][BUFSIZE] is a global array and peripheral will write into it rxBuffer[driverIndex] to start and to start readIndex = 0 and writeIndex = 0

    ISR   
        SEM_post(driverSem);
        writeIndex = (writeIndex++) % NUMBUFS;
        // prime peripheral with rxBuffer[writeIndex]
        // enable interrupts for this peripheral

    Task
        while (TRUE) {
            SEM_pend(driverSem);
            //process data in rxBuffer[readIndex]
           readIndex = (readIndex++) % NUMBUFS;
        }  

    The semaphore must be counting in this case to allow burst of incoming data or some starvation of the Task. You'd need logic to handle the case where too much data is coming in or the Task is starved too long and all NUMBUFS entries in rxBuffer are full of unprocessed data. What you do in this case (e.g. discard, not enable interrupts, etc.) is up to you.

    The above implementations are very standard regardless of the RTOS you use.

    Specifically about your ROV output. You can look TSK to see the state of your tasks and what they are blocked on. You can look at SEM to what semaphores are in the system and their state.

    Todd

  • Tod,

    If I have to re-enable the peripheral interrupt after data is processed then what is the purpose of using semaphore ? Is it not the same as processing the buffer inside HWI ISR because interrupt is not enable either as long as it is executing the ISR ?

    Will semaphore not work in a way that after posting it for the first time from ISR, it will not post another semaphore regardless of the interrupt and pend on semaphore untill buffer is processed inside TSK ?

    Thanks for your help.

  • If you want, you can process the incoming buffer in the ISR. However, no Swi and Tasks will run during the processing time because Hwis are higher priority. Also, depending on the device, interrupt controller, and configuration, you might starve other interrupts out also.

    When you create the semaphore, you get to set the initial count. I expect you should set it to zero. There are two cases.

    1. Task runs first. In this case the Task will pend

    2. The ISR runs first. In this case, the post will increment the semaphore so when the Task runs, it will not pend.

    Todd

  • Todd,

    Initial count is set to zero but it doesn't pend. TSK is over running real-time because time to fill a buffer is faster than processing it. Do you think semaphore is the best solution in this scenario to synchronize filling a buffer and processing it ?

  • If data is coming in faster than you can process it, you have a fundamental problem. You either need to slow down the incoming data or speed up the processing. There is no single driver design. It is up to you to decide how to design your driver. I think using a semaphore is fine for certain designs. Using a Swi instead is another option. Or, as a I mentioned, doing it in the ISR is an option.

    Todd