Какие прерывания Cortex-M3 я могу использовать для работы общего назначения? - PullRequest
7 голосов
/ 02 мая 2010

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

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

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

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

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

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

Спасибо

Ответы [ 5 ]

15 голосов
/ 03 мая 2010

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

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

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

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

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

3 голосов
/ 02 мая 2010

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

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

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

Для обработки полученных данных через UART - один метод, который я использовал при работе с более простой системой, которая не имеет полной поддержки задач (т. Е. Задачи циклически перерабатываются в простом цикле while) должен иметь общую очередь для данных, полученных из UART. Когда срабатывает прерывание UART, данные считываются из RDR (регистра данных приема) UART и помещаются в очередь. Уловка, чтобы справиться с этим таким образом, чтобы указатели очереди не были повреждены, состоит в том, чтобы тщательно сделать указатели очереди изменчивыми и убедиться, что только обработчик прерываний изменяет указатель хвоста и что только задача «переднего плана», которая читает данные вне очереди изменил указатель головы. Общий обзор:

  • производитель (обработчик прерывания UART):

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

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

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

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

1 голос
/ 24 ноября 2010

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

1 голос
/ 02 мая 2010

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

0 голосов
/ 04 мая 2010

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

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

...