Sunday, June 26, 2016

C2000 programming basics, code skeleton

In this article we're going to put together our first C2000 application to control the on-board LEDs.
Parts of this article are based on an old article from the Forty-Two, and now? blog. Huge thanks to that guy, as I learned some of the basics there - I'm just going to extend and update that article a bit here, as the original one was written in 2012.


Okay, suppose you installed the latest CCS (6.1.3 at the time of writing this article) and controlSUITE (3.3.9) to their default locations.
Let's start CCS, and select File -> New -> CCS Project.
In the popping up window, select '2802x Piccolo' as the Target, and then select either 'Experimenter's Kit - Piccolo F28027' or 'TMS320F28027' - it doesn't matter which one, as they're exactly the same (confirmed by looking at the XMLs under ccsv6\ccs_base\common\targetdb). Anyways, I chose 'TMS320F28027'.
We have an on-board XDS100v1 USB Debug Probe, so select that in the Connection drop-down.


At this point, you will want to verify the connection. For this, we need to get familiar with the switches on the LaunchPad. If you didn't do so already, download the C2000 LaunchPad User's Guide and start reading it from page 7, which should give you a (very) basic understanding of the switches.
To put it simply, S4 (the big switch) connects the Piccolo SCI peripheral (C2000 UART peripheral) to the XDS100 UART channel, which allows UART communication with the device through the USB port. For now, this switch should be in the UP position - obviously, if we want to connect an external UART device, we need to switch this to DOWN.
S1 contains the boot mode selection switches - unfortunately, the LaunchPad User's Guide really only tells the very basics, so let's download the TMS320x2802x Piccolo Boot ROM Reference Guide and start reading from page 17, which explains these switches in detail.
Since we want  to use the XDS100 emulator to upload and debug our application, we need to use emulation boot mode - keep S1 in the UP position, that is. In this mode, S2 and S3 is ignored, so I'm not really going to explain them - the Boot ROM reference guide describes them pretty well.

Now, once you connect the LaunchPad through USB to your computer and install the necessary drivers (this should be done automatically), you should be able to successfully verify the connection in this window.


Before pressing the Finish button, open the 'Advanced settings' drop-down and select 'F28027.cmd' as the 'Linker command file'. This will cause our application to load into the Flash instead of the RAM, which is too small to hold more advanced examples. As the project template, choose 'Empty project (with main.c)', and click Finish.
Now, an issue with this linker command file included in CCS is that it seems to use only a very little part of the built-in FLASH, again, causing bigger apps not to fit inside. To resolve the issue, simply overwrite F28027.cmd inside the project directory with the one from 'C:\ti\controlSUITE\device_support\f2802x\v230\f2802x_common\cmd\F28027.cmd'. You can read more about the linker command file in the TI Wiki.

Before we can begin writing our first program, we need to add the F2802x include path and driver library to our projects - this is where the controlSUITE installation comes handy.
Open your project properties and select Build -> C2000 Compiler -> Include Options, then add the following dir to the #include search path: 'C:\ti\controlSUITE\device_support\f2802x\v230'. Do note that if the F2802x device support receives an update, you might want to select that one instead - at the time of writing this article, v230 is the latest version. As a side note, you could use the 'development_kits\C2000_LaunchPad' include path as well, but a quick diff reveals that the device support in that directory wasn't updated since a while - so I recommend sticking to f2802x instead.


Finally, add the driver library by browsing to Build -> C2000 Linker -> File Search Path, and adding the 'C:\ti\controlSUITE\device_support\f2802x\v230\f2802x_common\lib\driverlib.lib' entry to link against. After that, you can close this dialog and open main.c.


Now, simply replace the contents of main.c with the skeleton below, which I think is a great starting point for any application. Don't worry, I'm going to tell what's happening here.
#include "f2802x_headers/include/F2802x_Device.h"
#include "f2802x_common/include/f2802x_examples.h"

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

CPU_Handle myCpu;
CLK_Handle myClk;
PIE_Handle myPie;
PLL_Handle myPll;
WDOG_Handle myWDog;

void setup_handles() {
    myClk = CLK_init((void *) CLK_BASE_ADDR, sizeof(CLK_Obj));
    myCpu = CPU_init((void *) NULL, sizeof(CPU_Obj));
    myPie = PIE_init((void *) PIE_BASE_ADDR, sizeof(PIE_Obj));
    myPll = PLL_init((void *) PLL_BASE_ADDR, sizeof(PLL_Obj));
    myWDog = WDOG_init((void *) WDOG_BASE_ADDR, sizeof(WDOG_Obj));
}

void init_system() {
    // running from flash - copy RAM based functions to RAM
    memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t) &RamfuncsLoadSize);

    // disable watchdog
    WDOG_disable(myWDog);

    // load factory calibration
    CLK_enableAdcClock(myClk);
    (*Device_cal )();
    CLK_disableAdcClock(myClk);

    // select the internal oscillator 1 (10 MHz) as the clock source
    CLK_setOscSrc(myClk, CLK_OscSrc_Internal);

    // setup the PLL for 10 MHz * 12 / 2 = 60 MHz
    PLL_setup(myPll, PLL_Multiplier_12, PLL_DivideSelect_ClkIn_by_2);

    // disable PIE and all interrupts
    PIE_disable(myPie);
    PIE_disableAllInts(myPie);
    CPU_disableGlobalInts(myCpu);
    CPU_clearIntFlags(myCpu);
}

void main() {
    setup_handles();
    init_system();

    // your code here

    while (1)
        ;
}

Now, although I tried to place a lot of comments in the code so it's easier to understand, I'll go ahead and explain some of the basics.

This coding style is called software driver model, you can read more about it in the F2802x Peripheral Driver Library User's Guide (note: a newer version of this document is available in 'C:\ti\controlSUITE\device_support\f2802x\v230\doc').

In the software driver model, before a driver for a peripheral can be used, that peripherals driver header file should be included and a handle to that peripheral should be initialized.

This is the first thing the code skeleton does in the setup_handles() function. It initializes the device clocking (CLK), CPU, Peripheral Interrupt Expansion Module (PIE), Phase Locked Loop (PLL) and the Watchdog (WDOG) peripheral drivers by passing them the peripheral registers base address. The handles are defined globally, so they can be accessed in any function in main.c.

The second thing the code skeleton does, the init_system() function is more interesting. Let's see what's going on here.

First of all, some functions are placed in the RAM for faster execution - one such function I noticed is DELAY_US. Since we are running from the flash, we need to copy these functions to the RAM, otherwise, they won't work. I have to admit that this area (along with the linker command file contents) isn't fully clear to me, but I think I at least understand what's going on; the TI Wiki contains a bit more details.
// running from flash - copy RAM based functions to RAM
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t) &RamfuncsLoadSize);

The user software must regularly reset the CPU-watchdog counter within a certain time frame; otherwise, the CPU-watchdog generates a reset to the processor. It is recommended to disable the CPU-watchdog in the testing phase, and only consider using it in the finished product, where an automatic reset can be handy if the MCU hangs for some reason, and relying on user reset isn't acceptable. It is important to reset the CPU-watchdog soon enough so it won't kick in before time:
// disable watchdog
WDOG_disable(myWDog);

Now, we can load the factory calibration for the internal oscillators and ADC. The Device_cal() routine is programmed into TI reserved memory by the factory. The boot ROM automatically calls the Device_cal() routine to calibrate the internal oscillators and ADC with device specific calibration data. During normal operation, this process occurs automatically and no action is required by the user.
If the boot ROM is bypassed by Code Composer Studio during the development process, then the calibration must be initialized by application. The ADC clocks must be enabled before making this call. For more details, refer to the TMS320x2802x Piccolo Boot ROM Reference Guide.
// load factory calibration
CLK_enableAdcClock(myClk);
(*Device_cal )();
CLK_disableAdcClock(myClk);

The datasheet reveals that the device can be clocked by either of the two internal zero-pin oscillators running at 10 MHz, an external oscillator, or by a crystal attached to the on-chip oscillator circuit.  A PLL is provided supporting up to 12 input-clock-scaling ratios. The PLL ratios can be changed on-the-fly in software. So let's configure the MCU to use the internal oscillator 1, and the PLL just so it operates at the maximal frequency it's capable of (60 MHz):
// select the internal oscillator 1 (10 MHz) as the clock source
CLK_setOscSrc(myClk, CLK_OscSrc_Internal);

// setup the PLL for 10 MHz * 12 / 2 = 60 MHz
PLL_setup(myPll, PLL_Multiplier_12, PLL_DivideSelect_ClkIn_by_2);

Finally, we disable the Peripheral Interrupt Expansion (PIE) block, and all interrupts. It's advised to disable all interrupts on init and enable them later on if necessary.
// disable PIE and all interrupts
PIE_disable(myPie);
PIE_disableAllInts(myPie);
CPU_disableGlobalInts(myCpu);
CPU_clearIntFlags(myCpu);

At this point, building the project should complete without any errors or warnings; the program can be loaded onto the device by pressing the debug button (or pressing F11), although not much will happen until we move on to the next chapter, where we will make use of the on-board UART and GPIO peripherals.

2 comments:

  1. Bonjour les gars, si vous avez besoin d'embaucher un vrai hacker pour surveiller / pirater le téléphone de votre partenaire à distance, échanger et doubler votre argent en quelques jours / semaines, ou pirater une base de données, le tout avec confidentialité garantie, contactez easybinarysolutions@gmail.com, ou whatsapp: +1 3478577580, ils sont efficaces et confidentiels.

    ReplyDelete
  2. Join the world’s largest community of ethical hackers and start hacking today! Be challenged and earn rewarding bounties. Learn more! https://www.hackerone.com/for-hackers/how-to-start-hacking

    ReplyDelete