...
- All code running on our electrical system is written in C. It would be a good idea to become familiar with C before continuing with this tutorial. You can find many resources online about programming in C such as this one.
- Code Composer Studio (CCS) should be installed.
- A MSP430 EXP430F5529LP Launchpad. (There is some available in the bay to use or you can purchase your own here).
- Read Clearing, Toggling, Setting, and Checking a Bit.
- MSP430F5529 datasheets
Setting up a project
Go to the top menu bar and click File->New->CCS Project. The dialog that appears should look something like this:
...
I've already explained the PxOUT
and PxDIR
registers, so we'll skip over them and look at the for loop. In the for loop, we are toggling bit 0 of P1OUT
using the XOR operator (See Clearing, Toggling, Setting, and Checking a Bit) and then we call a special function, __delay_cycles
.
Code Block | ||||
---|---|---|---|---|
| ||||
__delay_cycles(100001000000); |
This function delays the processor for x cycles. In our case, we chose 1,000,000 because MCLK runs at 1Mhz by default so it should be around 1 second of delay. So, in our loop, we toggle the state of the LED (if it's on, it turns off, and if it's off, it turns on) and then we wait for a little bit. This creates the effect of the LED blinking.
...
First, to understand how timers work, it would be a good idea to look at the timer section in the datasheet (Documentation for Timer A starts on page 462). Here, we can see all the documentation about the registers that interact with Timer A on the microcontroller. From this, we find out that in order to use the timer, we need to set some information in the Timer A control register (TACTLTA0CTL)
and handle the interrupts.
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
#include <msp430.h> /* * main.c */ int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer P1OUT &= ~BIT0; P1DIR |= BIT0; TACTLTA0CTL |= TASSEL_2 | MC_2 | ID_3; TACCTL0TA0CCTL0 |= CCIE; TA0CCR0 TACCR0 = 65535; __enable_interrupt(); for (;;) { } return 0; } #pragma vector = TIMERA0TIMER0_A0_VECTOR __interrupt void TIMERA0TIMER0_A0_ISR(void) { P1OUT ^= BIT0; } |
Explanation
At the beginning of the main function, we can see the IO and timer setup code. The IO configuration is the same as before, but the timer setup is new.
First, we setup the Timer A control register (TACTL
TA0CTL
) to use SMCLK SMCLK (TASSEL_2
), up-down mode (MC_2
), and a frequency divider of 8 (ID_3
). Next, we set the Timer A capture/compare control register (TACCTL0
TA0CCTL0
) to enable interrupts locally for the timer. After that, we set the value we will be counting to by setting TACCR0
TA0CCR0
to 65535 (the maximum value it can store). This will cause the timer to start counting. Lastly, we globally enable interrupts by calling __enable_interrupt
and loop forever.
Here at the bottom in the #pragma
section, we can see the ISR we created for Port 1 Timer A interrupts. All this service routine does is toggle the state of the LED to make it blink.
...