From f16d9f9f48fb5e74ab10fe79a8206223342d5010 Mon Sep 17 00:00:00 2001 From: Uri Shaked Date: Tue, 28 Apr 2020 23:42:20 +0300 Subject: fix(timer): incorrect high counter byte behavior According to the datasheet, the value of the high byte of the counter for 16-bit timers (such as timer 1) is only updated when the low byte is being read/written. close #37 --- src/peripherals/timer.ts | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) (limited to 'src/peripherals/timer.ts') diff --git a/src/peripherals/timer.ts b/src/peripherals/timer.ts index ebd7b58..04c09aa 100644 --- a/src/peripherals/timer.ts +++ b/src/peripherals/timer.ts @@ -191,16 +191,24 @@ export class AVRTimer { private ocrB: u16 = 0; private timerMode: TimerMode; private topValue: TimerTopValue; + private tcnt: u16 = 0; private tcntUpdated = false; constructor(private cpu: CPU, private config: AVRTimerConfig) { this.updateWGMConfig(); - this.registerHook(config.TCNT, (value: u16) => { - this.TCNT = value; + this.cpu.readHooks[config.TCNT] = (addr: u8) => { + if (this.config.bits === 16) { + this.cpu.data[addr + 1] = this.tcnt >> 8; + } + return (this.cpu.data[addr] = this.tcnt & 0xff); + }; + + this.cpu.writeHooks[config.TCNT] = (value: u8) => { + const highByte = this.config.bits === 16 ? this.cpu.data[config.TCNT + 1] : 0; + this.tcnt = (highByte << 8) | value; this.tcntUpdated = true; - this.timerUpdated(value); - return true; - }); + this.timerUpdated(); + }; this.registerHook(config.OCRA, (value: u16) => { // TODO implement buffering when timer running in PWM mode this.ocrA = value; @@ -234,19 +242,6 @@ export class AVRTimer { this.cpu.data[this.config.TIFR] = value; } - get TCNT() { - return this.config.bits === 16 - ? this.cpu.dataView.getUint16(this.config.TCNT, true) - : this.cpu.data[this.config.TCNT]; - } - - set TCNT(value: u16) { - this.cpu.data[this.config.TCNT] = value & 0xff; - if (this.config.bits === 16) { - this.cpu.data[this.config.TCNT + 1] = (value >> 8) & 0xff; - } - } - get TCCRA() { return this.cpu.data[this.config.TCCRA]; } @@ -306,12 +301,12 @@ export class AVRTimer { if (divider && delta >= divider) { const counterDelta = Math.floor(delta / divider); this.lastCycle += counterDelta * divider; - const val = this.TCNT; + const val = this.tcnt; const newVal = (val + counterDelta) % (this.TOP + 1); // A CPU write overrides (has priority over) all counter clear or count operations. if (!this.tcntUpdated) { - this.TCNT = newVal; - this.timerUpdated(newVal); + this.tcnt = newVal; + this.timerUpdated(); } const { timerMode } = this; if ( @@ -341,12 +336,13 @@ export class AVRTimer { } } - private timerUpdated(value: u8) { + private timerUpdated() { + const value = this.tcnt; if (this.ocrA && value === this.ocrA) { this.TIFR |= OCFA; if (this.timerMode === TimerMode.CTC) { // Clear Timer on Compare Match (CTC) Mode - this.TCNT = 0; + this.tcnt = 0; this.TIFR |= TOV; } } -- cgit v1.2.3