Atmega собирает и ретранслирует вызовы прерывания
Мне нравится собирать все возможные прерывания и передавать их в альтернативную таблицу прерываний обработчика, которую может установить пользователь.
Для этого я должен:
1) собрать все/любые запросы на прерывание
2) определить, откуда произошло прерывание
3) ретранслировать вызов на другой стол, указанный пользователем.
Если вы знакомы с прерываниями, то знаете, что если вы регистрируете одну функцию для всех обработчиков прерываний, то нет способа идентифицировать источник прерывания. Но регистрация уникального обработчика прерывания, который несет информацию об источнике и вызывает другую функцию для отправки вызова, для каждого прерывания — это пустая трата места в коде. Например: atmega328 имеет 24 обработчика прерываний. Каждый из них, скомпилированный с помощью avr-gcc, занимает 76 байт.
Но у меня есть идея, как можно зарегистрировать одну функцию-обработчик и идентифицировать источник:
00000000 <__vectors>:
0: 0c 94 34 00 jmp 0x68 ; 0x68 <__ctors_end>
4: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
8: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
c: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
Если я определяю обработчик прерывания (даже если он умещается в 4 байта), помещается инструкция jmp. Если его можно заменить, например, на вызов 0xa2 (который может уместиться в 4 байта), его можно использовать для идентификации адреса источника прерывания.
Поскольку call
хранит адрес возврата, функция, запущенная по адресу 0xa2, может прочитать этот адрес и тем самым идентифицировать вызывающего абонента. Затем добавьте дополнительный pop
(извлекает адрес стека, накопленный вызовом
в таблице прерываний) и reti
(для возврата из прерывания обработчик) после тела функции.
Если это может работать теоретически, для достижения этого остается только один вопрос:
Как заменить инструкции jmp
на call
в таблице прерываний?
@Dankó Dávid, 👍0
2 ответа
Лучший ответ:
Таблица векторов прерываний предоставлена среда выполнения C. Это
обычно не предназначено для переопределения пользовательским кодом. Вы можете, однако,
сделать это, если вы замените всю среду выполнения C на свою собственную и скомпилируете свой
скетч с параметром -nostartfiles
.
Я играл в эту игру, когда пытался точно оценить прерывание задержки. См. подробности в этом ответе (ответ длинный, но вы можете сразу перейти к последнему разделу).
Ответ, который я принял, является правильным ответом на проблему, которую я задал. Однако замена среды выполнения C требует присоединения и поддержки большого количества файлов crt.S, изначально связанных с GCC. Чтобы избежать этого, я «несколько раз спал над этой проблемой» и нашел другое решение.
После компиляции хост-приложения, которое должно перенаправлять вызовы прерывания (исходник скрипта). Я написал утилиту, которая перезаписывает все переходы прерываний в начале ihex (source) со смещением к целевому приложению.
Хорошо, это решение не собирает, не идентифицирует и не ретранслирует входящие прерывания, а просто ретранслирует их. Поскольку нет целевого приложения, ничто не разрешает эти прерывания и не вызывает ошибки. Это решение также не требует дополнительного места для кода.
- Заставить TCNT оставаться ниже OCRxA на ATmega328P
- Проблема с таймером 0
- Отправка последовательных данных в прерывании
- Поскольку double и float представляют один и тот же тип данных (обычно), что предпочтительнее?
- Нужна помощь в программировании ардуино на ассемблере
- Как создать задержки на языке ассемблера AVR
- Прерывание переполнения таймера AVR не работает
- Заменить предохранители Arduino Uno (может ли Arduino Uno заменить свои собственные предохранители?)