Является ли хорошей встроенной практикой программирования отключение прерывания в прерывании?

Я хочу реализовать что-то в процессоре ARM Cortex-M3 (с NVIC). У меня ограниченные знания о встроенных системах, но я знаю, что процедура ISR должна быть максимально простой.

Теперь у меня есть следующая проблема: у меня есть процедура прерывания, которая вызывается при получении сообщения CAN. В одном случае мне нужно вычислить какую-то трудоемкую задачу с CAN-сообщением, задача которой не может быть прервана другим CAN-сообщением, но во время этой операции могут обслуживаться другие прерывания. Моя идея заключается в следующем:

  1. Сообщение CAN получено, ISR запущен, выполните несколько простых действий (например, установка флагов)
  2. Отключите прерывания CAN в процедуре CAN ISR. Также сохраните сообщение CAN в глобальной переменной, чтобы его можно было получить в основном цикле.
  3. В основном цикле выполните трудоемкую задачу.
  4. После этой задачи снова включите обработку прерываний CAN.

Это хорошая (или не совсем плохая) идея или я должен сделать это по-другому?


person Zoltán Várnagy    schedule 25.01.2016    source источник
comment
Незнаю - что у вас с системой задач? Потоки и семафоры?   -  person Martin James    schedule 25.01.2016
comment
В общем, оставлять прерывания замаскированными в течение длительного времени - это то, чего вам следует избегать, если можно использовать лучшую схему управления потоком.   -  person Martin James    schedule 25.01.2016
comment
Возможно, используйте кольцевой буфер, достаточно большой для хранения 2 или более сообщений (или пару буферов, которые вы чередуете). Тогда вам не нужно копировать данные, и следующее сообщение CAN может быть получено во время обработки первого.   -  person Weather Vane    schedule 25.01.2016
comment
@WeatherVane Ему придется скопировать данные из аппаратного буфера CAN в ОЗУ, это неизбежно. Так что нет смысла иметь больше буферов, чем один. Аппаратное обеспечение CAN обычно имеет несколько внутренних буферов, поэтому вам не нужно беспокоиться о том, какой буфер заполняется, что делается и т. д. Обо всем этом позаботятся в момент срабатывания CAN ISR.   -  person Lundin    schedule 25.01.2016
comment
Если ввод с шины «прерывистый», как это часто бывает, когда вы ограничены только 8 байтами на передачу, тогда пул буферов, т.е. более одного, не является необоснованным.   -  person Martin James    schedule 25.01.2016


Ответы (2)


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

В этом случае вы должны воспользоваться тем, что сам ISR не прерывается. Вы можете создать простой семафор с логической переменной, и, поскольку прерывание, которое ее устанавливает, является непрерываемым, вам даже не нужно беспокоиться об атомарном доступе к этому логическому значению. C-подобный псевдокод для обработчика банок:

typedef struct
{
  bool busy;
  can_msg_t msg;
} special_msg_t;

// must be volatile, to prevent optimizer-related bugs:
volatile static special_msg_t special = { false, {0} };

interrupt void can_isr (void)
{
  // non-interruptable ISR, no other interrupt can fire

  if(id==SPECIAL && !special.busy)
  {
    special.busy = true;
    // right here you can open up for more interrupts if you want
    memcpy(&special.msg, &new_msg, size);
  }
}

result_t do_things_with_special (void) // called from main loop
{
  if(!special.busy) 
    return error; // no new message received, no can do

  // do things with the message

  special.busy = false; // flag that processing is done
  return ok;
}
person Lundin    schedule 25.01.2016
comment
Обратите внимание, что в этом коде предполагается, что нет другого буфера, кроме аппаратного буфера CAN. В противном случае вы можете немного ускорить ISR, поменяв местами указатели вместо того, чтобы делать твердую копию буфера. - person Lundin; 25.01.2016
comment
Не будет ли безопаснее открываться для прерываний после того, как данные из new_msg будут скопированы? - person AlphaGoku; 22.02.2018

Процедура ISR должна быть максимально простой. <Бр/>

Точно.

Существует концепция ядра Linux, называемая нижняя половина. i.e Сохранение ISR как можно более простым. Остальные операции обработки прерывания откладываются на более позднее время.

Существует множество способов реализовать нижнюю половину, например задачи, рабочие очереди и т. д.

Предлагаем прочитать следующие ссылки
http://www.makelinux.net/ldd3/chp-10-sect-4
http://www.ibm.com/developerworks/library/l-tasklets/

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

person Jeyaram    schedule 25.01.2016
comment
Можете ли вы действительно втиснуть ядро ​​Linux в Cortex-m3... и даже если сможете, хорошая ли это идея? Я предполагаю, что это голый металлический MCU. - person Lundin; 25.01.2016
comment
@Lundin, я предположил, что это встроенная система, в которой работает Linux. - person Jeyaram; 25.01.2016
comment
Да, я забыл упомянуть, что это простой микроконтроллер без ОС, моя ошибка. - person Zoltán Várnagy; 25.01.2016
comment
Linux будет работать на Cortex-m3, и это всего ~ 300k-1M при минимальном планировщике и управлении памятью. Файловые системы, сети и т. д. занимают много места в коде. Тем не менее, если вы используете только такой минимальный набор, возможно, будут доступны лучшие решения в зависимости от ваших конкретных потребностей. См.: Минимальный размер ядра Linux - person artless noise; 25.01.2016