stm32freertosmultitasking

Using one UART in three same priority tasks in FreeRTOS with STM32


I'm trying to use one UART in three same priority tasks like the code below, but what is happening is confusing for me! In fact, I want any task to send a string once per second, so I should have 3 statements in terminal each second, but the UART transmit function only works once and the 2 other transmit functions are omitted.

When I change the task priorities to high, normal and low it works well. How can I fix this issue without changing the priority of tasks?

In fact, I don’t want to have a complicated RTOS program. I just want a simple multitasking program with no semaphores or mutexes! I hope it would be possible because I don’t want to add complexity to my program. (Note that if I add a wait for UART ready function the program works fine, but it is not a common method in microcontroller programming).

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* definition and creation of myTask02 */
  osThreadDef(myTask02, StartTask02, osPriorityNormal, 0, 128);
  myTask02Handle = osThreadCreate(osThread(myTask02), NULL);

  /* definition and creation of myTask03 */
  osThreadDef(myTask03, StartTask03, osPriorityNormal, 0, 128);
  myTask03Handle = osThreadCreate(osThread(myTask03), NULL);

void StartDefaultTask(void const * argument)
{
  /* Infinite loop */
  for(;;)
  {
    //while (HAL_UART_GetState (&huart2) != HAL_UART_STATE_READY);
    HAL_UART_Transmit(&huart2,(uint8_t*)"T1\r\n",sizeof("T1\r\n")-1,100);
    osDelay(1000);
  }
}

void StartTask02(void const * argument)
{
  /* Infinite loop */
  for(;;)
  {
    //while (HAL_UART_GetState (&huart2) != HAL_UART_STATE_READY);
    HAL_UART_Transmit(&huart2,(uint8_t*)"T2\r\n",sizeof("T2\r\n")-1,100);
    osDelay(1000);
  }
}

void StartTask03(void const * argument)
{
  /* Infinite loop */
  for(;;)
  {
    //while (HAL_UART_GetState (&huart2) != HAL_UART_STATE_READY);
    HAL_UART_Transmit(&huart2,(uint8_t*)"T3\r\n",sizeof("T3\r\n")-1,100);
    osDelay(1000);
  }
}

Solution

  • What's the problem with using a mutex? You obviously need some way to prevent the three tasks from accessing the UART at the same time, and a mutex is the obvious way to do it.

    Simplest would be to move all the UART functionality (including mutex) into a single function, thus removing that "complexity" from your individual tasks:

    static StaticSemaphore_t uart_mutex;
    static SemaphoreHandle_t h_uart_mutex = NULL;
    
    void init_mutex(void) // Called before tasks are created
    {
        h_uart_mutex = xSemaphoreCreateMutexStatic ( &uart_mutex );
    }
    
    void send_string(const char *str)
    {
        xSemaphoreTake(h_uart_mutex, ( TickType_t ) 1000);
        HAL_UART_Transmit(&huart2, (uint8_t *)str, strlen(str), 100);
        xSemaphoreGive(h_uart_mutex);
    }
    
    void StartTask02(void const * argument)
    {
      /* Infinite loop */
      for(;;)
      {
        send_string("T2\r\n");
        osDelay(1000);
      }
    }
    

    An alternative would be to have something like a message queue that your tasks feed strings into, and another task that reads them out and sends them to the UART. But this is even more complicated in my opinion, and internally it is probably using a mutex anyway to protect the queue.