Какие прерывания Cortex-M3 можно использовать для работы общего назначения?

У меня был бы код,который нужно запустить в результате определенного прерывания.

Я не хочу выполнять его в контексте самого прерывания, но я также не хочу, чтобы он выполнялся в режиме потока.

Я хотел бы запустить его с приоритетом, который ниже, чем прерывание высокого уровня, которое ускорило его запуск, но также приоритет, который выше уровня потока (и некоторых других прерываний).

Я думаю, что нужно использовать один из другие обработчики прерываний.

какие из них лучше всего использовать и какой лучший способ их вызвать?

на данный момент я планирую просто использовать обработчики прерываний для некоторых периферийных устройств, которые я не использую, и вызывать их, устанавливая биты непосредственно через NVIC, но я надеялся, что есть лучший, более официальный способ.

спасибо,

5 ответов


ARM Cortex поддерживает особый вид исключения, называемый PendSV. Кажется, вы можете использовать это исключение именно для выполнения своей работы. Практически все упреждающие RTOSes для ARM Cortex используют PendSV для реализации контекстного переключателя.

чтобы заставить его работать, вам нужно установить приоритет pendsv low (напишите 0xFF в регистр PRI_14 в NVIC). Вы также должны приоритизировать все IRQ выше PendSV (напишите более низкие номера в соответствующих регистрах приоритетов в NVIC). Когда вы будете готовы чтобы обработать все сообщение, запустите PendSV из высокоприоритетного ISR:

*((uint32_t volatile *)0xE000ED04) = 0x10000000; // trigger PendSV

затем процессор ARM Cortex завершит ваш ISR и все другие ISR, которые, возможно, были опережены им, и в конечном итоге он будет привязан к исключению PendSV. Вот где должен быть ваш код для разбора сообщения.

обратите внимание, что PendSV может быть вытеснен другими СИОЗС. Это все хорошо, но вам нужно, очевидно, помнить о защите всех общих ресурсов критическим раздел кода (краткое отключение и включение прерываний). В коре руку, вы отключить прерывания, выполнив ключевое слово __ASM("cpsid я") и разрешить прерывания на слово __ASM("cpsie я"). (Большинство компиляторов языка C имеют встроенные встроенные функции или макросы для этой цели.)


вы используете RTOS? Обычно этот тип вещей обрабатывается с помощью высокоприоритетного потока, который получает сигнал о выполнении некоторой работы прерыванием.

если вы не используете RTOS, у вас есть только несколько задач, и работа, запускаемая прерыванием, не слишком ресурсоемкая, может быть проще всего выполнить работу с высоким приоритетом в контексте обработчика прерываний. Если эти условия не выполняются, то реализация того, о чем вы говорите будет началом самой базовой многозадачной ОС. Это может быть интересный проект сам по себе, но если вы хотите просто выполнить работу, вы можете рассмотреть простой RTOS.

поскольку вы упомянули некоторые особенности о работе, которую вы делаете, вот обзор того, как я справлялся с подобной проблемой в прошлом:

для обработки полученных данных через UART один метод, который я использовал при работе с более простой системой, которая не имеет полной поддержки для постановки задач (т. е. задачи круглого robined я на простой while loop) должен иметь общую очередь для данных, полученных от UART. Когда срабатывает прерывание UART, данные считываются из RDR UART (receive Data Register) и помещаются в очередь. Трюк, чтобы справиться с этим таким образом, чтобы указатели очереди не были повреждены, - это тщательно сделать указатели очереди изменчивыми и убедиться, что только обработчик прерываний изменяет указатель хвоста и что только "передний план" задача, считывающая данные из очереди, изменила указатель head. Обзор высокого уровня:

  • producer (обработчик прерываний UART):

    1. читать queue.head и queue.tail на местных жителей;
    2. увеличить локальный указатель хвоста (не фактический queue.tail указатель). Оберните его в начало буфера очереди, если вы увеличили его после окончания буфера очереди.
    3. сравнить local.tail и local.head - если они равны, очередь заполнена, и вам придется делать все, что подходит для передачи ошибок.
    4. в противном случае вы можете записать новые данные, где local.tail точки
    5. только сейчас вы можете установить очередь.хвост = = местный.хвост!--32-->
    6. возврат из прерывания (или обработка других задач, связанных с UART, если это необходимо, например, чтение из очереди передачи)
  • потребитель (на переднем плане 'задача')

    1. читать queue.head и queue.tail на местных жителей;
    2. если local.head ==local.tail очередь пуста; вернуться, чтобы следующая задача сделать некоторую работу
    3. прочитайте байт, на который указывает local.head
    4. инкремент local.head и оберните его в случае необходимости;
    5. set queue.head = local.head
    6. перейти к шагу 1

убедитесь в том, что queue.head и queue.tail are volatile (или напишите эти биты в сборке), чтобы убедиться, что нет проблем с последовательностью.

теперь просто убедитесь, что ваша очередь данных UART received достаточно велика, что она будет содержать все байты, которые могут быть получены до того, как задача переднего плана получит шанс запустить. Задача переднего плана должна вытащить данные из очереди в собственные буферы, чтобы создать сообщения для задачи "обработчик сообщений".


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


то, что вы просите, довольно просто на Cortex-M3. Вам нужно включить регистр перемешивания, чтобы вы могли запускать ISR с низким приоритетом с помощью программного обеспечения. Когда высокоприоритетный ISR завершает работу с критическим материалом, он просто запускает прерывание с низким приоритетом и выходит. NVIC будет затем хвостовой цепью к обработчику с низким приоритетом, если нет ничего более важного.


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

"программное обеспечение может имитировать прерывание, устанавливая любой флаг ожидания прерывания на логику 1. Если для флага включены прерывания, будет сгенерирован запрос прерывания, и процессор будет вектор к адресу ISR, связанному с ожидающим прерывания флаг."