//
// hello.servo-registers.D11C.ino
//
// D11C servo hello-world, registers version
//
// Neil Gershenfeld 11/6/22
//
// This work may be reproduced, modified, distributed,
// performed, and displayed for any purpose, but must
// acknowledge this project. Copyright is retained and
// must be preserved. The work is provided as is; no
// warranty is provided, and users accept all liability.
//

void setup() {
   //
   // set up PWM
   //
   GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(4) | // use clock generator 4
      GCLK_GENCTRL_GENEN | // enable clock generator
      GCLK_GENCTRL_SRC_DFLL48M | // 48MHz source
      GCLK_GENCTRL_IDC; // 50-50 duty cycle
   while (GCLK->STATUS.bit.SYNCBUSY); // sync
   GCLK->GENDIV.reg = GCLK_GENDIV_DIV(1) | // divide by 1
      GCLK_GENDIV_ID(4); // apply to GCLK4
   while (GCLK->STATUS.bit.SYNCBUSY); // sync
   GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // enable clock control
      GCLK_CLKCTRL_GEN_GCLK4 | // select GCLK4
      GCLK_CLKCTRL_ID_TCC0; // connect to TCC0
   while (GCLK->STATUS.bit.SYNCBUSY); // sync
   TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1_Val); // divide by 1
   TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // normal PWM
   while (TCC0->SYNCBUSY.bit.WAVE); // sync
   TCC0->PER.reg = 48e6/50; // 48 MHz/50 Hz period
   while (TCC0->SYNCBUSY.bit.PER); // sync
   TCC0->CC[1].reg = 0; // compare WO[1] for PA05
   while (TCC0->SYNCBUSY.bit.CC1); // sync
   PORT->Group[PORTA].DIRSET.reg = PORT_PA05; // set pin output
   PORT->Group[PORTA].OUTCLR.reg = PORT_PA05; // set pin low
   PORT->Group[PORTA].PINCFG[5].reg |= PORT_PINCFG_PMUXEN; // enable port mux
   PORT->Group[PORTA].PMUX[2].reg = PORT_PMUX_PMUXO_F; // connect pin 2*2+1 to TCC0
   TCC0->CTRLA.reg |= (TCC_CTRLA_ENABLE); // enable TCC
   while (TCC0->SYNCBUSY.bit.ENABLE); // sync
   }

void loop() {
   //
   // rotate servo between limits
   //
   uint32_t minimum = 48e6*0.5e-3; // 0.5 ms at 48 MHz
   uint32_t maximum = 48e6*2.5e-3; // 2.5 ms at 48 MHz
   for (uint32_t compare = minimum; compare < maximum; ++compare) {
      TCC0->CC[1].reg = compare;
      delayMicroseconds(10);
      }
   for (uint32_t compare = maximum; compare > minimum; --compare) {
      TCC0->CC[1].reg = compare;
      delayMicroseconds(10);
      }
}
