Hi joelcrouch,
Welcome to the Arduino Zero forum.
Both the AVR and the ARM processors are capable of controlling both the phase and frequency using dual slope PWM. If you're interested in reading further, it's detailed in the SAMD21 datasheet, page 660, under the heading “Dual Slope PWM Generation”. In dual slope PWM the timer counts up to a given value then counts back down to zero, and so on...
Dual slope PWM on the SAMD21 is provided by the timers TCC0, TCC1 and TCC2. These timers are clocked by one of the processor's generic clocks (GCLK). There are 8 GCLKs in total, 0 to 3 are used by Arduino, but you're free to use the others. It's possible to set up a given GCLK to feed a 48MHz (CPU clock frequency) signal to one of the timers. However, due to the high speed of your 250kHz PWM signal in relation to the 48MHz clock frequency, you'll end up with poor resolution. Here's the calculations:
The frequency for dual slope PWM is determined by:
Frequency = GCLK frequency / (2 * N * PER) where N = prescaler value (CTRLA register)
The value in the PER register determines the maximum value the timer counts up to.
In your case N = 1 (as we'd like to clock the timer as fast as possible), therefore...
Frequency = 48MHz / (2 * 1 * 96) = 250kHz
So the PER should be set at 96 (decimal).
The resolution for dual slope PWM is given by:
Resolution = log(PER + 1)/log(2), therefore:
Resolution at 250kHz = log(96 + 1) / log(2) = 6.6 = 6 bits (rounding down)
To change the PWM pulse width (phase), just load the timer's CCBx register with a value between 0 and 96. 0 outputs 0V (0% duty cycle), 96 outputs 3.3V (100% duty cycle). Loading the CCBx register with 48 gives a 50% duty cycle.
The following code sets up GCLK 4 to feed timer TCC0 with 48MHz. The TCC0 is set up for dual slope PWM operation and connected to ouput D7. To control the PWM output just load the REG_TCC0_CCB3 register with a value between 0 and 96. Using my old multimeter I've sucessfully tested the code for 125kHz, however it's not capable of measuring 250kHz and I haven't got a scope, so I'm unable to test it at this higher frequency.
// Output 250kHz PWM on timer TCC0 (6-bit resolution)
void setup()
{
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide the 48MHz clock source by divisor 1: 48MHz/1=48MHz
GCLK_GENDIV_ID(4); // Select Generic Clock (GCLK) 4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK4
GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source
GCLK_GENCTRL_ID(4); // Select GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Enable the port multiplexer for the digital pin D7
PORT->Group[g_APinDescription[7].ulPort].PINCFG[g_APinDescription[7].ulPin].bit.PMUXEN = 1;
// Connect the TCC0 timer to digital output D7 - port pins are paired odd PMUO and even PMUXE
// F & E specify the timers: TCC0, TCC1 and TCC2
PORT->Group[g_APinDescription[6].ulPort].PMUX[g_APinDescription[6].ulPin >> 1].reg = PORT_PMUX_PMUXO_F;
// Feed GCLK4 to TCC0 and TCC1
REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK4 to TCC0 and TCC1
GCLK_CLKCTRL_GEN_GCLK4 | // Select GCLK4
GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK4 to TCC0 and TCC1
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Dual slope PWM operation: timers countinuously count up to PER register value then down 0
REG_TCC0_WAVE |= TCC_WAVE_POL(0xF) | // Reverse the output polarity on all TCC0 outputs
TCC_WAVE_WAVEGEN_DSBOTH; // Setup dual slope PWM on TCC0
while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization
// Each timer counts up to a maximum or TOP value set by the PER register,
// this determines the frequency of the PWM operation:
REG_TCC0_PER = 96; // Set the frequency of the PWM on TCC0 to 250kHz
while (TCC0->SYNCBUSY.bit.PER); // Wait for synchronization
// Set the PWM signal to output 50% duty cycle
REG_TCC0_CC3 = 48; // TCC0 CC3 - on D7
while (TCC0->SYNCBUSY.bit.CC3); // Wait for synchronization
// Divide the 48MHz signal by 1 giving 48MHz (20.83ns) TCC0 timer tick and enable the outputs
REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV1 | // Divide GCLK4 by 1
TCC_CTRLA_ENABLE; // Enable the TCC0 output
while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
}
void loop() { }