/* p11_4.c Variable duty cycle PWM to control LED on duration * * This program uses TCC0 to generate periodic waveform outputs. * The program is based on p11_3.c with one change: * The prescaler is configured to divide the clock by 16 to * slow down the frequency so that the output change is * visible by the naked eyes. * * PB30 is used for TCC0 output channel 0 (TCC0/WO[0]), which * is connected to the on-board LED0. You may observe the change * of the duration the light is on because of the change of * duty cycle. * * Tested with Atmel Studio 7 v7.0.1006 and Keil MDK-ARM v5.21a. */ #include "samd21.h" void delayMs(int n); unsigned char* ARRAY_PORT_PINCFG1 = (unsigned char*)®_PORT_PINCFG1; unsigned char* ARRAY_PORT_PMUX1 = (unsigned char*)®_PORT_PMUX1; int main (void) { REG_GCLK_CLKCTRL = 0x401A; /* GCLK0 -> TCC0, TCC1 */ REG_PM_APBCMASK |= 0x00000100; /* enable TCC0 Clock in PM */ REG_TCC0_CTRLA = 1; /* reset */ while (REG_TCC0_CTRLA & 1) {} /* wait till out of reset */ REG_TCC0_CTRLA |= 0x00000400; /* prescaler divided by 16 */ REG_TCC0_WAVE = 2; /* Normal PWM */ REG_TCC0_PER = 16666 - 1; /* period */ REG_TCC0_CC0 = 1000; /* pulse width */ REG_TCC0_DRVCTRL |= 0x00010000; /* invert ch0 output */ REG_TCC0_CTRLA |= 2; /* enable */ ARRAY_PORT_PINCFG1[30] |= 1; /* make PB30 output for TCC0 */ ARRAY_PORT_PMUX1[15] = 0x04; /* PB30 = TCC0/WO[0] */ while(1) { REG_TCC0_CC0 = REG_TCC0_CC0 * 110 / 100; if (REG_TCC0_CC0 > 16665) /* wrap around when reaches 100% */ REG_TCC0_CC0 = 1000; delayMs(400); } } /* millisecond delay based on 1 MHz system clock */ void delayMs(int n) { int i; for (; n > 0; n--) for (i = 0; i < 199; i++) __asm("nop"); }