aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/peripherals/timer.spec.ts52
-rw-r--r--src/peripherals/timer.ts17
2 files changed, 67 insertions, 2 deletions
diff --git a/src/peripherals/timer.spec.ts b/src/peripherals/timer.spec.ts
index 9330168..609908d 100644
--- a/src/peripherals/timer.spec.ts
+++ b/src/peripherals/timer.spec.ts
@@ -908,6 +908,58 @@ describe('timer', () => {
expect(cpu.readData(R17)).toEqual(0x4);
expect(cpu.readData(R18)).toEqual(0x1);
});
+
+ it('should update OCR0A when TCNT0=TOP and TOP=0 in PWM Phase Correct mode (issue #119)', () => {
+ const { program, instructionCount } = asmProgram(`
+ ; Set waveform generation mode (WGM) to PWM, Phase Correct
+ LDI r16, 0x01 ; TCCR0A = (1 << WGM00);
+ OUT 0x24, r16
+ LDI r16, 0x09 ; TCCR0B = (1 << WGM02) | (1 << CS00);
+ OUT 0x25, r16
+ LDI r16, 0x0 ; TCNT0 = 0x0;
+ OUT 0x26, r16
+
+ IN r17, 0x26 ; R17 = TCNT; // TCNT0 should read 0x0
+ IN r18, 0x26 ; R18 = TCNT; // TCNT0 should read 0x0
+ LDI r16, 0x2 ; OCR0A = 0x2; // TCNT0 should read 0x0
+ OUT 0x27, r16 ; // TCNT0 should read 0x1
+ NOP ; // TCNT0 should read 0x2
+ IN r19, 0x26 ; R19 = TCNT; // TCNT0 should read 0x1
+ `);
+
+ const cpu = new CPU(program);
+ new AVRTimer(cpu, timer0Config);
+
+ const runner = new TestProgramRunner(cpu);
+ runner.runInstructions(instructionCount);
+
+ expect(cpu.readData(R17)).toEqual(0);
+ expect(cpu.readData(R18)).toEqual(0);
+ expect(cpu.readData(R19)).toEqual(0x1);
+ });
+
+ it('should not overrun when TOP < current value in Phase Correct mode (issue #119)', () => {
+ const { program, instructionCount } = asmProgram(`
+ ; Set waveform generation mode (WGM) to PWM, Phase Correct
+ LDI r16, 0x01 ; TCCR0A = (1 << WGM00);
+ OUT 0x24, r16
+ LDI r16, 0x09 ; TCCR0B = (1 << WGM02) | (1 << CS00);
+ OUT 0x25, r16
+ LDI r16, 0xff ; TCNT0 = 0xff;
+ OUT 0x26, r16
+
+ IN r17, 0x26 ; R17 = TCNT; // TCNT0 should read 255
+ `);
+
+ const cpu = new CPU(program);
+ const timer = new AVRTimer(cpu, timer0Config);
+
+ const runner = new TestProgramRunner(cpu);
+ runner.runInstructions(instructionCount);
+
+ expect(cpu.readData(R17)).toEqual(255);
+ expect(timer.debugTCNT).toEqual(0); // TCNT should wrap
+ });
});
describe('16 bit timers', () => {
diff --git a/src/peripherals/timer.ts b/src/peripherals/timer.ts
index 6167394..93b9d19 100644
--- a/src/peripherals/timer.ts
+++ b/src/peripherals/timer.ts
@@ -496,6 +496,11 @@ export class AVRTimer {
}
}
+ /** Expose the raw value of TCNT, for use by the unit tests */
+ get debugTCNT() {
+ return this.tcnt;
+ }
+
private updateWGMConfig() {
const { config, WGM } = this;
const wgmModes = config.bits === 16 ? wgmModes16Bit : wgmModes8Bit;
@@ -637,7 +642,15 @@ export class AVRTimer {
};
private phasePwmCount(value: u16, delta: u8) {
- const { ocrA, ocrB, ocrC, hasOCRC, TOP, tcntUpdated } = this;
+ const { ocrA, ocrB, ocrC, hasOCRC, TOP, MAX, tcntUpdated } = this;
+ if (!value && !TOP) {
+ delta = 0;
+ if (this.ocrUpdateMode === OCRUpdateMode.Top) {
+ this.ocrA = this.nextOcrA;
+ this.ocrB = this.nextOcrB;
+ this.ocrC = this.nextOcrC;
+ }
+ }
while (delta > 0) {
if (this.countingUp) {
value++;
@@ -683,7 +696,7 @@ export class AVRTimer {
}
delta--;
}
- return value;
+ return value & MAX;
}
private timerUpdated(value: number, prevValue: number) {
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.