Handling communication packets in a task

Hello everyone, I would like to have some advice regarding an application that I am building which requires handling data packets coming from an external device via USART. I should mention first that I am working with SAMD21 Microcontroller from Atmel and using Atmel Studio for development. I am using a simple ring buffer to handle the incoming data over USART and once a message is received I set an event flag. Since the data packets are variable in length I am using a timeout on the packets so as soon as the timer runs out and no further data is received, the flag is set. Now, my task is waiting for port_MaxDelay on this event flag to be set, once the flag is set I read the ring buffer and evaluate the message. This is working as far as I can say until now. What I want to ask here is, since the task has a vtaskdelay which means that if the incoming messages are very fast lets say if the task delay is 500 then any messages coming in this duration will be lost. How can I handle this case so that a complete communication is done without any messages lost and what are the general practices for handling such communication? Thanks in advance. Hope to hear from someone soon. Regards, Owais.

Handling communication packets in a task

I’m not sure I understand your question, but perhaps discussing will make it clearer. Which task is blocking using vTaskDelay()? The one that is also reading from the ring buffer. If so, could it not block on taking event group (with the appropriate timeout) rather than using vTaskDelay() and then using an infinite block time on the event group? The bytes are being sent to a ring buffer by an interrupt, so presumably provided the ring buffer is large enough, no messages will actually get missed even if the task reading then from the ring buffer is blocked – although it might be that the ring buffer contains more than one message at a time. Is the problem that the event group is only binary, yet the ring buffer might contain more than one message? If that is the case could you using a counting semaphore instead of the event group? Or use a task notification like a counting semaphore (which would be faster anyway). The semaphore/notification value will then keep a count of the number of messages in the ring buffer. Regards.

Handling communication packets in a task

Yes you got it right. Yes, there is just one task reading from the ring buffer and waiting on the event flag for an infinite block time set by port_MaxDelay. I shall try this instead of a task delay so the task is ready whenever the flag becomes set. Yes correct, the bytes are being sent to the ring buffer from the interrupt handler. The size of the ring buffer is 128 at the moment, I think I should increase it as well so that it can hold more messages. Yes, the event group is binary, I have created 2 different binary flags in the event group, one indicates a message ready and the other one triggers a special action inside the task(configuring the external device to a different role). To be more specific, each messages ends with a . If I understood correctly, you mean that I could use a counting semaphore instead of an event group bit and after receiving a I increase the count of semaphore which will then be a track keeper of the incoming messages, did I understand this correctly? Thanks for the quick response. Regards.

Handling communication packets in a task

Yes – if each time a new message is received you ‘give’ the semaphore, and each time you process the message you ‘take’ the semaphore then the semaphore holds a count of the number of messages in the ring buffer. If there are no messages in the ring buffer, the semaphore count will be zero (so it cannot be taken), and when you attempt to take the semaphore you can enter the blocked state, and be unblocked immediately that the semaphore is given (and therefore know the ring buffer contains a message) or a timeout (the return value of the xSemaphoreTake() function will be pdFALSE). If the semaphore count is already greater than zero when you attempt to take the semaphore, because the buffer already contains one or more messages, then the call to xSemaphoreTake() will return immediately. Using a semaphore for that is fine – but the same functionality can be achieved in a lighter touch and faster way using the vTaskNotifyGive() and ulTaskNotifyTake() API functions. Regards.

Handling communication packets in a task

Thanks for the detailed response. I shall give it a try. In the meantime, since I was using another event flag in the same group for triggering another action, can this also be handled using a semaphore in the same task which reads from the ring buffer?

Handling communication packets in a task

Any suggestion on the above post?

Handling communication packets in a task

I think there are several ways you could do it. For example… You could use the xTaskNotifyGiveFromISR() API function with the eSetBits action instead of the event group – but then you are back to only have a binary indication that there is something in the circular buffer, rather than an indication of how many messages were in the circular buffer. You would then need another method of knowing how many messages were in the buffer. Would could use a counting semaphore to count the number of messages in the buffer, but the task notification to unblock the task:
if( xTaskNotifyWait( 
. . . ) == pdPASS )
{
     /* Is the bit set that says there is something in the buffer? */
     if( notification value & something in buffer bit )
     {
         while( xSemaphoreTake( xSemaphore, 0 ) /* no block time */
         {
             process message from buffer.
         }
     }

     /* Is the bit set that says the other action needs performing? */
     if( notification value & other action bit )
     {
         perform other action.
     }
}
or more easily, as you are no longer using the semaphore for blocking, just have the interrupt that places messages in the circular buffer increment a variable each time a new message is placed into the buffer, and have the task decrement the variable each time it removes a message from the buffer. The interrupt can increment the count without a critical section, but the task would need to use a critical section when it decremented the count.
     while( message_count > 0 )
     {
         process message from buffer

         taskENTER_CRITICAL();
         message_count--;
         taskEXIT_CRITICAL();
Regards.

Handling communication packets in a task

The link to the xTaskNotifyWait() was wrong in the last post. This is the real link: http://www.freertos.org/xTaskNotifyWait.html

Handling communication packets in a task

Thanks again for the response. I have some confusion regarding the xTicksToWait parameter in xSemaphoreTake, what exactly happens if the semaphore is not available and the xTicksToWait is set to portMaxDelay? I am still having trouble incorporating the counting semaphore into my application. the problem maybe that, I am writing a driver for the external module which communicates via USART with the microcontroller so in order to use the module I need to first configure it by sending some commands in the task setup (before the infinite loop of task). What I am using at the moment is as follows:
  1. Receive a character from the module via the USART interrupt handler and put it in ring buffer
  2. Trigger a hardware counter from the USART handler after saving the received character
  3. If the counter reaches 0 and no further character is received from the module set an event flag bit.
  4. The task is blocked for portMaxDelay on the event group flag bit.
  5. As soon as the flag bit is set the task copies message from the ring buffer and does some action.
In the above mentioned method, I feel that the only thing I can include is the counting semaphore, which I can set in the USART handler after a complete message is received which is indicated by . Next coming to the task, I can take the semaphore before copying the message from the ring buffer and give the semaphore back this way I can keep track of the number of messages. please let me know if there is any fault in the above method or any reason where it might fail to do the job. Thanks again. Regards.

Handling communication packets in a task

Probably the thing you are doing wrong is giving back the semaphore. I’m not sure why you are doing that. The interrupt should be the only thing giving the semaphore as it is the only thing adding messages to the buffer, and the task should be the only thing taking the semaphore (and not giving it back) as it is the only thing removing messages from the buffer. That way the semaphore is a count of how many messages are in the buffer. However, I can’t help thinking you are overcomplicating this problem. I’m not sure why there is a hardware timer being used at all. The following pseudo code would seem the be something towards a workable solution that is somewhat simpler.
uint32_t ulMessagesWaiting = 0;

void interrupt_handler( void )
{
char c;

   c = read_character_from_uart();
   place_character_in_ring_buffer( c );

   /* Was the character the end of the
    message. */
   if( c == 'n' )
   {
     /* The buffer contains another
     complete message. */
     ulMessagesWaiting++;

     /* Unblock the task using a
     notification, or event group, or
     whatever. */
     unblock_task();
   }
}


void vMyTask( void *pvParameters )
{
   /* Do whatever init is necessary
   here. */


   for( ;; )
   {
     /* Block to wait for the interrupt,
     or any other event, using an event
     group, task notification, or whatever. */
     block();

     /* The task has been unblocked, are
     there any messages in the buffer?
     If so, process them, and keep
     processing them until there are no
     more in the buffer. */
     while( ulMessagesWaiting > 0 )
     {
       process_message_from_buffer();

       /* Protect the ulMessagesWaiting variable
       with a critical section because it is
       updated from the interrupt. */
       taskENTER_CRITICAL();
       /* Message has been processed. */
       ulMessagesWaiting--;
       taskEXIT_CRITICAL();
     }
   }
}
Regards.