Subzee
Subzee

Reputation: 23

How can I acquire a semaphore and release it from another task in FreeRTOS in STM32H?

I have enabled TIM1 and have created 3 tasks where the highest priority task will acquire the semaphore and will sleep for 10 seconds after that the normal priority task will sleep for 10 secnds and release the semaphore, after this the lower priority task will acquire the semaphore and blink the LEDs But that's not happening only the Higher priority task is acquiring the semaphore waiting for 10 seconds and again it's acquiring the semaphore

what seems to be the problem??

I have attached the snippet of the code here

void StartHighTask(void *argument)
{
  /* USER CODE BEGIN StartHighTask */
  /* Infinite loop */
  for(;;)
  {
      if ( osSemaphoreAcquire(BinSemHandle, osWaitForever)== osOK){
                    char *s1 = " Semaphore Acquired by High Task\n\r";
                    HAL_UART_Transmit(&huart3, (uint8_t*)s1, strlen(s1), 1000);
                    HAL_Delay(10000);


                  }

                  else {
                    char *s3 = " Waiting for the Semaphore \n\r";
                HAL_UART_Transmit(&huart3, (uint8_t*)s3, strlen(s3), 1000);
                  }


    osDelay(1000);
  }
  /* USER CODE END StartHighTask */
}

/* USER CODE END Header_StartNormalTask */
void StartNormalTask(void *argument)
{
  /* USER CODE BEGIN 5 */
  /* Infinite loop */
  for(;;)
  {
      HAL_Delay(10000);
      osSemaphoreRelease(BinSemHandle);
      char *s2 = " Semaphore released by Normal Task\n\r";
      HAL_UART_Transmit(&huart3, (uint8_t*)s2, strlen(s2), 1000);

    osDelay(1000);
  }
  /* USER CODE END 5 */
}

/* USER CODE END Header_StartLowTask */
void StartLowTask(void *argument)
{
  /* USER CODE BEGIN StartLowTask */
  /* Infinite loop */
  for(;;)
  {
      if ( osSemaphoreAcquire(BinSemHandle, osWaitForever)== osOK){

                    char *s1 = " Semaphore Acquired by low Task\n\r";
                    HAL_UART_Transmit(&huart3, (uint8_t*)s1, strlen(s1), 1000);

                    osDelay(1000);
                    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, 1);
                    HAL_Delay(500);
                    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, 0);

                    char *s2 = " Semaphore released by low Task\n\r";
                    HAL_UART_Transmit(&huart3, (uint8_t*)s2, strlen(s2), 1000);
                osSemaphoreRelease(BinSemHandle);


                  }

                  else {
                    char *s3 = " Waiting for the Semaphore \n\r";
                HAL_UART_Transmit(&huart3, (uint8_t*)s3, strlen(s3), 1000);
                  }

    osDelay(1000);
  }
  /* USER CODE END StartLowTask */
}

Upvotes: 0

Views: 383

Answers (1)

Issylin
Issylin

Reputation: 565

As mentioned by HS2, you have to replace HAL_Delay calls by osDelay ones, which is a FreeRTOS function.

The reason is that osDelay uses vTaskDelay() internally. The OS will be notified about the requested delay in ticks and will change the status of the task to blocked for that particular period.

osStatus osDelay (uint32_t millisec)
{
#if INCLUDE_vTaskDelay
  TickType_t ticks = millisec / portTICK_PERIOD_MS;

  vTaskDelay(ticks ? ticks : 1);          /* Minimum delay = 1 tick */

  return osOK;
#else
  (void) millisec;

  return osErrorResource;
#endif
}

On the other hand, HAL_Delay is part of the STM32 HAL (Hardware Abstraction Layer) and is not part of FreeRTOS. Therefore it can not notify the OS.

__WEAK void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = 0;
  tickstart = HAL_GetTick();
  while((HAL_GetTick() - tickstart) < Delay)
  {
  }
}

Finally, a side note, using FreeRTOS, you can't use osDelay in the idle task as stated by the documentation because :

There must always be at least one task that is ready to run. It is therefore imperative that the hook function does not call any API functions that might cause the idle task to block (vTaskDelay() [...]

In this specific case, you can however use HAL_Delay().

Upvotes: 0

Related Questions