@@ -415,13 +415,13 @@ describe('timer', () => {
415415 describe ( 'Phase-correct PWM mode' , ( ) => {
416416 it ( 'should count up to TOP, down to 0, and then set TOV flag' , ( ) => {
417417 const { program, instructionCount } = asmProgram ( `
418+ LDI r16, 0x3 ; OCR0A = 0x3; // <- TOP value
419+ OUT 0x27, r16
418420 ; Set waveform generation mode (WGM) to PWM, Phase Correct, top OCR0A
419421 LDI r16, 0x1 ; TCCR0A = 1 << WGM00;
420422 OUT 0x24, r16
421423 LDI r16, 0x9 ; TCCR0B = (1 << WGM02) | (1 << CS00);
422424 OUT 0x25, r16
423- LDI r16, 0x3 ; OCR0A = 0x3;
424- OUT 0x27, r16
425425 LDI r16, 0x2 ; TCNT0 = 0x2;
426426 OUT 0x26, r16
427427
@@ -448,13 +448,13 @@ describe('timer', () => {
448448
449449 it ( 'should clear OC0A when TCNT0=OCR0A and counting up' , ( ) => {
450450 const { program, lines, instructionCount } = asmProgram ( `
451+ LDI r16, 0xfe ; OCR0A = 0xfe; // <- TOP value
452+ OUT 0x27, r16
451453 ; Set waveform generation mode (WGM) to PWM, Phase Correct
452- LDI r16, 0x81 ; TCCR0A = (1 << COM0A1) || (1 << WGM01 );
454+ LDI r16, 0x81 ; TCCR0A = (1 << COM0A1) | (1 << WGM00 );
453455 OUT 0x24, r16
454456 LDI r16, 0x1 ; TCCR0B = (1 << CS00);
455457 OUT 0x25, r16
456- LDI r16, 0xfe ; OCR0A = 0xfe;
457- OUT 0x27, r16
458458 LDI r16, 0xfd ; TCNT0 = 0xfd;
459459 OUT 0x26, r16
460460
@@ -491,6 +491,46 @@ describe('timer', () => {
491491 expect ( cpu . readData ( TCNT0 ) ) . toEqual ( 0xfe ) ;
492492 expect ( gpioCallback ) . toHaveBeenCalledWith ( 6 , PinOverrideMode . Set , 0x2b ) ;
493493 } ) ;
494+
495+ it ( 'should only update OCR0A when TCNT0=TOP in PWM Phase Correct mode (issue #76)' , ( ) => {
496+ const { program, instructionCount } = asmProgram ( `
497+ LDI r16, 0x4 ; OCR0A = 0x4;
498+ OUT 0x27, r16
499+ ; Set waveform generation mode (WGM) to PWM, Phase Correct
500+ LDI r16, 0x01 ; TCCR0A = (1 << WGM00);
501+ OUT 0x24, r16
502+ LDI r16, 0x09 ; TCCR0B = (1 << WGM02) | (1 << CS00);
503+ OUT 0x25, r16
504+ LDI r16, 0x0 ; TCNT0 = 0x0;
505+ OUT 0x26, r16
506+
507+ LDI r16, 0x2 ; OCR0A = 0x2; // TCNT0 should read 0x0
508+ OUT 0x27, r16 ; // TCNT0 should read 0x1
509+ NOP ; // TCNT0 should read 0x2
510+ NOP ; // TCNT0 should read 0x3
511+ IN r17, 0x26 ; R17 = TCNT; // TCNT0 should read 0x4 (that's old OCR0A / TOP)
512+ NOP ; // TCNT0 should read 0x3
513+ NOP ; // TCNT0 should read 0x2
514+ NOP ; // TCNT0 should read 0x1
515+ NOP ; // TCNT0 should read 0x0
516+ NOP ; // TCNT0 should read 0x1
517+ NOP ; // TCNT0 should read 0x2
518+ IN r18, 0x26 ; R18 = TCNT; // TCNT0 should read 0x1
519+ ` ) ;
520+
521+ const cpu = new CPU ( program ) ;
522+ new AVRTimer ( cpu , timer0Config ) ;
523+
524+ // Listen to Port D's internal callback
525+ const gpioCallback = jest . fn ( ) ;
526+ cpu . gpioTimerHooks [ PORTD ] = gpioCallback ;
527+
528+ const runner = new TestProgramRunner ( cpu ) ;
529+ runner . runInstructions ( instructionCount ) ;
530+
531+ expect ( cpu . readData ( R17 ) ) . toEqual ( 0x4 ) ;
532+ expect ( cpu . readData ( R18 ) ) . toEqual ( 0x1 ) ;
533+ } ) ;
494534 } ) ;
495535
496536 describe ( '16 bit timers' , ( ) => {
@@ -638,5 +678,52 @@ describe('timer', () => {
638678 expect ( cpu . readData ( TCNT1 ) ) . toEqual ( 0x4a ) ;
639679 expect ( gpioCallback ) . toHaveBeenCalledWith ( 2 , PinOverrideMode . Toggle , 0x25 ) ;
640680 } ) ;
681+
682+ it ( 'should only update OCR0A when TCNT0=BOTTOM in PWM Phase/Frequency Correct mode (issue #76)' , ( ) => {
683+ const { program, instructionCount } = asmProgram ( `
684+ LDI r16, 0x0 ; OCR1AH = 0x0;
685+ STS 0x89, r16
686+ LDI r16, 0x4 ; OCR1AL = 0x4;
687+ STS 0x88, r16
688+ ; Set waveform generation mode (WGM) to PWM Phase/Frequency Correct mode (9)
689+ LDI r16, 0x01 ; TCCR1A = (1 << WGM10);
690+ STS 0x80, r16
691+ LDI r16, 0x11 ; TCCR1B = (1 << WGM13) | (1 << CS00);
692+ STS 0x81, r16
693+ LDI r16, 0x0 ; TCNT1H = 0x0;
694+ STS 0x85, r16
695+ LDI r16, 0x0 ; TCNT1L = 0x0;
696+ STS 0x84, r16
697+
698+ LDI r16, 0x8 ; OCR1AL = 0x8; // TCNT1 should read 0x0
699+ STS 0x88, r16 ; // TCNT1 should read 0x2 (going up)
700+ LDS r17, 0x84 ; // TCNT1 should read 0x4 (going down)
701+ LDS r18, 0x84 ; // TCNT1 should read 0x2 (going down)
702+ NOP ; // TCNT1 should read 0x0 (going up)
703+ NOP ; // TCNT1 should read 0x1 (going up)
704+ NOP ; // TCNT1 should read 0x2 (going up)
705+ NOP ; // TCNT1 should read 0x3 (going up)
706+ NOP ; // TCNT1 should read 0x4 (going up)
707+ NOP ; // TCNT1 should read 0x5 (going up)
708+ LDS r19, 0x84 ; // TCNT1 should read 0x6 (going up)
709+ NOP ; // TCNT1 should read 0x8 (going up)
710+ LDS r20, 0x84 ; // TCNT1 should read 0x7 (going up)
711+ ` ) ;
712+
713+ const cpu = new CPU ( program ) ;
714+ new AVRTimer ( cpu , timer1Config ) ;
715+
716+ // Listen to Port D's internal callback
717+ const gpioCallback = jest . fn ( ) ;
718+ cpu . gpioTimerHooks [ PORTD ] = gpioCallback ;
719+
720+ const runner = new TestProgramRunner ( cpu ) ;
721+ runner . runInstructions ( instructionCount ) ;
722+
723+ expect ( cpu . readData ( R17 ) ) . toEqual ( 0x4 ) ;
724+ expect ( cpu . readData ( R18 ) ) . toEqual ( 0x2 ) ;
725+ expect ( cpu . readData ( R19 ) ) . toEqual ( 0x6 ) ;
726+ expect ( cpu . readData ( R20 ) ) . toEqual ( 0x7 ) ;
727+ } ) ;
641728 } ) ;
642729} ) ;
0 commit comments