This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/MSP430F5438A: Difficulty with Timer A - Capture mode

Part Number: MSP430F5438A

Tool/software: Code Composer Studio

Hi,

I am doing a coursework, using MSP430F5438A microcontroller and Code Composer Studio v7.

My task is to measure the temperature and write it on the LCD. I have a digital temperature sensor with a PWM (gives duty-cycle) output, which goes on a P8.0/TA0.0.

All functions for LCD work properly, but the temperature is not being written on the LCD, even though interrupt function also works properly.

I am not sure if I have set all the registers correct. I have done this:

TA0CTL = TACLR; // Setting this bit clears TAR, the clock divider logic, and the count direction
TA0CTL = TASSEL__SMCLK | MC_2; // SMCLK, mode control: continual

TA0CCTL0 = CCIE | CM_1 | SCS | CAP | CCIS_1; // CCR0, capture on rising edge

In the interrupt function, I change Capture mode depending on the which of the half-periods I measure, positive or negative. I change it this way:

if (TA0CCTL0 & CCIFG) { // CCP0 interrupt

if ((TA0CCTL0 & CM_1) && (pp_done == 0)) { // rising edge

TA0CTL = TACLR; // Setting this bit clears TAR, the clock divider logic, and the count direction
TA0CTL = TASSEL__SMCLK | MC_2; // SMCLK, mode control: continual

TA0CCTL0 &= ~CM0;
TA0CCTL0 |= CM1; // Set CCP0 module interrupt on the falling edge
TA0CCTL0 &= ~CCIFG; // Reset the interrupt flag

}

...

}

Datasheet is given on the link http://www.ti.com/lit/ds/symlink/msp430f5438a.pdf
User’s Guide http://www.ti.com/lit/ug/slau208p/slau208p.pdf

Do you see any incorrect set-up?

Thank you in advance for your help.

  • The best way to go about resolving this kind of problems is to use break points in CCS and literally use wires (maybe with an RC at the input to smooth the transition) to create a rising or a falling edge. I would recommend that you first confirm the interrupt triggers at the rising edge. Then, confirm it triggers at the falling edge. If your code can do this with a very slow signal, then there is no reason why it wouldn't with the PWMed signal (given the PMWed signal is slower compared to the frequency of the MCU).
  • I have used breakpoints and debugger but my code is never coming from the interrupt, and I don't understand why, because the sensor is working on 1-4 kHz, and my timer has a much faster frequency - SMCLK. I give you my code to glance at it and tell me if you see any illogical part... The code for the LCD is working properly, so you don't have to check that.

    #include <msp430.h>
    #include <stdio.h>
    #include <stdlib.h>

    // uC Port definitions
    #define lcd_port P8OUT
    #define lcd_port_dir P8DIR

    // LCD Registers masks based on pin to which it is connected
    #define LCD_EN BIT3
    #define LCD_RS BIT2

    #define title1 "Temperature:"
    #define title2 "Out of range!"

    /*SMT 16030 temperature sensor
    DC=0.320+0.00470*t ( t = degrees C)
    DC is in range from 0,1 to 1
    t=(DC-0.320)/0.00470
    For 0,1 t=-46
    For 1 t=144
    */

    unsigned long int result = 0; //temperature in degrees C
    unsigned long int pom = 0;
    unsigned long int temp = 0;
    unsigned long int duty = 0;
    unsigned int pp_done = 0;
    unsigned int np_done = 0;
    char buffer[20];
    char n[4];
    unsigned long int count_pp_1=0;
    unsigned long int count_np_1=0;

    void lcd_reset()
    {
    lcd_port_dir = 0xff; // output mode
    lcd_port = 0xff;
    __delay_cycles(20000);
    lcd_port = 0x30+LCD_EN;
    lcd_port = 0x30;
    __delay_cycles(10000);
    lcd_port = 0x30+LCD_EN;
    lcd_port = 0x30;
    __delay_cycles(1000);
    lcd_port = 0x30+LCD_EN;
    lcd_port = 0x30;
    __delay_cycles(1000);
    lcd_port = 0x20+LCD_EN;
    lcd_port = 0x20;
    __delay_cycles(1000);
    }

    void lcd_cmd (char cmd)
    {
    // Send upper nibble
    lcd_port = (cmd & 0xF0)|LCD_EN;
    lcd_port = (cmd & 0xF0);

    // Send lower nibble
    lcd_port = ((cmd << 4) & 0xF0)|LCD_EN;
    lcd_port = ((cmd << 4) & 0xF0);

    __delay_cycles(4000);
    }

    void lcd_init ()
    {
    lcd_reset(); // Call LCD reset
    lcd_cmd(0x28); // 4-bit mode - 2 line - 5x7 font.
    lcd_cmd(0x0C); // Display no cursor - no blink.
    lcd_cmd(0x06); // Automatic Increment - No Display shift.
    lcd_cmd(0x80); // Address DDRAM with 0 offset 80h.
    lcd_cmd(0x01); // Clear screen
    }


    void lcd_data (unsigned char dat)
    {
    // Send upper nibble
    lcd_port = ((dat & 0xF0)|LCD_EN|LCD_RS);
    lcd_port = ((dat & 0xF0)|LCD_RS);

    // Send lower nibble
    lcd_port = (((dat << 4) & 0xF0)|LCD_EN|LCD_RS);
    lcd_port = (((dat << 4) & 0xF0)|LCD_RS);

    __delay_cycles(4000); // a small delay may result in missing char display
    }

    void display_line(char *line)
    {
    while (*line)
    lcd_data(*line++);
    }

    /**
    * main.c
    */
    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer

    // Initialize LCD
    lcd_init();
    // Writing on the LCD
    lcd_cmd(0x80); // select 1st line (0x80 + addr) - here addr = 0x00
    display_line(title1);

    // Setup PWM sensor
    P8SEL |= BIT0; // Select port P8.0 for TA0
    P8DIR &= ~BIT0; // Configure P8.0 as input

    TA0CTL = TACLR; // Setting this bit clears TAR, the clock divider logic, and the count direction
    TA0CTL = TASSEL__SMCLK | MC_2; // ACLK, mode control: continual

    TA0CCTL0 = CCIE | CM_1 | SCS | CAP | CCIS_1; // CCR0, capture on rising edge
    int i;

    __enable_interrupt(); // GIE

    while (1) {
    if(np_done) {

    duty = 10000 * (count_pp_1 / (count_pp_1 + count_np_1));
    result = (duty - 3200) / 47;


    if ((result <= 100) && (result >= 0)) { //software debouncing
    temp = result;
    for (i = 3; i >= 0; i--) {
    n[i] = ((temp % 10) + '0');
    temp /= 10;
    }

    lcd_cmd(0xc0);
    display_line(niz);
    }
    else {
    lcd_cmd(0xc0);
    display_line(title2);
    }

    __delay_cycles(4000);


    count_pp_1 = 0;
    count_np_1 = 0;
    pp_zavrseno = 0;
    np_zavrseno = 0;

    TA0CTL = TACLR; // Setting this bit clears TAR, the clock divider logic, and the count direction
    TA0CTL = TASSEL__SMCLK | MC_2; // ACLK, mode control: continual

    //Next CCP0 interrupt one rising edge
    TA0CCTL0 &= ~CM1;
    TA0CCTL0 |= CM0;
    TA0CCTL0 |= CCIE;
    TA0CCTL0 &= ~CCIFG;

    }
    }

    return 0;
    }

    void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) timerA0Isr(void)
    {
    if (TA0CCTL0 & CCIFG) { //CCP0 interrupt

    if ((TA0CCTL0 & CM_1) && (pp_done == 0)) { //rising edge

    TA0CTL = TACLR; // Setting this bit clears TAR, the clock divider logic, and the count direction
    TA0CTL = TASSEL__SMCLK | MC_2; // ACLK, mode control: continual

    TA0CCTL0 &= ~CM0;
    TA0CCTL0 |= CM1; //Set CCP0 module interrupt on the falling edge
    TA0CCTL0 &= ~CCIFG; // Reset the interrupt flag

    }

    else if((TA0CCTL0 & CM_2) && (pp_done == 0)) { //falling edge

    count_pp_1 = TA0CCR0; // TA0R

    TA0CTL = TACLR; // Setting this bit clears TAR, the clock divider logic, and the count direction
    TA0CTL = TASSEL__SMCLK | MC_2; // ACLK, mode control: continual

    TA0CCTL0 &= ~CM0;
    TA0CCTL0 |= CM1; //Set CCP0 module interrupt on the falling edge
    TA0CCTL0 &= ~CCIFG; // Reset the interrupt flag

    pp_done = 1;
    }

    else if((TA0CCTL0 & CM_2) && (pp_done == 1) && (np_done == 0)) {

    TA0CTL = TACLR; // Setting this bit clears TAR, the clock divider logic, and the count direction
    TA0CTL = TASSEL__SMCLK | MC_2; // ACLK, mode control: continual

    TA0CCTL0 &= ~CM1;
    TA0CCTL0 |= CM0; //Set CCP0 module interrupt on the rising edge
    TA0CCTL0 &= ~CCIFG; // Reset the interrupt flag

    }

    else if((TA0CCTL0 & CM_1) && (pp_done == 1) && (np_done == 0)) {

    count_np_1 = TA0CCR0; // TA0R

    TA0CTL = TACLR; // Setting this bit clears TAR, the clock divider logic, and the count direction
    TA0CTL = TASSEL__SMCLK | MC_2; // ACLK, mode control: continual

    TA0CCTL0 &= ~CCIFG; // Reset the interrupt flag
    TA0CCTL0 &= ~CCIE; // Disable CCP0 interapt

    np_done = 1;// finished
    }
    }
    }
  • > if (TA0CCTL0 & CCIFG) { //CCP0 interrupt

    The CCIFG will have already been cleared by the time you get here (ref SLAU208P sec 17.2.6.1), so you shouldn't check for it. CCR0 is special in this regard.

**Attention** This is a public forum