Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с прерываниями в Xmega
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Kantik
Добрый день уважаемые форумчане.
В данный момент активно активно разбираюсь с ATXmega 128A1.
Суть проблемы. По ходу выполнения программы возникает прерывание по переполнению счетчика TCC1, соответ. переход в подпрограмму обработки этого прерывания, подпрограмма выполняется, а вот выход должен быть нештатным, т.е. не по команде reti, а переход по команде rjmp.
Ранее, при работе с обычными мегами, вначале выполнения программы сохранял во временном рег. адрес указателя стека, разрешал прерывание по переполению, глобал. прерывания и т.д. Перед завершением подпрограммы обработки прерывания очишал флаг прерывания по переполнению счетчика, восстанавливал бит I в SREG и затем восстанавливал адрес указателя стека в рег. SPH/SPL и выполнял команду rjmp.
Теперь о проблеме с XMega. Кроме разрешения прерывания по переполнеию выставляется так же уровень в регистре TCC1_INTCTRLA (например высокий), разрешение прерывание высокого уровня в регистре PMIC_CTRL, разрешаются глобальные прерывания в SREG. при возникновении прерывания возникает флаг в регистре PMIC_STATUS. Судя по описанию биты в данном регистре очишаются только при выполнении команды reti. Не очишенный флаг в регистре PMIC_STATUS блокирует возникновение этого перывания в дальнейшем. Возможно ли обойти данную проблему?
demiurg_spb
Цитата(Kantik @ Jun 14 2010, 23:40) *
возникает прерывание по переполнению счетчика TCC1, соответ. переход в подпрограмму обработки этого прерывания, подпрограмма выполняется, а вот выход должен быть нештатным, т.е. не по команде reti, а переход по команде rjmp.
Поделитесь, зачем такой хак используете?
Без этого никак что-ли не обойтись?
Kantik
Цитата(demiurg_spb @ Jun 14 2010, 23:55) *
Поделитесь, зачем такой хак используете?
Без этого никак что-ли не обойтись?

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

Цитата(Kantik @ Jun 15 2010, 00:01) *
Программа обрабатывает сигналы от внешней микросхемы, при этом алгоритм достаточно сложный (например прием сигналов от беспроводного модуля), одновременно необходимо контролировать окно ожидания прихода пакетов и в случае переполнеия окна выполнять некоторые действия по завершению процесса приема и переход в другую ветку. Конечно можно контролировать флаг переполнения вручную , но это неудобно. Как то так.

На самом деле проблема не в алгоритме, его можно модернизировать. Непонятна новая логика работы с прерываниями, получается все стало значительно менее гибко? А вот работа с Event system наоборот очень понравилась.
Duhas
а выставить в прерывании флаг, а потом его обработать не пробовали?

вы по сути рвете программу на части.. она вам такой подход однажды не простит...
V_G
Только что решил аналогичную проблему. Без reti не обойтись, флаг обработки прерывания заданного уровня в PMIC никак не сбрасывается, только через reti. А если флаг не сброшен, система может войти только в прерывание более высокого уровня. Проверено на эмуляторе.

На самом деле это нормально, разработчики xmega проповедуют более строгий подход к программированию, что в конечном итоге даст более надежный код. Так что модифицируйте алгоритм.
Лично я в проблемном прерывании выставляю флаг по его приходу, а обработку выставленного флага сосредотачиваю в основном цикле, вне прерываний. Внутри обработчиков - только критичные ко времени куски.

ЗЫ. Но если хочется обмануть систему, можно засунуть в стек требуемый адрес возврата, а потом выполнить reti. Однако со стеком шутки плохи.
element
Добрый день.
Аналогичная проблема возникла при адаптации многозадачной ОС для XMega. На обычных мегах операционка живёт уже десяток лет, но при запуске на XMeg-е отказалась работать.
Работа системы в следующем: по прерываю таймера обработчик переключает задачи - сохраняет/восстанавливает регистры, стек, точки возврата и (ЭТО ВАЖНО!) регистр флагов SREG. При инициализации системы ячейки контекста задач, хранящие SREG неопределённые (как правило нулевые после сброса) - и это в принципе не важно, т.к. в процессе работы задачи флаги меняются - потом сохраняются и т.д. Выход из диспетчера задач (обработчика прерывания таймера) всегда завершается командой RETI, - т.е. I-бит в SREG поднимается - прерывания разрешаются.
Что получилось в XMeg-е: При выходе из прерывания RETI не поднимал I-бит, прерывания оказались выключенными, ОС зависала на одной задаче.
При детальном изучении поведения I бита и команды RETI выяснилось:
код, не являющийся обработчиком прерывания
CLI
RETI
поднимает бит I
код
RETI
в обработчике прерывания НИКАК не влияет на I-бит.
В общем, проблема решилась просто: добавил команду SEI перед RETI.
Вывод: поведение RETI зависит от текущего состояния PMIC. Никакого волшебства.
Однако, в атмел можно кинуть камень, за НЕОПИСАНИЕ такого поведения команды RETI в своих даташитах.
zombi
Цитата(element @ Sep 18 2011, 19:50) *
выяснилось:
код, не являющийся обработчиком прерывания
CLI
RETI
поднимает бит I
код
RETI
в обработчике прерывания НИКАК не влияет на I-бит.

...
Т.е. для выхода из обработчика прерывания не достаточно одной команды RETI ? надо еще и SEI перед ним лепить?

Шо то слабо верится в такой баг laughing.gif
_Артём_
Цитата(zombi @ Sep 18 2011, 23:48) *
...
Т.е. для выхода из обработчика прерывания не достаточно одной команды RETI ? надо еще и SEI перед ним лепить?

Шо то слабо верится в такой баг laughing.gif


Нет такого бага...
В xmega бит I не сбрасывается при переходе на вектор прерывания, а запрещаются прерывания с более низким уровнем или равным уровнем.

Не надо лепить...
demiurg_spb
Цитата(element @ Sep 18 2011, 20:50) *
В общем, проблема решилась просто: добавил команду SEI перед RETI.
Не в ассемблерной вставке на обычной меге это бы кончилось плачевно. Т.к. производить раскрутку стека (модифицировать SPL+SPH) надо атомарно.
На Xmega это решено видимо как-то иначе?
Navovvol
Вы где нашли таблицу векторов прерываний? всё излазил, ну нигде нет.
Палыч
Цитата(Navovvol @ Sep 20 2011, 09:34) *
Вы где нашли таблицу векторов прерываний? всё излазил, ну нигде нет.

В разделе "PMIC - Programmable Multi-level Interrupt Controller"
Navovvol
Цитата(Navovvol @ Sep 20 2011, 09:34) *
Вы где нашли таблицу векторов прерываний? всё излазил, ну нигде нет.

ААА... всё нашел.

Цитата(Палыч @ Sep 20 2011, 09:53) *
В разделе "PMIC - Programmable Multi-level Interrupt Controller"

Какая то странная теперь таблица векторов 0_о
Это теперь для каждого прерывания добавлять смещение к адресу модуля ? Мда... это ппц самому всё прописывать, а если учитывать объем, то допустить ошибку в расчетах адреса проще простого.
V_G
Цитата(demiurg_spb @ Sep 19 2011, 15:38) *
Цитата
В общем, проблема решилась просто: добавил команду SEI перед RETI.


Не в ассемблерной вставке на обычной меге это бы кончилось плачевно. Т.к. производить раскрутку стека (модифицировать SPL+SPH) надо атомарно.
На Xmega это решено видимо как-то иначе?

Написали же, xmegа в прерываниях не сбрасывает флаг I, и рецепт "добавил команду SEI перед RETI" не есть правильный. Случайно заработало, в следующий раз при аналогичной проблеме не заработает. Ни в mege, ни в xmege не стоит лишний раз дергать флаг I, тем более в прерываниях.
У xmegи вообще трехуровневая система прерываний, и надо очень грамотно расставлять их изначальные приоритеты, не дергая I.


Цитата(Navovvol @ Sep 20 2011, 17:27) *
Это теперь для каждого прерывания добавлять смещение к адресу модуля ? Мда... это ппц самому всё прописывать, а если учитывать объем, то допустить ошибку в расчетах адреса проще простого.

Что Вы имеете в виду? Адреса прерываний по-прежнему фиксированы, никаких проблем в ассемблере не встретил.
Откройте из Студии (у меня 4 версия) файл ATxmega32A4def.inc (или другой под нужный проц), и в разделе "INTERRUPT VECTORS, ABSOLUTE ADDRESSES" увидите их все.
Можно, конечно, добавлять смещение к базовому адресу модуля (в том же файле ниже), но я для себя пока такой необходимости не увидел
Navovvol
Цитата(V_G @ Sep 20 2011, 11:17) *
Что Вы имеете в виду? Адреса прерываний по-прежнему фиксированы, никаких проблем в ассемблере не встретил.
Откройте из Студии (у меня 4 версия) файл ATxmega32A4def.inc (или другой под нужный проц), и в разделе "INTERRUPT VECTORS, ABSOLUTE ADDRESSES" увидите их все.
Можно, конечно, добавлять смещение к базовому адресу модуля (в том же файле ниже), но я для себя пока такой необходимости не увидел

Похоже, что я как то не рационально организовываю таблицу векторов на асме. Копирую таблицу из даташита, чуть-чуть редактирую и получается пример:
.org $0000 rjmp RESET ; Переход на обработку сброса
.org $0002 reti//jmp OSCF_INT_vect //Crystal Oscillator Failure Interrupt vector (NMI)
.org $0004 reti//jmp PORTC_INT_base //Port C Interrupt base
.org $0008 reti//jmp PORTR_INT_base //Port R Interrupt base
.org $000C reti//jmp DMA_INT_base //DMA Controller Interrupt
.............

Так вот, о смещении: у порта С два прерывания INT0 и INT1, значит:

.org $0004 reti//jmp PORTC_INT0_vect // смещение 0х00
.org $0006 reti//jmp PORTC_INT1_vect// смещение 0х02
.org $0008 reti//jmp PORTR_INT_base //Port R Interrupt base
......

стандартными инклудами вообще не пользовался.... Я хз как надо и лучше, но так точно работает.
ILYAUL
QUOTE (Navovvol @ Sep 20 2011, 11:55) *
Похоже, что я как то не рационально организовываю таблицу векторов на асме. Копирую таблицу из даташита, чуть-чуть редактирую и получается пример:
.org $0000 rjmp RESET ; Переход на обработку сброса
.org $0002 reti//jmp OSCF_INT_vect //Crystal Oscillator Failure Interrupt vector (NMI)
.org $0004 reti//jmp PORTC_INT_base //Port C Interrupt base
.org $0008 reti//jmp PORTR_INT_base //Port R Interrupt base
.org $000C reti//jmp DMA_INT_base //DMA Controller Interrupt
.............

Так вот, о смещении: у порта С два прерывания INT0 и INT1, значит:

.org $0004 reti//jmp PORTC_INT0_vect // смещение 0х00
.org $0006 reti//jmp PORTC_INT1_vect// смещение 0х02
.org $0008 reti//jmp PORTR_INT_base //Port R Interrupt base
......

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

Вы знаете зачем перед вектором прерывания стоит .org ? И что она делает?
Navovvol
Цитата(ILYAUL @ Sep 20 2011, 12:11) *
Вы знаете зачем перед вектором прерывания стоит .org ? И что она делает?

могу предположить, что определяет абсолютный адрес.
element
Цитата(zombi @ Sep 19 2011, 00:48) *
...
Т.е. для выхода из обработчика прерывания не достаточно одной команды RETI ? надо еще и SEI перед ним лепить?

Шо то слабо верится в такой баг laughing.gif


Добрый день.

В обычном обработчике прерываний ничего, кроме RETI лепить не нужно.
Вы, видимо, невнимательно читали мой пост. В моём случае такая комбинация необходима для XMeg-и потому, что обработчк прерываний - менеджер задач, он переключает задачи и соответсвенно их контексты, а это значит, что он все системно-критичные объекты сохраняет-восстанавливает для каждой задачи: стек, регистр флагов, набор регистров общего назначения. Таким образом при восстановлении регистра флагов бит I оказывался сброшенным. В обычной меге при входе в прерывание I-бит сбрасывается а при выходе из прерывания достаточно было RETI - там она железно подымала I. Прикол в том, что в XMeg-е при входе в прерывание I-бит не сбрасывается, а блокируется только ЭТОТ уровень прерываний, а прерывания более высокого уровня приоритета могут прервать текущий (согласно даташиту).
Такая схема сделана для работы многоуровневой системы прерываний, потому что если будет сброшен I-бит, то ВООБЩЕ НИКАКИЕ прерывания не сработают.
Команда RETI завязана на PMIC, она просто сообщает контроллеру, что данный уровень приоритетов освободился. Интересно, что в обычном режиме - не из прерывания - RETI всё таки подымает I-бит sm.gif.

Информация для тех - кто играет на мегах и иск-мегах на асме виртуозно, с применением фигур высшего пилотажа. На си там вабще всё компилер разруливает.

И ещё - для того что бы читать/писать указатель стека НЕ НУЖНО атомарная операция (в терминах её трактовки для AVR), но прерывания должны быть запрещены, - иначе - "УПС..."


[quote name='V_G' date='Sep 20 2011, 11:17' post='974064']
Написали же, xmegа в прерываниях не сбрасывает флаг I, и рецепт "добавил команду SEI перед RETI" не есть правильный. Случайно заработало, в следующий раз при аналогичной проблеме не заработает. Ни в mege, ни в xmege не стоит лишний раз дергать флаг I, тем более в прерываниях.
У xmegи вообще трехуровневая система прерываний, и надо очень грамотно расставлять их изначальные приоритеты, не дергая I.



Случайностей в процессоре не бывает.
Приоритеты все грамотно расставлены, поверьте.
А откуда такая боязнь дёргать I-бит? даже в прерываниях?
Прерывание - обычная процедура, просто она вызывается асинхронно по отношению к основной нити программы, реагируя на событие в нужный момент. В обычных мегах, где не было приоритетов, для эмуляции многоуровневой системы прерываний в обработчике я ставил sei, давая возможность более приоритеным событиям прервать текущий уровень.
Я использую архитектуру построения программы клиент-сервер, с системой событий. Прерывания у меня выставляют флаги - далее основной цикл по мере возможностей разгребает события (аналогичноый подход у V_G). Но иногда бывают события, никак не позволяющие отлагательств - например обработка КЗ в IGBT-транзисторе. Здесь и спасает "дёргание I-бита".
demiurg_spb
Цитата(V_G @ Sep 20 2011, 11:17) *
Написали же...
Исправьте каменты в 13 сообщении. Не стоит приписывать мне того, что я не писал.
А суть моего вопроса была в том, как на Xmega решается проблема атомарности модификации регистра SP...
Navovvol
element, если прерывание не сбрасывает I бит, тогда что вам даст SEI перед RETI ?
demiurg_spb
Цитата(V_G @ Sep 20 2011, 11:17) *
Ни в mege, ни в xmege не стоит лишний раз дергать флаг I, тем более в прерываниях.
Абсолютно голословно. Чем это чревато? Поясните на примере обычной меги для конкретики.
Я абсолютно точно знаю что и когда дёргаю, если дёргаю, а главное знаю зачем это нужно...
Вы знакомы с концепциями SST (super simple threading)? Вижу что нет. Почитайте, узнаете много нового.
ReAl
Цитата(Navovvol @ Sep 20 2011, 11:46) *
element, если прерывание не сбрасывает I бит, тогда что вам даст SEI перед RETI ?

Ну, например, даст возможность не инициализировать важные переменные
Цитата(element @ Sep 18 2011, 19:50) *
по прерываю таймера обработчик переключает задачи - сохраняет/восстанавливает регистры, стек, точки возврата и (ЭТО ВАЖНО!) регистр флагов SREG. При инициализации системы ячейки контекста задач, хранящие SREG неопределённые (как правило нулевые после сброса) - и это в принципе не важно,
в частности, образ SREG в контексте задачи.
Если бы в образе SREG была поднята 1-ка, то не нужно было бы уповать на поднятие I командой reti, всё отрабатывало бы по восстановлению SREG.
element
Цитата(ReAl @ Sep 20 2011, 13:26) *
Ну, например, даст возможность не инициализировать важные переменные
в частности, образ SREG в контексте задачи.
Если бы в образе SREG была поднята 1-ка, то не нужно было бы уповать на поднятие I командой reti, всё отрабатывало бы по восстановлению SREG.

Абсолютно верно!
Все важные переменные инициализируются, просто нафига инициализировать то, что не нужно инициализировать?
Подготовить образы SREG с поднятым I для всех задач конечно можно, но тогда первая задача в списке (это именно та задача, в нити которой происходит первичная инициализация процессора) будет с разрешёнными прерываниями, а прерывания можно разрешить только после полной инициализации. Да и не было такой проблемы в меге. В х-меге вылезло-решилось. Поэтому здесь и описал ситуацию, чтобы другие уже не наступали на г...

Кстати, для скептиков, которые считают стрёмным дёргать I, модифицировать стек-поинтер, и т.п. Вы даже не представляете какие софтовые извраты прохавывает процессор. Архитектура AVR очень удобна для работы в системе многозадачки. Оч. не хватает команды групповой записи регистров в память sad.gif , но в авр32 это уже реализовано, там вабще можно миниWindows на асме сляпать sm.gif

хотя идея с поднятым I в образах SREG здоровая, сначала думал так сделать, но решил, что для большей стабильности кода лучше комбинация SEI-RETI

Цитата(demiurg_spb @ Sep 20 2011, 12:52) *
Абсолютно голословно. Чем это чревато? Поясните на примере обычной меги для конкретики.
Я абсолютно точно знаю что и когда дёргаю, если дёргаю, а главное знаю зачем это нужно...
Вы знакомы с концепциями SST (super simple threading)? Вижу что нет. Почитайте, узнаете много нового.


5 баллов!
Navovvol
1. SREG не сохраняется автоматически при запросе прерывания
2. в прерывании бит I не сбрасывается
3. в прерывании нельзя сбросить бит I
Т.О при выходе из прерывания командой RETI бит I не может быть сброшен, если вы сохраняли/восстанавливали SREG, то скорее всего ошибка в его сохранении/восстановлении.
И вообще команда SEI в прерывании ничего вам не даст на Atxmega.
Палыч
Цитата(Navovvol @ Sep 20 2011, 14:37) *
3. в прерывании нельзя сбросить бит I
.....И вообще команда SEI в прерывании ничего вам не даст на Atxmega.

Это - Вы нашли такие отклонения реального "железа" от документации производителя? Или это - Ваши домыслы?
Navovvol
Цитата(Палыч @ Sep 20 2011, 14:45) *
Это - Вы нашли такие отклонения реального "железа" от документации производителя? Или это - Ваши домыслы?

я не правильно выразился.

в общем вот что я имел ввиду:
"Interrupts must be globally enabled for any interrupts to be generated. This is done by setting
the global interrupt enable bit (I-bit) in the CPU Status Register. The I-bit will not be cleared
when an interrupt is acknowledged
. Each interrupt level must also be enabled before interrupts
with the corresponding level can be generated."

doc8210, 95 стр.

т.е. нельзя потерять I, если прерывание "подтверждено"
element
Цитата(Navovvol @ Sep 20 2011, 14:37) *
1. SREG не сохраняется автоматически при запросе прерывания
2. в прерывании бит I не сбрасывается
3. в прерывании нельзя сбросить бит I
Т.О при выходе из прерывания командой RETI бит I не может быть сброшен, если вы сохраняли/восстанавливали SREG, то скорее всего ошибка в его сохранении/восстановлении.
И вообще команда SEI в прерывании ничего вам не даст на Atxmega.


1. Какие откровения...
2. CLI никто не отменял. да и in R16,CPU_SREG; cbr R16,1<<IFLAG ;out CPU_SREG,R16 с успехом работает.
3. смотри п. 2
Читаете внимательно? Ошибок нет. Всё работает. Ситуацию хорошо обрисовал ReAl (см. Сообщение #21)
И вообще, простите, вы совершенно не представляете, о чём говорите.
ILYAUL
Может быть проще объяснить ситуацию.

В MEGA-x для многозадачного уровня , что бы не пропустить важное прерывание - в текущем прерывании нужно было добавлять команду SEI (т.к. флаг при входе сбрасывался) - вложенные прерывания
В XMEGA-x сделали приоритет прерываний , который Вы и задаёте до первой команды SEI. В связи с этим при входе в прерывания флаг I не сбрасывается , но Вы можете сделать это CLI или ( не пробывал может кто и знает) - отключить уровни прерываний , которые не имеют право прервать выполняемое прерывание ( повторюсь - надо уточнить).
_Артём_
Цитата(ILYAUL @ Sep 20 2011, 14:25) *
но Вы можете сделать это CLI или ( не пробывал может кто и знает) - отключить уровни прерываний , которые не имеют право прервать выполняемое прерывание ( повторюсь - надо уточнить).


И сброс бита I, и запрет уровня ненужного прерывания работают...
Navovvol
Цитата(ILYAUL @ Sep 20 2011, 15:25) *
Может быть проще объяснить ситуацию.

В MEGA-x для многозадачного уровня , что бы не пропустить важное прерывание - в текущем прерывании нужно было добавлять команду SEI (т.к. флаг при входе сбрасывался) - вложенные прерывания
В XMEGA-x сделали приоритет прерываний , который Вы и задаёте до первой команды SEI. В связи с этим при входе в прерывания флаг I не сбрасывается , но Вы можете сделать это CLI или ( не пробывал может кто и знает) - отключить уровни прерываний , которые не имеют право прервать выполняемое прерывание ( повторюсь - надо уточнить).

Вот это уже похоже на правду, а то пишут тут, что выход из прерывания теперь связка из SEI и RETI (которая магическим образом отменяет какие то "важные" переменные)
ReAl
Цитата(element @ Sep 20 2011, 12:52) *
хотя идея с поднятым I в образах SREG здоровая, сначала думал так сделать, но решил, что для большей стабильности кода лучше комбинация SEI-RETI
А получили меньшую переносимость без реального повышения стабильности по сравнению с нормальным путём.
Если первой задаче нужно стартовать с запрещёнными прерываниями, то пропишите это явно, либо статически при инициализации этой задачи, либо во время выполнения в чём-то типа os_start(), чтобы она модифицировала образ стека первой задачи (в зависимости от построения оси, как оно будет проще/лучше)
И всё будет «честно», всё будет работать без необходимости подсовывать костыль SEI.
element
В общем, с учётом всех советов и личного опыта система работает стабильно.

При начальной инициализации контекстов в образах SREG устанавливаются I - дальше флаги в любых комбинациях, согласно выполнению задачи меняются, но I уже никуда не девается.
Я просто хотел добится максимальной универсальности ядра - чтобы оно работало на классике и на иксах. Что в итоге и получено.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.