Программирование ARM Приоритеты прерываний Cortex-M и приоритеты FreeRTOS Thu, November 21 2019  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

Приоритеты прерываний Cortex-M и приоритеты FreeRTOS Печать
Добавил(а) microsin   

Многие тысячи приложений работают в среде FreeRTOS на микроконтроллерах с ядрами ARM Cortex-M (STM32). Основные проблемы, которые происходят с этим портом FreeRTOS, случаются из-за некорректной настройки приоритетов прерываний. Этого вероятно следовало ожидать, потому что несмотря а то, что организация прерываний ARM Cortex-M очень мощная, она также в некотором роде неуклюжая, и не интуитивно-понятная для инженеров, которые привыкли использовать традиционную схему приоритетов прерываний. Назначение этой статьи (перевод документации [1]) - дать описание, как механизм приоритетов ARM Cortex-M должен использоваться в ядре FreeRTOS.

Примечание: информация в этой статье относится к вложенности приоритетов при использовании FreeRTOS на платформах Cortex-M3, Cortex-M4, Cortex-M4F и Cortex-M7. Она не относится к ядрам Cortex-M0 или Cortex-M0+ cores, в которых нет регистра BASEPRI.

Следует помнить, что хотя схема приоритетов, реализованная в аппаратуре ядра ARM Cortex-M3, может показаться сложной, каждый официальный порт FreeRTOS поставляется с корректно сконфигурированным демонстрационным приложением, которое может использоваться как образец. В дополнении FreeRTOS V7.5.0 добавлен вызов configASSERT(), специально предназначенный для перехвата ситуаций с неправильно сконфигурированным контролером прерываний (NVIC) микроконтроллера ARM Cortex-M. Так что убедитесь, что configASSERT() определен во время разработки приложения.

[Доступные уровни приоритета]

Аппаратура приоритетов Cortex-M. Первое, что нужно знать - общее количество доступных приоритетов определяется общей реализацией, т. е. от всей системы целиком, вплоть до аппаратной системы приоритетов производителя микроконтроллера, использующего ядро ARM Cortex-M. В результате не все микроконтроллеры ARM Cortex-M предоставляют одинаковое количество уникальных приоритетов прерываний.

Архитектура ARM Cortex-M сама по себе позволяет максимум 256 разных приоритетов (существует максимум 8 битов приоритета, поэтому возможны приоритеты от 0 до 0xff включительно), однако большинство, но не все микроконтроллеры, в которых ядро ARM Cortex-M, позволяют использовать только подмножество из этих приоритетов. Например, микроконтроллеры TI Stellaris Cortex-M3 и ARM Cortex-M4 реализуют 3 бита приоритетов. Это дает 8 уникальных значений приоритета. Другой пример - микроконтроллеры NXP LPC17xx ARM Cortex-M3 реализуют 5 бит уровня приоритета, это дает 32 уникальных значений приоритета.

Если в Вашем проекте подключены заголовочные файлы библиотеки CMSIS, то проверьте определение __NVIC_PRIO_BITS, чтобы увидеть, сколько бит приоритетов доступно.

Как это относится к FreeRTOS. Схема вложенности прерываний RTOS делит все доступные приоритеты на 2 группы – те, которые будут маскироваться критическими секциями RTOS, и те, которые на маскируются критическими секциями, и поэтому всегда разрешены. Настройка configMAX_SYSCALL_INTERRUPT_PRIORITY в FreeRTOSConfig.h определяет границу между этими двумя группами. Оптимальное значение для этой установки зависит от количества бит приоритетов, реализованных в микроконтроллере.

[Приоритет вытеснения и субприоритет]

Аппаратура приоритетов Cortex-M. 8-битный регистр приоритетов делится на 2 части: приоритет вытеснения (preempt priority) и субприоритет (subpriority). Количество бит, назначенное на каждую часть, программируется. Приоритет вытеснения определяет, может ли прерывание прервать (вытеснить) уже выполняющееся прерывание. Subpriority определяет, какое прерывание будет выполняться первым, когда два происходят одновременно два прерывания с одинаковым приоритетом вытеснения.

Как это относится к FreeRTOS. Рекомендуется назначить все биты приоритета для бит приоритета вытеснения, не оставляя никаких бит приоритета на subpriority. Любые другие конфигурации усложняют прямую взаимосвязь между установкой configMAX_SYSCALL_INTERRUPT_PRIORITY и приоритетом, назначенным отдельным прерываниям периферийных устройств.

Большинство систем по умолчанию следует желаемой конфигурации, за исключением библиотеки драйверов STM32. Если Вы используете STM32 вместе с STM32 driver library, то убедитесь, что все биты приоритета назначены на биты preempt priority, путем вызова NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); перед запуском RTOS.

[Инверсная взаимосвязь числовых значений приоритетов]

Между нумерацией приоритетов аппаратуре Cortex-M и настройкой логической нумерации приоритетов FreeRTOS существует инверсная взаимосвязь. Если у Cortex-M чем меньше числовое значение приоритета прерывания, тем у него приоритет выше, то у FreeRTOS большему числовому приоритету задачи соответствует более высокий приоритет.

Аппаратура приоритетов Cortex-M. Следующее, что нужно знать - в ядрах ARM Cortex-M малые значения приоритета логически соответствуют более высоким приоритетам прерываний. Например, логический приоритет прерывания, которому назначен числовое значение приоритета 2 будет выше, чем у прерывания, которому назначен числовой приоритет 5. Другими словами, прерывание с числовым уровнем приоритета 2 более приоритетное, чем прерывание с числовым уровнем приоритета 5, хотя число 2 меньше, чем число 5. Для полной ясности: у Cortex-M прерывание, которому назначен числовой приоритет 2, может вытеснить прерывание, которому назначен числовой приоритет 5, но прерывание с приоритетом 5 не может прервать (вытеснить) прерывание с приоритетом 2.

Это не интуитивный аспект приоритезации прерываний ARM Cortex-M, потому что не совпадает с большинством не ARM Cortex-M3 архитектур микроконтроллеров.

Как это относится к FreeRTOS. Функции FreeRTOS, которые заканчиваются на "FromISR", являются безопасными для вызова из обработчика прерывания (interrupt safe), но даже эти функции не могут быть вызваны из прерываний, у которых логический приоритет (не числовой!) выше, чем приоритет, определенный макросом configMAX_SYSCALL_INTERRUPT_PRIORITY (configMAX_SYSCALL_INTERRUPT_PRIORITY определен в файле заголовка FreeRTOSConfig.h). Таким образом, любой ISR, который использует функцию RTOS API, должен быть с установленным вручную приоритетом, на значение, которое как число равно или больше  чем configMAX_SYSCALL_INTERRUPT_PRIORITY. Это гарантирует, что логический приоритет этого ISR равен или меньше логической установки приоритета configMAX_SYSCALL_INTERRUPT_PRIORITY.

Приоритет прерывания Cortex-M по умолчанию равен 0. Это значит самый высокий логический приоритет. Таким образом, никогда не оставляете приоритет по умолчанию для ISR, который использует вызовы interrupt safe RTOS API.

[Внутреннее представление приоритетов Cortex-M]

Аппаратура приоритетов Cortex-M. Ядро ARM Cortex-M сохраняет значения приоритетов прерывания в старших значащих битах своих 8-битных регистрах приоритета прерываний. Например, если реализация микроконтроллера Cortex-M имеет только 3 бита приоритета, то эти 3 бита сдвигаются в биты 5, 6 и 7 соответственно. Биты от 0 до 4 могут иметь любое значение, хотя для наилучшей будущей совместимости они должны быть установлены в 1. Внутреннее представление приоритетов ARM Cortex-M демонстрируется на картинках ниже.

У регистров приоритета Cortex-M всего есть место для максимум 8 бит приоритета. Если, в качестве примера, микроконтроллер реализует только 3 бита из этих восьми, то используются только 3 старшие бита:

Cortex M priority register

На следующей картинке показано, как значение 5 (в двоичной форме 101) сохраняется в регистре приоритета прерывания микроконтроллера, в котором реализованы только 3 бита приоритета. Диаграмма показывает, почему значение 5 (двоичное 00000101) может рассматриваться как 191 (двоичное 10111111), когда 3 бита приоритета сдвинуты в требуемую позицию, и остальные биты установлены в 1:

Cortex M priority register 3bits

На следующей картинке показано, как значение 5 (двоичное 101) сохраняется в регистре приоритета прерывания микроконтроллера, в котором реализованы 4 бита приоритета. Диаграмма показывает, почему значение 5 (двоичное 00000101) может рассматриваться как 95 (двоичное 01011111), когда 4 бита приоритета сдвинуты в требуемую позицию, и остальные биты установлены в 1:

Cortex M priority register 4bits

Как это относится к FreeRTOS. Как было описано выше, важным является тот момент, чтобы ISR, которая делает вызовы RTOS API, имел логический приоритет равный или ниже, чем установлено значением configMAX_SYSCALL_INTERRUPT_PRIORITY (чем меньше логическое значение приоритета тем больше числовое значение приоритета прерывания Cortex-M).

CMSIS, и разные производители микроконтроллеров предоставляют библиотечные функции, которые можно использовать для установки приоритета прерывания. Некоторые библиотечные функции ожидают, чтобы приоритет прерывания был указан в младших значащих битах байта, в то время как другие ожидают указания приоритета прерывания в самых старших битах байта. Проверьте документацию на функцию, которая должна быть вызвана для Вашего случая, так как ошибка здесь может привести к непредсказуемому поведению программы.

Макросы настроек configMAX_SYSCALL_INTERRUPT_PRIORITY и configKERNEL_INTERRUPT_PRIORITY можно найти в файле FreeRTOSConfig.h. Необходимо, чтобы значения приоритетов в них были сдвинуты так, как того требует сама архитектура ядра ARM Cortex-M – они должны быть уже сдвинуты к самым старшим значащим битам байта. По этой причине configKERNEL_INTERRUPT_PRIORITY, которое должно быть установлено в самый низкий уровень приоритета, установлено в 255 (двоичное 11111111) хедера FreeRTOSConfig.h, поставляемого с каждым официальным демо FreeRTOS. Есть несколько причин, почему значение указанно таким способом: ядро RTOS обращается к аппаратуре ARM Cortex-M3 напрямую (без использования каких-либо библиотечных функций сторонних производителей), реализация ядра RTOS появилась раньше реализации большинства библиотечных функций, и эта схема использовалась первыми библиотеками ARM Cortex-M3, вышедшими на рынок.

[Критические секции]

Аппаратура приоритетов Cortex-M. В ядре RTOS реализована поддержка критических секций с использованием регистра BASEPRI архитектуры ядра ARM Cortex-M. Это позволяет ядру RTOS маскировать только подмножество прерываний, предоставляя тем самым более гибкую модель вложенности прерываний.

BASEPRI это битовая маска. Установка BASEPRI в определенное значение маскирует все прерывания, у которых приоритет равен этому значению и ниже (логически). Поэтому нельзя использовать BASEPRI для маскирования прерываний, у которых приоритет 0.

Функции FreeRTOS API, которые безопасны для вызова из ISR, используют BASEPRI для реализации критических секций, безопасных для прерываний (interrupt safe critical sections). BASEPRI устанавливается в configMAX_SYSCALL_INTERRUPT_PRIORITY, когда происходит вход в критическую секцию, и в 0, когда происходит выход из критической секции. Получено множество сообщений об ошибках (bug report), которые утверждают, что BASEPRI должно быть возвращено в свое оригинальное значение при выходе, не просто установлено в 0, но Cortex-M NVIC никогда не примет прерывание, у которого (логический) приоритет ниже текущего выполняемого прерывания – независимо от того, что установлено в BASEPRI. Реализация, которая всегда устанавливает BASEPRI в 0, будет выполнять код быстрее, чем та реализация, которая сохраняет и затем восстанавливает значение BASEPRI (при включенном оптимизаторе компилятора).

Как это относится к FreeRTOS. Ядро RTOS создает критическую секцию записью значения configMAX_SYSCALL_INTERRUPT_PRIORITY в регистр BASEPRI архитектуры ARM Cortex-M. Поскольку прерывания 0 (с самым высоким возможным логическим приоритетом) не могут маскироваться с помощью BASEPRI, configMAX_SYSCALL_INTERRUPT_PRIORITY не должно быть установлено в 0.

Здесь в качестве примеров показаны назначения приоритетов прерываний блоков USART6 и Ethernet микроконтроллера STM32F407xx. Для упрощения здесь приведены только части заголовков и модулей, касающиеся только настройки приоритетов прерывания.

[FreeRTOSConfig.h]

Конфигурационный файл FreeRTOS:

...
 
/* Определения, специфичные для Cortex-M. */
#ifdef __NVIC_PRIO_BITS
 /* __BVIC_PRIO_BITS будет задано, когда используется CMSIS. */
  #define configPRIO_BITS         __NVIC_PRIO_BITS
#else
  #define configPRIO_BITS         4
#endif
 
/* Самый низкий приоритет прерывания, который можно использовать для вызова
   функции установки приоритета. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
 
/* Самый высокий уровень приоритета прерывание, который может использоваться в любом ISR,
   чтобы он был безопасным по отношению к прерываниям функций FreeRTOS API.
   НЕ ВЫЗЫВАЙТЕ ФУНКЦИИ INTERRUPT SAFE FREERTOS API ИЗ ЛЮБОГО ПРЕРЫВАНИЯ,
   У КОТОРОГО ПРИОРИТЕТ ВЫШЕ, ЧЕМ ЭТОТ! (у более высоких приоритетов FreeRTOS
   числовое значение приоритета меньше.) */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
 
...

[settings.h]

Мои настройки приоритета для прерываний аппаратуры USART6 и Ethernet:

// Здесь должны быть указаны значения приоритетов прерываний в интервале
// от configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY-1 (самое высокоприоритетное
// прерывание) до configLIBRARY_LOWEST_INTERRUPT_PRIORITY (самое низкоприоритетное
// прерывание).
#define USART6HW_INTERRUPT_PRIORITY    (configLIBRARY_LOWEST_INTERRUPT_PRIORITY-4)
 
// У Ethernet приоритет аппаратных прерываний выше, чем у USART6:
#define ETHERNETHW_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY-5)

[stm32f4xx_hal_usart.c]

Конфигурация приоритета прерываний приема USART6:

...
__HAL_USART_ENABLE_IT(husart, USART_IT_RXNE);
//__HAL_USART_CLEAR_IT(husart, USART_IT_TXE);
HAL_NVIC_SetPriority(USART6_IRQn, USART6HW_INTERRUPT_PRIORITY, 1);
HAL_NVIC_EnableIRQ(USART6_IRQn);
...

[ethernetif.c]

Конфигурация приоритета прерываний Ethernet:

...
HAL_NVIC_SetPriority(ETH_IRQn, ETHERNETHW_INTERRUPT_PRIORITY, 0);
HAL_NVIC_EnableIRQ(ETH_IRQn);
...

[Ссылки]

1. Running the RTOS on a ARM Cortex-M Core site:freertos.org.
2. STM32: словарик.
3. PM0214 STM32 Cortex®-M4 MCUs and MPUs programming manual site:st.com.
4. FreeRTOS Customisation FreeRTOSConfig.h site:freertos.org.

 

Добавить комментарий


Защитный код
Обновить

Top of Page