Need help with queue and task priority

ephobb wrote on Thursday, December 31, 2015:

Hi,
I am using three task. two task are sending data to queue(both having priority as 1) and one task is reading that data(priority as 2 and periodic 1000ms).
but i m observing bit different output. Initially both task queueing data. but after some time only one task in queueing data.
here is my code.

#include "stm32f1xx_hal.h"
#include "cmsis_os.h"
#include "task.h"     /* RTOS task related API prototypes. */

UART_HandleTypeDef huart1;
xQueueHandle uart_queue=0;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
void StartDefaultTask(void const * argument);
void send_str1(void const * argument);
void send2(void const * argument);
void Sd_uart(void const * argument);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();

	uart_queue	= xQueueCreate(11,sizeof(uint8_t *));	
	xTaskCreate((TaskFunction_t)send_str1,"string1",128,NULL,1,NULL);
	xTaskCreate((TaskFunction_t)send2,"string2",64,NULL,1,NULL);
	xTaskCreate((TaskFunction_t)Sd_uart,"Suart",64,NULL,2,NULL);

vTaskStartScheduler();
  

while (1)
  {

  }

}

void StartDefaultTask(void const * argument)
{
  for(;;)
  {
    osDelay(1);
  }
}

void send_str1(void const * argument)
{
	uint8_t *dat="Task1";
	for(;;)
	{
		xQueueSend(uart_queue,&dat,500);
				GPIOA->ODR = 0x00000000;
		taskYIELD();
	}
}

void send2(void const * argument)
{
	uint8_t *dat=" Task2";
	for(;;)
	{
		xQueueSendToBack(uart_queue,&dat,500);
				GPIOA->ODR = 0x00000020;
		taskYIELD();
	}
}

void Sd_uart(void const * argument)
{
	TickType_t xLastWakeTime;
	     // Initialise the xLastWakeTime variable with the current time.
     xLastWakeTime = xTaskGetTickCount();
	uint8_t *data;
	for(;;)
	{
		if(xQueueReceive(uart_queue,&data,100))
		{
			HAL_UART_Transmit(&huart1,data,11,1000);			
		}
		else
		{
			HAL_UART_Transmit(&huart1,"--",2,1000);
		}
		vTaskDelayUntil(&xLastWakeTime,1000/portTICK_RATE_MS);

	}
}

and output is

Task1 Task2 Task2Task1 Task2Task1 Task2Task1 Task2Task1 Task2Task1 Task2 Task2 Task2 Task2 Task2 Task2 Task2 Task2 Task2 Task2 Task2 Task2 Task2 Task2 Task2 Task2

plz help me with this.

rtel wrote on Thursday, December 31, 2015:

It would be very hard to predict how the code would execute. send_str1() and send2() are writing to the queue continuously (or at least, attempting to), but Sd_uart() is only removing data from the queue every 1000ms, therefore, other than for the first few milliseconds, the queue will always be full.

Once the queue is full, send_str1() and send2() will block attempting to write to the queue, but time out before Sd_uart() times out.

I think what you are seeing is task1 and task2 being written to the queue while the queue is being filled - then once the queue is full, which task happens to get unblocked, if any, when Sd_uart() removes and item from the queue is unpredictable.

ephobb wrote on Friday, January 01, 2016:

Thanks.
Yeah, two task’s are writting to queue continously.
but we can see output is, flow of task is as follow:
task1 - > Sd_uart -> Task2->Sd_Uart->Task1->…

But instead, i was trying to use following sequeunce as ,
Task1->Task2->Sd_Uart->Task1->Task2->Sd_Uart->…

i m just wondering that, in Task1 and Task2 i m calling taskYIELD(). If i m calling taskYIELD from Task1 then control should go to Task2 and then again Task1.and Sd_uart will get call after 1000 ms.
So till the time queue will be fulled and Task1 and task2 will be in block state.
Sd_uart will remove item from queue and again Task1 and Task2 will be in ready and runnning state.

but it is not working as expected.
Plz suggest me on this.

rtel wrote on Friday, January 01, 2016:

But instead, i was trying to use following sequeunce as ,
Task1->Task2->Sd_Uart->Task1->Task2->Sd_Uart->…

In which case you can have Sd_Uart use a long block time, and control the flow with the Task1 and Task2.

Task1 and Task2 can do something like:

for( ;; )
{
    xQueueSend(...);
    vTaskDelay( [whatever rate you want to send at] );
}

Then one task will unblock, write to the queue, and go back into the Blocked state for however long you like. While that task is in the Blocked state the other sending task will run and do the same. That way they will write to the queue in turn. In the mean time the receiving task just unblocks when there is data in the queue. If you want both senders to post to the queue before the receiver executes then the receiver must have the lower priority.

There are more elaborate ways you could control the sequencing, but if the two senders are the same priority and use the same block time then the above should work. You could even give one sender a higher priority than the other to ensure the order never changes even when tick interrupts occur while one of them is running.