Skip to content

Commit

Permalink
timer: Avoid infinite cycle timer on TCNT write
Browse files Browse the repository at this point in the history
In some situations, it was possible to enter an infinite cycle timer
loop. In avr_timer_tcnt_write, the tov cycle timer registration is not
protected and can register a timer with p->tov_cycles == 0.

The following atmega1280 program demonstrates this issue:

int main() {

	TCCR1A = 0;
	TCCR1B = (1<<WGM12) | (1<<ICES1);
	OCR1B = OCR1A = 960;

	/* Start */
	TCNT1 = 0;
	TCCR1B |= (1<<CS11);

	/* Stop */
	TCCR1B &= ~(1<<CS11);
	TIFR1 |= (1<<OCF1A) | (1<<OCF1B);

	/* Start */
	TCNT1 = 0; /**< Registers timer with tov_cycles == 0. */
	TCCR1B |= (1<<CS11);

	while (1) ;
	return 0;
}
  • Loading branch information
schuay committed Aug 29, 2012
1 parent cbc735e commit 27bab45
Showing 1 changed file with 5 additions and 3 deletions.
8 changes: 5 additions & 3 deletions simavr/sim/avr_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,11 @@ static void avr_timer_tcnt_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t
// printf("%s-%c %d/%d -- cycles %d/%d\n", __FUNCTION__, p->name, tcnt, p->tov_top, (uint32_t)cycles, (uint32_t)p->tov_cycles);

// this reset the timers bases to the new base
p->tov_base = 0;
avr_cycle_timer_register(avr, p->tov_cycles - cycles, avr_timer_tov, p);
avr_timer_tov(avr, avr->cycle - cycles, p);
if (p->tov_cycles > 1) {
avr_cycle_timer_register(avr, p->tov_cycles - cycles, avr_timer_tov, p);
p->tov_base = 0;
avr_timer_tov(avr, avr->cycle - cycles, p);
}

// tcnt = ((avr->cycle - p->tov_base) * p->tov_top) / p->tov_cycles;
// printf("%s-%c new tnt derive to %d\n", __FUNCTION__, p->name, tcnt);
Expand Down

0 comments on commit 27bab45

Please sign in to comment.