Timer PWM - RGB LED

In this tutorial i will show how to use the timers to generate a PWM output. The RGB LED that comes in the launchpad will be used to show a variable PWM duty. We will control each color brightness and mix them together to create other colors.

Code made using IAR Workbech free 32kb code size version

What is PWM?

PWM stand for Pulse Width Modulation. It's a signal with a certain frequency that a percentage of the period is high and the rest is low. It can be used to control motors, LED brightness or sometimes send data like to control a servo motor.

How can we control LED brightness with this?

The trick is to switch the LED on and off very fast. The human eye can't notice flicker at high frequencies, that's why you can see images put together moving to form a video. By switching the LED fast enough we won't notice it turning it off but instead it will be less bright. By changing the percentage of the period that is on we change the brightness.

Now code!

Like always don't forget the system clock, at 80Mhz in here.

SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);

Now the timer,

To control the Red LED in PF1 we check the datasheet and see what timer it uses. It's the Timer0 B. Remember that in PWM mode you need to use the timer in split mode.

First set the GPIO to work with the timer:

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); SysCtlDelay(3); GPIOPinConfigure(GPIO_PF1_T0CCP1); GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_1);

When using a alternate function of a GPIO you need to always do 2 things with TivaWare. Use GPIOPinConfigure and GPIOPinTypeTimer, the last being specific for the timer, each peripheral will have a different function but remember you always need 2 things, GPIOPinConfigure + the peripheral specific.

GPIO_PF1_T0CCP1 is for the pin PF1 and Timer0 B. It would be different for other pins and timers, for example, for PF2 Timer1 A it would be GPIO_PF2_T1CCP0.

GPIOPinTypeTimer just takes the GPIO base has the 1st parameter and logical or of the pins as the second parameter.

Second we setup the timer:

Some variables to set up the frequency and duty:

uint32_t Period, dutyCycle; Period = SysCtlClockGet()/100000; //100Khz dutyCycle = Period/2;

The math for the frequency is: System clock / frequency.

Duty cycle should be between 0 and Period. It's not a percentage value. 0% and 100% duty doesn't really work, for that just use simple digital output.

SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); SysCtlDelay(3); TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_B_PWM); TimerLoadSet(TIMER0_BASE, TIMER_B, Period -1); TimerMatchSet(TIMER0_BASE, TIMER_B, dutyCycle);

In timer configure we first split the timer into 16bit and then configure TimerB into PWM mode.

The load is the value that the timer reloads when it reaches 0 so it's our Period value. It's -1 because remember, 0 counts.

Match is when the output goes to LOW, or HIGH if you invert the PWM which is possible. So the bigger the value, the bigger is the percentage the output is LOW (or HIGH if inverted). When the counter reaches 0 and reload the output goes back to HIGH.

Then just enable the timer to start the PWM

TimerEnable(TIMER0_BASE, TIMER_B);

Now to make the Red LED pulse you just need to keep changing the duty cycle with a delay:

while(1){ for(int i=Period-2; i > 0;i--){ TimerMatchSet(TIMER0_BASE, TIMER_B, i); SysCtlDelay(56666); } for(int i=1; i <= Period-2;i++){ TimerMatchSet(TIMER0_BASE, TIMER_B, i); SysCtlDelay(56666); } }

The delay is about 2ms. This will make the LED fade up and down.

I hope you like the tutorial and that now you understand the basics of using the Timer PWM mode.

You can make various combinations

This code bellow configures also the PF2 and PF3 as PWM outputs from Timer1 A and Timer1 B respectively. PF2 is the blue LED and PF3 is the Green LED

/*

This code was made using TivaWare 2.1.0.12573. TivaWare rights are all own byTexas Instruments

This code is to show how to use the timers for basic PWM output. It's used to control the RGB LED in the TM4C123 launchpad that usesthe tm4c123gh6pm MCU.

Luís Afonso */void PWMint();#include "inc/hw_ints.h"#include "inc/hw_timer.h"#include "inc/hw_gpio.h"#include "driverlib/pin_map.h"#include "driverlib/sysctl.c"#include "driverlib/sysctl.h"#include "driverlib/Timer.c"#include "driverlib/Timer.h"#include "driverlib/gpio.c"#include "driverlib/gpio.h" //about 2ms at 80Mhz#define time 56666//PWM frequency in hz uint32_t freq = 100000;int main(){ //Set system clock to 80Mhz SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ); uint32_t Period, dutyCycle; Period = SysCtlClockGet()/freq ; dutyCycle = Period-2; /* Configure PF1 as T0CCP1 Configure PF2 as T1CCP0 Configure PF3 as T1CCP1 */ SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); SysCtlDelay(3); GPIOPinConfigure(GPIO_PF1_T0CCP1); GPIOPinConfigure(GPIO_PF2_T1CCP0); GPIOPinConfigure(GPIO_PF3_T1CCP1); GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3); // /* Configure timer 0 to split pair and timer B in PWM mode Set period and starting duty cycle. */ SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); SysCtlDelay(3); TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_B_PWM); TimerLoadSet(TIMER0_BASE, TIMER_B, Period -1); TimerMatchSet(TIMER0_BASE, TIMER_B, dutyCycle); // PWM /* Configure timer 1 to split pair and timer A and B in PWM mode Set period and starting duty cycle. */ SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); SysCtlDelay(3); TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM|TIMER_CFG_B_PWM); TimerLoadSet(TIMER1_BASE, TIMER_A, Period -1); TimerLoadSet(TIMER1_BASE, TIMER_B, Period -1); TimerMatchSet(TIMER1_BASE, TIMER_A, dutyCycle); TimerMatchSet(TIMER1_BASE, TIMER_B, dutyCycle); //Turn on both timers TimerEnable(TIMER0_BASE, TIMER_B); TimerEnable(TIMER1_BASE, TIMER_A|TIMER_B); //Start by rising Red LED for(int i=Period-2; i > 0;i--){ TimerMatchSet(TIMER0_BASE, TIMER_B, i); SysCtlDelay(time); } while(1){ //Blue brightness goes up - PF2 for(int i=Period-2; i > 0;i--){ TimerMatchSet(TIMER1_BASE, TIMER_A, i); SysCtlDelay(time); } //Red brightness goes down - PF1 for(int i=1; i < Period-1; i++){ TimerMatchSet(TIMER0_BASE, TIMER_B, i); SysCtlDelay(time); } //Green brightness goes up - PF3 for(int i=Period-2; i > 0;i--){ TimerMatchSet(TIMER1_BASE, TIMER_B, i); SysCtlDelay(time); } //Blue brightness goes down - PF2 for(int i=1; i < Period-1; i++){ TimerMatchSet(TIMER1_BASE, TIMER_A, i); SysCtlDelay(time); } //Red brightness goes up - PF1 for(int i=Period-2; i > 0;i--){ TimerMatchSet(TIMER0_BASE, TIMER_B, i); SysCtlDelay(time); } //Green brightness goes down - PF3 for(int i=1; i < Period-1; i++){ TimerMatchSet(TIMER1_BASE, TIMER_B, i); SysCtlDelay(time); } } }