Search Microcontrollers

Showing posts with label Code Composer Studio. Show all posts
Showing posts with label Code Composer Studio. Show all posts

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.

Tuesday, October 16, 2012

C2000 launchpad - code skeleton

Maybe I am just lazy, maybe laziness is a bit "the geek way".

Each time I start a new project I like to copy from a skeleton, some kind of template instead of typing everything from scratch.
The real reason, I think, is that in most of the cases I cannot recall how to start and with the C2000 Launchpad I always forget something, so I created a file with all the steps and code snippets.

I am posting it here, just in case it might turn useful for others.

First, in CCS start a new project (FIle, new Project, CCS Project )


Then  set the basic project properties (see the highlighted parts)


Some tweaks are then needed in the project properties after the project is created, right click the project name in the project explorer, select properties and add the laiunchpad specific location for the include files.
You may need to adjust that path according to your ControlSuite install dir


Finally add the library


You are now good to go, open your main.c file and copy & paste the following skeleton

Update : Make sure you select the correct linker command file, by mistake I selected 28027 instead of F28027 and spent some time to figure out why the program would not fit in memory according to the linker.



//-------------------------------------------------------

#include <stdio.h>
#include <file.h>

#include "DSP28x_Project.h"     // DSP28x Headerfile

#include "f2802x_common/include/pll.h"
#include "f2802x_common/include/clk.h"
#include "f2802x_common/include/wdog.h"

#include "f2802x_common/include/flash.h"
#include "f2802x_common/include/gpio.h"
#include "f2802x_common/include/pie.h"
#include "f2802x_common/include/adc.h"
#include "f2802x_common/include/sci.h"
#include "f2802x_common/include/sci_io.h"


extern void DSP28x_usDelay(Uint32 Count);

// you probably need these
CPU_Handle myCpu;
PLL_Handle myPll;
WDOG_Handle myWDog;
CLK_Handle myClk;

// these are optional
ADC_Handle myAdc;
FLASH_Handle myFlash;
GPIO_Handle myGpio;
PIE_Handle myPie;
SCI_Handle mySci;




void setup_handles()
{

    myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));
    myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));
    myWDog = WDOG_init((void *)WDOG_BASE_ADDR, sizeof(WDOG_Obj));
    myCpu = CPU_init((void *)NULL, sizeof(CPU_Obj));

    myFlash = FLASH_init((void *)FLASH_BASE_ADDR, sizeof(FLASH_Obj));
    myGpio = GPIO_init((void *)GPIO_BASE_ADDR, sizeof(GPIO_Obj));
    myPie = PIE_init((void *)PIE_BASE_ADDR, sizeof(PIE_Obj));
    mySci = SCI_init((void *)SCIA_BASE_ADDR, sizeof(SCI_Obj));
    myAdc = ADC_init((void *)ADC_BASE_ADDR, sizeof(ADC_Obj));


}

void init_system()
{
  WDOG_disable(myWDog);
  (*Device_cal)();
  CLK_setOscSrc(myClk, CLK_OscSrc_Internal);
  PLL_setup(myPll, PLL_Multiplier_12, PLL_DivideSelect_ClkIn_by_2);

  PIE_disable(myPie);
  PIE_disableAllInts(myPie);
  CPU_disableGlobalInts(myCpu);
  CPU_clearIntFlags(myCpu);
#ifdef _FLASH
    memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
#endif
}

void main()
{
  setup_handles();
  init_system();
}
//---------------------------------------------

Note that this is just a skeleton, you may need to remove parts you may not need such as include files, handles etc (unless the linker is smart enough to get rid of them, which I think it's something we might expect).

Also, you will need to add specific peripheral initialization according to your needs and... your program.