Skip to content

Commit

Permalink
Merge pull request #441 from gatk555/timer
Browse files Browse the repository at this point in the history
Fix TOV/ICR handling, SEI delay - updated version
  • Loading branch information
buserror committed Aug 9, 2021
2 parents d2aaebd + b653a13 commit ea4c450
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 26 deletions.
39 changes: 19 additions & 20 deletions simavr/sim/avr_timer.c
Expand Up @@ -745,26 +745,25 @@ avr_timer_write_pending(
void * param)
{
avr_timer_t * p = (avr_timer_t *)param;
// save old bits values
uint8_t ov = avr_regbit_get(avr, p->overflow.raised);
uint8_t ic = avr_regbit_get(avr, p->icr.raised);
uint8_t cp[AVR_TIMER_COMP_COUNT];

for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++)
cp[compi] = avr_regbit_get(avr, p->comp[compi].interrupt.raised);

// write the value
// avr_core_watch_write(avr, addr, v); // This raises flags instead of clearing it.

// clear any interrupts & flags
if (avr_regbit_from_value(avr, p->overflow.raised, v))
avr_clear_interrupt_if(avr, &p->overflow, ov);
if (avr_regbit_from_value(avr, p->icr.raised, v))
avr_clear_interrupt_if(avr, &p->icr, ic);

for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++)
if (avr_regbit_from_value(avr, p->comp[compi].interrupt.raised, v))
avr_clear_interrupt_if(avr, &p->comp[compi].interrupt, cp[compi]);

// All bits in this register are assumed to be write-1-to-clear.

if (addr == p->overflow.raised.reg &&
avr_regbit_from_value(avr, p->overflow.raised, v)) {
avr_clear_interrupt(avr, &p->overflow);
}
if (addr == p->icr.raised.reg &&
avr_regbit_from_value(avr, p->icr.raised, v)) {
avr_clear_interrupt(avr, &p->icr);
}

for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) {
if (addr == p->comp[compi].interrupt.raised.reg &&
avr_regbit_from_value(avr, p->comp[compi].interrupt.raised,
v)) {
avr_clear_interrupt(avr, &p->comp[compi].interrupt);
}
}
}

static void
Expand Down
2 changes: 1 addition & 1 deletion simavr/sim/sim_core.h
Expand Up @@ -113,7 +113,7 @@ static inline void avr_sreg_set(avr_t * avr, uint8_t flag, uint8_t ival)
if (flag == S_I) {
if (ival) {
if (!avr->sreg[S_I])
avr->interrupt_state = -2;
avr->interrupt_state = -1;
} else
avr->interrupt_state = 0;
}
Expand Down
30 changes: 25 additions & 5 deletions tests/atmega48_enabled_timer.c
Expand Up @@ -14,8 +14,11 @@
#include "avr_mcu_section.h"
AVR_MCU(F_CPU, "atmega48");

volatile uint8_t count;

ISR(TIMER0_COMPA_vect)
{
++count;
}

int main(void)
Expand All @@ -27,13 +30,30 @@ int main(void)

TCCR0B |= (1 << CS00) | (1 << CS01); // Start timer: clk/64

while ((TIFR0 & (1 << OCF0A)) == 0)
;

// Now interrupt is pending. Try and clear it.

TIFR0 = 0;
if (TIFR0 & (1 << OCF0A))
++count; // Should not clear
TIFR0 = (1 << OCF0A);
if ((TIFR0 & (1 << OCF0A)) == 0)
++count; // Should clear!

sei(); // Enable global interrupts

// here the interupts are enabled, but the interupt
// vector should not be called
sleep_mode();
// Let it run to next interrupt.

// this should not be reached
cli();
sleep_mode();
TIMSK0 = 0; // Disable CTC interrupt

if (count == 3) // Expected
cli();

// Time out if interrupting or count wrong.

for (;;)
sleep_mode();
}

0 comments on commit ea4c450

Please sign in to comment.