STMicroelectronics / STM32CubeH7

STM32Cube MCU Full Package for the STM32H7 series - (HAL + LL Drivers, CMSIS Core, CMSIS Device, MW libraries plus a set of Projects running on all boards provided by ST (Nucleo, Evaluation and Discovery Kits))
https://www.st.com/en/embedded-software/stm32cubeh7.html
Other
497 stars 305 forks source link

Question: ISR Triggered Task priority #116

Closed rxa1031 closed 3 years ago

rxa1031 commented 3 years ago

Hello,

I have a query with regards to Task that is to be triggered only when an ISR routine triggers it.

The task is meant to dequeue the data stored by ISR (say CAN receive) into the Queue and then act upon the received data.

Question 1: Maximum allowed task priority value

Please help me understand what is the maximum allowed task priority for the above task. Will it be:

  1. osPriorityISR
  2. osPriorityRealtime7

Also please help me understand who can report or use the priority:

  1. osPriorityError
  2. osPriorityReserved

Question 2: Task triggering mechanism

Whether it is sufficient to have the task waiting for Task notification from ISR (with help of ulTaskNotifyTake( pdTRUE, portMAX_DELAY); API call) and the ISR triggering the task execution with help of vTaskNotifyGiveFromISR(SW_IRQHandlerTaskHandle, NULL) call?

Task related Global variables:

osThreadId_t SW_IRQHandlerTaskHandle;
uint32_t SW_IRQHandlerTaskBuffer[ 1024 ];
osStaticThreadDef_t SW_IRQHandlerTaskControlBlock;
const osThreadAttr_t SW_IRQHandlerTask_attributes = {
  .name = "SW_IRQ_HandlerTask",
  .stack_mem = &SW_IRQHandlerTaskBuffer[0],
  .stack_size = sizeof(SW_IRQHandlerTaskBuffer),
  .cb_mem = &SW_IRQHandlerTaskControlBlock,
  .cb_size = sizeof(SW_IRQHandlerTaskControlBlock),
  .priority = (osPriority_t) osPriorityNormal1,
};

Task initialization code in function main()

    if ( NULL == (SW_IRQHandlerTaskHandle = osThreadNew(T_SW_IRQHandler, NULL, &SW_IRQHandlerTask_attributes)))
    {
        // Error handling here
        assert_failed((uint8_t *)__FILE__, __LINE__);
    }

Query 3: Queue implementation and use by ISR and task

Concern: Code crashes often

Dequeue mechanism below:

Globals:

osMessageQueueId_t Q_EventHandlerHandle;
uint8_t Q_EventHandlerBuffer[ 16 * sizeof( toTaskEventHandler* ) ];
osStaticMessageQDef_t Q_EventHandlerControlBlock;
const osMessageQueueAttr_t Q_EventHandler_attributes = {
  .name = "Q_EventHandler",
  .cb_mem = &Q_EventHandlerControlBlock,
  .cb_size = sizeof(Q_EventHandlerControlBlock),
  .mq_mem = &Q_EventHandlerBuffer,
  .mq_size = sizeof(Q_EventHandlerBuffer)
};

Called by main()

  Q_EventHandlerHandle = osMessageQueueNew (16, sizeof(toTaskEventHandler*), &Q_EventHandler_attributes);

Task code:

#define dDummyMessagePriority                   ( 0 )

void T_SW_IRQHandler(void * argument)
{
...
        while(1)
        {
            dvDisableInterrupts;
            {
                if(0 < osMessageQueueGetCount(Q_EventHandlerHandle))
                {
                    if (osOK != osMessageQueueGet(Q_EventHandlerHandle, &poA_ThisEventHandler, dDummyMessagePriority, 0 /* Do not use osWaitForever as IRQ is disabled */))
                    {
                        // #DRA: #ToDo: add error handling here
                        assert_failed((uint8_t*)__FILE__, __LINE__);
                    }
                }
                else
                {
                    poA_ThisEventHandler = NULL;
                }
            }
            dvEnableInterrupts;
            if( poA_ThisEventHandler == (toTaskEventHandler *)NULL )
            {
                break;
            }
            poA_ThisEventHandler->pArvFunction( poA_ThisEventHandler );
        }
...
}

Code called from CAN Receive ISR:

void                                    rvAddEventToInterruptEvents
    (
        toTaskEventHandler  *       poTaskEventHandler
    )
{
    uint32_t u32IRQMasked;
    MvTraceTime;
    dvDisableInterrupts;
    {
        void *pv = poTaskEventHandler;
        if (osOK != osMessageQueuePut(Q_EventHandlerHandle, &pv, dDummyMessagePriority, 0 /* Do not use osWaitForever as IRQ is disabled */))
        {
            // #DRA: #ToDo: add error handling here
            ++u32EventHandlerErrorCounts;
            assert_failed((uint8_t*)__FILE__, __LINE__);
        }
        else
        {
            vTaskNotifyGiveFromISR(SW_IRQHandlerTaskHandle, NULL);
        }
    }
    dvEnableInterrupts;
    MvTraceTime;

    return;
}

Please suggest which normal code and FreeRTOS API calls should I review and/or modify.

Thanks, Rajeev

rxa1031 commented 3 years ago

Hello,

The code I am working on uses below:

Used STM32CubeMX version 6.1.0 Mcu.UserName=STM32H753BITx MxCube.Version=6.1.0 MxDb.Version=DB.6.0.10

STM32CubeH7 package version 1.8.0 ProjectManager.FirmwarePackage=STM32Cube FW_H7 V1.8.0

Regards, Rajeev

rxa1031 commented 3 years ago

Hello @RKOUSTM ,

Are there any findings / updates that you may be able to share with me.

Thanks, Rajeev

RKOUSTM commented 3 years ago

Hi @rxa1031,

Thank you for your contribution. Please excuse the delay we may take sometimes to reply. The CMSIS-RTOS2 offers the osPriority_t value to specify the priority for a specific thread.

Concerning the first point in the Question 1, the osPriorityRealtime7 priority is the highest possible priority for a normal task which is set to 55. Therefore, the osPriorityISR priority is reserved for an Interrupt Service Routine (ISR) and should not be attributed to a normal task as defined in CMSIS-RTOS2 v 2.1.3 :

osPriorityISR: Reserved for ISR deferred thread. This highest priority might be used by the RTOS implementation but must not be used for any user thread.

About the second point, the osPriorityError is returned when the priority cannot be determined. For example, if you try to get the thread priority for an inexistent thread ID, osPriorityError is returned. According to CMSIS-RTOS2 v2.1.3, the definition of this priority a is :

osPriorityError : priority cannot be determined or is illegal. It is also returned when the function is called from Interrupt Service Routines.

On the other hand, osPriorityReserved is a "virtual" priority, as it is used to prevent enumerations down-size compiler optimization (i.e to keep the enumerated values encoded as a 32 bit integer). The value of this priority is set to 0x7FFFFFFF as mentioned in the CMSIS-RTOS2 v2.1.3.

Concerning Question 2, the question is not clear, could you please give us more details? Anyway, it is fully possible to use ulTaskNotifyTake() and vTaskNotifyGiveFromISR() to ensure that a task is notified when a hardware event takes place (rising front, fifo full, etc...). The task as defined in your question would have no issue to use this signaling mechanism.

For Question 3, does dvDisableInterrupts, as it name suggests, disables all interrupts? If so, using taskENTER_CRITICAL() and taskEXIT_CRITICAL() would be better. Regardless of this, disabling the interrupts for these code sections seems a bit suspicious. There might be a possibility that getting rid of them would make the code a bit more overall unstable. It would be appreciated if you'd activate stack overflow checking as referenced in this link.

I hope the links I provided you with was helpful. Unfortunately, we don't treat these aspect related to FreeRTOS in our GitHub repositories. They are rather treated at FreeRTOS GitHub.

Please allow me to close this issue now. Thank you again for your contribution.

With regards,