cancel
Showing results for 
Search instead for 
Did you mean: 

FreeRTOS - timing weird-ness

Thomas Carrington
Associate III

Hi All,

I'm building up my understanding of using FreeRTOS, and what I've setup is a Nucleo-F103RB connected to a logic analyser. The plan here is to have a few tasks setup with RTOS to toggle LEDs at varies rates and timings and then check how this actually looks (i.e. timing delays, etc.)

A few notes, I've created a few classes - GPIO, GenBuffer, and UARTPeriph, which I have tested and debugged and seem to be working as I expect.

So a breakdown of the tasks - 

"StartDefaultTask" - displays a USART message - "Hello World", and then toggles an LED continually.

PRIORITY = IDLE

void StartDefaultTask(void const * argument)
 
{
 
  GPIO CH0LED(CH0_GPIO_Port, CH0_Pin,  GPIO::OUTPUT);      // 3 words
 
 
 
  GenBuffer<uint8_t>USART1GenBuff[2] = {
 
            {&UART1Arr[0][0], 1024}, // Receive Queue     4 words
 
            {&UART1Arr[1][0], 1024}  // Transmit Queue     4 words
 
  };
 
 
 
  GlobGenBuff  = &USART1GenBuff[1];
 
 
 
  UARTPeriph  UART2Dev(&huart2, &USART1GenBuff[0], &USART1GenBuff[1]); //   3 words
 
  UART2Dev.PoleTransmit((uint8_t *) "Hello World\n\r", 14);        //   14bytes (4 w)
 
  GlobUART2   = &UART2Dev;
 
 
 
  while (GlobGenBuff->State() != GenBuffer_Empty) {}
 
 
 
  CH0LED.setValue(GPIO::LOW);
 
 
 
 /* Infinite loop */
 
 for(;;)
 
 {
 
   CH0LED.toggleOutput();
 
 }
 
 /* USER CODE END 5 */ 
 
}

"StartTask01" - just toggles an LED at 500ms (using the osDelay, so should put task in WAITING state till 500ms)

PRIORITY = LOW

void StartTask01(void const * argument)
 
{
 
 /* USER CODE BEGIN StartTask01 */
 
 
 
  GPIO CH1LED(CH1_GPIO_Port, CH1_Pin,  GPIO::OUTPUT);      // 3 words
 
 
 
 /* Infinite loop */
 
 
 
 for(;;)
 
 {
 
   //HAL_GPIO_TogglePin(CH1_GPIO_Port, CH1_Pin);
 
 
 
   CH1LED.toggleOutput();
 
 
 
   osDelay(500);
 
 }
 
 /* USER CODE END StartTask01 */
 
}

"StartTask02" - switch LED on for 50ms,then off for 200ms (again using osDelay)

PRIORITY = Below Normal

void StartTask02(void const * argument)
 
{
 
 /* USER CODE BEGIN StartTask02 */
 
 
 
  GPIO CH2LED(CH2_GPIO_Port, CH2_Pin,  GPIO::OUTPUT);      // 3 words
 
 
 
 /* Infinite loop */
 
 for(;;)
 
 {
 
   //HAL_GPIO_WritePin(CH2_GPIO_Port, CH2_Pin, GPIO_PIN_SET);
 
   CH2LED.setValue(GPIO::HIGH);
 
   osDelay(50);
 
 
 
   //HAL_GPIO_WritePin(CH2_GPIO_Port, CH2_Pin, GPIO_PIN_RESET);
 
   CH2LED.setValue(GPIO::LOW);
 
   osDelay(200);
 
 }
 
 /* USER CODE END StartTask02 */
 
}

"StartTask03" - Toggle LED, without any delay. Test here is to see the Round-Robin that would occur between this task and "StartDefault"

PRIORITY = IDLE

void StartTask03(void const * argument)
 
{
 
 /* USER CODE BEGIN StartTask03 */
 
 
 
  GPIO CH3LED(CH3_GPIO_Port, CH3_Pin,  GPIO::OUTPUT);      // 3 words
 
 
 
  CH3LED.setValue(GPIO::LOW);
 
 
 
  HAL_GPIO_WritePin(CH3_GPIO_Port, CH3_Pin, GPIO_PIN_RESET);
 
 
 
 /* Infinite loop */
 
 for(;;)
 
 {
 
   //HAL_GPIO_TogglePin(CH3_GPIO_Port, CH3_Pin);
 
   CH3LED.toggleOutput();
 
 }
 
 /* USER CODE END StartTask03 */
 
}

"StartTask04" - Switch LED on for 1ms, then off. Uses a period trigger of 250

PRIORITY = NORMAL

void StartTask04(void const * argument)
 
{
 
 /* USER CODE BEGIN StartTask04 */
 
  GPIO CH4LED(CH4_GPIO_Port, CH4_Pin,  GPIO::OUTPUT);      // 3 words
 
 
 
  CH4LED.setValue(GPIO::LOW);
 
 
 
 /* Infinite loop */
 
  uint32_t PreviousWakeTime = osKernelSysTick();
 
  for(;;)
 
  {
 
    //HAL_GPIO_WritePin(CH4_GPIO_Port, CH4_Pin, GPIO_PIN_SET);
 
    CH4LED.setValue(GPIO::HIGH);
 
    osDelay(1);
 
 
 
    //HAL_GPIO_WritePin(CH4_GPIO_Port, CH4_Pin, GPIO_PIN_RESET);
 
    CH4LED.setValue(GPIO::LOW);
 
    osDelayUntil(&PreviousWakeTime, 250);
 
  }
 
 /* USER CODE END StartTask04 */
 
}

Attached is a copy of the timing plots - I have lined up the task names with the channel numbers (i.e. Task 1 = Channel 1, Task 2 = Channel 2, etc.) note - "StartDefault" is Channel 0.

What I was expecting to see is that CH0, CH3 - would continually toggle alternating at each time slice (1ms) due to same priority.

CH1 would change state every 500ms, CH2 would be PWM - ON for 50ms, and off for 200ms, and similar for CH4 however would be more strict on the periodic.

When I have the USART2 interrupt enabled (in NVIC) however not used or switched on, I get the plots in "USARTInterrupt" - where the IDLE is good, however the timings of everything else is off - CH4 is not on for 1ms (more ~25us), CH2 is similar occassionally and CH1 seems to have a very quick toggle.

If I now remove the USART2 interrupt entirely, so that the only interrupts are the "default" ones that I cannot remove from STM32cubeMX. - see "GOOD". As the name would suggest this is working as expected...

Now if I change the optimisation, so that C++ is "Optimize most" - O3, the timing is again wrong...

Additionally, the other day I had the timing working correctly with the USART2 interrupt enabled (NVIC), its just today that it appears to not be working. Actually doing the course of writing this query, I've re-tested the USART part, and it appears to have worked - no idea why...

Whilst looking into this, I'd noticed that if I set the total stack size to a multiple of 32, it would cause the same timing issues... so this is now at a multiple of 32, minus 1. Which appears to work, in some instances (as stated above)

So the question...can anyone example to me whats happening here? I've been racking my brain, and scanning the internet and cannot see to get an answer.

Any help would be greatly appreciated.

0 REPLIES 0