forked from buserror/simavr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make the global interrupt pending IRQ behave consistently, so that the value is always a vector number. Make the floating flag more useful; when set it indicates the next interrupt expected. Remove a call that added no information. Add a test.
- Loading branch information
ga
committed
Apr 11, 2022
1 parent
7c4afd1
commit 38ac00f
Showing
3 changed files
with
240 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
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 <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <avr/io.h> | ||
#include <stdio.h> | ||
#include <avr/interrupt.h> | ||
#include <avr/sleep.h> | ||
#include <util/delay.h> | ||
#include <avr/cpufunc.h> | ||
#include "avr_mcu_section.h" | ||
|
||
AVR_MCU(F_CPU, "attiny44"); | ||
AVR_MCU_VOLTAGES(5000, 5000, 3000) // VCC, AVCC, VREF - millivolts. | ||
|
||
static volatile int nest; | ||
|
||
ISR(INT0_vect) | ||
{ | ||
GPIOR1 = 1; // Signal to test harness | ||
if (nest) | ||
sei(); | ||
} | ||
|
||
ISR(PCINT1_vect) | ||
{ | ||
GPIOR1 = 2; | ||
if (nest) | ||
sei(); | ||
} | ||
|
||
ISR(ADC_vect) | ||
{ | ||
GPIOR1 = 3; | ||
if (nest) | ||
sei(); | ||
} | ||
|
||
void go(void) | ||
{ | ||
|
||
/* Turn on the ADC. */ | ||
|
||
ADCSRA = _BV(ADEN) + _BV(ADSC) + _BV(ADIE); // Enable, start, clk scale = 2 | ||
|
||
/* Wait for ADC. */ | ||
|
||
while ((ADCSRA & (1 << ADIF)) == 0) | ||
; | ||
|
||
sei(); // Three interrupts. | ||
|
||
/* Wait for ADC interrupt. */ | ||
|
||
while (ADCSRA & _BV(ADIF)) | ||
; | ||
cli(); | ||
} | ||
|
||
int main(void) | ||
{ | ||
/* Cause "external" and pin-change interrupts. */ | ||
|
||
GIMSK = _BV(INT0) + _BV(PCIE1); // Enable INTO and PORTB pin change. | ||
MCUCR = 1; // Interrupt on either edge of PB2. | ||
PCMSK1 = _BV(PCINT10); // Pin change interrupt for PB2. | ||
PORTB = _BV(2); // Two interrupts if pull-ups configured. | ||
DDRB = _BV(2); // Make sure of it. | ||
|
||
go(); | ||
|
||
/* Do it again with interrupt nesting. */ | ||
|
||
nest = 1; | ||
PORTB = 0; // Two interrupts. | ||
go(); | ||
|
||
/* Final check: writing to GPIOR1 should have had not effect as the | ||
* handler did not writr thr passed value. | ||
*/ | ||
|
||
if (GPIOR1) | ||
GPIOR1 = 0xff; | ||
|
||
/* Stop test by sleeping with interrupts off. */ | ||
|
||
sleep_cpu(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/* | ||
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 <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#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; | ||
} |