После довольно сложного процесса изучения некоторых вещей о приоритете прерывания я все еще немного застрял, пытаясь понять, какие значения мне разрешено вызывать для 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 - запрещено? Не знаю ... Я запуталась ...