Handling Interrupts and LPM in C language

Introduction

Well I’ve already written about handling interrupts in assembly language. Now I thought of writing about handling interrupts in C language. Since most of us are used to writing in C language, it is very important that one learns how to handle interrupts and write interrupt subroutines. Now first things first. Whatever you use be it C,C++ or assembly language, the controller understands only binary language. So when you burn the code its the hex file and nothing else that matters. Now the C language code is converted to assembly language which in turn is compiled to create the hex file. So one must know this fact to be able to use C language properly. In C language we can declare variables of various data types like char,int,etc. but when it comes to embedded C care must be taken. If your ALU size is 16 bit then the register size is 16 bit as well. So when you initialize a variable in C it is nothing but a register which is being initialized and used. Thus if you use double or any other type which is greater than the size of ALU you are bound to get error. Now to a C programmer it might seem absurd but if you know what is happening behind the scene its always easier to debug and understand what is happening. So if one knows assembly language then viewing the disassembly and debugging is easier.

Interrupts in C language

Handling interrupt is nothing but writing a code at a location whose starting address is written at the vector address of the interrupt being handled. In order to do this one must know the concept of #pragma vector. Now #pragma vector=Vector_Address is a directive just like ORG is in assembly language. What it tells the compiler is that the function that is being written next is a ISR and its starting address has to be stored at the Vector_Address. That being said, the function for ISR has a particular syntax which has to be followed.

Syntax for ISR function

__interrupt void function_name(void){}

(Note there are two underscores before the interrupt keyword). Now the function name can be anything except a keyword(which is quite obvious.). In the body of this function is what you write for handling the interrupt.

Syntax for writing a complete ISR

#pragma vector=Vector_Address

__interrupt void function_name(void)

{

// code for ISR

}

With that being covered what remains is the Vector_Address, one cannot type the vector address directly in hexadecimal value. In the msp430.h header file (rather see the device specific header file for e.g. msp430g2553.h ) there is a section for vector addresses where all vector addresses have been assigned a macro. I’ll paste the portion of header file concerning the topic at hand.

/************************************************************
* Interrupt Vectors (offset from 0xFFE0)
************************************************************/

#define VECTOR_NAME(name)       name##_ptr
#define EMIT_PRAGMA(x)          _Pragma(#x)
#define CREATE_VECTOR(name)     void (* const VECTOR_NAME(name))(void) = &name
#define PLACE_VECTOR(vector,section) EMIT_PRAGMA(DATA_SECTION(vector,section))
#define ISR_VECTOR(func,offset) CREATE_VECTOR(func); \
PLACE_VECTOR(VECTOR_NAME(func), offset)

#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define PORT1_VECTOR            “.int02”                     /* 0xFFE4 Port 1 */
#else
#define PORT1_VECTOR            (2 * 1u)                     /* 0xFFE4 Port 1 */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define PORT2_VECTOR            “.int03”                     /* 0xFFE6 Port 2 */
#else
#define PORT2_VECTOR            (3 * 1u)                     /* 0xFFE6 Port 2 */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define ADC10_VECTOR            “.int05”                     /* 0xFFEA ADC10 */
#else
#define ADC10_VECTOR            (5 * 1u)                     /* 0xFFEA ADC10 */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define USCIAB0TX_VECTOR        “.int06”                     /* 0xFFEC USCI A0/B0 Transmit */
#else
#define USCIAB0TX_VECTOR        (6 * 1u)                     /* 0xFFEC USCI A0/B0 Transmit */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define USCIAB0RX_VECTOR        “.int07”                     /* 0xFFEE USCI A0/B0 Receive */
#else
#define USCIAB0RX_VECTOR        (7 * 1u)                     /* 0xFFEE USCI A0/B0 Receive */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define TIMER0_A1_VECTOR        “.int08”                     /* 0xFFF0 Timer0)A CC1, TA0 */
#else
#define TIMER0_A1_VECTOR        (8 * 1u)                     /* 0xFFF0 Timer0)A CC1, TA0 */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define TIMER0_A0_VECTOR        “.int09”                     /* 0xFFF2 Timer0_A CC0 */
#else
#define TIMER0_A0_VECTOR        (9 * 1u)                     /* 0xFFF2 Timer0_A CC0 */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define WDT_VECTOR              “.int10”                     /* 0xFFF4 Watchdog Timer */
#else
#define WDT_VECTOR              (10 * 1u)                    /* 0xFFF4 Watchdog Timer */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define COMPARATORA_VECTOR      “.int11”                     /* 0xFFF6 Comparator A */
#else
#define COMPARATORA_VECTOR      (11 * 1u)                    /* 0xFFF6 Comparator A */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define TIMER1_A1_VECTOR        “.int12”                     /* 0xFFF8 Timer1_A CC1-4, TA1 */
#else
#define TIMER1_A1_VECTOR        (12 * 1u)                    /* 0xFFF8 Timer1_A CC1-4, TA1 */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define TIMER1_A0_VECTOR        “.int13”                     /* 0xFFFA Timer1_A CC0 */
#else
#define TIMER1_A0_VECTOR        (13 * 1u)                    /* 0xFFFA Timer1_A CC0 */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define NMI_VECTOR              “.int14”                     /* 0xFFFC Non-maskable */
#else
#define NMI_VECTOR              (14 * 1u)                    /* 0xFFFC Non-maskable */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define RESET_VECTOR            “.reset”                     /* 0xFFFE Reset [Highest Priority] */
#else
#define RESET_VECTOR            (15 * 1u)                    /* 0xFFFE Reset [Highest Priority] */
#endif

/************************************************************
* End of Modules
************************************************************/

As you can see there is macro for each vector address of the controller. You have to use the macro, I tried using the “.int08” value but it gave error. If you find out any other way please share it with me. One can’t have enough knowledge.

So we covered the interrupt handling in C part. Now let’s see the LPM part.

LPM in C language

Well entering into LPM mode in assembly language is a piece of cake. Just set the required bits of SR and its done. When I first tried to enter into LPM in C language I wrote SR |= LPM3|GIE and I got an error. I remembered that in C we can’t use the registers directly. So I had to see an example project given in the MSP430ware. There I came across this BIS instruction equivalent function.

_BIS_SR(bits_to_be_set);

This is a function which will write BIS.W #bits_to_be_set,SR in the disassembly. So just write the bits you want to set in this function and you are ready to enter into LPM.

Example

_BIS_SR(LPM3_bits + GIE);

Program to demonstrate above concepts

/*
*  inception.c
*  Created on    : 24-Nov-2013 10:59:50 AM
*  Author        : Manpreet Singh Minhas
*  Website       : https://learningmsp430.wordpress.com
*
*  Description   : In this program we toggle the SMD LED1 after one 
*                  second delay.We use timer in up mode. I’ve enabled the TAIE so
*                  that we get an interrupt on roll over.Also we have to set GIE 
*                  bit in SR. And I’ve used LPM3 for this, since I need only the
*                  ACLK for this. (Note: The 32KHz crystal needs to be soldered 
*                  on the Launchpad.) 
*/

#include <msp430g2553.h>

void main(void)
{
WDTCTL = WDTPW|WDTHOLD;
P1DIR |= BIT0;
P1OUT |= BIT0;
TA0CCR0 = 0x8000;
TA0CTL = TASSEL_1|ID_0|MC_1|TAIE;

_BIS_SR(LPM3_bits + GIE);

}

#pragma vector=TIMER0_A1_VECTOR
__interrupt void Timer_A(void)
{
P1OUT ^= BIT0;
TA0CTL &= ~(TAIFG);
}

So I’ll be ending this post here. Hope you found it useful. Thank you for reading and as always you can ask me any doubts you have. This will help me gain new knowledge and perspective.

Advertisements

1sec delay using 32Khz crystal and Grace!!!

grace_logo

I tried to experiment with a video tutorial this time. So I won’t be like writing the steps down but instead will show you how this grace magic works visually.

Something to know about the 32.768 KHz crystal that came along with your launchpad. You might be wondering why this crystal and upon that why this precise value?? The answer is simple we need external crystal to give precise clock pulses (i.e heart beats of your processor). There is an inbuilt digital controlled oscillator in msp430, but then this does not give frequency stable enough for precise operations for example a real time clock. Now regarding the 32768 Hz value. 65536 is a number that makes sense to most people who have experience with memories. Maximum 16bit data is 0FFFFh or 11111111b or 2^16 i.e 65532d and exactly half of that is 32768. So if you count every pulse generated by this crystal (counter action using Timer A), after you’ve reached 32768 counts you would have waited 1 sec exactly. Isn’t this really amazing?? Now that you have 1 sec, I don’t think there is any need for me to tell you the importance of 1 sec right??  Anyways one of the most basic and fundamental operation of this is in real tune clock(RTC) chips.

So in this program we’ve tried to see this one second delay using whatever resources we have on launchpad i.e LED1 and LED2. We’ll be toggling the led’s exactly after 1 sec.

And we should not forget the main motto i.e learning grace. So we’ll use grace to create this project. Hope this post was informative and useful for you. Thank you for reading this.

The tutorial link is(I’ll try to be more clear next time :D):

The led video link:

Code Composer Studio : Grace !!!

grace_logo

I recently learned about this wonderful graphical user interface(GUI) called Grace which is a part of the Code Composer Studio by Texas Instruments. I must tell you that the interface is simply amazing. I mean you can initialize all the peripherals, interrupt subroutines, interrupt handling, etc using this interface. I tried this 1 sec delay program using grace and was amazed at the fact that TI has literally make it a cake walk for programmers to initialize all peripherals and interrupts in c language. I like writing code in assembly language and for that matter even in c, but as you would come to know while programming in c you need to use some explicit functions defined by the compiler to write the various interrupt subroutines. So if you want to focus on whether your concept is correct or not and want to do testing then grace is a blessing for you. Once you know that your code is working using grace, you can anytime write the assembly language program( initializing all the peripherals using their command registers, handle the interrupt vector addresses and so on).

I’ll be covering how to make a project using grace in CCS very soon.

How to create a new project in CCS5.4

In this post I’m assuming you have already installed code composer studio after downloading it from http://processors.wiki.ti.com/index.php/Download_CCS. The steps involved are covered visually via images. The first step is to open the software by double clicking on its icon. Subsequent steps are shown below.

Step2

step3 step4 step5 step6 step7 step8 step9

Summary:

1) Open code composer studio.

2)Select new->project

3)Select CSS project in the dialogue box that appears

4) Since I am using msp430g2231 I have selected that ic from the list you can choose whichever ic you intend to use. Give the project a suitable na
me. You have to select an empty project with main.c else you’ll have to manually add c file which is not that difficult but I won’t be covering that in this list.

5)Make your project as active project by clicking on it in the project explorer.

6) Expand your current project by clicking on the small plus on the folder. Then double click on the main.c to open the file.

7) Now you are ready to start the c programming in main.c

8) After writing the code you can debug it. If there are no errors then you’ll get an option to run/play the program.

 

Things one requires for starting with MSP430 programming

MSP430 Launchpad Development toolkit, laptop/pc, Code Composer Studio.

We can purchase the kit from  http://www.ti.com/ . We have to make an account on the website for the same. The software code composer studio is available from www.ti.com/launchpadwiki . We require license for ccs v5.

The Launchpad kit contains the experimenter board, microcontroller chip, connectors, USB cable.

MSP-EXP30G2usb-a-to-b-10ft-cable

Connect the USB cable to the corresponding ports on the laptop and experimental board. There is a preinstalled programme on our microcontroller. If the LED on the board blink then everything is ok. The pattern in which they blink depends on the program that is burnt on the microcontroller.