Search Microcontrollers

Wednesday, June 5, 2013

Stellaris Launchpad - Coding

In the previous post I illustrated a basic example code using the Stellaris Launchpad and CCS.
While it was indeed an interesting view, it might have surprised some of you since the code was somewhat similar to the MSP430 style more than the more advanced high level programming of the C2000.

Fact is that you can go both ways.

The Stellaris has plenty of RAM, computational power etc, so you might actually embark in bigger, more complex projects.
For those a high level approach is often beneficial.

I would like now to illustrate how the previous problem (blinking the colored led) could be tackled using high level programming style.

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"

int main(void)
{
    volatile unsigned long ulLoop;

     //set system clock
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
                       SYSCTL_OSC_MAIN);

  // Enable the GPIO port that is used for the on-board LED.
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    // Enable the GPIO pins for the LEDS
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);

    unsigned int color = 2;
    while(1)
    {
        // Turn on the color LED.
        GPIOPinWrite(GPIO_PORTF_BASE, color, color);

        // Delay for a bit.
        SysCtlDelay(SysCtlClockGet() / 10 / 3);

        // Turn off the color LED.
        GPIOPinWrite(GPIO_PORTF_BASE, color, 0);
        color = color<<1;
        if (color>8) color =2;
        
// Delay for a bit.
        SysCtlDelay(SysCtlClockGet() / 10 / 3);
    }
}

First thing to notice is that to use those high level libraries, you need to include the appropriate header files, which may vary depending on which peripherals you are planning to use. 
Once that is done, you can forget (well, almost) about all those specific registers and interact a bit more high level with your hardware.
The beauty of this is that the code becomes more readable, still you can chose the style that better suits yours, what I would not recommend is to mix the two approaches.
If you like the high level coding, then you'd  better stick to the functions as black-boxes, but as usual, your mileage may vary.

Happy (high level or low level) coding!

Note : there is one instruction which is not directly related to the LEDs, although it does affect the blinking frequency :

ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | 
                      SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

This actually sets the System Clock, like you probably guessed.
As many other MCUs the Stellaris can source many different internal / external oscillators (SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN), however these feed the onboard PLL system, which you are most likely going to use (SYSCTL_USE_PLL).
The PLL runs at 400MHz (you can find that in the LM4F120HQ datasheet), which is hardware divided by 2, giving a maximum frequency of 200MHz.
Dividing this 200MHz by 4 (SYSCTL_SYSDIV_4) we obtain 50MHz, which is the frequency our clock will run by issuing that instruction.

Note 2 : Curious about the funny formula expressed in the  SysCtlDelay(SysCtlClockGet() / 10 / 3); instruction to specify the delay?
Let's  just start to say that with that value the delay will be 1/10th of second, but where those numbers come from?
The SysCtlClockGet() function returns the number of cpu cycles per seconds, meaning if we are running at 50MHz it will be 50.000.000.
Now, the SysCtlDelay function delays 3 cycles per each loop it does internally and performs the number of loops you specify as a parameter.
This means that if you specify SysCtlDelay(SysCtlClockGet() / 3) the delay will be exactly 1 second, regardless of the CPU frequency you selected.