Skip to content

Instantly share code, notes, and snippets.

@dwblair
Last active June 2, 2016 20:42
Show Gist options
  • Select an option

  • Save dwblair/052463156457dd38e6c650c7bf9fab33 to your computer and use it in GitHub Desktop.

Select an option

Save dwblair/052463156457dd38e6c650c7bf9fab33 to your computer and use it in GitHub Desktop.
// Output 20kHz PWM on timer TCC0 (8-bit resolution)
void setup()
{
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(3) | // Divide the 48MHz clock source by divisor 3: 48MHz/3=16MHz
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 4 PWM channels: timer TCC0 outputs
const uint8_t CHANNELS = 4;
const uint8_t pwmPins[] = { 2, 5, 6, 7 };
for (uint8_t i = 0; i < CHANNELS; i++)
{
PORT->Group[g_APinDescription[pwmPins[i]].ulPort].PINCFG[g_APinDescription[pwmPins[i]].ulPin].bit.PMUXEN = 1;
}
// Connect the TCC0 timer to the port outputs - port pins are paired odd PMUO and even PMUXE
// F & E specify the timers: TCC0, TCC1 and TCC2
PORT->Group[g_APinDescription[2].ulPort].PMUX[g_APinDescription[2].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;
PORT->Group[g_APinDescription[6].ulPort].PMUX[g_APinDescription[6].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_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_DSBOTTOM; // 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:
// 400 = 20kHz; 800= 10 kHz; 4000 = 2 kHz
REG_TCC0_PER = 4000; // Set the frequency of the PWM on TCC0 to X khz
while(TCC0->SYNCBUSY.bit.PER);
// The CCBx register value corresponds to the pulsewidth in microseconds (us)
REG_TCC0_CCB0 = 200; // TCC0 CCB0 - 50% duty cycle on D2
while(TCC0->SYNCBUSY.bit.CCB0);
REG_TCC0_CCB1 = 200; // TCC0 CCB1 - 50% duty cycle on D5
while(TCC0->SYNCBUSY.bit.CCB1);
REG_TCC0_CCB2 = 200; // TCC0 CCB2 - 50% duty cycle on D6
while(TCC0->SYNCBUSY.bit.CCB2);
REG_TCC0_CCB3 = 200; // TCC0 CCB3 - 50% duty cycle on D7
while(TCC0->SYNCBUSY.bit.CCB3);
// Divide the 16MHz signal by 1 giving 16MHz (62.5ns) 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
pinMode(13, OUTPUT);
}
void loop() {
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for a second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
delay(500); // wait for a
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment