Каковы допустимые значения HAL_NVIC_SetPriority () при использовании STM32 и FreeRTOS?

После довольно сложного процесса изучения некоторых вещей о приоритете прерывания я все еще немного застрял, пытаясь понять, какие значения мне разрешено вызывать для HAL_NVIC_SetPriority() в SysTick_IRQn (это ISR, вызывающий планировщик FreeRTOS каждые 1 мс).

TL; DR;

Часть меня думает, что разрешено все, что находится между HAL_NVIC_SetPriority(SysTick_IRQn, 15 ,0U) (самый низкий возможный приоритет) и HAL_NVIC_SetPriority(SysTick_IRQn, 10 ,0U) (немного выше), а часть меня думает, что разрешено все, что находится между HAL_NVIC_SetPriority(SysTick_IRQn, 15 ,0U) (самый низкий возможный приоритет) и HAL_NVIC_SetPriority(SysTick_IRQn, 5 ,0U) (немного выше). Предполагается, что configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY в FreeRTOSConfig.h имеет значение 5. Путаница заключается в том, что во FreeRTOS более высокие числа имеют более высокий приоритет, но в STM32 более высокие числа имеют более низкий приоритет, а документация довольно сложно понять.


Подробности:

Чтобы доказать, что я приложил отважные усилия, и помочь вам заполнить пробелы, вот мое текущее понимание. Я собираюсь написать описание того, что я знаю, чтобы быть правдой, таким образом, чтобы это выглядело так, как будто я учу вас, даже если я ищу ответ на мой вышеупомянутый вопрос, а также на исправление, подтверждение или дополнительную информацию по вашему усмотрению.

Хотя это, вероятно, относится ко многим микроконтроллерам или семействам STM32, давайте обсудим это с точки зрения В частности, STM32F207ZG.

Примечание. STM32CubeF2 для загрузки здесь.

Мое понимание:

Если вы посмотрите на стандартный файл FreeRTOSConfig.h (например, STM32Cube_FW_F2_V1.7.0 / Projects / STM322xG_EVAL / Applications / FreeRTOS / FreeRTOS_ThreadCreation / Inc / FreeRTOSConfig.h), вы увидите следующее:

/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
    /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
    #define configPRIO_BITS             __NVIC_PRIO_BITS
#else
    #define configPRIO_BITS             4        /* 15 priority levels */
#endif

/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY         0xf

/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5

/* Interrupt priorities used by the kernel port layer itself.  These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY         ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

__NVIC_PRIO_BITS определен в STM32Cube_FW_F2_V1.7.0 / Drivers / CMSIS / Device / ST / STM32F2xx / Include / stm32f217xx.h как 4U, поскольку «STM32F2XX использует 4 бита для уровней приоритета».

Во-первых, это интересно, потому что это означает, что фактически используются только 4 из 8 доступных битов приоритета! Вызов библиотеки STM32 HAL HAL_NVIC_SetPriority() имеет заголовок, который выглядит следующим образом и, кажется, указывает, что вам нужно установить 8 бит (PreemptPriority от 0 до 15 и SubPriority от 0 до 15), но на самом деле это не так - у вас всего 4 биты для установки.

/**
  * @brief  Sets the priority of an interrupt.
  * @param  IRQn: External interrupt number.
  *         This parameter can be an enumerator of IRQn_Type enumeration
  *         (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f2xxxx.h))
  * @param  PreemptPriority: The preemption priority for the IRQn channel.
  *         This parameter can be a value between 0 and 15
  *         A lower priority value indicates a higher priority 
  * @param  SubPriority: the subpriority level for the IRQ channel.
  *         This parameter can be a value between 0 and 15
  *         A lower priority value indicates a higher priority.          
  * @retval None
  */
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)
{ 

Итак, вам нужно установить только 4 бита, но оказывается, что вы можете решить, сколько PreemptPriority бит и сколько SubPriority бит, следующим образом:

HAL_NVIC_SetPriorityGrouping() из UM1940, 9.2.4, p124 / 1371. введите здесь описание изображения

FreeRTOS говорит в своей документации:

Если вы используете STM32 с библиотекой драйверов STM32, убедитесь, что все биты приоритета назначены для битов приоритета вытеснения, вызвав NVIC_PriorityGroupConfig (NVIC_PriorityGroup_4); перед запуском ОСРВ.

Итак, одно из самых первых действий, которые вы должны сделать в своем коде (по крайней мере, перед запуском планировщика FreeRTOS через osKernelStart() или vTaskStartScheduler():

/* Set Interrupt Group Priority */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

Это настраивает все 4 ваших приоритета как PreemptPriority бит, а ни один из них не должен быть SubPriority бит. Это означает, что при любых вызовах функции HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority) теперь всегда будет использоваться 0 как самый правый параметр.

Затем вы должны по существу позвонить (примечание: это вызывается через HAL_InitTick():

/*Configure the SysTick IRQ priority */
HAL_NVIC_SetPriority(SysTick_IRQn, 15 ,0U);

где 15 - приоритет тика SysTick. Поскольку у нас есть все 4 бита, это дает нам диапазон приоритета от 0 до 15, где 15 - самый низкий приоритет прерывания, а 0 - самый высокий приоритет.

Итак, почему мы устанавливаем для SysTick самый низкий приоритет? Ответ: потому что это хорошая практика для планировщика FreeRTOS, который вызывает прерывание SysTick. Собственно говоря, согласно их собственной документации, слишком высокий приоритет сломает FreeRTOS. Попробуем разобраться в этом.

Мы знаем, что наши параметры прерывания теперь составляют от 0 до 15 для параметра PreemptPriority, но он даже уже, чем это: мы можем установить только PreemptPriority для прерывания SysTick, равное 10-15 (я думаю - Мне нужно немного помощи здесь). Почему от 10 до 15? Что ж, документация FreeRTOS (хотя это очень сбивает с толку) даже прямо состояния:

Функции FreeRTOS, которые заканчиваются на "FromISR", безопасны для прерываний, но даже эти функции не могут быть вызваны из прерываний, которые имеют логический приоритет выше [т.е. численно ниже] приоритета, определенного configMAX_SYSCALL_INTERRUPT_PRIORITY (configMAX_SYSCALL_INTERRUPT_PRIORITY определяется в файле FreeRTOSConf). . Следовательно, для любой подпрограммы обслуживания прерывания, использующей функцию RTOS API, необходимо вручную установить приоритет на значение, численно равное или превышающее значение параметра configMAX_SYSCALL_INTERRUPT_PRIORITY. Это гарантирует, что логический приоритет прерывания равен или меньше значения configMAX_SYSCALL_INTERRUPT_PRIORITY.

Теперь вернитесь к FreeRTOSConfig.h вверху этой страницы. Мы знаем, что __NVIC_PRIO_BITS равно 4, и видим, что:

configMAX_SYSCALL_INTERRUPT_PRIORITY равно (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)), что означает 5 << (8 - 4) = decimal 80 = 0b01010000.

Документация FreeRTOS предлагает ценную информацию о том, почему сдвиг влево (см. Раздел «Внутреннее представление приоритета Cortex-M»), но я не могу понять, что дальше.

Итак, теперь, делая некоторые обоснованные предположения и зная, что наши варианты приоритета от 0 до 15, где 0 - самый высокий, а 15 - самый низкий, и зная, что configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY равно 5, нам, возможно, разрешено использовать 15-5 = 10 как самый высокий приоритет и 15 как самый низкий, или, может быть, от 5 до 15 - нормально, но от 0 до 4 - запрещено? Не знаю ... Я запуталась ...


person Gabriel Staples    schedule 09.05.2018    source источник
comment
Я бы сказал - если вы не понимаете, как работает система приоритетов, лучше не трогайте ее в такой сложной среде, как RTOS. Сначала узнайте, как это работает в среде с нуля, подумайте, почему вы хотите его изменить, и когда вы станете мастером NVIC, настройте RTOS. Я бы предложил вместо этого использовать функции CMSIS   -  person 0___________    schedule 09.05.2018
comment
Габриэль, спасибо за этот вопрос! Это действительно помогло мне больше разобраться в этой теме :). Пока что довольно сложная дорога ..!   -  person bas    schedule 01.06.2021


Ответы (1)


Во-первых, не путайте приоритеты задач FreeRTOS с приоритетами NVIC. Они совсем другие.

В приведенном выше примере вы можете использовать приоритеты прерываний от 5 до 15 для ваших прерываний, если они выполняют вызовы FreeRTOS API. Если они не обращаются к FreeRTOS API, вы можете использовать прерывания с любым приоритетом от 0 до 15.

Не беспокойтесь о сдвиге, поскольку все это делается за вас, но причина в том, что используются верхние 4 бита регистров приоритета (обратите внимание, что некоторые процессоры используют другое количество битов приоритета).

person Realtime Rik    schedule 09.05.2018
comment
Спасибо за этот ответ. Итак, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY описывает приоритет NVIC, правильно - даже если он находится внутри FreeRTOSConfig.h? И приоритет FreeRTOS (задача) - это то, что вы передаете, когда вызываете xTaskCreate(taskFunction, "Task Name", configMINIMAL_STACK_SIZE * 5, NULL, tskIDLE_PRIORITY + 1, NULL), например, где приоритет задачи FreeRTOS в этом примере на 1 выше, чем у незанятой задачи. - person Gabriel Staples; 09.05.2018
comment
Итак, чтобы подтвердить: configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY - это ограничение на приоритеты NVIC (которые передаются в HAL_NVIC_SetPriority()), а приоритеты FreeRTOS используются в xTaskCreate(), uxTaskPriorityGet(), vTaskPrioritySet() и т. Д., Правильно? Это различие, о котором вы говорите, когда говорите, что их нельзя путать? - person Gabriel Staples; 09.05.2018
comment
да. MAX SYSCALL PRIORITY - это максимальный приоритет прерывания NVIC, которое может вызвать систему (API). Причина этого в том, что ОСРВ использует прерывания с более высоким приоритетом, которые не должны прерываться вызовами ОСРВ, поскольку они могут повредить данные ОСРВ. Как вы говорите, приоритеты задач используются xTaskCreate, где 0 - задача с самым низким приоритетом. - person Realtime Rik; 10.05.2018