MSP430m06 TIMERS-1
MSP430m06 TIMERS-1
MSP430m06 TIMERS-1
Introduction
Timers are often thought of as the heartbeat of an embedded system.
Whether you need a periodic wake-up call, a one-time delay, or need a means to verify that the
system is running without failure, Timers are the solution.
This chapter begins with a brief summary of the MSP430 Timers. Most of the chapter, though, is
spent digging into the details of the MSP430’s TIMER_A module. Not only does it provide
rudimentary counting/timing features, but provides sophisticated capture and compare features
that allow a variety of complex waveforms – or interrupts – to be generated. In fact, this timer can
even generate PWM (pulse width modulation) signals.
Along the way, we examine the MSP430ware DriverLib code required to setup and utilize
TIMER_A.
As the chapter nears conclusion, there’s a brief summary of the differences between TIMER_A
and TIMER_B. Bottom line, if you know how to use TIMER_A, then you can use TIMER_B; but,
there are a couple of extra features that TIMER_B provides.
Learning Objectives
Objectives
Chapter Topics
Timers .......................................................................................................................................... 6-1
Prerequisites and Tools ............................................................................................................ 6-2
Overview of MSP430 Timers .................................................................................................... 6-3
TIMER_A/B Nomenclature .................................................................................................... 6-4
Timer Summary..................................................................................................................... 6-5
Timer Basics: How Timers Work ............................................................................................... 6-6
Counter.................................................................................................................................. 6-6
Frequency, Time-Period, Resolution ................................................................................ 6-7
Capture.................................................................................................................................. 6-8
Compare................................................................................................................................ 6-9
Timer Details: Configuring TIMER_A ...................................................................................... 6-12
1. Counter: TIMER_A_configure…() ................................................................................ 6-13
Timer Counting Modes .................................................................................................... 6-14
Summary of Timer Setup Code – Part 1 ......................................................................... 6-18
2a. Capture: TIMER_A_initCapture() ............................................................................... 6-19
2b. Compare: TIMER_A_initCompare() ............................................................................. 6-21
Summary of Timer Setup Code – Part 2 ......................................................................... 6-23
Output Modes .................................................................................................................. 6-24
PWM anyone? ................................................................................................................. 6-29
3. Clear Interrupt Flags and TIMER_A_startTimer() ........................................................... 6-30
4. Interrupt Code (Vector & ISR) ......................................................................................... 6-31
TIMER_A DriverLib Summary ................................................................................................. 6-32
Differences between Timer’s A and B..................................................................................... 6-33
Lab Exercise ........................................................................................................................... 6-35
The “Timers in Training” callout box describes where the various timers are discussed in this
workshop. Timers A and B are covered in this chapter. We have already covered the Watchdog
timer in a previous chapter.
The RTC module will be discussed in a future chapter. A brief description of the RTC tells us that
it’s a very low-power clock; has built-in calendar functions; and often includes “alarms” that can
interrupt the CPU. It is frequently used for keeping a time-base while the CPU is in low-power
mode.
Nomenclature is
discussed on the
next page
TIMER_A/B Nomenclature
The nomenclature of the TIMER_A and _B peripherals is a little unusual. First of all, you may
have already noticed that the MSP430 team often adds one of two suffixes to their peripheral
names to indicate when features have been added (or modified).
• Some peripherals, such as the Watchdog Timer go from “WDT” to “WDT+”. That is, they add
a “+” to indicate the peripheral has been updated (usually with additional features).
• Other peripherals are enumerated with letters. For example, three sophisticated MSP430
timers have been introduced: TIMER_A, TIMER_B, and TIMER_D. (What happened to _C?
Even I don’t know that. <ed>)
The use of a suffix is the generic naming convention found on the MSP430. With the timers,
though, there are a couple more naming variations to be discussed.
As we will cover in great detail during this chapter, these timers contain one or more Capture and
Compare Registers (CCR); these are useful for creating sophisticated timings, interrupts and
waveforms. The more CCR registers a timer contains, the more independent waveforms that can
be generated. To this end, the documentation often includes the number of CCR registers when
listing the name of the timer. For example, if TIMER_A on a given device has 5 CCR registers,
they often name it:
Timer_A5
But wait, that’s not all. What happens when a device, such as the ‘F5529 has more than one
instance of TIMER_A? Each of these instances needs to be enumerated as well. This is done by
appending the instance number after the word “Timer”, as in Timer0.
To summarize, here’s the long (and short) names for each of the ‘F5529 TIMER_A modules:
1 Timer1_A3 TA1
2 Timer2_A3 TA2
Timer Summary
The ‘F5529 contains most of the different types of timers found across the MSP430 family; in fact,
the only type of timer not present on this device is the high-resolution TIMER_D.
The following summary provides a snapshot of what timers are found on various MSP430
devices. You’ll find our ‘F5529 and ‘FR5969 devices in the last two columns of the table.
MSP430 Timers
L092 G2553 FR4133 F5172 F5529 FR5969
1 x A5 2 x A3
Timer_A 2 x A3 2 x A3 2 x A3 1 x A3
2 x A3 2 x A2*
Timer_B 1 x B7 1 x B7
Timer_D 2 x D3
Real-Time RTC
RTC_A RTC_B
Clock Counter
Counter
A counter is the fundamental hardware element found inside a timer.
The other essential element is a clock input. The counter is incremented each time a clock pulse
is applied to its clock input. Therefore, a 16-bit timer will count from zero (0x0000) up to 64K
(0xFFFF).
When the counter reaches it reaches its maximum value, it overflows – that is, it returns to zero
and starts counting upward again. Most timer peripherals can generate an interrupt when this
overflow event occurs; on TIMER_A, the interrupt flag bit for this event is called TAIFG (TIMER_A
Interrupt Flag).
Timer/Counter Basics
15 TAR 0
/ounter /ounter
Overflow Action
/lock Input Register Interrupt (TAICG)
/lock
GtIO tin (TA/LK)
Each pulse 04
of clock input
03
increments the
counter register 02
01 01
Notes
Timers are often called “Timer//ounters” as a counter is the essential element
“Timing” is based on counting inputs from a known clock rate
Actions don’t occur when writing value to counter
Can I 'capture' a count/time value?
The clock input signal for TIMER_A (named TACLK) can be one of the internal MSP430 clocks or
a signal coming from a GPIO pin.
Many engineers call these peripherals “Timer/Counters” as they provide both sets of functionality.
They can generate interrupts or waveforms at a specific time-base – or could be used to count
external events occurring in your system.
One final note about the MSP430 timers: they do not generate interrupts (or other actions) when
you write to the counter register. For example, writing “0” to the counter won’t generate the TAIFG
interrupt.
Definitions
Frequency: How many times per second
Time teriod: Amount of time between successive events
Resolution: Granularity in determining system events
If a timer only consisted of a single counter, its resolution would be limited to the size of the
counter.
If some event were to happen in a system – say, a user pushed a button – we could only
ascertain if that event occurred within a time period. In other words, we can only determine if it
happened between two interrupts.
Looking at the above diagram, we can see that there is “more data” available – that is, if we were
to read the actual counter value when the event occurred. Actually, we can do this by setting up a
GPIO interrupt; then, having the ISR read the value from the counter register. In this case the
resolution would be better, but it is still limited by:
• It takes more hardware (an extra GPIO pin is needed)
• The CPU has to execute code – this consumes power and processing cycles
• The resolution is less deterministic because it’s based upon the latency of the interrupt
response; in other words, how fast can the CPU get to reading the counter … and how
consistent can this be each time it occurs
There is a better way to implement this in your system … turn the page and let’s examine the
timer’s Capture feature.
Capture
The Capture feature does just that. When a capture input signal occurs, a snapshot of the
Counter Register is captured; that is, it is copied into a capture register (CCR for Capture and
Compare Register). This is ideal since it solves the problems discussed on the previous page; we
get the timer counter value captured with no latency and very, very little power used (the CPU
isn’t even needed, so it can even remain in low-power mode).
The diagram below builds upon our earlier description of the timer. The top part of the diagram is
the same; you should see the Counter Register flanked by the Clock Input to the left and TAIFG
action to the right.
The bottom portion of the slide is new. In this case, when a Capture Input signal occurs, the value
from the Counter Register is copied to a capture register (i.e. CCR).
FMpture BMsics
15 TAR 0
Counter Counter
Overflow Action
Clock Input Register Interrupt (TAIFG)
Clock
GtIO tin (TACLK)
Capture Actions
Capture Input Capture/Compare Interrupt (CCIFGn)
CCInA
CCInB Register (CCRn)
Signal peripheral
Modify pin (TAx.n)
Software
Notes
Capture time (i.e. count value) when Capture Input signal occurs
When capture is triggered, count value is placed in CCR and an interrupt is generated
Capture Overflow (COV): indicates 2nd capture to CCR before 1st was read
AlternMtively, use FFR for compMre...
As we just discussed, the Capture feature provides a deterministic method of capturing the count
value when triggered. While handy, there is another important requirement for timers…
Compare
A key feature for timers is the ability to create a consistent, periodic interrupts.
As we know, TIMER_A can do this, but the timer’s frequency (i.e. time period) is limited to
dividing the input clock by 216. So, while the timer may be consistent, but not very flexible.
Thankfully, the Compare feature of TIMER_A (TIMER_B & TIMER_D) solves this problem.
Compare Basics
15 TAR 0
Counter Counter
Overflow Action
Clock Input Register Interrupt (TAICG)
Clock
GPIO Pin (TACLK)
Compare Actions
Capture/Compare Interrupt (CCICGn)
Register (CCRn)
Signal peripheral
aodify pin (TAx.n)
Notes
There are usually 2 to 7 compare registers (CCR’s), therefore
up to 8 interrupts or signals can be generated
Counter must count-to Compare value to generate action
Once again, the top portion of this diagram remains the same (Clock Input + Counter Register).
The bottom portion of the diagram differs from the previous diagrams. In this case, rather than
using the CCR register for capture, it’s used as a compare register. In this mode, whenever a
match between the Counter and Compare occurs, a compare action is triggered. The compare
actions include generating an interrupt, signaling another peripheral (e.g. triggering an ADC
conversion), or changing the state of an external pin.
The “modify pin” action is a very powerful capability. Using the timer’s compare feature, we can
create sophisticated PWM waveforms. (Don’t worry, there’s more about this later in the chapter.)
Example: Timer0_A7
15 0
5ivide 16-bit Counter Enable Interrupt
by 5-bits (TA0IFG)
(up to ÷ 64) (TA0R) (TA0IE)
CCR0
CCR1
CCR2
CCR3
CCR4
CCR5
CCR6
Remember:
• Timer0 means it’s the first instance of Timer_A on the device.
• _A7 means that it’s a Timer_A device and has 7 capture/compare registers (CCR’s)
• The clock input, in this example, can be driven by a TACLK signal/pin, ACLK, SMCLK or
another internal clock called INCLK.
• The clock input can be further divided down by a 5-bit scalar.
• The TA0IE interrupt enable can be used to allow (or prevent) an interrupt (TA0IFG) from
reaching the CPU whenever the counter (TA0R) rolls over.
This next diagram allows us to look more closely at the Capture and Compare functions.
Timer_A7 Summary
15 0
5ivide 16-bit Counter Enable Interrupt
by 5-bits (TAIFG)
(up to ÷ 64) (TAR) (TAIE)
CC0IE CC0IFG
...
CAP=0 CCR0
TA0.0
CAP=1 CC6IE CC6IFG
Ca
SCS CCR6
COV TA0.6
Timer0_A7:
Is the first instance (Timer0 or TA0) of Timer_A7 on the device
_A7 means it has 7 Capture/Compare Registers (CCR’s)
CCR registers can be configured for:
Compare (set when CAP=0) generates interrupt (CCnIFG) and
modifies OUT signal when TAR = CCRn
Capture (when CAP=1) grabs the TAR value and sets an interrupt (CCnIFG)
when triggered by the selected CCIx input
Every CCR register has its own control register. Notice above, that the “CAP” bit configures
whether the CCR will be used in capture (CAP=1) or compare mode (CAP=0).
You can also see that each CCR has an interrupt flag, enable, and output signal associated with
it. The output signal can be routed to a pin or a number of other internal peripherals.
As we go through the rest of this chapter, we’ll examine further details of the CCR registers as
well as the various “actions” that the timer generates.
In the next section, we’ll begin examining how to configure the timer using the MSP430ware
DriverLib API.
4. Finally, if your timer is generating interrupts, you need to have an associated ISR for each
one. (While interrupts were covered in the last chapter, we briefly summarize this again in context of
the Timer_A.)
We will intermix how to write code for the timer with further examination of the timer’s features.
1. Counter: TIMER_A_configure…()
The first step to using TIMER_A is to program the main timer/counter control register. The
MSP430ware Driver Library provides 3 different functions for setting up the main part of the timer:
TIMER_A_configureContinuousMode()
TIMER_A_configureUpMode()
TIMER_A_configureUpDownMode()
We will address the different modes on the next page. For now, let’s choose ‘continuous’ mode
and see how we can configure the timer using the DriverLib function.
1. Configure Timer/Counter
15 0
5ivide 16-bit /ounter Enable Interrupt
by 5-bits (TAICG)
(up to ÷ 64) (TAR) (TAIE)
Timer_A_init/ontinuousModetaram inittaram = { 0 };
inittaram.clockSource = TIMER_A_/LO/KSOUR/E_A/LK;
inittaram.clockSource5ivider = TIMER_A_/LO/KSOUR/E_5IVI5ER_1;
inittaram.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUtT_ENA.LE;
inittaram.timer/lear = TIMER_A_5O_/LEAR;
inittaram.startTimer = false;
Timer_A_init/ontinuousMode( TIMER_A0_.ASE, &inittaram );
From the diagram, we can see that 3 different hardware choices need to be made for our timer
configuration; the arrows demonstrate how the function parameters relate to these choices. Let’s
look at each parameter one-by-one:
• The first parameter chooses which Timer_A instance you want to program. In our example,
we have chosen to program TA0 (i.e. Timer0_A). Conveniently, the DriverLib documentation
provides enumerations for all the supported choices. (This is the same for all DriverLib
parameters, so we won’t keep repeating this statement. But, this is very handy to know!)
• The 2nd parameter lets you choose which clock source you want to use. We chose SMCLK.
• The next parameter picks one of the provided clock pre-scale values. The h/w lets you
choose from one of 20 different values; we picked ÷ 64.
• Parameter four lets us choose whether to interrupt the processor Remember…
when the counter (TA0R) rolls over to zero. This parameter ends up
TAR: Timer_A count Register
setting the TA0IE bit.
TA0R: Name for count register
• Finally, do you want to have the timer counter register (TA0R) reset when referring to instance “0”
when the other parameters are configured? (i.e. Timer0_A)
1B Configure TimerCCounPer
1D 0
Divide 16-bit Counter Enable Interrupt
by 5-bits (TAICG)
(up to ÷ 64) (TAR) (TAIE)
Timer_A_initContinuousModeParam initParam = { 0 };
initParam.clockSource = TIMER_A_CLOCKSOURCE_ACLK;
initParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
initParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;
initParam.timerClear = TIMER_A_DO_CLEAR;
initParam.startTimer = false;
Timer_A_initContinuousMode( TIMER_A0_BASE, &initParam );
Continuous Mode
Thus far we have described the timer’s counter operating in the Continuous mode; in fact, this
was the configuration example we just discussed.
TIMER_A_configureContinuousMode( );
FFFFh
Continuous mode
TAR runs full range of
16-bit counter
INT occurs at count to 0
TAR must transition to
zero – it won’t happen
if you write 0 to TAR
0h
TA0ICG TA0ICG
What differs with Up mode?
The different counting modes describe how the timer counter register (TAR) is incremented or
decremented. For example, in Continuous mode, the timer counts from 0x0 up to 0xFFF and then
rolls back to 0x0, where it begins counting up again. (This is shown in the diagram above.)
As you can see, every time the counter rolls back to zero, the TAIFG bit gets set; which, if
enabled, interrupts the processor every 216 input clocks. (Since our previous example was for
Timer0_A, the diagram shows TA0IFG getting set.)
Up Mode
The Up counting mode differs from the Continuous mode by resetting back to zero whenever the
counter matches CCR0 (Capture and Compare Register 0).
You can see the different waveforms compared on the slide below. The green waveform
counts Up to the value found in CCR0, and then resets back to zero.
On the other hand, the grey dotted waveform shows how, when in Continuous mode, the counter
goes past CCR0 and all the way to 0xFFFF.
TAR in UP Mode
Divide Interrupts
16-bit Counter Enable
by 5-bits TA0IFG
(up to ÷ 64) (TAR) (TAIE)
Timer_A_initUpMode( ); UP mode
FFFFh Ints at ‘custom’ (higher)
frequencies
Both interrupts are
CCR0 generated 1-cycle apart
CC0IFG when TAR = CCR0
TA0IFG when TAR0h
CCR0 is special CCR
hnly CCR0 affects TAR’s
count in this way
0h CCR0 is a dedicated IFG,
the rest are grouped
CC0IFG CC0IFG
TA0IFG TA0IFG
In Up mode, since we are using the CCR0 register, the timer can actually generate two interrupts:
• CC0IFG (for Timer0_A, this bit is actually called TA0CC0IFG)
• TAIFG (for Timer0_A, this bit is called TA0IFG)
You’re not seeing a color misprint; the two interrupts do not happen at the exact same time, but
rather 1 cycle apart. The CC0IFG occurs when there is a compare match, while the TA0IFG
interrupt occurs once the counter goes back to zero.
If you compare these two Up mode interrupts to the one generated in the Continuous mode, you’ll
see they occur at a more rapid frequency. This is a big advantage of the Up mode; your
frequency is not limited to 216 counts, but rather can be anywhere within the 16-bit counter’s
range. (The downside is that you also have to configure the CCR0 registers.)
Note: The CCR0 (Capture and Control Register 0) is special. That is, it is special in comparison to the
other CCR registers. It is only CCR0 that can be used to define the upper limit of the counter in Up
(or UpDown) count mode.
The other special feature of CCR0 is that it provides a dedicated interrupt (CC0IFG). In other
words, there is an Interrupt Vector location dedicated to CC0IFG. All the other Timer_A interrupts
share a common vector location (i.e. they make up a grouped interrupt).
Up/Down Mode
The UpDown count mode is similar to Up in that the counter only reaches the value in CCR0
before changing. In this case, though, it actually changes direction and starts counting down
rather than resetting immediately back to zero.
Not only does this double the time period (i.e. half the timer’s frequency), but it also spreads out
the two interrupts. Notice how CC0IFG occurs at the peak of the waveform, while TAIFG occurs
at the base of the waveform.
TIMER_A_iniPUpDownMode( );
FFFFh
CCR0
UP/DhWN mode
TAR counts up & down
2x period of UP mode
i.e. half the interrupts
Remembers count dir 0h
If TAR stopped then
started, it keeps going
in same direction
CC0IFG TA0IFG CC0IFG
In our diagram we show all three counter mode waveforms. The UpDown mode is shown in red;
Up is shown in green; and the Continuous mode is shown in grey.
void main(void) {
// Setup/Hold Watchdog Timer (WDT+ or WDT_A)
initWatchdog();
//----------------------------------------------------------
// Then, configure any other required peripherals and GPIO
initTimers();
__bis_SR_register( GIE );
while(1) {
...
}
Our earlier example for the Timer/Counter setup code demonstrated using the Continuous mode.
The following example shows using the Up mode. Here’s a quick comparison between the two
functions – notice that the Up mode requires two additional parameters.
CCR0
Capture or Compare (CAt)
CAt=1 for capture
CCR1
Which Edge (Ca)
Rising, Calling, or Both CCR2
Sync’d to Clock (SCS)
Is capture sync or async? CCR3
Capture Overflow (COV)
5id you miss a capture? CCR4
CCR5
CAt=1
Ca Interrupt
SCS CCR6 CC6IE (CC6ICG)
COV
Hint: Each CCR can be configured independently. The flip side to this is that you must
configure each one that you want to use; this might involve calling the ‘capture’ and/or
‘compare’ configuration functions multiple times.
Use one for capture and the rest for compare. Or, use all for capture. You get to decide
how they are used.
Warning: If you are using Up or UpDown count modes, you should not configure CCR0. Just
remember that the TIMER_A_configureUpMode() and TIMER_A_configureUpDownMode()
configuration functions handle this for you.
To configure a CCR register for Capture mode, use the TIMER_A_initCapture() function.
Thankfully, when using DriverLib the code is pretty easy to read (and maintain). Hopefully
between the diagram and the following table, you can make sense of the parameters.
We’ve briefly talked about every feature (i.e. function parameter) found in this function except
OutputMode. The “OUTBITVALUE” (for CCR6) indicates that the value of CCR6’s IFG bit should
be output to CCR6’s Output signal. The output signal can be used by other peripherals or routed
to the TA0.6 pin.
Note: With regards to OutputMode, this is just the tip-of-the-iceberg. There are actually 8
possible output mode settings. We will take you through them later in the chapter.
CCR0
CCR1 Enable Interrupt
(CC2IE) (CC2ICG)
CAP=0 CCR2
OUT
(TA0.2)
CAP=0 (Capture off) CCR3
Compare mode on
If CCR2 = TAR (named EQU2): CCR4
Interrupt occurs (if enabled)
OUT is set/reset/toggled CCR5
OUT can be:
Connected to pin (TA0.2) CCR6
Routed to peripherals
OUT bit can be polled I
aany OUT signal options
5iscussed later in the chapter
Once again, before we walk through the function that initializes CCR for Compare, let’s examine
its options:
• Set CAP=0 for the CCR to be configured for Compare Mode. (Opposite from earlier.)
• You must set the CCR2 register to a 16-bit value. When TAR = CCR2:
− An internal signal called EQU2 is set.
− If enabled, EQU2 drives the interrupt flag high (CC2IFG).
− Similar to the Capture mode, the CCR’s output signal is modified by EQU2. Again, this
signal is available to other internal peripherals and/or routed to a pin (in this case, TA0.2).
− Again, similar to the Capture mode, there are a variety of possible output modes for the
OUT2 signal (which will be discussed shortly).
One thing you might notice about the TIMER_A_initCompare() function is that it requires fewer
parameters than the complementary initCompare function.
The OutputMode setting will be configured using the “Set/Reset” mode (which correlates to the
value 0x3). Once again, with so many different output mode choices, we’ll defer the full
explanation of this until the next topic.
void initTimerA0(void) {
// Setup TimerA0 in Up mode with CCR2 compare
TIMER_A_configureUpMode( TIMER_A0_BASE,
TIMER_A_CLOCKSOURCE_SMCLK,
1
TIMER_A_CLOCKSOURCE_DIVIDER_1,
TIMER_PERIOD,
TIMER_A_TAIE_INTERRUPT_ENABLE,
TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE,
TIMER_A_DO_CLEAR );
TIMER_A_initCompare( TIMER_A0_BASE,
TIMER_A_CAPTURECOMPARE_REGISTER_2,
2
TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,
TIMER_A_OUTPUTMODE_SET_RESET,
0xBEEF // Compare Value
);
Part 1 of our code configures the timer/counter; i.e. the main element of Timer_A.
Part 2 configures the various Capture/Compare registers (CCR). Due to limited space on the slide
we have only included the initCompare function for CCR2. In a real application, you might use all
of the CCR registers – in which case, our initTimerA0() function would become a lot longer.
Before we move onto Part 3 of our timer configuration code, let’s spend a few pages explaining
the 8 different output mode options available when configuring Capture/Compare Registers.
Output Modes
As you may have already seen, each CCR register has its own associated pin. For CCR1 on
Timer0 this pin would be named “TA0.1”. Depending upon which mode you put the CCR into; this
pin can be used as an input (for Capture) or an output (for either Capture or Compare).
When the pin is used as an output, its value is determined by the OUT bit-field in its control
register. The exact details for this are TA0.1 = TA0CCTL1.OUT. (Sometimes you’ll just see this
OUT bit abbreviated as OUT1.)
Besides routing the CCR OUT signal to a pin, it can also be used by other MSP430 peripherals.
For example, on some devices the A/D converter could be triggered by the timer directly.
So, what is the value of OUT for any given CCR register?
The value of OUT is determined by the OutputMode, as we discussed earlier. (Each CCR control
register has its own OUTMOD bit-field). This setting tells the OUT bit how to react as each
compare or capture occurs. As previously stated, there are 8 different OutputMode choices.
For example, setting OUTMOD = 0 mean it’s not changed by the timer’s hardware. That is, it’s
under software control. You can set OUT to whatever you like by writing to it in the CCRx control
register.
Output aode 1
OUTaOD = 01 is called “Set”
This means that OUT (e.g. TA0.1) is
set on EQU1
That is, whenever TAR=CCR1
As we can see from the diagram above, when the timer/counter (TAR) counts up to the value in
CCR1 (i.e. TAR = CCR1), then a valid comparison is true.
The enumeration for OUTMOD = 1 is called “Set”; whenever TAR=CCR1, then OUT will be “Set”
(i.e. OUT = 1). In fact, OUT will remain = 1 until the CCR is reconfigured.
Why use “Set” mode? You might find this mode useful in creating a one-shot type of signal.
EQU
Before we examine OutputMode 2, let’s consider the nomenclature used in the MSP430 User’s
Guide.
Apparently, there is an EQU (equate) signal inside the timer for each CCR. For example, the
equate signal for CCR1 would be called EQU1. While these EQU values cannot be read directly
from any of the timer control registers, the documentation makes use of them to describe when a
comparison becomes true.
Therefore, when the timer counter (TAR) becomes equal to a compare register (CCR), the
associated EQU signal becomes true.
This can be seen in the following diagram captured from the TIMER_A documentation. Notice
how EQU0 becomes true when TAR=CCR0; likewise, EQU1 becomes true when TAR=CCR1.
In other words, when the OutputModes are defined by two names, the first one dictates the value
of OUTn whenever the TAR=CCR n (i.e. whenever EQU n becomes true). The second name
describes what happens to OUT n whenever TAR=CCR0.
Note: Remember what we said earlier, CCR0 is often used in a special way. This is another
example of how CCR0 behaves differently than the rest of the CCR’s.
Looking at the diagram below, we can see that in OutputMode 2, the OUT1 signal appears to be
a pulse whose duty cycle (i.e. width) is proportional to the difference between CCR0 and CCR1.
on EQUn on CCR0
By showing both OUTMOD=1 and OUTMOD=2 in the same diagram, you can see how the value
of OUT n can be very different depending upon the OutputMode selected.
Routing the OUT signal to a pin, as shown here, lets us drive external hardware directly from the
output of the timer. (In fact, we’ll use this feature to let the timer directly drive an LED during one
of the upcoming lab exercises.)
Completely automatic
Independent frequencies with different
duty cycles can be generated for each CCR
Iooking at all tOe Output Modes…
04 Toggle
Do tOese look like PWM signals?
Here's a simple PWM example... 05 Reset
Toggle/
06
Set
Reset/
07
Set
In this case, though, CCRn = CCR0. That means these modes could be trying to change OUT0
in two different ways at the same time.
PWM anyone?
PWM, or pulse-width modulation, is commonly used to control the amount of energy going into a
system. For example, by making the pulse widths longer, more energy is supplied to the system.
Looking again at the previous example where OUTMOD = 2, we can see that by changing the
difference between the values of CCR0 and CCRn we can set the width of OUTn.
TA0CCR0
CCRn sets duty cycle
TA0CCR1
TA0CCR2
0x0
OUT1
Duty cycle (“on” time ) is set by selecting Output aode and varying CCRx value
In this example, CCR0 – CCR1 = amount of time Signal is High
In the case of the MSP430, any timer can generate a PWM waveform by configuring the CCR
registers appropriately. In fact, if you are using a Timer_A5, you could output 4 or 5 different
PWM waveforms.
TA0CCR0
TA0CCR1
TA0CCR2
0x0
OUT1
OUT2
Duty cycle (“on” time ) is set by selecting Output aode and varying CCRx value
In this example, CCR0 – CCR1 = amount of time Signal is High
As described earlier in the workshop, you are not required to clear interrupt flags before enabling
an interrupt, but once again, this is common practice. In Part 3 of the example below, we first
clear the Timer flag (TA0IFG) using the function call provided by DriverLib. Then, we clear all the
CCR interrupts using a single function; notice that the “+” operator tells the function that we want
to clear both of these IFG bits.
void initTimerA0(void) {
// Setup TimerA0 in Up mode with CCR2 Compare
TIMER_A_configureUpMode( TIMER_A0_BASE,
TIMER_A_CLOCKSOURCE_SMCLK,
1
TIMER_A_CLOCKSOURCE_DIVIDER_1,
TIMER_PERIOD,
TIMER_A_TAIE_INTERRUPT_ENABLE,
TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE,
TIMER_A_DO_CLEAR );
TIMER_A_initCompare( TIMER_A0_BASE,
2
TIMER_A_CAPTURECOMPARE_REGISTER_2,
TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,
TIMER_A_OUTPUTMODE_SET_RESET,
0xBEEF ); // Compare Value
TIMER_A_clearTimerInterruptFlag(
TIMER_A0_BASE );
TIMER_A_clearCaptureCompareInterruptFlag(
3 TIMER_A0_BASE,
TIMER_A_CAPTURECOMPARE_REGISTER_0 +
TIMER_A_CAPTURECOMPARE_REGISTER_2 );
TIMER_A_startCounter( TIMER_A0_BASE,
TIMER_A_UP_MODE ); //Make sure this
Old API – Slide will be updated on }
next workshop revison // matches config fxn
We conclude the code for Part 3 by starting the timer. The start function only has two parameters:
• It’s probably obvious that you need to specify which timer that needs to be started.
• The other parameter specifies, once again, the count mode for the timer’s counter.
Warning!
Did we get your attention? The timer “start” function ended up being one of the biggest problems
during the development of this workshop.
As dumb as it sounds, we missed the fact that you need to set the counter mode (e.g. “UP”) in this
function. When we cut/pasted this function from another example, we never thought to change this
parameter.
Why, because we thought it had already been specified by using the TIMER_A_configureUpMode()
function. Well, we found out the hard way that you need to do both. Use the correct function AND
specify the correct count mode in the start function.
Remember, TIMER_A has two interrupt vectors: one dedicated to CCR0; another shared by
TAIFG and all the other CCR’s. Below, we provide a simple example of handling both.
#pragma vector=TIMER0_A1_VECTOR
__interrupt void myISR_TA0_Other(void) {
switch(__even_in_range( TA0IV, 10 )) {
case 0x00: break; // None
4
case 0x02: break; // CCR1 IFG
case 0x04: // CCR2 IFG
GPIO_toggleOutputOnPin(…);
I{w for break;
//w2 case 0x06: break; // CCR3 IFG
and TA0ICG case 0x08: break; // CCR4 IFG
case 0x0A: break; // CCR5 IFG
case 0x0C: break; // CCR6 IFG
case 0x0E: // TA0IFG
GPIO_toggleOutputOnPin(…);
break;
default: _never_executed();
}
}
Many of the functions have arrows pointed to/from the three main parts of the timer peripheral:
TAR (the main timer/counter); CCR (used for Compare); and CCR (used for Capture). The arrows
indicate whether the function reads or writes the associated registers.
TIaEw_A_initCapture()
CCw6 Ctrl weg
TIaEw_A_getCaptureCompareCount() CCw6
The bottom of the slide contains two boxes: one summarizes the Interrupt related functions while
the other contains three functions that read/write the input and output bit values.
Hint: For a more complete understanding of these differences, we highly recommend that you
refer to MSP430 Microcontroller Basics. John Davies does a great job of describing the
differences between these timers. Furthermore, his discussion of generating PWM
waveforms using these timers is extremely good. If you’ve never heard of the differences
between edge-aligned and centered PWM waveforms, check out his MSP430 book.
Notes
Note: The solutions exist for all of these exercises, but the instructions for Lab 6d are not yet
included. These will appear in a future version of the course.
Lab Topics
Timers ........................................................................................................................................ 6-33
Lab 6 – Using Timer_A ........................................................................................................... 6-35
Lab 6a – Simple Timer Interrupt ............................................................................................. 6-37
Lab 6a Worksheet ............................................................................................................... 6-37
Lab 6a Procedure................................................................................................................ 6-42
Edit myTimers.c .................................................................................................................. 6-43
Debug/Run .......................................................................................................................... 6-44
(Extra Credit) Lab 6b – Timer using Up Mode ........................................................................ 6-45
Lab 6b Worksheet ............................................................................................................... 6-45
File Management ................................................................................................................ 6-48
Change the Timer Setup Code ........................................................................................... 6-49
Debug/Run .......................................................................................................................... 6-49
Archive the Project .............................................................................................................. 6-50
Timer_B (Optional) ............................................................................................................. 6-51
(Extra Credit) Lab 6c – Drive GPIO Directly From Timer........................................................ 6-52
Lab 6c Abstract ................................................................................................................... 6-52
Lab 6c Worksheet ............................................................................................................... 6-53
File Management ................................................................................................................ 6-57
Change the GPIO Setup ..................................................................................................... 6-57
Change the Timer Setup Code ........................................................................................... 6-58
Debug/Run .......................................................................................................................... 6-59
(Optional) Lab 6c – Portable HAL ...................................................................................... 6-63
(Optional) Lab 6d – Simple PWM (Pulse Width Modulation) ........................................................ 6-64
Chapter 6 Appendix ................................................................................................................ 6-65
As we write the ISR code, you should see that TIMER_A has two interrupts:
− One is dedicated to CCR0 (capture and compare register 0).
− The second handles all the other timer interrupts
This first TIMER_A lab will use the main timer/counter rollover interrupt (called TA0IFG). As with
our previous interrupt lab (with GPIO ports), this ISR should read the TimerA0 IV register (TA0IV)
and decipher the correct response using a switch/case statement.
Lab 6a Worksheet
Goal: Write a function setting up Timer_A to generate an interrupt every two seconds.
1. How many clock cycles does it take for a 16-bit counter to ‘rollover’? (Hint: 16-bits)
________________________________________________________________________
2. Our goal is to generate a two second interrupt rate based on the timer clock input
diagramed above.
Using myClocks.c provided for this lab, we created a table of example clock & timer rates:
15 0
SM/LK 8 MIz 8 1 ms 15 Iz 66 ms
A/LK 32 KIz 2 62 ms ½ Iz 4s
Pick a source clock for the timer. (Hint: At 2 seconds, a slow clock might work best.)
3. Calculate the Timer settings for the clocks & divider values needed to create a timer
interrupt every 2 seconds. (That is, how can we get a timer period rate of 2 seconds.)
Which clock did you choose in the previous step? Write its frequency below and then
calculate the timer period rate.
Timer Clock = ÷ =
input clock frequency timer clock divider timer clock freq
Timer Rate = x =
65536
timer clock period counts for timer to timer rate period
(i.e. 1 / timer clock freq) rollover
i.e. 64K
Write down the timer enumeration you need to use: TIMER_ _______ _BASE
Timer_A_initContinuousModeParam initContParam = { 0 };
initContParam.clockSource = _____________________________________________________;
initContParam.clockSourceDivider = _____________________________________________;
initContParam.timerInterruptEnable_TAIE = _______________________________________;
initContParam.timerClear = TIMER_A_DO_CLEAR;
initContParam.startTimer = false;
Timer_A_initContinuousMode(TIMER_ _____ _BASE, &initContParam );
Hint: Where do you get help writing this function? We highly recommend the MSP430ware
DriverLib Users Guide. (See ‘docs’ folder inside MSP430ware’s driverlib folder.)
Another suggestion would be to examine the header file: (timer_a.h).
7. Complete the code to for the 3rd part of the “Timer Setup Code”.
The third part of the timer setup code includes:
− Enable the interrupt (IE) … we don’t have to do this, since it’s done by the
TIMER_A_configureContinuousMode() function (from question 5 on page 6-39 ).
− Clear the appropriate interrupt flag (IFG)
− Start the timer
8. Change the following interrupt code to toggle LED2 when Timer_A rolls-over.
b) Here is the interrupt code that exists from a previous exercise, change it as
needed.
Mark up the following code – crossing out what is old or not needed and writing in the
modifications needed for our timer interrupt.
#pragma vector=PORT1_VECTOR
__interrupt void pushbutton_ISR (void)
{
switch( __even_in_range( P1IV , 16 )) {
case 0: break; // No interrupt
case 2: break; // Pin 0
case 4: // Pin 1
GPIO_toggleOutputOnPin( GPIO_PORT_P1, GPIO_PIN0 );
break;
case 6: break; // Pin 2
case 8: break; // Pin 3
case 10: break; // Pin 4
case 12: break; // Pin 5
case 14:
break; // Pin 6
case 16: break; // Pin 7
default: _never_executed();
}
}
Please verify your answers before moving onto the lab exercise.
Lab 6a Procedure
File Management
1. Verify that all projects (and files) in your workspace are closed.
If some are open, we recommend closing them.
It doesn’t matter whether you copy this project into your workspace or not. If you “copy” it into
your workspace, the original files will remain untouched. If do not copy, but rather “link” to the
project, you will only have one set of files and any changes you make inside of CCS will be
reflected in the C:\msp430_workshop\<target>\lab_06a_timer directory.
Edit myTimers.c
4. Edit the myTimers.c source file.
We want to setup the timer to generate an interrupt two seconds. The TAIFG interrupt service
routine will then toggle LED2 on/off.
void initTimers(void)
Worksheet {
Question #5 // 1. Setup Timer (TAR, TACTL)in Continuous mode using ACLK
(page 6-39) TIMER_A_ _______________________(
TIMER_A__BASE, // Which timer
TIMER_A_ ________________, // Which clock
TIMER_A_ _____________________, // Clock divider
TIMER_A_ _____________________, // Enable INT on rollover?
TIMER_A_DO_CLEAR // Clear timer counter
);
Debug/Run
7. Launch the debugger.
Notice that you may still see the clock variables in the Expressions pane. This is convenient,
if you want to double-check the MSP430 clock rates.
12. Once you’ve got the LED toggling, you can terminate your debug session.
From the discussion you might remember that TIMER_A has two interrupts:
• One is dedicated to CCR0 (capture and compare register 0).
• The second handles all the other timer interrupts
In our previous lab exercise, we created an ISR for the grouped (non-dedicated) timer interrupt
service routine (ISR). This lab adds an ISR for the dedicated (CCR0 based) interrupt.
Lab 6b Worksheet
1. Calculate the timer period (for CCR0) to create a 1 second interrupt rate.
Here’s a quick review from our discussion.
Timer_A’s counter (TAR) will count up until it reaches the value in the CCR0 capture register,
then reset back to zero. What value do we need to set CCR0 to get a ½ second interval?
1
Timer Rate =
/32768 x =
1 second
timer clock period timer counter period timer rate period
(i.e. 1 / timer clock freq) (i.e. CCRO value)
Hint: Where to get help for writing this function? Once again, we recommend the
MSP430ware DriverLib users guide (“docs” folder inside MPS430ware’s DriverLib).
Timer_A_initUpModeParam initUpParam = { 0 };
initUpParam.clockSource = TIMER_A_CLOCKSOURCE_ACLK;
initUpParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
3. Modifying our previous code, we need to clear both interrupts and start the timer.
We copied the following code from the previous exercise. It needs to be modified to meet the
new objectives for this lab.
Here are some hints:
− Add an extra line of code to clear the CCR0 flag (we left a blank space below for this)
− Don’t make the mistake we made … look very carefully at the ‘startCounter’ function.
Is there anything that needs to change when switching from Continuous to Up mode?
TIMER______BASE,
______________________________________________ );
4. Add a second ISR to toggle the LED1 whenever the CCR0 interrupt fires.
On your Launchpad, what Port/Pin number does the LED1 use? ______________
Hints:
What port/pin does your LED1 use? Look back at question 8 (page 6-40).
Look at the unused_interrupts.c file for a list of interrupt vector symbol names.
_______________________________________________________________
Please verify your answers before moving onto the lab exercise.
File Management
5. Copy/Paste lab_06a_timer to lab_06b_upTimer.
a) In CCS Project Explorer, right-click on the lab_06a_timer project and select “Copy”.
b) Then, click in an open area of Project Explorer pane and select “Paste”.
This will create a new copy of your project inside the Workspace directory.
c) Finally, rename the copied project to lab_06b_upTimer.
Note: If you didn’t complete lab_06a_timer – or you just want a clean starting solution –
you can import the lab_06a_timer archived solution.
7. Delete the old, readme file and import the new one.
You can import the new readme text file from this folder:
C:\msp430_workshop\<target>\lab_06b_upTimer
8. Make sure the project is selected (i.e. active) and build it to verify no errors were
introduced during the copy.
10. Modify the rest of the timer set up code, where we clear the interrupt flags, enable the
individual interrupts and start the timer.
Please refer to the Lab Worksheet for assistance. (Question 3, Page 6-46).
11. Add the new ISR we wrote in the Lab Worksheet to handle the CCR0 interrupt.
When this step is complete, you should have two ISR’s in your main.c file.
Please refer to the Lab Worksheet for assistance. (Question 4, Page 6-47).
13. Build the code to verify that there are no syntax (or any other kind of) errors; fix any
errors, as needed.
Debug/Run
Follow the same basic steps as found in the previous lab for debugging.
14. Launch the debugger and set a breakpoint inside both ISR’s.
Why? ____________________________________________________________________
16. Remove the breakpoints and let the code run. Do both LED’s toggle?
An easy way to quickly remove all of the breakpoints is to open the Breakpoints View
window:
View → Breakpoints
− Fill out the dialog as shown below, choosing: the ‘upTimer’ lab; “Save in zip format”,
“Compress the contents of the file”; and the following destination:
C:\msp430_workshop\<target>\lab_06b_upTimer\my_lab_06b_upTimer.zip
Timer_B (Optional)
Note: Since the ‘FR4133 does not include the Timer_B peripheral, you can skip this exercise if
you’re using the MSP-EXP430FR4133 Launchpad.
Do you remember during the discussion that we said Timer_A and Timer_B were very similar? In
fact, the timer code we have written can be used to operate Timer_B … with 4 simple changes:
• It’s a different API … but not really.
Rather than using the TIMER_A module from DriverLib, you will need to use TIMER_B;
unless you’re using one of the few unique features of TIMER_B, the rest of the API is the
same. In other words, you can carefully search and replace TIMER_A for TIMER_B.
• Specify a different timer.
Since you’re using a different timer, you need to specify a different timer ‘base’. For either
the ‘F5529 or ‘FR5969 you should use TIMER_B0_BASE to specify the timer instance you
want to use.
• You need to use the TIMER_B interrupt vector.
This changes the #pragma line where we specify the interrupt vector.
• You need to use the TIMER_B interrupt vector register.
You need to read the TB0IV register to ascertain which TIMER_B flag interrupted the CPU.
All of these are simple changes. Try implementing TIMER_B on your own.
Note: While we don’t provide step-by-step directions, we did create a solution file for this
challenge.
We are still using Up mode, which means that CCR0 is used to reset TAR back to 0. We needed
to choose another signal to connect to the external pin… we arbitrarily chose to use CCR2 to
generate our output signal for this exercise.
In our case, we want to drive an LED directly from the timer’s output signal…
…unfortunately, the Launchpad does not have an LED connected directly to a timer output pin,
therefore we'll need to use a jumper in order to make the proper connection. As we alluded to
earlier in the chapter, in the case of Timer_A, the Launchpad’s route different timer pins to the
BoosterPack pin-outs.
(Note: Later in the lab instructions, we’ll show a picture of connecting the jumper wire.)
Lab 6c Worksheet
1. Figure out which BoosterPack pin will be driven by the timer’s output.
To accomplish our goal of driving the LED from a timer, we need to choose which Timer CCR
register to output to a pin on the device. In the lab abstract (on the previous page) we stated
that for this lab writeup, we arbitrarily chose to use CCR2.
Based on the choice of CCR2, we know that the timer’s output signal will be: TAn.2.
We’ve summarized this information in the following table:
GPIO Is Pin on
Device Timer CCRx Signal
Port/Pin Boosterpack?
Your job is to fill in the remaining two columns for the device that you are using.
a) Looking at the datasheet, which GPIO port/pin is combined with TA0.2 (or TA1.2)?
For example, here we see that P1.1 is combined with TA0.0:
Look for the correct pin in your device’s datasheet and enter it in the table above.
Hint: There are a couple places in the datasheet to find this information. We
recommend searching your device’s datasheet for “TA0.2” or “TA1.2”.
Bottom line, we wanted to choose a Timer pin that was connected to the BoosterPack pinout since it
would make it easy for us to jumper that signal over to LED1.
The problem was that neither board connected the same TimerA outputs to its Boosterpack pinout.
In looking carefully at the datasheets for both devices, as well as the Boosterpack pinouts for each
Launchpad, we found a timer that we could use. The only issue is that one device mapped TA0.2 to
a pin, while the other mapped out TA1.2.
‘F5529
F5529
FR4133
‘FR5969
FR5969
2. Complete the following function to “select” P1.3 as a timer function (as opposed to GPIO).
Hint: We discussed the port select function in the GPIO chapter. You can also find the details
of this function in the Driver Library User’s Guide.
___________________,
___________________ );
FR4133 ___________________,
___________________,
________________________________________ );
Timer_A_initUpModeParam initUpParam = { 0 };
initUpParam.clockSource = TIMER_A_CLOCKSOURCE_ACLK;
initUpParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
initUpParam.timerPeriod = 0xFFFF / 2;
initUpParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;
initUpParam.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;
initUpParam.timerClear = TIMER_A_DO_CLEAR;
initUpParam.startTimer = false;
Timer_A_initUpMode( TIMER____BASE, &initUpParam );
4. What ‘compare’ value does CCR2 need to equal in order to toggle the output signal at
a ½ second?
1 Second
CCR0=0x8000
CCR2 = __________________
CCR2
0x0
½ Second
5. Add a new function call to set up Capture and Compare Register 2 (CCR2). This should
be added to initTimers().
initCcr2Param.compareValue = _______________________________________;
6. Compare your ISR code from myTimers.c in the previous lab to the code below. What
is different in the code shown here?
#pragma vector=TIMER0_A1_VECTOR
__interrupt void timer0_ISR(void)
{
switch(__even_in_range( TA0IV, 14 )) {
case 0: break; // No interrupt
case 2: break; // CCR1 IFG
case 4: // CCR2 IFG
_no_operation();
break;
case 6: break; // CCR3 IFG
case 8: break; // CCR4 IFG
case 10: break; // CCR5 IFG
case 12: break; // CCR6 IFG
case 14: break; // TAR overflow
GPIO_toggleOutputOnPin( GPIO_PORT_P4, GPIO_PIN7 );
break;
default: _never_executed();
}
}
_________________________________________________________________________
_________________________________________________________________________
7. Why is it better to toggle the LED directly from the timer, as opposed to using an interrupt
(as we’ve done in previous lab exercises)?
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
File Management
1. Copy/Paste the lab_06b_upTimer to lab_06c_timerDirectDriveLed.
a) In Project Explorer, right-click on the lab_06b_upTimer project and select “Copy”.
b) Then, click in an open area of Project Explorer and select paste.
c) Finally, rename the copied project to lab_06c_timerDirectDriveLed.
Note: If you didn’t complete lab_06b_upTimer – or you just want a clean starting solution
– you can import the archived solution for it.
5. Modify the initGPIO function, defining the appropriate pin to be configured for the
timer peripheral function.
Please refer to the Lab6c Worksheet for assistance. (Question 2, Page 6-54).
Then again, it doesn’t hurt anything if you leave it in the code… if so, an unused bit gets
cleared.
9. Make the minor modification to the timer isr function as shown in the worksheet.
Please refer to the Lab Worksheet for assistance. (Step 6, Page 6-56).
‘FR5969 users – we only showed the ‘F5529 code in the worksheet. Please be careful that
you do not change the interrupt vector or IV register values in your code. That’s not what
we’re asking you to do in this step.
10. Build the code verifying there are no syntax errors; fix any as needed.
Debug/Run
11. Launch the debugger and set three breakpoints inside the two ISR’s.
• When we run the code, the first breakpoint will indicate if we received the CCR0 interrupt.
If we wrote the code properly, we should NOT stop here.
• We should NOT stop at the second breakpoint either. CCR2 was set up to change the
Output Signal, not generate an interrupt.
• We should stop at the 3rd breakpoint. We left the timer configured to break whenever TAR
rolled-over to zero. (That is, whenever TA0IFG or TA1IFG gets set.)
Note: As of this writing, due to an emulator bug with the ‘FR5969 – as we discussed in an
earlier lab exercise – terminating, restarting, or resetting the ‘FR5969 with two or
more breakpoints set may cause an error. If this occurs, load a different program,
then reload the current one again.
12. Remove the breakpoints and let the code run. Do both LED’s toggle?
13. Add the jumper wire to your board to connect the timer output pin to LED1.
a) Remove the jumper (JP8 or J6) that connects the LED1 to P1.0 (or P4.6).
(We recommend reconnecting it to the top pin of the jumper so that you don’t lose it.)
b) On the ‘F5529 Launchpad, connect P1.3 (fifth pin down, right-side of board,
inside row of pins) to the bottom of the LED1 jumper (JP8) using the jumper wire.
(See the next page for the ‘FR5969 Launchpad.)
c) On the ‘FR5969 (not shown), connect P1.3 (in the lower, right-hand corner of the
BoosterPack pins to the LED1 jumper (J6).
d) We didn’t include a picture showing the ‘FR4133 pin P8.3 being connected to LED1. It’s
fairly easy to find, though as it’s in the lower-left corner of the Boosterpack pins.
16. Modify one parameter of the function that configures CCR2, changing it to use the
mode:
TIMER_A_OUTPUTMODE_TOGGLE
Hint, if you haven’t already tried this trick, delete the last part of the parameter and hit
Ctrl_Space:
Eclipse will provide the possible variations. Double-click on one (or select one and hit return)
to enter it into your code.
17. Build and run your code with the new Output Mode setting.
______________________________________________________________________
If a compare match (TAR = CCR2) causes the output to be SET (i.e. LED goes ON),
what causes the RESET (LED going OFF)?
______________________________________________________________________
______________________________________________________________________
You may want to experiment with a few other output mode settings. It can be fun to see them
in action.
For the most part, “Yes”. This is often done by creating a HAL (hardware abstraction layer).
We’ve created a rudimentary HAL version of Lab 6c. You can find this in the solution file:
lab_06c_timerHal_solution.zip
While the timer file is shared between the two HAL solutions, we didn’t get too fancy with this.
There are a couple of things we didn’t handle; for example, we didn’t do anything with
unused_interrupts.c and so it hade to be edited manually when porting between processors.
The lab_06d_simplePWM project uses this DriverLib function to create a single PWM
waveform. As with Lab 6c, the output is routed to LED1 using a jumper wire. By default, it creates
a 50% duty cycle … which means it blinks the light on/off (50% on, 50% off) similar (but slightly
faster) than our previous lab exercise.
One big change, though, is that we added two arguments to the initTimers() function. These
values are the “Period” and “Duty Cycle” values that are passed to the simplePWM function. We
also rewrote the main while{} loop so that it calls initTimers() every second.
The purpose of these changes was to allow you to have an easy way to experiment with different
Period & Duty Cycle values without having to re-build and re-start the program over-and-over
again. The values for period and duty-cycle were created as global variables – again, this makes
it easier to change them while debugging the project.
The easiest way to experiement with this program once you’ve started it running is to:
− Halt (i.e. Suspend) the program
− View the two values in the Expressions watch window
− Change the values, as desired
− Continue running the program – in a second, literally, the values should take effect
By the way, if you change the period to something smaller, you won’t be able to see the LED
going on/off anymore – it will just appear to stay on. At this point, changing the duty cycle will
cause the LED to appear bright (or dim).
As the name implies, this is a simple example, using a Driver Library function to quickly get PWM
running.
Both Timer_A and Timer_B peripherals can create multiple/complex PWM (pulse-width
modulation) waveforms. At some point, we may add additional PWM examples to the workshop,
but if you want to learn more right now, we highly recommend that you review the excellent
discussion in John Davies book: MSP430 Microcontroller Basics by John H. Davies, (ISBN-10
0750682760) Link
Chapter 6 Appendix
Lab6a Answers
216 = 64K
Ln Lab 4c we configured
ACLK for 32KHz
32 KHz
1 sec
32K cycles 2 sec
TLaER_A_CLhCKShURCE_ACLK
TLaER_A_CLhCKShURCE_5LVL5ER_1
TLaER_A_TALE_LbTERRUtT_EbABLE
AO/A1
Timer_A_clearTimerLnterruptFlag
Timer_A_startCounter
Ah or A1
TLaER_A_ChbTLbUhUS_ahDE
4 7
TIMER0_A1
TA0IV
‘FR5969 Solution
1 0
TIMER1_A1
TA1IV
Lab6b Answers
0x8000
0xFFFF / 2
TLaER_A_CCLE_CCR0_LbTERRUtT_EbABLE
Ah or A1
Ah or A1
Timer_A_clearCaptureCompareLnterruptFlag
TIMER_A_CAPTURECOMPARE_REGISTER_0
Ut Ut
Lab6c Answers
Lab 6c Worksheet (1)
t1.3 Yes
t8.3 Yes
t1.3 Yes
F5529
FR5969
PeripheralModuleFunctionOutputPin
GtLh_thRT_t1
GtLh_tLb3
PeripheralModuleFunctionOutputPin
GtLh_thRT_t1
GtLh_tLb3
GtLh_tRLaARY_ahDULE_FUbCTLhb
PeripheralModuleFunctionOutputPin
GtLh_thRT_t1
GtLh_tLb3
GtLh_tRLaARY_ahDULE_FUbCTLhb
0x4000
CompareModeParam
TLaER_A_CAtTUREChatARE_REGLSTER_2
0x4000
CompareMode
We disabled the LbT because we’re driving the signal directly to the pin
Lower tower:
When the Timer drives the pin; no need to wake up the CtU. (Either
that, or it leaves the CtU free for other processing.)
Less Latency:
When the CtU toggles the pin, there is a slight delay that occurs since
the CtU must be interrupted, then go run the LSR.
aore Deterministic:
The delay caused by generating/responding to the interrupt may vary
slightly. This could be due to another interrupt being processed (or a
higher priority interrupt occurring simultaneously). Directly driving the
output removes the variance and makes it easy to “determine” the time
that the output will change!
Lab 6c Debrief
bo
LED2 is based on the timer counting up to the value in CCR0 (0x8000); while
LED1 toggles when the counter reaches CCR2 (set to 0x4000) and is reset
whenever the counter reaches CCR0.
Lab 6c Debrief