countdown timer w led

MrChips

Joined Oct 2, 2009
30,808
Here is your next installement:

Let us review the LED flash program with a twist.

Rich (BB code):
// Patrol Cruiser Flashing LEDs Example
// 2013.04.25 - MrChips
#include "io430.h"

#define ON 1
#define OFF 0

#define LED1 P1OUT_bit.P0
#define LED2 P1OUT_bit.P6

#define DELAY 10000

void init(void)
{

  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;

  P1OUT = 0x00;
  P1DIR = 0xFF;
}

void delay(unsigned long d)
{
  unsigned long i;
  for (i = 0; i < d; i++);
}

void main( void )
{
  init();
  
  while (1)
  {
    LED1 = ON;
    LED2 = OFF;
    delay(DELAY);
    LED1 = OFF;
    LED2 = ON;
    delay(DELAY);
  }
  
}
This program will alternate between the red LED1 and green LED2 on the MSP-EXP430G2 LaunchPad evaluation board.

I have used the #define preprocessor statement as described in the previous blog post to make the code more readable.
 

Thread Starter

stillafloat

Joined Apr 16, 2013
41
quick question.. for the sake of testing and learning we are just overwriting the main.cpp file every time we add new code?

i think this is the case but just verifying
 

MrChips

Joined Oct 2, 2009
30,808
quick question.. for the sake of testing and learning we are just overwriting the main.cpp file every time we add new code?

i think this is the case but just verifying
Yes, we are overwriting the main.c file. You may keep backups if you wish but once you get the hang of it you can replicate these at anytime. These programs are very short, as you can see. Make notes to yourself.

You should be compiling a main.c file. If not, you can go back and create a new project and select C instead of C++. I really don't know if it makes any difference.
 

MrChips

Joined Oct 2, 2009
30,808
I don't want to overwhelm you with too much at once. You should proceed at your own comfortable pace. If you wish to proceed with the timer module here is the next step:

The MSP430G2553 has everything we need, including an internal clock, in order to make a decent timer. This is the first of two solutions I will present.

This chip also has a low frequency, low power crystal oscillator circuit. So if we really want to do this properly we might as well go all the way and install the 32768Hz clock crystal.

That very same crystal was included in the LaunchPad kit in a tiny plastic package. I hope you didn't toss that away but kept it in a safe place. We are going to need it.


Solution #1 - Using the built-in oscillator, timer module and interrupts


Here is where the fun really begins. We will program the timer module to create interrupts at fixed intervals.


Timer Module

I will present the first timer example code followed by explanations.

Rich (BB code):
// Timer Example without interrupts
// 2013.04.25 - MrChips
#include "io430.h"

#define ON 1
#define OFF 0

#define LED1 P1OUT_bit.P0
#define LED2 P1OUT_bit.P6

void init(void)
{

  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;

  P1OUT = 0x00;
  P1DIR = 0xFF;

  // initialize Timer0_A
  TA0CCR0 = 62500;  // set up terminal count
  TA0CTL = TASSEL_2 + ID_3 + MC_1; // configure and start timer
}


void main( void )
{
  init();
  
  while (1)
  {
    while (TA0CCTL0_bit.CCIFG == 0);  // wait for overflow flag
    TA0CCTL0_bit.CCIFG = 0;          // reset flag
    LED1 = ~LED1;                     // toggle LED1
  }
  
}
The MSP430 family features a number of timer modules. You have to check what is available on each specific chip.

To confuse things, there are different styles of timers, Timer_A and Timer_B.

On the MSP430G2553 there are two timers Timer0_A and Timer1_A. And to add to the confusion, a default timer is given a generic name which defaults to Timer0_A. I have not used the generic names to avoid this confusion.

Timer0_A is a 16-bit timer. The actual timer register is named TA0R.

TA0CCR0 is the capture/compare register which is used as the terminal count when counting UP.

TA0CTL is the control register used to configure the timer. We set three fields (or functions) as follows:

TASSEL_2 selects the internal 1MHz clock (SMCLK).
ID_3 sets the clock division to 8. Hence one timer clock cycle is 8μs.
MC_1 sets the count mode to count up.
In this mode, the timer will count for 62500 x 8μs = 500000μs or 0.5s before restarting at zero.

In the main loop, we wait for the flag CCIFG to go high which happens when the terminal count is reached. We then reset the CCIFG bit to zero and then toggle LED1.

The operator ~ takes the complement of the value.

Hence LED1 will be on for 0.5s and off for 0.5s.
(On my oscilloscope the time measured is 0.49s and this can be fine tuned if a more accurate time is required.)

Note that the operator to test for equality is ==.

A common error in C programming is to mistake the = assignment operator for the == equality test.

I will show the timer example using interrupts in the next blog post.
 
Last edited:

Thread Starter

stillafloat

Joined Apr 16, 2013
41
not going to fast and if you are i can just ask questions :)

I am getting an error when compiling your current code..

Error[Pe020]: identifier "TAC0CCTL0_bit" is undefined C:\Users\...\main.cpp 33
 

MrChips

Joined Oct 2, 2009
30,808
My error, it should be TA0CCTL0_bit
I am programming on one computer and posting on another. Hence I don't actually test the code that gets posted. Instead of retyping I really ought to copy and paste actual code that has been debugged.
 
Last edited:

Thread Starter

stillafloat

Joined Apr 16, 2013
41
My error, it should be TA0CCTL0_bit
I am programming on one computer and posting on another. Hence I don't actually test the code that gets posted. Instead of retyping I really ought to copy and paste actual code that has been debugged.
copy and paste is a beautiful thing :)

I was able to get LED1 to flash I also replaced LED1 with LED2 to make the green LED flash. I also made both LED1 and LED2 flash together.

i like to mess with the different settings and see what results i get :)
 

MrChips

Joined Oct 2, 2009
30,808
That's the best way to learn.

I will give you one more program change before calling it a day. You've had enough for one day.


Interrupts can be tricky to program and they function somewhat magically.

However, it is a very important feature of embedded microcontroller systems and should be used to its full advantage.

Here is a simple example of the interrupt mechanism followed by some explanations.

Rich (BB code):
// Timer example using interrupts
// 2013.04.26 - MrChips

#include "io430.h"

#define ON 1
#define OFF 0

#define LED1 P1OUT_bit.P0
#define LED2 P1OUT_bit.P6

void init(void)
{

  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;

  P1OUT = 0x00;
  P1DIR = 0xFF;

  // initialize Timer0_A
  TA0CCR0 = 62500;  // set up terminal count
  TA0CTL = TASSEL_2 + ID_3 + MC_1; // configure and start timer

  // enable interrupts
  TA0CCTL0_bit.CCIE = 1;   // enable timer interrupts
  __enable_interrupt();    // set GIE in SR
}

#pragma vector = TIMER0_A0_VECTOR
__interrupt void myTimerISR(void)
{
  LED1 = ~LED1;
}

void main( void )
{
  init();
  
  while (1)
  {
    // any code goes here
  }
  
}
You will notice only three or four changes from our previous program.

Programming for interrupts is like following a cake recipe. There are a number of essential steps in order to make it work. Make a single mistake in any one step and your cake will turn out to be a flop.

Thank goodness that I am better at programming than I am at baking cakes!

There are four essential steps in setting up interrupts and getting it to work properly.

  1. The interrupt service routine (ISR) to handle the interrupt must be written.
  2. The microcontroller must have the address of the ISR located in the interrupt vector table.
  3. The device must be enabled to generate interrupts.
  4. The microprocessor must have its interrupt hardware enabled to handle interrupts.

Step 1

I have created a timer ISR called myTimerISR( ). The name can be anything you choose and is of importance only to you. The compiler will accept any name you choose as long as it follows the naming conventions and is not already being used.

Note that definition of this ISR is preceeded with the word __interrupt which starts with double underscore.

What the heck is this #pragma thing anyway?

#pragma is a catch-all preprocessor directive that is used to extend the functionality of the compiler that is not already covered by predefined directives.

In this example, the compiler (and the linker) is being told that we are going to create an ISR for TIMER0_A0_VECTOR.

Look at the contents of the header file "io430g2553.h" and you will find at the end of the file the #define statements for all the interrupt vectors for this chip.

Our ISR is called when the timer register (TA0R) counts up to the terminal count (TA0CCR0).

What we do in the ISR is entirely up to us. In this simple example, we will simply toggle LED1 as in the previous example. That is, I have moved the task that was previously performed in the main loop to the ISR. This leaves nothing for us to do in the main loop.

In general, this frees up the main program loop for some other task to be performed.

When the device interrupt flag is set, an interrupt is generated provided that the remaining Steps 2 to 4 are in place. When the interrupt is acknowledged, the device interrupt flag must be cleared otherwise the same device will keep on interrupting. On the MSP430 mcu, the interrupt flag is automatically cleared when the interrupt is acknowledged.


Step 2

The address of our ISR, i.e. myTimerISR( ), must be burned into location 0xFFF2 of the mcu flash memory. This is done automatically for us by our #pragma statement and the __interrupt statement.


Step 3

The device will only generate an interrupt if its interrupt enable flag is set. We do this with the instruction

TA0CCTL0_bit.CCIE = 1;


Step 4

The mcu will not respond to any interrupts unless the general interrupt enable (GIE) bit is set in the status register (SR).

This is done using

__enable_interrupt( );

Again, note that this statement starts with double underscore.


There you have it, your first simple timer interrupt example.


Coming up next

Using the low frequency 32768Hz crystal oscillator.

It's time to find that crystal and get out the soldering iron.
 

Thread Starter

stillafloat

Joined Apr 16, 2013
41
i jumped to the next step using your blog, however I am getting some errors

Error[Pe020]: identifier "BCSTL1" is undefined C:\Users\...\main.cpp 22
Error[Pe020]: identifier "BCSTL3" is undefined C:\Users\...\main.cpp 23
Error[Pe020]: identifier "delay" is undefined C:\Users\...\main.cpp 39
 

MrChips

Joined Oct 2, 2009
30,808
Thanks for pointing out these errors. Actually this is a test to see who is attempting to run the code or just reading the blogs.

I had deleted the delay( ) function and forgot to replace it.

BCSTL1 should be BCSCTL1.
BCSTL3 should be BCSCTL3.
 

Thread Starter

stillafloat

Joined Apr 16, 2013
41
the changes seem to have worked.. I have moved on to your last set of codes but seem to be lost on what is happening.. is the IC now programmed properly? if so is there anyway i can see whats going on like in a BIOS of a CPU. I would think the process is counting down and would like to be able to see this.
 

Thread Starter

stillafloat

Joined Apr 16, 2013
41
also I would like to take my breadboard and set up a working example on the breadboard. I have seen your example in your blog entry however I don't know where to place the LED? Also on the IC you state putting a capacitor between pin 1 and 20, now if i didn't have a picture example how would one know which pin is what since they don't seem to be labeled?

sorry for the rookie questions but if i don't know the answer i feel i should ask :)
 

MrChips

Joined Oct 2, 2009
30,808
the changes seem to have worked.. I have moved on to your last set of codes but seem to be lost on what is happening.. is the IC now programmed properly? if so is there anyway i can see whats going on like in a BIOS of a CPU. I would think the process is counting down and would like to be able to see this.
You can peek inside the CPU using the debugger but there is no need to do that. The exercises were designed to test the code with delay times that are convenient to observe. Verifying the code for delay times of 1 hour and 24 hours will, um, take a bit of time.

You can modify the code to show that it is counting up every minute (or any time interval you desire).

The final code shown should meet your original requirements.
 

MrChips

Joined Oct 2, 2009
30,808
also I would like to take my breadboard and set up a working example on the breadboard. I have seen your example in your blog entry however I don't know where to place the LED? Also on the IC you state putting a capacitor between pin 1 and 20, now if i didn't have a picture example how would one know which pin is what since they don't seem to be labeled?

sorry for the rookie questions but if i don't know the answer i feel i should ask :)
There is a U-shaped notch on the end of the IC to indicate pins 1 and 20.

The LED has been moved to P2.2 which is on pin-10.
 

MrChips

Joined Oct 2, 2009
30,808
You ought to put a current limiting resistor in series with the LED.
A resistance of about 220Ω to 470Ω should be ok. Adjust for suitable brightness. The brighter it is the more power it will draw from the battery.
 
Top