Являются ли назначение указателей функций атомарными в Arduino?

Ниже приведены фрагменты из исходного кода библиотеки TimerOne :

// TimerOne.h:
void (*isrCallback)();

// TimerOne.cpp:
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  Timer1.isrCallback();
}

// TimerOne.cpp:
void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
{
  if(microseconds > 0) setPeriod(microseconds);
  isrCallback = isr; // register the user's callback with the real ISR
  TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
  resume();                                                                                            
}

Вопрос: если таймер уже запущен, а основная программа вызывает attachInterrupt(), возможно ли прерывание таймера там во время назначение указателя функции isrCallback = isr;? Затем, с удачным сроком, указатель функции Timer1.isrCallback(); будет состоять частично из старого и частичного нового адреса, вызывая переключение ISR в фиктивное местоположение?

Я полагаю, что это может быть так, поскольку указатели функций, конечно, более одного байта, и доступ к> 1 байт данных не является атомарным. Возможные обходные пути:

  • Всегда вызывайте detachInterrupt(), чтобы убедиться, что таймер не запущен, перед вызовом attachInterrupt(), то есть уточните документы Timer1.
  • Или измените Timer1, временно отключив прерывания переполнения таймера непосредственно перед isrCallback = isr;

Это имеет смысл, или есть что-то в Timer1 источниках или назначениях указателей функций, которые я пропустил?

10 голосов | спросил Joonas Pulakka 2 J0000006Europe/Moscow 2014, 15:19:43

2 ответа


6

Посмотрите на код для attachInterrupt () и detachInterrupt () в /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/WInterrupts.c (ну, вот где они находятся на Mac, так или иначе). Структура файлов Arduino на других операционных системах «вероятно, выглядит аналогичным на более низких уровнях пути).

Похоже, что attachInterrupt () предполагает, что запрос прерывания еще не включен, поскольку он записывает указатель на функцию без принятия каких-либо мер предосторожности. Обратите внимание, что detachInterrupts () отключает целевое прерывание перед записью NULL-указателя на его вектор. Поэтому я бы хотя бы использовал пару detachInterrupt() /attachInterrupt()

Я хотел бы запустить любой такой код в критическом разделе, сам. Кажется, ваш первый способ (отсоединить, затем прикрепить) будет работать, хотя я не могу быть уверен, что он не может пропустить к сожалению прерывание времени. Спецификация для вашего MCU может иметь больше об этом. Но на данный момент я не уверен, что глобальный cli() /sei() тоже не пропустит его. В техническом описании ATMega2560, раздел 6.8, говорится: «При использовании инструкции SEI для включения прерываний команда, следующая за SEI, будет выполняться перед любыми ожидающими прерываниями, как показано в этом примере», по-видимому, подразумевает, что она может буферизовать прерывание, в то время как прерывания отключены.

ответил JRobert 2 J0000006Europe/Moscow 2014, 20:34:59
0

Похоже, у вас есть точка. Логичным было бы отключить прерывания таким образом, чтобы вы не повторно активировали их, если они были отключены в первую очередь. Например:

   uint8_t oldSREG = SREG;  // remember if interrupts are on
  cli();                   // make the next line interruptible
  isrCallback = isr;       // register the user's callback with the real ISR
  SREG = oldSREG;          // turn interrupts back on, if they were on before

  

"При использовании команды SEI для включения прерываний команда, следующая за SEI, будет выполнена перед любыми ожидающими прерываниями, как показано в этом примере"

Цель состоит в том, чтобы вы могли написать такой код:

  sei ();         // enable interrupts
  sleep_cpu ();   // sleep

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

ответил Nick Gammon 24 +03002016-10-24T03:04:30+03:00312016bEurope/MoscowMon, 24 Oct 2016 03:04:30 +0300 2016, 03:04:30

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132