Search Microcontrollers

Sunday, August 12, 2012

C2000 Piccolo - Coding - Basics

The C2xxx, like all the common MCUs has several modules performing different functions, such as ADC, PWM, Timers, UART etc.
On the coding side, to partially "hide" the complexity behind this a set of header files are provided, specific to each mcu family in the range.

Those header files contain the methods needed to operate the module they are referred to, and each one of them provides a "handle".

As an example the Clock module is supported by the clk.h header file :

#include "f2802x_common/include/clk.h"

this header file defines a CLK_Handle pointer to a CLK_Obj structure, which we will use to interact with the clock.

CLK_Handle myClk;
myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));

CLK_BASE_ADDR is the base address for the clock registers and its value is also defined in clk.h.
What this init does is to simply point the structure to the actual address in memory of the registers needed to operate the clock.
In fact, if ye check the clk.h file , we discover that there is this define :

#define  CLK_BASE_ADDR                   (0x00007010)

Checking the tms320f28027 datasheet, we discover that at that address there are the System Control Registers


There is a specific technical document called "TMS320F2802x/TMS320F2802xx Piccolo System
Control and Interrupts" which describes that particular functionality (analogue guides are available for ADC, PWM etc).


if we check in clk.h how the Clk_Obj structure is defined, we obviously find a matching definition (although in some case not the full register range may be mapped).


typedef struct _CLK_Obj_
{
    volatile uint16_t   XCLK;         //!< XCLKOUT/XCLKIN Control
    volatile uint16_t   rsvd_1;       //!< Reserved
    volatile uint16_t   CLKCTL;       //!< Clock Control Register
    volatile uint16_t   rsvd_2[8];    //!< Reserved
    volatile uint16_t   LOSPCP;       //!< Low-Speed Peripheral Clock Pre-Scaler Register
    volatile uint16_t   PCLKCR0;      //!< Peripheral Clock Control Register 0
    volatile uint16_t   PCLKCR1;      //!< Peripheral Clock Control Register 1
    volatile uint16_t   rsvd_3[2];    //!< Reserved
    volatile uint16_t   PCLKCR3;      //!< Peripheral Clock Control Register 3
} CLK_Obj;


Now we can control the clock subsystem using the handle :

CLK_enableAdcClock(myClk);

Notice that  CLK_enableAdcClock is a normal function, not a method of an object, it will take the handle as parameter, allowing cross compilation with other devices of the family, supported by different header files and therefore with different addresses.

At this point we can also configure the peripheral, in the next case we set the source oscillator to be the internal one.

CLK_setOscSrc(myClk, CLK_OscSrc_Internal);

When performing these tasks, we typically chose an option from a list, and there is a easy way to get the full list in order to see the other options.
If you press ctrl and you hover your mouse over an expression or a constant, in some cases the text gets underlined.
If this happens CCS (Eclipse) can take you to the declaration of such expression, simply click with the mouse while keeping the ctrl key down.

Ctrl-clicking over CLK_OscSrc_Internal we are taken to the clk.h file where the enumeration  CLK_OscSrc_e is defined with its two options and their bits settings (which we don't need to care of). 

typedef enum
{
    CLK_OscSrc_Internal=(0 << 0),  //!< Denotes an internal oscillator source
    CLK_OscSrc_External=(1 << 0)   //!< Denotes an external oscillator source
} CLK_OscSrc_e; 

This is a rather simple way of discovering the options offered by the different modules.
While in order to grasp the concepts related to a specific peripheral it is always advisable to check the pdf guide, this may give a quicker way of discovering the various options supported.






No comments: