/*
  Bresenham pin toggling/frequency generator
   with Scope https://github.com/Dlloydev/Wokwi-Chip-Scope
        and https://github.com/Dlloydev/Wokwi-Chip-PWM

  Wokwi Uno https://wokwi.com/projects/390819301187622913
  Wokwi Mega: https://wokwi.com/projects/390819455604080641

  for https://forum.arduino.cc/t/three-square-waves/1233317/23
  
*/
int32_t D;
int32_t y = 0;

byte Pins[] = {12,11,10};
byte initalVal[] = {HIGH,LOW,HIGH};

const uint32_t dt = 8;  // chunk time // less than 8us is unstable
// 3/2000 for toggling at 666.6666us / 750Hz
// 3/1000 for toggling at 333.333us / 1500Hz
// 300/9900 for 1515.15Hz matching tone(1500) results
// 2/2000 for toggling at 1000us  / 500Hz
const int32_t dy = 300;  // rise
const int32_t dx = 100000; // run

boolean bresenham(void) {
  const uint32_t interval = dt;
  static uint32_t last = -interval;
  uint32_t now = micros();
  bool retval = false;
  if (now - last >= interval) {
    if (D >= 0 ) {
      ++y;
      digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == HIGH ? LOW : HIGH);
      if (false) { // report
        Serial.print("t:");
        Serial.print(now);
        Serial.print(" D:");
        Serial.print(D);
        Serial.print(" y:");
        Serial.print(y);
        Serial.println();
      }
      D -= dx;
      retval = true;
    }
    D += dy * dt;
    last += interval; // stay phase-locked
  }
  return retval;
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  D = -dx / 2; //phase shift -1/2 cycle
  
  float freq = (dy)/(2*dx/1000000.0);
  Serial.print("Toggle at Float ratio:");
  Serial.print((1.0 * dx) / dy, 3);
  Serial.print("us Bresenham ratio: ");
  Serial.print(dx);
  Serial.print("/");
  Serial.print(dy);
  Serial.print(" Frequency:");
  Serial.print(freq,3);
  Serial.println("Hz");
  pinMode(LED_BUILTIN, OUTPUT);
  byte index = 0;
  for(auto &pin:Pins){
    pinMode(pin,OUTPUT);
    digitalWrite(pin,initalVal[index]);
    ++index;
  }
}

void loop() {
  static byte pin = 0;
  // put your main code here, to run repeatedly:
  if(bresenham()){ // toggle pins in round robin
    digitalWrite(Pins[pin],digitalRead(Pins[pin])==HIGH?LOW:HIGH);
    ++pin;
    if(pin >=3) pin = 0;
  };
}
Loading chip...chip-scope
Loading chip...chip-pwm