Эмуляция Arduino Uno с помощью QEMU: прерывания не работают
Итак, я написал этот код для Arduino Uno:
// file qemu.ino
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(millis());
}
А затем скомпилировал и загрузил его в настоящий микроконтроллер. Все работает как надо, печать миллисекунд прошла. Значение millis()
обновляется регулярно.
Затем я попытался выполнить тот же код в QEMU, используя эти команды:
arduino-cli compile -b arduino:avr:uno -e .
qemu-system-avr -M uno -nographic -bios build/arduino.avr.uno/qemu.ino.with_bootloader.bin
Последовательная печать работает, но millis()
все время остается на 0. Так что печатается просто куча нулей.
Дальнейшее исследование исходного кода Arduino выявило проблему: millis()
считывает переменную timer0_millis
, которая обновляется в ISR(TIMER0_OVF_vect)
, то есть в 16-м векторе прерывания. Функция init()
также обеспечивает включение этого прерывания.
Кроме того, поскольку millis()
никогда не обновляется, delay()
и Serial.read()
зависают навсегда.
Итак, вывод такой: прерывания работают на реальном устройстве, но по какой-то причине не работают на QEMU. Может быть я что-то упускаю?
@lch361, 👍1
1 ответ
В документации qemu-system-avr говорится:
[...] Контроллер ATmega, модель которого ограничена устройствами USART и 16-битного таймера, достаточными для запуска приложений на базе FreeRTOS [...]
Это означает, что эмулятор не поддерживает 8-битный таймер 0, который используется функциями синхронизации Arduino, такими как millis()
.
- ATmega328P - проблема с использованием таймера 2 для генерации тона
- Точность синхронизации Arduino nano
- Интервальный таймер на Arduino: Сомнения по поводу библиотеки TimerOne
- Можно ли отсоединить прерывание на определенное время
- Заставить TCNT оставаться ниже OCRxA на ATmega328P
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- Генерация стабильной частоты
- 4-битный счетчик вверх и вниз