Revisiting the TM4C123

I have had reason to work with the TIVA C launchpad recently. It’s been around a while and can still be found in various retailers. I had never explored the dedicated PWM system on the device which can generate 16 outputs. Three of these are connected to the onboard RGB LEDs so you can vary brightness of them individually. The configuration is pretty straightforward as shown below:

void initPWM()
{
    SYSCTL_RCGCPWM |= (1 << 1); // turn on PWM1
    SYSCTL_RCGC2 = SYSCTL_RCGC2 | (1 << 5); // turn on GPIOF
    SYSCTL_GPIOHBCTL = SYSCTL_GPIOHBCTL | (1 << 5); // turn on AHB access to GPIOF

    // Will drive the LED's using PWM
    // PF1 -> pin 29 -> Red  -> M1PWM5 Module 1, PWM Gen 2, GPIOPCTL value = 5
    // PF2 -> pin 30 -> Blue -> M1PWM6 Module 1, PWM Gen 3, GPIOPCTL value = 5
    // PF3 -> pin 31 -> Green-> M1PWM7 Module 1, PWM Gen 3, GPIOPCTL value = 5
    GPIOF_AFSEL |= (1<<3) | (1 << 2) | (1 << 1); // select alternative function for GPIOF1,2,3
    GPIOF_DEN = GPIOF_DEN | ( (1 << 3) | (1 << 2 ) | (1 << 1) ); // digital mode bits 1,2,3 of GPIOF
    GPIOF_PCTL = (5 << 12) | (5 << 8) | (5 << 4);

    PWM1_PWMENABLE |= (1 << 7)| (1 << 6) | (1 << 5);
    PWM1_PWM2LOAD = 50000000/25000; // 25kHz assuming system clock is 50MHz
    PWM1_PWM3LOAD = 50000000/25000; // 25kHz assuming system clock is 50MHz
    // PWM counter will count down.  When it reaches 0 the output is set to zero
    // when it counts down to the value in the CMPA or CMPB register the output is
    // driven high.  This means that the duty is proportional to the value in CMPA or CMPB
    PWM1_PWM2GENB = (2 << 0) + (3 << 10); // Drive high on match, low on zero (gen b)
    PWM1_PWM3GENA = (2 << 0) + (3 << 6); // Drive high on match, low on zero (gen a)
    PWM1_PWM3GENB = (2 << 0) + (3 << 10); // Drive high on match, low on zero (gen b)
    PWM1_PWM2CMPB = 0;
    PWM1_PWM3CMPA = 0;
    PWM1_PWM3CMPB = 0;
    PWM1_PWM2CTL |= (1 << 0); // enable pwm block
    PWM1_PWM3CTL |= (1 << 0); // enable pwm block
    PWM1_PWMSYNC = 0x0f; // synchronize all counters
}
void setRed(uint32_t Percent)
{
    Percent = (Percent * PWM1_PWM2LOAD)/100;
    PWM1_PWM2CMPB = Percent;
}
void setBlue(uint32_t Percent)
{
    Percent = (Percent * PWM1_PWM3LOAD)/100;
    PWM1_PWM3CMPA = Percent;
}
void setGreen(uint32_t Percent)
{
    Percent = (Percent * PWM1_PWM3LOAD)/100;
    PWM1_PWM3CMPB = Percent;
}

The helper functions setRed,setBlue,setGreen take a single argument which represents the percentage duty. This cuts down resolution but is fine for our purposes. (The maximum possible resolution in this example is 1 in 2000 which is the reload value used by the PWM generator blocks). Full code is available over here on github. Code was developed using Code Composer Studio from Texas Instruments.