// Super helpful thread: // https://forum.arduino.cc/t/metro-m4-express-atsamd51-pwm-frequency-and-resolution/566491 #include "SAMDTimerInterrupt.h" void setup() { Serial.begin(115200); SAMDTimer ITimer0(TIMER_TC3); if (ITimer0.attachInterruptInterval(1000, TimerHandler0)) Serial.println("Starting ITimer0, millis()=" + String(millis())); else Serial.println("Failed to start ITimer0"); // Set up the generic clock (GCLK7) to clock timer TCC0 GCLK->GENCTRL[7].reg = GCLK_GENCTRL_DIV(1) | // Divide the 48MHz clock source by divisor 1: 48MHz/1 = 48MHz GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW GCLK_GENCTRL_GENEN | // Enable GCLK7 //GCLK_GENCTRL_SRC_DFLL; // Select 48MHz DFLL clock source //GCLK_GENCTRL_SRC_DPLL1; // Select 100MHz DPLL clock source GCLK_GENCTRL_SRC_DPLL0; // Select 120MHz DPLL clock source while (GCLK->SYNCBUSY.bit.GENCTRL7); // Wait for synchronization GCLK->PCHCTRL[25].reg = GCLK_PCHCTRL_CHEN | // Enable the TCC0 peripheral channel GCLK_PCHCTRL_GEN_GCLK7; // Connect generic clock 7 to TCC0 // Enable the peripheral multiplexer on pin D7 PORT->Group[g_APinDescription[7].ulPort].PINCFG[g_APinDescription[7].ulPin].bit.PMUXEN = 1; PORT->Group[g_APinDescription[9].ulPort].PINCFG[g_APinDescription[9].ulPin].bit.PMUXEN = 1; // Set the D7 (PORT_PB12) peripheral multiplexer to peripheral (even port number) E(6): TCC0, Channel 0 PORT->Group[g_APinDescription[7].ulPort].PMUX[g_APinDescription[7].ulPin >> 1].reg |= PORT_PMUX_PMUXE(6); PORT->Group[g_APinDescription[9].ulPort].PMUX[g_APinDescription[9].ulPin >> 1].reg |= PORT_PMUX_PMUXO(6); TCC0->CTRLA.reg = TC_CTRLA_PRESCALER_DIV1 | // Set prescaler to 1, 120MHz/1 = 120MHz TC_CTRLA_PRESCSYNC_PRESC; // Set the reset/reload to trigger on prescaler clock TCC0->WAVE.reg = TC_WAVE_WAVEGEN_NPWM; // Set-up TCC0 timer for Normal (single slope) PWM mode (NPWM) while (TCC0->SYNCBUSY.bit.WAVE) // Wait for synchronization TCC0->PER.reg = 5999; // Set-up the PER (period) register 1000Hz PWM while (TCC0->SYNCBUSY.bit.PER); // Wait for synchronization TCC0->CC[0].reg = 2999; // Set-up the CC (counter compare), channel 0 register for 50% duty-cycle while (TCC0->SYNCBUSY.bit.CC0); // Wait for synchronization TCC0->CC[1].reg = 2999; while (TCC0->SYNCBUSY.bit.CC1); TCC0->CTRLA.bit.ENABLE = 1; // Enable timer TCC0 while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization } float phinc; // phase increment float ph; // phase accumulator unsigned long ampl; // amplitude scaling void TimerHandler0(void) { float s, c; ph += phinc; s = sin(ph); c = cos(ph); TCC0->CCBUF[0].reg = ampl * s + 3000; TCC0->CCBUF[1].reg = ampl * c + 3000; analogWrite(A0, s*2047 + 2048); analogWrite(A1, c*2047 + 2048); } uint16_t value; uint16_t oldvalue; void loop() { value = analogRead(A4); if (value < 10) value = 10; phinc = value * (M_PI / 16384); ampl = 1000; //if ((value > oldvalue+5) || (value < oldvalue-5)) // Serial.printf("%d value\n", value); oldvalue = value; }