Meet the MSP430 TimerA
Timing can be pretty important in embedded systems. In fact, in many situations precise timing is critical. In the previous tutorial we used basic digital output port functions to make a pulse width modulation (PWM) signal, that we then used to adjust the brightness of the D3 LED on the LaunchPad board. In this addition, we’re going to be doing the same thing, but instead of using code to generate the PWM signal, we will use the TimerA module.
Now that we’ve told you what we aim to do, let’s talk about just what this TimerA module actually is. The figure below shows the functional block diagram of a TimerA module. It’s broken up into two main sections: the Timer Block, and the the Counter Control Register (CCR) blocks. The Timer block sets up the base timing of the module, one is able to connect up to four different clock sources, and the selected clock can then be divided by 1, 2, 4, or even 8, making the timing options somewhat versatile.
In addition to this versatile clocking system the actual TAR counter has 4 different modes of counting: STOP, UP, UP/DOWN, and Continuous. The STOP mode, is as one would imagine, a stop mode. In this mode the TAR counter does not count. Two of the three modes ( UP, and UP/DOWN) make use of the CCR0 for counting. In UP mode the TAR will count up to the value held in CCR0 and then roll over to zero, so that the period is the value in CCR0 + 1. In UP/ DOWN mode the TAR will count up to the value in the CCR0 and then back down to 0, so that the period is twice the value in CCR0. Finally, in Continuous counting mode the TAR counts until the register rolls over. The counting mode of the Timer is determined by the MCx bits in the Timer A Control Register (TACTL).
Before you start feeling over whelmed by all the timer’s options and functionality, just know that this module is controlled by just five types of registers, and 3 of those registers are responsible for reporting the modules state and status. The other two registers control function.
TACTL, Timer_A Control Register: this register controls the functionality of the Timer Block. Fields in this register allow you to select the clock source, clock divider, counting mode, enable interrupts, and couple other functions.
TAR, Register: counting register for Timer A module.
TACCTLx, Timer A Capture/Compare Control X Register: control register for the capture compare register. Through this register you can enable interrupts, change the output mode, and other options related to capture/compare functionality.
TACCRx, Timer A Capture/Compare Register: when the Timer A is in Compare mode, this register holds the value to be compared to the TAR register. However, if Timer A is in Capture mode, this register copies the value in the TAR when triggered by an input.
TAIV, Timer A Interrupt Vector Register: this register informs us which capture compare triggered an interrupt, or if the module’s TAR register rolled over. If TACCR1 triggered the interrupt it will contain the value 2, if TACCR2 triggered the interrupt it will contain 4, else if the TAR rolled over it will contain 10. Typically the TAIV is checked with a case statement, as will be shown shortly.
Each capture and compare block contains an output unit which is used to control one or more output pins. The output pinout is shown below for the 20 pin MSP4302553 package. These pins need to be properly selected with the PxSEL register.
program Flow and PWM code (Output Only)
The program flow for this project will consist of 4 parts (shown below), just like the previous port tutorial. In fact, this project will be identical to the input driven example in that tutorial, except in this example we will be using the Timer A module to handle all the PWM timing, instead of using software.
MSP430 library declaration and program definitions
Function Prototypes
Main Routine
Turn off Watchdog Timer
Set the clock speed
Setup the modules being used
Enter "forever" loop
ISR’s or Function Definitions if used
Start Code Composer, and then select File -> CCS Project, from the main menu tab.
The New CCS Project wizard should pop up as shown below. Choose MSP430G2553 as the target, name the project name whatever you want (I chose TA_PWM) in the Project Name box, select “Empty Project (with main.c)” as a template, and press finish.
After you press Finish in the last step Code Composer will generate your project with a main.c template file. The template given completes Step 3.i of the program format we will be adhering to, but we need to work a bit on Step 3.ii, changing the clock speed. To do this we will be using some calibration labels loaded into the Basic Clock System Control 1 (BCSCTL1), and DCO Control (DCOCTL) registers.
In this step (3.iii) we're going to set P2.1 as output (line 32), enable the output module of Timer A to control it (line 33), and configure Timer A (lines 36-40). Line 40 actually sets up the Timer module to be clocked by the SMCLK divided by 1, in UP mode. The duty cycle is determined by the ratio the values TA1CCR1 (Line 37) over TA1CCR0 (Line 36) - in this case 50% (127/255). The value in TA1CCR0 sets the period of the PWM signal. Basically the TAR counter will roll over once it reaches the value in TA1CCR0. Upon rolling over it will automatically set P2.1 high, however, once the TAR is equal to the value held in TA1CCR1 the output of P2.1 will be set low, making our PWM signal possible.
Now we are going to setup P1.3 as an input that can drive interrupts. Basically if we press it, we grab the MSP430's attention immediately. The five lines needed are shown below, with a brief description of what they actually do.
Moving onto Step 3.iv, we will enabling interrupts, go into sleep mode and enter our forever loop. We're not write done yet though we still need to write our interrupt routine for when P1.3 is pressed.
The only thing left to do is to write the ISR for our P1.3 button push. We're just going to use a simple case statement that checks the current value of TA1CCR1 , and changes it accordingly. It's similar to the case statement in the Ports tutorial, except instead of switching on the variable Duty we switch on the value in the TA1CCR1 register. Outside of that the ISR's are identical.
The output of this program is identical to that of the Ports interrupt tutorial. You might experience bit debouncing issues with this program, where pressing the button skips a case, or even a couple cases. You can add a delay in the ISR to alleviate this issue.
Below is the PWM code. You can download and play with the duty cycle values yourself in the ISR. It's pretty straight forward code.
Timer A Interrupts
In the PWM_Timer_A example above, no Timer A interrupts were used, so in this section we’re going to utilize the Timer A interrupt capabilities.
Timer A has two types of interrupt vectors associated with it: one for the counter control register 0 (CCR0), and another one for all the other counter control (CCR) registers and TAR roll over. In the second type the TAIV is used to determine which CCR register triggered the interrupt, or if the interrupt was trigged by a TAR roll over. Right below is a snippet of the msp430g2553.h file, showing the interrupt vectors that will be used in this example.
In this example all three capture compare registers will be used, and both interrupt vectors will be utilized. When CCR0 is reached by the TAR the output of the green LED D1 will be turned off. When CCR1 is reached the D3 diode will be turned on, and when CRR2 is reached it will be turned off. The two corresponding PWM signals will be controlled by the roll over of the TAR. The Timer A module will be in Continuous mode. This will require both interrupt vectors in four parts:
the CCR0 vector will turn off the green LED D1,
the CCR1 counter will turn on D3,
the CCR2 counter will turn off D3,
upon TAR roll over the D1 will be turned on.
The first part of the list above is handled in the CCR0 interrupt vector. However, the other 3 parts are handled in the TAIV interrupt routine. In this routine the TAIV register is interrogated to determine what caused the Timer interrupt (CCR1, CCR2, or a TAR roll over).
Once again we're going to start a new project in Code Composer.
In the New CCS Project wizard: choose MSP439G2353 as the target, give the project a name (TA_Interrupts), and select "Empty Project (with main.c)" as a template, then press Finish.
The project wizard should create an empty main that turns off the watchdog timer. we need to set the clock speed. Since we're going to be running in Continuous mode and the TAR counter will be rolling over, we will want to have a pretty fast clock so the PWM signal has a small period. 16MHz is the largest frequency calibration data on the MSP430G2553, so we'll use that.
The next step is to setup our output pins as outputs and set them high to initialize the PWM signal. Here two bits are OR'ed into the P1DIR register to set the direction of P1.0 and P1.6 as output, the pins are set to the high state by writing these same bits into the P1OUT register. This same process is done on Port 2 for P2.1.
In this step we will setup Timer A. First we load values into the Counter control registers (CCR0, CCR1, and CCR2), which setups the three duty cycles as shown below. We then enable the CCR interrupts, and finally we setup the TA module control register and enable the TAR interrupt, which is responsible for the period of the PWM signal.
Now we enter our forever loop. However, we still have two ISR's to write for Timer A. In this loop we enable interrupts for the MSP430.
On to the ISR's! The first ISR we will do is the ISR for the CCR0 block. The pragma keyword is used to tell Code Composer that this is an ISR, and the vector is set equal to TIMER1_A0_VECTOR for the ISR location in memory. All this ISR will do is turn off the the D1, and because of the value we put in the CCR0 it will be the smallest duty cycle.
Here is the last and final ISR. In this ISR we have to interrogate the TAIV register to determine which CCR (1 or 2) triggered the ISR, or if the TAR rolled over. To do this we use a select statement, where case 2 indicates CCR1, case 4 is CCR2, and case 10 is a TAR roll over.
Both the CCR1 and the CCR2 ISR routines simply turn of there respective pin (P1.6 for CCR 1 and P2.1 for CCR2). The TAR interrupt is responsible for turning the pins of the 3 PWM signals back high at the end of the PWM period.
At this point you should be able to build and run the program. Once this done you should have 3 lit LEDs, a "dim" green LED(D1), a bright red LED P2.1 (D3), and slightly dimmer red LED P1.6 (D2). You might have a hard time perceiving the brightness of the LEDs in correlation to their duty cycle. Below is a scope capture of the green LEDs signal to the D3's LED.
As can be seen above, the duty cycle of CCR0 is 1/4th that of CCR2, which is exactly what we would expect.
Below is a link to the code for this example. Feel free to alter the duty cycles and play around.
Timer A with Interrupts
When I first started playing with Timers on the MSP430 they were my biggest confusion. I mean, sometimes you need an interrupt in a timer, sometimes you don't. It's very application specific. However, these two examples give a very simple overview of timers being used without interrupts and with. In fact, we've show both types of interrupt vectors used for a Timer A module.
This by no means is an exhaustive explanation. No, this is simply a "cook book" of sorts. I hope it helps, if you're stuck on parts of the tutorial send me a message and I'll try to help.
Good luck and cheers!