/* test_attiny44_interrupt_irq_test.c Copyright 2022 Giles Atkinson This file is part of simavr. simavr is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. simavr is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with simavr. If not, see . */ #include #include #include #include "sim_irq.h" #include "sim_interrupts.h" #include "tests.h" /* Accumulate log of events for comparison at the end. */ static char log[512]; static char *fill = log; #define LOG(...) \ (fill += snprintf(fill, (log + sizeof log) - fill, __VA_ARGS__)) #define GPIOR1 ((avr_io_addr_t)0x34) // Unused I/O register. /* Callbacks for interrupt events. */ static void any_pending(struct avr_irq_t *irq, uint32_t value, void *param) { LOG("P-%d%s ", value, irq->flags & IRQ_FLAG_FLOATING ? "f": ""); } static void any_running(struct avr_irq_t *irq, uint32_t value, void *param) { LOG("R-%d ", value); } static void ext_pending(struct avr_irq_t *irq, uint32_t value, void *param) { LOG("PX-%d ", value); } static void ext_running(struct avr_irq_t *irq, uint32_t value, void *param) { LOG("RX-%d ", value); } static void pc1_pending(struct avr_irq_t *irq, uint32_t value, void *param) { LOG("PC-%d ", value); } static void pc1_running(struct avr_irq_t *irq, uint32_t value, void *param) { LOG("RC-%d ", value); } static void adc_pending(struct avr_irq_t *irq, uint32_t value, void *param) { LOG("PA-%d ", value); } static void adc_running(struct avr_irq_t *irq, uint32_t value, void *param) { LOG("RA-%d ", value); } static void gpior1_change(struct avr_t *avr, avr_io_addr_t addr, uint8_t v, void *param) { LOG("*-%d ", v); } static const char *expected = "PX-1 P-1 PC-1 P-3 PA-1 P-13 " // Raise three interrupts. "RX-1 R-1 PX-0 P-3f *-1 RX-0 R-0 " // External (INT0) interrupt runs. "RC-1 R-3 PC-0 P-13f *-2 RC-0 R-0 " // Pin change interrupt runs. "RA-1 R-13 PA-0 P-0 *-3 RA-0 R-0 " // ADC interrupt runs. "PX-1 P-1 PC-1 P-3 PA-1 P-13 " // Second round: raise three. "RX-1 R-1 PX-0 P-3f *-1 " // External (INT0) interrupt runs. "RC-1 R-3 PC-0 P-13f *-2 " // Pin change interrupt runs. "RA-1 R-13 PA-0 P-0 *-3 RA-0 " // ADC interrupt runs. "R-3 RC-0 R-1 RX-0 R-0 "; // Unwind stack. int main(int argc, char **argv) { avr_t *avr; avr_irq_t *irq; tests_init(argc, argv); avr = tests_init_avr("attiny44_interrupt_irq_test.axf"); /* Request callbacks on events in the interrupt code.. */ irq = avr_get_interrupt_irq(avr, AVR_INT_ANY); avr_irq_register_notify(irq + AVR_INT_IRQ_PENDING, any_pending, NULL); avr_irq_register_notify(irq + AVR_INT_IRQ_RUNNING, any_running, NULL); irq = avr_get_interrupt_irq(avr, 1); // INT0 - pin PB2 avr_irq_register_notify(irq + AVR_INT_IRQ_PENDING, ext_pending, NULL); avr_irq_register_notify(irq + AVR_INT_IRQ_RUNNING, ext_running, NULL); irq = avr_get_interrupt_irq(avr, 3); // PCINT1 - Port B avr_irq_register_notify(irq + AVR_INT_IRQ_PENDING, pc1_pending, NULL); avr_irq_register_notify(irq + AVR_INT_IRQ_RUNNING, pc1_running, NULL); irq = avr_get_interrupt_irq(avr, 13); // ADC avr_irq_register_notify(irq + AVR_INT_IRQ_PENDING, adc_pending, NULL); avr_irq_register_notify(irq + AVR_INT_IRQ_RUNNING, adc_running, NULL); /* Watch GPIOR1 for interrupt handler activity. */ avr_register_io_write(avr, GPIOR1, gpior1_change, NULL); /* Run program and check results. */ if (tests_run_test(avr, 100000) == LJR_CYCLE_TIMER) fail("Timed out\n"); if (strcmp(expected, log)) fail("\nInternal log: %s.\n Expected: %s.\n", log, expected); tests_success(); return 0; }