Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 7

LESSON 4: CONFIGURING THE MSP430

The code for this lesson is available on github under the tag ‘lesson_4’. To get the latest code
with git, the following commands can be run from the project root directory. Checkout master
first since this is the branch that is tracking the origin and contains all the changes.

git checkout master


git pull
git checkout -b lesson_4_devel lesson_4

Part 1: Configuring the clock module

Start the Launchpad programmed with the code from lesson 3. How fast is the LED blinking?
What if you wanted to make the LED blink twice a second, what delay would be required?
That depends on the frequency of the CPU which is controlled by a clock source, or oscillator, in
conjunction with the configurable clock module of the MSP430. There are many types
oscillators which range in price and accuracy depending on the application. In general, a higher
frequency bus will require a more accurate clock, but there are other factors which can affect
accuracy such as temperature and electrical noise which must be taken into account by the
hardware designer. Clock sources can be internal or external. External oscillators are usually
more accurate, but they add to cost and space on the board. For the purposes of these
tutorials, using the internal oscillator shall be sufficient. The MSP430 clock module can have up
to four clock sources:

 DCOCLK: Internal digitally controller oscillator


 VLOCLK: Internal very low frequency oscillator (~12kHz)
 LFXT1CLK: Low or high frequency oscillator can be used with an external low frequency
crystal (i.e. 32768Hz for a clock) or at high frequency requiring an external crystal,
resonator or clock source in the range of 400kHz – 16MHz
 XT2CLK: High frequency oscillator which requires an external crystal, resonator or clock
source in the range of 400kHz – 16MHz

Not all devices support all clock sources. The MSP430G2553 does not have an XT2CLK nor does
it support the high frequency oscillator mode on LFXT1CLK. These clock sources can be
configured to drive the three internal clock signals:

 MCLK: The master clock used by the CPU


 SMCLK: The sub-main clock, used for peripherals
 ACLK: The auxiliary clock, also used for peripherals

On power up or after a reset, the device is configured such that MCLK is sourced from DCOCLK
which has a frequency of approximately 1.1MHz. SMCLK is also sourced from DCOCLK and
ACLK is sourced from LFXT1CLK. The use of SMCLK and ACLK for peripherals is controlled by
software configuration of the specific module. All the clocks have divider options, so even if the
source is 16MHz, the clock signal may be half, a quarter or an eighth of the frequency. This is
useful if there is only one clock source, say DCOCLK, configured to 16MHz, but the peripherals
using SMCLK should only be running at 4MHz.

There are four registers to configure the MSP430 clock module:

 DCOCTL: DCO control


 BCSCTL1: Basic clock system control 1
 BCSCTL2: Basic clock system control 2
 BCSCTL3: Basic clock system control 3

The register fields are illustrated in the diagram below.

Detailed definitions of these registers can be found in section 5.3 of the family reference
manual. The source of the master clock is selected using BCSCTL2[SELMx]. In case you are not
familiar with the latter notation, it is read as register[field in the register]. The default value
after reset is 0b00, which configures the source to be DCOCLK, therefore no modification is
required. Since the DCOCLK will be used as the source, the frequency must be configured.
Three fields are required to do so, DCOCTL[DCOx], DCOCTL[MODx] and BCSCTL1[RSELx].
Selecting the values for DCOCTL[DCOx] and BCSCTL1[RSELx] can be done using figure 5-6 in
the family reference manual. Choosing MODx is more involved and beyond the scope of this
course as it requires knowledge of clock spreading and its effects on electromagnetic
interference (EMI).

So what if an MCLK frquency of 1MHz clock is required? Using the values from the figure in the
reference manual is not very accurate, and there is no easy way to determine what MODx
should be. Luckily TI provides the data for us stored right on the chip. In the last lesson when
we looked at the device specific memory organization (table 8 in the datasheet), there was a
section in the flash called ‘Information Memory’. This section of the flash contains calibration
data that TI has measured and provides to the user for accurate configuration of the device. The
data there is stored in what TI calls TLV (Tag-Length-Value) format, which is a table of data at
specific offsets defined by tags in the datasheet and reference manual. The TLV data is
protected from modification using a software protection mechanism, but the integrity of the
data should still be verified before using it. The first 2 bytes of the TLV area (address 0x10c0)
contain the checksum of the next 62 bytes which contains the data. The checksum is verified
by XOR’ing the data as 16-bit words and then adding the checksum. If the result is zero, the
data is valid, any other value means the data is corrupted. Please note, there are many
methods of calculating checksums, so this algorithm may not always be applicable. Below is a
function which demonstrates how to verify the integrity of information section.

1
2 static int _verify_cal_data(void)
{
3 size_t len = 62 / 2;
4 uint16_t *data = (uint16_t *) 0x10c2;
5 uint16_t crc = 0;
6
7 while (len-- > 0) {
8 crc ^= *(data++);
}
9
10 return (TLV_CHECKSUM + crc);
11 }
12

There are a few stylistic and code safety notes that are worth mentioning. First of all, the
function is declared static and therefore the function name is preceded with an underscore.
This is a personal preference and you don’t have to follow it, but it makes it easy to know which
functions are only accessible within the file. Next is the use of types size_t and uint16_t. To
access these types you must include “stddef.h” and “stdint.h” respectively. I almost always use
size_t as an index in loops since it is the type returned by the sizeof operator (sizeof() an array
for example). The use of uint16_t is more important however. When the specific length of data
is known, it is always safest and considered best practice to use the POSIX types (or equivalent)
which clearly indicate the size of the variable. In this case, using ‘unsigned int’ would be the
equivalent, but what if the same code was compiled on a PC. That variable would now be 32 bit
(or 64 bit) and the code would be incorrect. Of course this code is specific for the MSP430, but
the idea applies to any algorithm or calculation. Finally the return type follows the *nix standard
where a signed integer is returned such that 0 indicates success and any other value is a failure.
Again this is a personal preference but consistency is always good. Using too many return types
can be confusing and unless there is a need to know the reason for failure, a simple success or
failure status is often adequate.

Now that the calibration data can be validated, let’s take a look at how it can be used to
configure the device. The calibration data includes values for 1MHz, 8MHz, 12MHz, and 16MHz
based on a 25 degree Celsius ambient temperature. The tags for each frequency setting are
stored as two bytes, one contains the value for register DCOCTL and the other for BCSCTL1.
Only the fields mentioned above required to configure DCOCLK are set. All other fields in the
registers are cleared (except for BCSCTL1[X2OFF] if applicable to the device). To access this
calibration data and set the DCOCLK to 1MHz, the following code can be used.
1 /* Configure the clock module - MCLK = 1MHz */
2 DCOCTL = 0;
3 BCSCTL1 = CALBC1_1MHZ;
4 DCOCTL = CALDCO_1MHZ;

The first line of code clears DCOCTL to set the DCOCLK to the lowest setting. Next the
calibration data is copied into the DCOCTL and BCSCTL1 registers respectively using the tags
from the TLV area. The DCOCLK is now running at 1MHz. The DCOCLK can also be configured
to any of the other supported frequency values in the calibration data using the available tags.
Since BCSCTL2 still has its default values the current configuration can be summarized as
follows:

 MCLK source is DCOCLK


 MCLK divider is 1, therefore MCLK = DCOCLK = 1MHz
 SMCLK source is DCOCLK
 SMCLK divider is 1, therefore SMCLK = DCOCLK = 1MHz

The only clock is that is not configured is ACLK which can be sourced from either VCOCLK or
LFXT1CLK. Currently the frequency of ACLK will be 0Hz, and if it is to be enabled, either it must
be sourced from VCOCLK by setting BCSCTL3[LFXT1Sx] = 2, or by installing the external crystal
required for LFXT1CLK. I would have recommended using VCOCLK, but after looking in the
datasheet, VCOCLK can be anywhere from 4kHz – 20kHz, a range so wide it won’t be practical
for any of these tutorials. For now it can be left as is, and if needed in the future, a crystal can
be installed and the device configured accordingly.

Part 2: Setting the LED blinking frequency

Now that the CPU frequency is known, the frequency of the blinking LED can be accurately
configured. To blink the LED at a specific frequency, the number of CPU cycles to wait between
toggling the LED must be calculated. Since the frequency of the CPU is 1MHz, 1 million cycles
are executed per second. If the desired blinking frequency is 2Hz (2 toggles per second), the
LED should be toggled every 500000 cycles. [Update] As Jerry pointed out in the comments
below, my original definition of the frequency was incorrect. A frequency of 1Hz means that the
LED should toggle on and off once, since this is the periodic signal. Therefore to correct the
sentence above, a frequency of 2Hz would require the LED to be toggled 4 times a second, or
every 250000 cycles. The rest of the lesson has been updated to reflect this change. The
following formula can be used to calculate the delay:

This calculation can be implemented as a hash define in the code so that it will be calculated
automatically. Using the formula above along with the __delay_cycle function, the code from the
last lesson can be modified to set the blinking frequency to 2Hz.
1
2 /* LED blinking frequency */
3 #define LED_BLINK_FREQ_HZ 2
4
/* Number of cycles to delay based on 1MHz MCLK */
5 #define LED_DELAY_CYCLES (1000000 / (2 * LED_BLINK_FREQ_HZ))
6 ...
7 while (1) {
8 /* Wait for LED_DELAY_CYCLES cycles */
__delay_cycles(LED_DELAY_CYCLES);
9
10 /* Toggle P1.0 output */
11 P1OUT ^= 0x01;
12 }
13

Note the following two reasons why a hash define is used to calculate the number of cycles:

 The __delay_cycles function only takes a constant argument. If anything other than a
constant is passed as an argument to this function, the compiler will throw an error
 Using the hash define means the value is computed only once by the compiler. This
makes the code more efficient. It also means the loop is more accurate, because doing
division on an MSP430 could take many clock cycles, causing the delay to be longer than
intended

Part 3: Pin Configuration

Last lesson we briefly touched on the topic of pin configuration. Pin P1.0 could be configured as
a digital input or a digital output using the P1DIR register. This is only part of the story. Most
pins can actually be configured to perform several different functions. This is called pin
multiplexing. Almost every microcontroller supports pin multiplexing on pins which do not
have a dedicated function. Each pin is different and will have the ability to be configured for a
defined set of peripherals on the chip. Often, as is the case with the MSP430, the default
configuration of a pin is a digital input. To configure a pin to use one of its alternate functions,
the PxSEL1 and PxSEL2 registers are used. These registers follow the same bit to pin mapping
as described in lesson 3. When the bit for a given pin is cleared in both of these registers, as
they are on reset, the pin is configured as a digital I/O (also called a general purpose
input/output, or GPIO). Setting the appropriate bit in either or both of these registers will
enable the pin’s alternate functions. The list of alternate functions for each pin can be found in
device datasheet starting from table 16. It is important to note that even if a peripheral function
is selected for a specific pin, the other port configuration registers (such as PxDIR) may still
have to be appropriately configured. When we begin to use the peripheral devices, this concept
will become clear.
The GPIOs on the MSP430 also have the option to be connected to internal pull-up or pull-
down resistorsthrough the PxREN registers. When the PxREN bit for a specific pin is set, the
P1OUT register controls which resistor (pull-up or pull-down) the pin will be connected to. A
pin connected to pull-up/pull-down resistors can be still be driven to the any level by an
external device. For example, I2C uses pull-up resistors so that the idle state of the line is high.
The master drives the line low to begin communication. Internal pull-ups and pull-downs are
rarely used in practice as the value is fixed by the implementation of the microcontroller. Most
digital designers prefer to have control over the specific value and also the ability to change it if
required. The PxREN registers apply even if the pin is configured as an input.

Now lets go through an example to help solidify your understanding of pin configuration. The
objective is to modify the code such that the LED will start blinking only once switch 2 (SW2) on
the launchpad has been pressed. Switch 2 is connected to pin P1.3. From the datasheet, we can
see all the possible functions of this pin.

From
the MSP430G2553 Datasheet (SLAS735)

Pin P1.3 can be either a GPIO, an ADC clock output, a comparator output or a capacitive sensing
input using the P1SEL/2 registers. It can also be configured as an ADC voltage reference or
input as well as a comparator input by setting some additional registers, but lets leave these
aside for now. The goal is to read a push button, so GPIO functionality is required, therefore
P1SEL[3] and P1SEL2[3] should be cleared. Next, P1DIR[3] should be cleared to set the direction
as an input. On rev 1.5 Launchpads, TI has removed the external pull-up resistor for the button
so we must use the internal one. If your Launchpad is older this will still work. Set P1REN[3] and
P1OUT[3] to enable the internal pull-up resistor. Finally, the register P1IN is read to obtain the
value of the switch. In the example code below, each of these registers will be explicitly set
even if the default value is correct. This is done for code clarity and robustness.

1 /* Configure P1.3 to digital input */


2 P1SEL &= ~0x08;
3 P1SEL2 &= ~0x08;
4 P1DIR &= ~0x08;
5
6 /* Pull-up required for rev 1.5 Launchpad */
7 P1REN |= 0x08;
P1OUT |= 0x08;
8
9 /* Wait forever until the button is pressed */
10 while (P1IN & 0x08);
11

Polling a register is a valid way to determine if the input has changed value; however, it is not
the best way. While the code sits in an infinite loop waiting for the button to be pressed,
nothing else can happen – no other code can be executed. In this simple example, this is not a
problem because that is all we want to do. But say you wanted to stop the LED from flashing,
when would you read P1IN? If you do it only once per loop, it will only check the value of the pin
twice per second. If the button is pushed and released in less than that time, it will not be
detected. This is where interrupts come in, and allow the microcontroller to notify the software
when the hardware has been changed almost immediately. In the next lesson, we will learn
more about the MSP430 architecture which is required to understand how interrupts work. Then
in the following lesson we will dive into the very important topic of interrupts.

You might also like