Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ARM7 от Atmel. Запрет прерываний.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Shein
Доброго всем времени суток.
Столкнулся с таким явлением как вызов обработчика Spurious Interrupt.
Суть вопроса:
Работа с UART через контроллер PDC. Обрабатываются прерывания END_RX и END_TX. Используются два кольцевых буфера, т.е. прием или передача по PDC идет непрерывно. Фактически работа с индексами этих буферов идет и из прерываний, и из основной программы.
Логично, что когда я, например, читаю из приемного буфера, то при обращении к индексам, запрещаю прерывания по приему END_RX. Аналогично, при записи в передающий буфер, при обращении к индексам, запрещаются прерывания передатчика END_TX.
Столкнулся с тем, что при интенсивном обмене данными, программа иногда залетает в Spurious Interrupt. Согласно даташиту, это происходит, если контроллер AIC выдал запрос на прерывание ядру, но на момент чтения вектора обработчика, запрос на прерывание уже был снят.
В процессе отладки программы эта версия абсолютно подтвердилась. Вход в Spurious Interrupt происходит если запрос на прерывание контроллеру AIC пришел в момент обработки инструкции запрета прерывания от приемника или передатчика. Соответственно запрет отрабатывается, бит interrupt pending снимается, и когда ядро читает вектор обработчика из AIC, получается что прерывания-то уже нет.

Собственно вопрос: это нормальная ситуация? Раньше у меня стояла заглушка (бесконечный цикл) на Spurious Interrupt и на всех неиспользуемых векторах в AIC. Когда на Spurious Interrupt поставил обработчик в котором просто формируется подтверждение (запись в AIC_EOICR) программа, в общем стала нормально работать. Но вызовы Spurious таки иногда наблюдаются. Вот я и думаю, оставить как есть, еле же есть некий корректный механизм, как запрещать прерывание без возникновения данного эффекта?
P.S. В догонку: наблюдал это явление на двух процессорах AT91RM3400 и AT91SAM7X256. Картина абсолютно идентичная.
aaarrr
Цитата(Shein @ Jun 8 2012, 18:17) *
Собственно вопрос: это нормальная ситуация? Раньше у меня стояла заглушка (бесконечный цикл) на Spurious Interrupt и на всех неиспользуемых векторах в AIC. Когда на Spurious Interrupt поставил обработчик в котором просто формируется подтверждение (запись в AIC_EOICR) программа, в общем стала нормально работать.

Нормальная ситуация. Как раз заглушка с бесконечным циклом на Spurious - это совершенно не нормально.
Lotor
Эти прерывания типичны не только для атмелов, мне понравилась объяснение в этом документе от nxp - Handling of spurious interrupts in the LPC2000.
jcxz
Цитата(Shein @ Jun 8 2012, 20:17) *
Вот я и думаю, оставить как есть, еле же есть некий корректный механизм, как запрещать прерывание без возникновения данного эффекта?

Корректный механизм в случае работы с UART через кольцевые буфера - вообще не запрещать прерывания. Зачем их запрещать если в кольцевой RX-буфер только один писатель - ISR, а в кольцевой TX-буфер - пишет только фоновый процесс?
Aaron
Если я не ошибаюсь, там же можно два буфера для передачи задавать. Один заполнился - читаем и обрабатываем его спокойно, а второй тем временем заполняется. Зачем запрещать прерывания? Ну и, конечно, из Spurious выходить надо - это по-любому, у меня в одном проекте много блокировок возможно из-за вложенных прерываний, дак там это SPU - обычное явление.
Shein
Народ, спасибо всем большое! sm.gif Вы развеяли мои сомнения. А то ведь я пытался с этим бороться, два дня убил. smile3046.gif
Цитата(jcxz @ Jun 9 2012, 09:56) *
Корректный механизм в случае работы с UART через кольцевые буфера - вообще не запрещать прерывания. Зачем их запрещать если в кольцевой RX-буфер только один писатель - ISR, а в кольцевой TX-буфер - пишет только фоновый процесс?

По сути, почти так и есть, только для всяких проверок (на наличие принятых данных, заполнение буфера) приходится обращаться к индексам, которые изменяются в ISR. Ну и, можно сказать, перестраховался.
prottoss
А если вот такая ситуация к примеру:
1. Фоновый процесс считывает в регистр индекс, дабы увеличить его на 1 с целью записать в FIFO новый байт для отправки.
3. Возникает прерывание по отправке данных. Считывается, опять же индекс из памяти дабы уменьшить индекс FIFO, так как очередной байт отправлен.
4. Декрементированый индекс записывается в память. Обработчик прерывания завершается.
5. Фоновый процесс инкрементирует индекс и записывает его в память.

Как Вам ситуация? sm.gif

ИМХО, запрещать прерывание нужно обязательно перед записью в буфер.
jcxz
Цитата(prottoss @ Jun 10 2012, 20:15) *
А если вот такая ситуация к примеру:
1. Фоновый процесс считывает в регистр индекс, дабы увеличить его на 1 с целью записать в FIFO новый байт для отправки.
3. Возникает прерывание по отправке данных. Считывается, опять же индекс из памяти дабы уменьшить индекс FIFO, так как очередной байт отправлен.
4. Декрементированый индекс записывается в память. Обработчик прерывания завершается.
5. Фоновый процесс инкрементирует индекс и записывает его в память.

Как Вам ситуация? sm.gif

Зачем же делать такое кривое FIFO??? crying.gif
Цитата(prottoss @ Jun 10 2012, 20:15) *
ИМХО, запрещать прерывание нужно обязательно перед записью в буфер.

Если иметь прямые руки и писать FIFO правильно - не нужно! sm.gif
Обычная реализация FIFO для межпроцессного (и даже - межпроцессорного взаимодействия):
Два индекса (у каждого процесса свой).
Каждый процесс (или ISR) модифицирует только свой индекс, чужой индекс он может только читать. Один процесс - только пишет в FIFO, другой - только читает.
Каждый процесс двигает свой индекс записывая или читая в FIFO до тех пор, пока не упрётся в чужой индекс (что является признаком опустошения/заполнения FIFO).
Минус такой реализации - реальная ёмкость FIFO на 1 элемент меньше выделенного для него буфера. Если элементы - байты - это ерунда.
prottoss
Цитата(jcxz @ Jun 10 2012, 21:53) *
Каждый процесс двигает свой индекс записывая или читая в FIFO до тех пор, пока не упрётся в чужой индекс (что является признаком опустошения/заполнения FIFO).
Ага, вот тут то и упрется, когда один процесс изменит, другой тож
jcxz
Читайте внимательнее:
Цитата(jcxz @ Jun 10 2012, 21:53) *

Каждый процесс (или ISR) модифицирует только свой индекс, чужой индекс он может только читать.

prottoss
Цитата(jcxz @ Jun 10 2012, 22:02) *
Читайте внимательнее:
Читайте внимательнее. Никто не запрещает одному индексу переехать через другой.
jcxz
Цитата(jcxz @ Jun 10 2012, 21:53) *

Каждый процесс двигает свой индекс записывая или читая в FIFO до тех пор, пока не упрётся в чужой индекс (что является признаком опустошения/заполнения FIFO).

prottoss
Цитата(jcxz @ Jun 10 2012, 22:07) *
Ваши красные буквы ни как меня не смущают sm.gif Еще раз вам повторяю, что один процесс должен приостановить второй, прежде чем он что то изменит в общих данных
MaslovVG
Цитата(prottoss @ Jun 10 2012, 18:15) *
А если вот такая ситуация к примеру:
1. Фоновый процесс считывает в регистр индекс, дабы увеличить его на 1 с целью записать в FIFO новый байт для отправки.
3. Возникает прерывание по отправке данных. Считывается, опять же индекс из памяти дабы уменьшить индекс FIFO, так как очередной байт отправлен.
4. Декрементированый индекс записывается в память. Обработчик прерывания завершается.
5. Фоновый процесс инкрементирует индекс и записывает его в память.

Здесь вы описываете не FIFO (очередь) а а стек (последний вышол первый вышел). Почитайте Кнут "основные алгоритмы".
jcxz
Цитата(prottoss @ Jun 10 2012, 22:16) *
Еще раз вам повторяю, что один процесс должен приостановить второй, прежде чем он что то изменит в общих данных
Зачем???? И какие данные "общие"?
prottoss
Цитата(MaslovVG @ Jun 10 2012, 22:17) *
Здесь вы описываете не FIFO (очередь) а а стек (последний вышол первый вышел). Почитайте Кнут "основные алгоритмы".
Не имеет значения. пусть будут два индекса - на чтение и на запись. Смысл один - нужно разрулить доступ к данным
jcxz
Разруливается это двумя индексами - у каждого процесса - свой.
Вот типичная реализация (проанализируйте методы read() и write()):
CODE
class clas {
volatile size_t rpos, wpos;
u8 buf[N + 1];
public:
size_t write(int);
int read();
clas() { rpos = wpos = 0; }
}
int clas::read() //если нет данных - возвращает отрицательное
{
int i;
size_t j = rpos;
if (i = j - wpos) {
i = buf[j] + 1;
rpos = ((j) ? j: ncell(buf)) - 1;
}
return i - 1;
}
size_t clas::write(int c) //если не удалось записать (буфер полон) возвращает != 0
{
size_t i, i1, i2;
if (!(i1 = i2 = wpos)) i1 = ncell(buf);
if (i = (--i1 - rpos)) {
buf[i2] = c;
wpos = i1;
}
return i;
}
#define ncell(m) (sizeof(m) / sizeof((m)[0]))
aaarrr
Жарко у вас тут sm.gif

Действительно, запрещать прерывания совсем не обязательно, если есть только два индекса.
Сам долго пользовался подобной реализацией, но потом все же отказался - ущерб от кратковременного запрета прерываний мизерный, а вот незадействованный элемент FIFO раздражает сильно.
jcxz
Только когда пишет один процессор, а читает - другой, тут запрет прерываний не спасёт wink.gif
aaarrr
Цитата(jcxz @ Jun 10 2012, 21:11) *
Только когда пишет один процессор, а читает - другой, тут запрет прерываний не спасёт wink.gif

Ну, у нас тут пока только прерывания обсуждались вроде wink.gif
Genadi Zawidowski
Цитата(aaarrr @ Jun 10 2012, 20:53) *
Действительно, запрещать прерывания совсем не обязательно, если есть только два индекса.

Это могут читать дети! Ваш совет применим, если индексы представлены типами данных, которые на процессоре атомарны.
В случае, когда индексы многобайтные, а компилятор выполняет операцию выборки или присваивания несколькми командами -
всё будет работать не так как ожидает программист.
jcxz
Смотрим на название форума sm.gif
В ARM все 8-/16-/32-разрядные команды сохранения атомарны. Ну если только преднамеренно не разместить их невыровненными...
aaarrr
Цитата(Genadi Zawidowski @ Jun 10 2012, 22:04) *
Это могут читать дети!

Если "дети" пишут реализацию FIFO, то такие грабли только на пользу. Как заметили уже, на ARM такое придется делать специально.
Shein
Цитата(jcxz @ Jun 10 2012, 21:17) *
Смотрим на название форума sm.gif
В ARM все 8-/16-/32-разрядные команды сохранения атомарны. Ну если только преднамеренно не разместить их невыровненными...

Кстати, про атомарность этих операций на ARM'е я провтыкал самым позорным образом 01.gif Да-а, трудно иногда скакать, то AVR/PIC, то ARM...
Убрал запрет прерываний, а сделал просто двойное чтение: если результаты разнятся - перечитать. А выходит и это лишнее.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.