wokwi / avr8js

Arduino (8-bit AVR) simulator, written in JavaScript and runs in the browser / Node.js
https://blog.wokwi.com/avr8js-simulate-arduino-in-javascript/
MIT License
461 stars 73 forks source link

Timer2 WGM2=5 OCR2B/OC2B/OC2A output doesn't work #119

Closed drf5n closed 2 years ago

drf5n commented 2 years ago

I was trying to generate a 32768Hz clock on OC2B by using WGM mode 5: Phase Correct,TOP=OC2A mode but I was unable to control OC2B in the mode.

Here is a sketch on the Uno: https://wokwi.com/projects/326859205681087060

The code is:

// simulate a 32kHZ clock on 3, read it into timer1 T1 on 5
// then divide timer1 by 32k and output on 10

// Does WGM=5, Phase Correct TOP=OC2A work on Timer2 in Wokwi?

const int mode = 0; // 1 = test, 0 = sim

void setup() {
  Serial.begin(115200);
  // put your setup code here, to run once:

 pinMode(5,INPUT); // T1 clock input
 pinMode(10,OUTPUT); // pin 10/OC1B 
 pinMode(11,OUTPUT);
 // WGM = 8 Phase & Freq Correct PWM TOP=ICR1
 TCCR1B = 0; // halt clock
 TCCR1A = 0b10 <<COM1B0;  // output on OCR1B
 ICR1 = 16384; // F_OC1B = F_T1/(2*ICR1) for up and down count
 TCNT1 = 0 ; // phase adjust?
 OCR1B = 8192 ; // 50% duty cycle on OC1B 
 //TCCR1B = 0b10<< WGM12 |  0b101 << CS10; // Clock from T1 Rising edge
TCCR1B = 0b10<< WGM12 |  0b111 << CS10; // Clock from T1 Rising edge

 pinMode(3,OUTPUT);

if(mode == 0){  // simulate a clock on timeer2/OC2B
// PIN 3 = OC2B, 32KHZ:  16MHz/32kHz = 500, so toggle every 250
// WGM=5 Phase Correct PWM(OCR2A); 
//
// XXXXXXXX
// Choose one:   WGM=5 doesn't work ????
//const byte myWGM = 0;  const byte myCOM2B = 0b01; // Normal 0xFF toggle OC2B
//const byte myWGM = 1;  const byte myCOM2B = 0b10; // PC 0xFF: clear OC2B on match 
//const byte myWGM = 2;  const byte myCOM2B = 0b01; // CTC OC2A: toggle OC2B on match 
//const byte myWGM = 3;  const byte myCOM2B = 0b01; // Fast 0xFF: toggle OC2B on match 
// ************ These don't work:  
//const byte myWGM = 5;  const byte myCOM2B = 0b00; // PC OC2A: do nothing on match 
//const byte myWGM = 5;  const byte myCOM2B = 0b01; // PC OC2A: reserved OC2B on match 
const byte myWGM = 5;  const byte myCOM2B = 0b10; // PC OC2A: clear OC2B on match 
//const byte myWGM = 5;  const byte myCOM2B = 0b11; // PC OC2A: set OC2B on match 
// ************ 
//const byte myWGM = 7;  const byte myCOM2B = 0b10; // fast OC2A : clear OC2B on match 

const byte myCOM2A = 0b01 ; // toggle OC1B //11 in WGM{0,2,5,7} 

const byte myWGMlow2 = myWGM &0b11;
const byte myWGMhigh2 = myWGM >>2;
 TCCR2B =  0;
 TCCR2A = (myCOM2B << COM2B0) |(myCOM2A <<COM2A0) | (myWGMlow2 << WGM20); //   
 OCR2A = 250;  // OC2B = pin 11 is some WGM modes
 OCR2B = 125;  // OC2B = pin 3
 TCCR2B = (0b001 << CS20) | (myWGMhigh2 << WGM22); 
 //digitalWrite(3,HIGH);
}
}

void report(){
  const unsigned long interval = 250000UL+7*21;
  static unsigned long last = - interval;
  if(micros() - last >= interval){
    last += interval;
    Serial.print("TCNT1: ");
    Serial.print(TCNT1);
    Serial.print(", TCNT2: ");
    Serial.print(TCNT2);
    Serial.print(", tccr2A=0b");
    Serial.print(TCCR2A,BIN);
    Serial.print(", tccr2B=0b");
    Serial.print(TCCR2B,BIN);
    Serial.print("; \n");
  }

}

void loop() {
  // put your main code here, to run repeatedly:

report();
  //delay(0);
  if( mode == 1){
    digitalWrite(3,!digitalRead(3));
  }
}

In the other WGM modes, I was able to generate a clock on pin 3/OC2B, which I could then count from T1, divide, and re-output on pin 10. If you change the commenting to try a different WGM mode, the LEDs toggle, and the T1 count increases.

To get my 32768Hz from 16MHz needs a divide by 500, which I could fit in a phase-correct PWM mode with OC2A=250 up and down, or a toggling mode WGM=2 CTC mode works to get the right frequency, and WGM=7 mode works, but at double the frequency.

-- Also OC2A output doesn't appear to work in Timer2 WGM=5 Maybe it's all Timer2 WGM=5 outputs?

urish commented 2 years ago

Thanks for the detailed report!

I tested this on a physical Arduino (connecting a logic probe to pin 3), these are the results:

image

  1. const byte myWGM = 7; const byte myCOM2B = 0b10;
  2. const byte myWGM = 5; const byte myCOM2B = 0b11;
  3. const byte myWGM = 5; const byte myCOM2B = 0b10;

The other two myWGM = 5 configurations show no output as expected (do nothing/reserved). So I can confirm this is a bug in the simulator.

urish commented 2 years ago

Fix released as AVR8js 0.18.10, and also updated on wokwi.com.

Thanks again for the super detailed report, it's been very helpful!