Learning‎ > ‎

MSP430: TI Chronos


Introduction

asdf


Installation

We need to (1) install the drivers for RF Access Point and eZ430 Emulator, and (2) software to interface with the default program running on the Chronos watch.

Chronos Software and Drivers


Code Composer Studio v4 Core Edition


Using eZ430-Chronos Control application

Acceleration data

asdf

Control PowerPoint slides

asdf

Sync the time with PC

adsf

Program Chronos watch wirelessly

adsf

Two paths to start learning

  1. Programming the watch
  2. Developing programs on the computer to use the watch's data

Developing Programs on the computer

adf

Programming the watch

I'm going through the book "MSP430 Microcontroller Basics" by John Davies to learn how the details of programming (in C) the MSP430. (TODO)

The chronos watch breakdown:

asdf






First program

(Refer to Chapter 4.2)

The first program to get used to programming the watch is to turn on the LCD backlight. This can be accomplished by setting P2.3 to high.

Caution: The P2.3 is also hardwired to KEY_BL button. I don't think LCD backlight was meant to be toggled by the program because pressing the button at the same time the microcontroller is trying to pull the pin low might cause a short?? (Need to check!)

Better safe that sorry (for now): Since the watch is disassembled from the strap (and the button interface), we wouldn't be pressing the KEY_BL by accident.

You won't be able to see the backlight too clearly unless you look from the side because the LCD display is still not turned on; we're just enabling the backlight behind it.

// first_program.c
// Turn on the backlight

#include <cc430x613x.h>

#define INITSTATE    0
#define BACKLIGHT    BIT3

void main(void){

    /* Configure the watchdog */
    WDTCTL = WDTPW | WDTHOLD;     //stop watchdog timer

    /* Configure all ports */
    P2OUT = INITSTATE;         //May not be necessary? (TODO)
    P2DIR = BACKLIGHT;         //Set (only the) backlight port as output

    P2OUT = BACKLIGHT;         //Set P2.3 High

    while(1);
    //__no_operation();        //TODO: Find out what this macro does
}


First program Updated

Split up the program into .c and .h file
Create a skeleton so that things stay organized when code gets complicated

Header file:
// backlight.h
// Header file for the updated first program

#ifndef MAIN_H_

#define MAIN_H_

#define INITSTATE    0
#define BACKLIGHT    BIT3

//Any debug flags

//Prototypes
void init_variables(void);
void init_configure(void);

#endif /*MAIN_H_*/


Source file:
#include <cc430x613x.h>
#include "main.h"

void main(void){

    init_variables();
    init_configure();
   
    //Turn on the backlight
    P2OUT = BACKLIGHT;
   
    while(1)
;
}

void init_variables(void){
}

void init_configure(void){

    /* Initialize the stack pointer - done by cstartup.h */
    /* Configure the watchdog */

    WDTCTL = WDTPW | WDTHOLD;        //stop watchdog timer

    /* Configure all ports */
    P2OUT = INITSTATE;         //May not be necessary? (TODO)
    P2DIR = BACKLIGHT;         //Set (only the) backlight port as output

    /* Set up the clock - N/A */
    /* Configure other peripherals - N/A */   
}


Reading Input

(Refer to Chapter 4.4)

Now that we know how to write to an LED, let's try reading from the switch and toggle the LED.

Following is the schematics for the buttons on the Chronos watch.
  • We have used P2.3, connected to KEY_BL, as an output to enable/disable the LED backlight.
  • Let's use P2.0, connected to KEY_S2 ("Submenu 2" button a.k.a "down-arrow" button), as an input to toggle the LED backlight.

Prerequisites

I am assuming that when the button is pressed, it pulls the pin to Vcc. (TODO: Check. Because I do not see any information for what KEY_S2 connects to!)
  • The assumption is due to the fact that pressing the KEY_BL enables the backlight; and in our first program, setting P2.3 to High enables the backlight.
We can enable the internal pull-down resistor to keep P2.0 at ground. Then pressing the button would pull the pin high.

Registers for configuring pins

PxIN: port input
Read the values on the pin. Works as long as ports are configured as Digital input/output

PxOUT: port output

A buffer to store the value to be driven to each pin if it's configured as output. Needs to be initialized before pin is configured as output.

PxSEL: port selection
If 0 (default), pin is selected for digital input/output. Otherwise, it's selected for alternative function (eg. Analog input)

PxDIR: port direction

When selected as digital in/output (i.e. PxSEL = 0):
if bit = 0 -> configured as input. If bit = 1 -> configured as output.

PxREN: port resistor Enable
If bit = 1, pull-up/down resistors are activated. 0 is selected by default.
When enabled:
if PxOUT = 1, resistor is pull-up (connected to Vcc). Else resistor is pull-down.

CAUTION: The above configurations can be overruled in some cases by other registers/functions (Page 209)

Masks
To set a bit to 1: (PORT) |= (BIT)
To set a bit to 0: (PORT) &= ~(BIT)
To toggle a bit:   (PORT) ^= (BIT)

To configure P2.3 as output:
  • Initialize output buffer: P2OUT -> BIT3 to 0. [P2OUT &= ~BIT3]
  • Configure pin as output: P2DIR -> BIT3 to 1. [P2DIR |= BIT3]
    • [page 215] leaving the others as inputs and leaving them unwired or with no pull-up/down resistors is bad (floating inputs). But whateverrrrrrrrrrrrr... for this example.
To configure P2.0 as input:
  • Configure pin as input: P2DIR -> BIT0 to 0 [P2DIR &= ~BIT0]
  • Enable internal pull-down resistors:
    • P2OUT -> BIT0 to 0. [P2OUT &= ~BIT0]
    • P2REN -> BIT0 to 1. [P2REN |= BIT0]

Single Polling method

  1. Start CCSv4.
  2. Select a Workspace. This is the folder where CCS stores all your projects. I try to keep one workspace for every chapter I will going through.

  3. File -> New -> CCS Project..
  4. Enter desired name for your project
  5. Select platform as MSP430 and Configurations for 'Debug' and 'Release'. Choose Next.

  6. Do not select any inter-project dependencies under 'Projects'. Leave the 'C/C++ Indexer' at 'Full C/C++ Indexer'. Choose Next.
  7. Select the following CCS Project settings. Particularly:
    • Device Variant: CC430F6137
  8. Select Finish to create the new project. This is what the window should look like.

  9. Right-click on the Project in the C/C++ Projects window -> New -> Source file

  10. Leave the 'Source Folder' the same (led-toggle-button in this case) and Enter name for the source file (led-button.c). Choose Finish.
  11. Also create the complementary header file in a similar fashion.
    • Right-click on the Project -> New -> Header file
    • Enter name for the header file (led-button.h). Choose Finish
  12. Enter the following code for the source file.
    //led-button.c
    //Toggle LED backlight depending on whether "down-arrow" button is pressed

    #include <cc430x613x.h>
    #include "led-button.h"

    void main(void){

        init_variables();
        init_configure();
      
        while(1){
            if((P2IN & BL_BUTTON) == BL_BUTTON) {    //if button pin == 1
                P2OUT |= BACKLIGHT;        //turn on LED backlight
            } else {
                P2OUT &= ~BACKLIGHT;    //turn off LED backlight
            }
        }
    }

    void init_variables(void){
    }

    void init_configure(void){

        /* Initialize the stack pointer - done by cstartup.h */
        /* Configure the watchdog */
        WDTCTL = WDTPW | WDTHOLD;        //stop watchdog timer

        /* Configure all ports */
        //configure P2.3 as output
        P2OUT &= ~BACKLIGHT;          //Initialize output buffer: P2OUT -> BIT3 to 0.
        P2DIR |= BACKLIGHT;              //Configure pin as output: P2DIR -> BIT3 to 1.
        //configure P2.0 as input
        P2DIR &= ~BL_BUTTON;          //Configure pin as input: P2DIR -> BIT0 to 0.
        P2OUT &= ~BL_BUTTON;          //Enable internal pull-down resistors: P2OUT -> BIT0 to 0.
        P2REN |= BL_BUTTON;              //P2REN -> BIT0 to 1
       
        /* Set up the clock - N/A */
        /* Configure other peripherals - N/A */  
    }

  13. Enter the following for the header file.
    //led-button.h

    #ifndef LEDBUTTON_H_
    #define LEDBUTTON_H_

    #define INITSTATE    0
    #define BACKLIGHT    BIT3
    #define BL_BUTTON     BIT0

    //Any debug flags

    //Prototypes
    void init_variables(void);
    void init_configure(void);

    #endif /*LEDBUTTON_H_*/

  14. Choose Project->Build Active Project (Ctrl+Shift+P)
    • The project should complete build without any errors. The 'Console' window should show the following message:
    • Any errors would be displayed in the 'Problems' window
  15. Connect the Chronos watch for debugging via the 'eZ430 Emulator for programming'. (Instructions below)
  16. To program the watch, Select Target -> Debug Active Project or click on the Debug button on the Toolbar. (Looks like a Green bug)
  17. (Explain the programming process after Debug is selected)
  18. The debugger runs any startup code and halts at the 1st line in the main() function. Remember that the 1st line hasn't been executed yet.
  19. We can Run the program and pause at anytime. Or we can 'Step Over..' each line of code
  20. Watch the results on the Chronos watch.
  21. Since we cannot select any buttons when the watch is disassembled from the watch strap, we either need to:
    • unplug the watch and assemble it into the strap and use the button, or
    • emulate the button press by changing the value in the Debugger.(TODO: Wasn't able to change the P2IN register. Probably because it's volatile)

Double Polling Method

The difference between the last method and this is that the LED backlight state isn't being set everytime around the loop. A nested while loop holds the program till the button is pressed. After setting the LED backlight on, another nested while loop holds the program till the button is released.

The single polling method code is also preserved in this program. A debug flag SINGLELOOP is set in the header file when I want to use the single polling method instead of the double polling method.

Source file:
//led-button-doublePoll.c
//Toggle LED backlight depending on whether "down-arrow" button is pressed

#include <cc430x613x.h>
#include "led-button.h"

void main(void){

    init_variables();
    init_configure();
 
#ifdef SINGLELOOP
    while(1){
        if((P2IN & BL_BUTTON) == BL_BUTTON) {    //if button pin == 1
            P2OUT |= BACKLIGHT;        //turn on LED backlight
        } else {
            P2OUT &= ~BACKLIGHT;    //turn off LED backlight
        }
    }
#else
    while(1){
        //Hold while button is not pressed
        while((P2IN & BL_BUTTON) == 0);     //button pin == 0
        //turn on LED backlight
        P2OUT |= BACKLIGHT;
        //Hold while button is pressed
        while((P2IN & BL_BUTTON) == BL_BUTTOn); //button pin == 0
        //turn off LED backlight
        P2OUT &= ~BACKLIGHT;
    }       
#endif

}

void init_variables(void){
}

void init_configure(void){

    /* Initialize the stack pointer - done by cstartup.h */
    /* Configure the watchdog */
    WDTCTL = WDTPW | WDTHOLD;        //stop watchdog timer

    /* Configure all ports */
    //configure P2.3 as output
    P2OUT &= ~BACKLIGHT;          //Initialize output buffer: P2OUT -> BIT3 to 0.
    P2DIR |= BACKLIGHT;              //Configure pin as output: P2DIR -> BIT3 to 1.
    //configure P2.0 as input
    P2DIR &= ~BL_BUTTON;          //Configure pin as input: P2DIR -> BIT0 to 0.
    P2OUT &= ~BL_BUTTON;          //Enable internal pull-down resistors: P2OUT -> BIT0 to 0.
    P2REN |= BL_BUTTON;              //P2REN -> BIT0 to 1
   
    /* Set up the clock - N/A */
    /* Configure other peripherals - N/A */  
}


Header file:
//led-button.h

#ifndef LEDBUTTON_H_
#define LEDBUTTON_H_

#define INITSTATE    0
#define BACKLIGHT    BIT3
#define BL_BUTTON     BIT0

//Any debug flags
//#define SINGLELOOP

//Prototypes
void init_variables(void);
void init_configure(void);

#endif /*LEDBUTTON_H_*/


Toggling LED

(Refer to section 4.5) Toggle the LED backlight using a software loop.

Source:
//loops-software.c
//Toggle LED backlight in a software loop

#include <cc430x613x.h>
#include "loops.h"

volatile unsigned int counter;

void main(void){

    init_variables();
    init_configure();
 
    while(1){
        for(counter = 0; counter<DELAY; counter++);     //Delay for "a while"
        P2OUT ^= BACKLIGHT;     //toggle the state of backlight
    }
}

void init_variables(void){
    counter = 0;
}

void init_configure(void){

    /* Initialize the stack pointer - done by cstartup.h */
    /* Configure the watchdog */
    WDTCTL = WDTPW | WDTHOLD;        //stop watchdog timer

    /* Configure all ports */
    //configure BACKLIGHT pin as output
    P2OUT &= ~BACKLIGHT;         //Initialize output buffer: P2OUT -> BIT3 to 0.
    P2DIR |= BACKLIGHT;           //Configure pin as output: P2DIR -> BIT3 to 1.

    /* Set up the clock - N/A */
    /* Configure other peripherals - N/A */  
}

Header:
#ifndef LOOPS_H_
#define LOOPS_H_

#define INITSTATE    0
#define BACKLIGHT    BIT3

#define DELAY        50000

//Any debug flags

//Prototypes
void init_variables(void);
void init_configure(void);

#endif /*LOOPS_H_*/


Interrupts

(From section 6.6) Learning how to configure interrupts on the msp430.

Prerequisites

ISR
Interrupt Handler/Interrupt Service Routine: Code to handle the interrupt

Flag
Each interrupt has a flag that is set when the condition for the interrupt occurs
  • Example: Timer_A sets the TAIFG flag in the TACTL register when the counter TAR returns to 0.
Enable
Each flag has an enable bit: Allows module to request interrupts
  • Example: For Timer_A: TAIE
GIE
Interrupt Enable bit (GIE): In the status register (SR)
It disables maskable interrupts when GIE = 0

Vectored Interrupts
Address of each ISR is stored in the vector table at a defined location in memory
(Diagram) Table of Interrupt Vector Addresses

Priority
Each of these vectors have a priority associated with them.
Hardwired, so cannot be changed.

Shared vs. Unique
ISRs could be shared or unique.

If Unique: Before executing the ISR, the interrupt request flag is cleared automatically.
If Shared: it remains set for the software to clear it (This way the ISR can check which condition caused this shared ISR)

Intrinsics.h

ISRs in C need intrinsic functions to set up the interrupts properly.

Some of the code is compiler dependent

For IAR Embedded Workbench:

  • __interrupt
Attached at the beginning of the function definition
Tells the compiler that this function is an ISR (For example: It does a reti call rather than ret in assembly)

  • #pragma vector = ***
Assosiates the function with an interrupt vector

//example

# pragma   vector = TIMERA0_VECTOR

__interrupt void TA0_ISR(void){
P2OUT ˆ= LED1|LED2; // Toggle LEDs
}

  • __enable_interrupt()
To set the GIE bit and turn on interrupts

For Code Composer Studio v4: (Refer to SLAU132)

We can still use the same functions as above because the header file in430.h (which is already called by the cc...file) converts the calls

  • __interrupt -> interrupt

//example

interrupt void int_handler()

{
unsigned int flags;
...
}

  • #pragma vector = ***
Should work as is. (TODO)

  • _enable_interrupt()
One underscore rather than two. Two might work (TODO)

Reading Input Revisited

(Refer to chapter 7.2 and 7.3) Repeat the example where the LED backlight is toggled by the down-arrow button. We will use interrupts to process the input rather than polling.

Important registers

Registers PxIN, PxOUT, PxSEL, PxDIR, PxREN are already mentioned earlier.

Additional registers needed for configuring interrupts:

PxIE: Interrupt Enable
Setting appropriate bits to 1 enables the interrupts on that pin. They are 0 by default
Whole port shares a single interrupt vector

PxIES: Interrupt edge select
0: generate on positive edge
1: generate on negative edge
Needs to be initialized before interrupts are enabled

PxIFG: Interrupt flag
Appropriate bit is set when the interrupt happens.
Can also be set by software for generating software interrupts

Interrupts for port P2 is controlled by the registers P2IE and P2IES

Debouncing

When the button is pressed, the actual input voltage goes through several transitions from low to high. Since we cannot make any hardware modifications, we can implement debouncing in software. Options:
  • wait for a fixed delay of the maximum length of expected bounces. around 10ms
  • use timers. More useful for toggle switches
  • use counters or shift registers. Recommended way (Also mentioned in 7.3.3)
I'm just going to use a fixed delay. feeling lazy...

Source:
//button-interrupt.c
//Toggle LED backlight depending on when down-arrow button is pressed.
//Using interrupts

#include <cc430x613x.h>
#include "button-interrupt.h"

volatile unsigned int counter;

void main(void){

    init_variables();
    init_configure();
 
    __enable_interrupt();
   
    while(1);

}

void init_variables(void){
    counter = 0;
}

void init_configure(void){

    /* Initialize the stack pointer - done by cstartup.h */
    /* Configure the watchdog */
    WDTCTL = WDTPW | WDTHOLD;        //stop watchdog timer

    /* Configure all ports */
    //configure BACKLIGHT as output
    P2OUT &= ~BACKLIGHT;             //Initialize output buffer: P2OUT -> BIT3 to 0.
    P2DIR |= BACKLIGHT;              //Configure pin as output: P2DIR -> BIT3 to 1.
   
    //configure BL_BUTTON as input

    P2DIR &= ~BL_BUTTON;             //Configure pin as input: P2DIR -> BIT0 to 0.
    P2OUT &= ~BL_BUTTON;             //Enable internal pull-down resistors: P2OUT -> BIT0 to 0.
    P2REN |= BL_BUTTON;              //P2REN -> BIT0 to 1
   
    //Enable interrupt on BL_BUTTON pin

    P2IES &= ~BL_BUTTON;             //Interrupt edge select on positive edge
    P2IE |= BL_BUTTON;               //Enable interrupt on BL_BUTTON
    do{
        P2IFG = 0;                   //Clear interrupt flag
    } while(P2IFG != 0);

    /* Set up the clock - N/A */
    /* Configure other peripherals - N/A */  
}

#pragma vector = PORT2_VECTOR
__interrupt void PORT2_ISR(void) {
    P2OUT ^= BACKLIGHT;              //toggle LED backlight
    for(counter = 0; counter < DELAY; counter++);   //delay for lazy debouncing
    do{
        P2IFG = 0;                   //Clear interrupt flag
    } while(P2IFG != 0);
}


Header:
//button-interrupt.h

#ifndef BUTTONINTERRUPT_H_
#define BUTTONINTERRUPT_H_

#define INITSTATE    0
#define DELAY        20000
#define BACKLIGHT    BIT3
#define BL_BUTTON    BIT0

//Any debug flags

//Prototypes
void init_variables(void);
void init_configure(void);

#endif /*BUTTONINTERRUPT_H_*/




Timers

Learn how to configure timers.
  • Timer is really no more than a counter. It has no direct concept of time. (Except for Real-time clock) [page 289]
  • It's the programmer's job to establish a relation between the value in the counter and real time.
  • This depends on the frequency of the clock for the timer.

Clock Sources

TODO

[From page 289]

SMCLK
  • internal
  • fast - MHz range
ACLK
  • internal
  • slow - MHz range
    • typically 32KHz from crystal
  • can be taken from the VLO
TACLK
  • external
INCLK
  • external
  • usually its connected so that INCLK = ~TACLK

Watchdog Timer

Counts up and resets system
  • when it counter reaches its limit
  • To prevent reset, code should clear the counter before its limit
There are two types of reset:
  • power-on reset (POR)
  • power-up clear (PUC): Less drastic
    • not all registers are reset to default
WDT creates a PUC reset. Upon reset,
  • WDTIFG flag is set in special function register IFG1
  • This bit can be checked to see if reset was caused by WDT.

WDTCTL: WDT Control register (16-bits)

upper byte:
For a proper write to WDTCTL, we need to write password WDTPW (0x5A)
Reading the upper byte gives us 0x69 - for protection
reset will occur if wrong password is written - Can be used for forcing a reset by software

lower byte:
Contains bits that control operation of WDT
Bits are reset to 0 upon POR but unaffected by PUC.

    • 'rw' means that its readable/writable
    • '(0)' means it's 0 by default and after POR
    • 'r0(w)' means bit is always read as 0; can be stimulated to 1 to provoke some action
      • for WDTCNTCL - clearing the counter
  • WDTSSEL bit: use SMCLK (default) or ACLK (1) for clocking
  • WDTISx bits: controls which bit from the watchdog counter is selected for reset.
    either bit 6, 9, 13 or 15 (default)
    Therefore, the period is 2^(bit# above); For default, thats 32, 768 clock cycles.
  • WDTTMSEL bit: Should be set for interval timer mode. Therefore, removes any protective features
    • same as the usual WDT except reset doesn't occur when WDTIFG is set
    • Interrupt is generated if WDTIE bit in special function register IE1 is set (maskable)
  • WDT (in its usual form) does have an interrupt vector (can we write ISR for it?? TODO)
    • WDTIFG is cleared automatically here

WDTCNT: watchdog counter (16-bits)

Not accessible by user

After initial reset, the default clock is SMCLK, derived from DCO, is 1 MHz.
This gives us 32ms before WDT causes a reset. Need to either clear, stop or reconfigure.

Examples

To stop WDT:
WDTCTL = WDTPW | WDTHOLD;

To clear WDT: (The bit is cleared after every reset; therefore need to be set again)
WDTCTL = WDTPW | WDTCNTCL;

Timer_A - General Description

This is the general purpose timer on MSP430.
TI-Chronos has two of these timers, TA0 and TA1

Consists of two main hardware parts:
  • Timer block
    • To choose from one of the clock sources
    • Choose modes of operation (below)
  • Several capture/compare channels
    • Each channel can capture, compare, request an interrupt, sample (TODO)
    • Name of each channel ends with the channel number
      • such as TIMER_A3 for the 3rd channel
    • Channel 0 is different for certain reasons (below)
  • All channels for the timer use the same timer block
    • needs software implementation if channels need to run @different frequencies
    • Use hardware of timer for parts of an event that needs precise timing (TODO)
      • Use software for less critical parts

Timer Block

TAR - 16-bit timer register i.e. "counter"
  • increments on the rising edge of the clock source
TACTL - control register

TASSELx bits
- Choose the clock source
  • SMCLK, ACLK, TACLK, or INCLK
  • Note: If timer needs to be working in real time, accurate & stable clock source is needed. Crystal (TODO)
IDx bits - To divide the frequency of the clock source
  • 1, 2, 4, or 8
  • slower clock ->
    • disadvantage - less resolution of the timer(X)
    • advantage - increases the natural period of timer
  • Table and example (TODO) pg. 290
MCx bits - Choose from one of the four modes of operation
  • 0 - Stop
    • halt the timer
    • all the registers retain their value
    • can be restarted later
  • 2 - Continuous
    • run freely from 0x0000 to 0xFFFF -> overflow -> start back from 0
    • range period = 2^16 = 65,536 counts
    • Used for
      • capturing inputs
      • running channels at different frequencies
  • 1 - Up
    • count from 0x0000 to TACCR0 -> return to 0 on the next transition -> repeat
      • TACCR0 = (counter/capture register for channel 0) <- Note: One reason why channel 0 is different
    • range period = TACCR0 + 1
    • Used for
      • pulse-width modulation (PWM)
      • when all channels provide outputs at same frequency
  • 3 - Up/Down
    • count from 0x0000 to TACCR0 -> count down to 0 -> repeat
    • range period = 2 x TACCR0
    • used for
      • centered PWM
      • specialized situations
  • Note: Channel 0 is different - because of Up and Up/Down mode
    • (advantage) precise control over the period of timer
    • (disadvantage) loss of channel 0 (unusable)
      • register TACCR0 is used to hold the modulus i.e. upper limit of the count
TACLR bit - Write a 1 to clear count in TAR ( and in Up/Down mode - resets the direction of counting)
  • clears itself after use
  • Do it when configuring the timer to ensure the first period will be correct
TAIE bit - Set to 1 if interrupt (maskable) needs to be enabled

TAIFG bit - flag
  • is set when timer counts to 0
    • only occurs when count goes to 0 due to normal counting
    • is NOT set when value is written directly to the counter.
      • Example: TACLR is used to clear counter
  • interrupt (maskable) is also requested if TAIE bit is set
Note: When modifying the configuration/operation of the timer
  • stop the timer before modifying
  • do NOT have to stop for:
    • interrupt enables
    • interrupt flags
    • TACLR
Note: Often, timer clock is NOT synchronized with the CPU clock (especially when timer is using ACLK).
To get a correct reading of the counter:
  • Do one of the following:
    • Stop the timer before reading the value of TAR
    • read the timer multiple times and use software to make a majority vote to determine the correct reading.
  • NOT an issue when reading values from TACCRn registers after a capture (below)

Capture/Compare Channels

Each Timer_A has multiple channels.

TACCTLn: Control register for nth channel


TACCRn: Capture/Compare channel for nth channel
  • In capture mode:
    • stores the value of TAR ("time") when an event occurs at the input
  • In compare mode:
    • specifies the time at which
      • output should be changed, and
      • an interrupt requested
CAP bit: Select between Capture and Compare mode (Each channel is independently configured)
  • Default is 0: Compare mode
  • Mode can be switched anytime (TODO)
Note: For pins to be used with the timers ("hardware use"), i.e. for capture/compare
  • PnSEL.x = 1
    • configure the pin for this rather than digital in/out
  • PnDIR.x = 0 or 1
    • for input or output (TODO)

Capture Mode hardware

CMx bits: choose the trigger edge of the input being captured
  • rising edge
  • falling edge
  • either edge
CCISx bits: select the input to be captured
  • Check datasheet for details (TODO)
  • CCInA
    • outside the timer module
    • Often connected to external pin TAn
  • CCInB
    • outside the timer module
    • Often connected internally to another module
      • advantage of internally connecting - TODO (SoC theme)
  • GND or VCC
    • allows capture from software
    • Procedure:
      • CMx = 11 - Capture both edges
      • CCIS1 = 1 - Select the pair of internal inputs i.e. either GND or VCC
      • Toggling CCIS0 generates the event for capture
        • it inverts the "apparent input" - the input switches from GND to VCC (or vice versa) simulating a change at the input
CCI bit: contains the state of the chosen input
  • volatile - can change at any time
  • good idea to use a synchronizer (below)
SCS bit: Enable the synchronizer by setting to 1
  • Capture events are recorded on the next falling edge of timer clock that follows the trigger (TODO)
CCIFG bit: channel flag
  • set when capture occurs and current value of TAR is copied to TACCRn
  • interrupt requested if CCIE bit = 1
CCIE bit: enable interrupt (maskable)
  • Important to react quickly to a capture because most applications are time-sensitive
COV bit: capture overflow bit
  • set if another capture occurs before TACCRn is read from previous capture event
  • warning that a capture event was missed
Compare Mode Hardware

EQUn (internal): set when TAR matches TACCRn.
  • triggers the actions in compare mode
  • Note: all channels can be triggered by EQU0 as well as EQUn. (TODO)
CCIFG bit: flag
  • set when EQUn is set
  • Interrupt is requested if it was enabled
SCCI bit: latched CCI
  • "sample mode of the timer" (TODO)
OUTMODx bits: determines the output mode of the channel
  • i.e. determines, along with the Counter mode, the behavior of channel's output OUTn
OUTn: channel's output
  • Behavior depends on the Output mode and the Counter mode
  • Note: sometimes there is not need for an external output
    • just the flag/interrupt is used by software
  • Note: sometimes used to in SoC to trigger modules internally (TODO)
Typical/straightforward use of different output modes (# - OUTMODx)
  • 0 - Output
    • output is controlled directly by OUT bit
    • TODO
  • 4 - Toggle
    • TODO
  • 1, 5 TODO
  • 7, 3 TODO
  • 2, 6 TODO
  • Influence of TACCR0
  • Uselessness of Channel 0 in modes 2, 3, 6, and 7
Note: When output modes are changed
  • glitches are possible on the output
  • Common situations
    • check User Guides
  • Changes between mode 1 and 5 are safe
  • Use mode 7 as an intermediate step to avoid glitches

Initial Configuration
  • TACCTLn are cleared by POR
    • not by PUC reset
  • Default state of channel: Compare mode
  • Default output mode: Mode 0 - output is determined by OUT bit
  • Default value of OUT bit - 0
    • OUT bit should be set before configuring the pin for Timer_A

Interrupts in Timer_A

TAIFG: Interrupt flag generated by timer block

TACCRn CCIFG: Interrupt flag generated by c/c channel n

TIMERA0_VECTOR: interrupt vector for TACCR0
  • has a higher priority than for the other channels
  • CCIFG0 is cleared automatically when interrupt is serviced
TIMERA1_VECTOR: interupt vector (shared) for rest of the TACCRn
  • CCIFG is not cleared automatically
  • One option: (slow)
    • determine the active flag - poll TAIFG and CCIFG bit for all channels
    • clear the flag
    • service the interrupt
  • use TAIV (below)
TAIV: Interrupt vector register
  • used to identify the source of interrupt rapidly
  • is loaded with value corresponding to the source w/ highest priority
    • Note: more than one flag could be set at a time
  • clears the register and corresponding flag when accessed
    • use switch() rather than if()
  • is reloaded with value of next highest priority source, if any


Timer_A - Specifics for TA0 and TA1

**Spring quarter has been busy; I wills start updating once summer starts**



Real-time clock

asdf



Using Timer for Toggling

asdf




Low-Power mode

Interrupts are needed to wake up from low-power modes.



ą
Arul Sekar,
Nov 27, 2010, 4:08 PM
Ċ
Arul Sekar,
Nov 27, 2010, 4:08 PM
Ċ
Arul Sekar,
Nov 27, 2010, 4:14 PM
Ċ
Arul Sekar,
Nov 25, 2010, 4:41 PM
Ċ
Arul Sekar,
Nov 27, 2010, 4:09 PM
Comments