Because of the holidays, TI E2E™ design support forum responses will be delayed from Dec. 25 through Jan. 2. Thank you for your patience.

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.

MSP430G2553: Program on launchpad with boosterpack only works when debugging

Part Number: MSP430G2553

Tool/software:

Hello:

Thank you in advance for any help that you can provide. I am running an app on the MSP-EXP430G2 Launchpad Development Kit with an older circuitco educational boosterpack. The app determines the speed of a spindle using a hall effect sensor and displays it on the boosterpack lcd when I am debugging the app but when I quit the debugger, the last bit of information displayed on the lcd before quitting remains and there is no update of spindle speed. The app also does not work when I remove jumpers for the emulation board and power the unit from an external power supply via J6. After powering up, I have to hit reset button and then only see the beginning splash screen no display of spindle speed.

I have looked at various forum examples of code running with debugger and not when the debugger is shut down but I cannot see what is relevant to my situation in those examples.

Do you have any suggestions how I might be able to troubleshoot this? Thanks again.

Set up:

Code composer studio Version: 11.1.0.00011, pc running windows 10.

Watch crystal installed on launchpad board and white LED on edu boosterpack removed (I am using that pin 13 as an input from the hall effect sensor circuit).

Hall effect sensor circuit.

and my code.

#include <msp430.h> 
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <intrinsics.h>

#define EBP_CS BIT0    //chip select
#define EBP_CLK BIT5   //clock
#define EBP_MOSI BIT7  //data line
#define EBP_RS BIT3    //command vs data
#define SENSOR_PIN BIT5   //attach key to P2_5 TA1.2
#define AFTER_BUSY_DELAY 40  //used to wait additional time after UCBUSY clears

void InitBPLCD(void);
void InitSPI(void);
void InitPorts(void);
void InitHallSensor(void);
void itoa(long unsigned int value, char *result, unsigned int base);

unsigned int WriteCommand(unsigned int cmd);
void WriteData(void);
void ClearHome(void);
void SetRowLine(unsigned int row, unsigned int line);

char charsToLCD[32] = {'\0'};
uint32_t timerDiff = 0;
uint8_t computeSpeed = 0;
uint8_t speedCount = 0;

volatile unsigned int cntOvrFloTAR = 0;
volatile unsigned int sendData = 0;
volatile uint16_t currTimerCounts = 4;
volatile uint16_t prevTimerCounts = 0;


/**
 * main.c
 */
int main(void)
{
	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
	//set up Basic Clock Module
    BCSCTL1 |= DIVA_3; //this write clears all other bits; divide ACLK/8
    BCSCTL3 |= XCAP_3; //sets internal capacitance for watch crystal

	InitPorts();
	InitSPI();
	InitHallSensor();
	InitBPLCD();
    __delay_cycles(1000);
    strcpy(charsToLCD, "0123456789012345testing testing!");
    WriteData();
    __delay_cycles(1000);

    //Set up Timer1A
    // capture on rising edge, CCI2B input, synchronous cap, capture mode, ints enabled
    TA1CCTL2 = CM_1 | CCIS_1 | SCS | CAP | CCIE;
    // Continuous, divide clock by 1, ACLK, clear, enable
    TA1CTL = MC_2 | ID_0 | TASSEL_1 | TACLR | TAIE;
    __enable_interrupt();

    for(;;){
        // do nothing
        if (computeSpeed > 0){
            computeSpeed = 0;
            timerDiff = currTimerCounts - prevTimerCounts;
            //clear buffer
            charsToLCD[0] = '\0';
            itoa(timerDiff, charsToLCD, 10);
            WriteData();
        }
        /*
        if (sendData == 2)
        {
            sendData = 0;
            charsToLCD[0] = '\0';
            strcpy(charsToLCD, "0123456789012345running testing!");
            WriteData();
        }
        */
    }

	return 0;
}
#pragma vector = TIMER1_A1_VECTOR
__interrupt void TIMER1_A1_ISR (void){
    switch (__even_in_range(TA1IV, 10)){
    case 0:
        break;
    case TA1IV_TACCR2:
        TA1CCTL2 &= ~CCIE;    // disable further CCIE interrupts
        prevTimerCounts = currTimerCounts;
        currTimerCounts = TA1CCR2;
        ++speedCount;
        if (speedCount > 3){
            computeSpeed = 1;
            speedCount = 0;
        }
        cntOvrFloTAR = 0; //reset TAR rollover counter
        TA1CCTL2 &= ~CCIFG; // clear the CCRO flag
        TA1CCTL2 |= CCIE; //enable interrupts
        break;
    case TA1IV_TAIFG:
        ++cntOvrFloTAR;
        /*if (cntOvrFloTAR > 2){ // been idle
            //set flag to go to sleep
            cntOvrFloTAR = 0;
            sendData = 2;
        }else{
            sendData = 1;
        }*/
        break;
    default:
        for (;;){
            //Should not be possible
        }
    }
}
void InitBPLCD(void){ //copying bp_LCD.cpp from Energia sketch
    WriteCommand(0x30); //function set
    __delay_cycles(27);
    WriteCommand(0x30); //function set
    __delay_cycles(27);
    WriteCommand(0x30); //function set
    __delay_cycles(27);
    WriteCommand(0x14); //cursor/display shift
    __delay_cycles(27);
    WriteCommand(0x0c); //display on/off
    __delay_cycles(27);
    WriteCommand(0x06); //entry mode set
    __delay_cycles(27);
    WriteCommand(0x39); //function set (2 lines, instruction table 1)
    __delay_cycles(27);
    ClearHome(); //clear
    WriteCommand(0x57); //power/ICON control/contrast set upper bits
    __delay_cycles(27);
    WriteCommand(0x6b); //follower control
    __delay_cycles(27);
    WriteCommand(0x72); //contrast set lower bits
    __delay_cycles(1000);
}
unsigned int WriteCommand(unsigned int cmd){
    if (UC0IFG & UCB0TXIFG){  //ready for new data?
        P2OUT &= ~(EBP_RS + EBP_CS); // need to clear _SS and RS LOW for command
        __delay_cycles(10);
        UCB0TXBUF = cmd; //begin transaction
        while(UCB0STAT & UCBUSY); //wait for transfer to finish
        __delay_cycles(AFTER_BUSY_DELAY);
        P2OUT |= EBP_RS + EBP_CS;
    }
    __delay_cycles(5);
    return 1;
}
void ClearHome(void){
    unsigned int wait = WriteCommand(0x01);
    if (wait == 1){
        WriteCommand(0x02);
    }
}
void WriteData(void){
    ClearHome();
    SetRowLine(0,0);
    char *ptr_lcdUp = charsToLCD;
    char *ptr_lcdLow = charsToLCD + 16;
    unsigned int i;
    for(i = 0; i < 16 && *ptr_lcdUp != '\0'; ++i, ++ptr_lcdUp){
        if (UC0IFG & UCB0TXIFG){  //ready for new data?
            P2OUT &= ~EBP_CS;
            __delay_cycles(10);
            UCB0TXBUF = *ptr_lcdUp;    //load shift register for transfer
            while(UCB0STAT & UCBUSY); //wait for transfer to finish
            __delay_cycles(AFTER_BUSY_DELAY);
            P2OUT |= EBP_CS; // need to set _SS HIGH
        }
    }
    SetRowLine(0,1);
    for(i = 0; i < 16 && *ptr_lcdLow != '\0'; ++i, ++ptr_lcdLow){
        if (UC0IFG & UCB0TXIFG){  //ready for new data?
            P2OUT &= ~EBP_CS;
            __delay_cycles(10);
            UCB0TXBUF = *ptr_lcdLow;    //load shift register for transfer
            while(UCB0STAT & UCBUSY); //wait for transfer to finish
            __delay_cycles(AFTER_BUSY_DELAY);
            P2OUT |= EBP_CS; // need to set _SS HIGH
        }
    }
}
void SetRowLine(unsigned int row, unsigned int line){
    //NewHaven LCD with 2 lines 16 rows, expect line (0,1) row (0,15)
    if ((row < 16) && (line < 2))
        WriteCommand(0x80 | (line * 0x40) | row);
}
void InitSPI(void){
    P2OUT |= (EBP_CS | EBP_RS); //start off high (
    P1SEL |= (EBP_CLK | EBP_MOSI);   //select primary peripheral USCI_B
    P1SEL2 = (EBP_CLK | EBP_MOSI);
    //SPI mode 3 needs CPOL=CKPL=1, CPHA=1 -> CKPH=0; msb first, master,
    //8 bit (default), 3-wire (default, mode 0), synchronous
    UCB0CTL0 = UCCKPH | UCMSB | UCMST | UCMODE_0 | UCSYNC;
    UCB0CTL1 = UCSSEL1 | UCSWRST;  //clock from SMCLK; hold in reset
    UCB0BR1 = 0; //upper byte of divider word
    UCB0BR0 = 60; //Clock = SMCLK/60 = 100KHz
    UCB0STAT = UCLISTEN;  //Internal loopback; try this since no MISO pin
    UCB0CTL1 &= ~UCSWRST; //release from reset
}
void InitPorts(void){
    P1OUT = 0;
    P1DIR = 0xFF;
    P2OUT = 0;
    P2DIR = 0xFF;
}
void InitHallSensor(void){
    P2DIR &= ~SENSOR_PIN; //Set pin as input
    P2SEL |= SENSOR_PIN; //Set pin for Timer1_A CCI1A capture
}
void itoa(long unsigned int value, char* result, unsigned int base){
    // check that the base is legit
    if (base < 2 || base > 36) { *result = '\0';}

    char *ptr = result, *ptr1 = result, tmp_char;

    unsigned int tmp_value;

    do{
        tmp_value = value;
        value /= base;
        *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
    } while (value);

    //Apply negative sign
    if(tmp_value < 0) *ptr++ = '-';
    *ptr-- = '\0';
    while(ptr1 < ptr){
        tmp_char = *ptr;
        *ptr-- = *ptr1;
        *ptr1++ = tmp_char;
    }
}

  • I'm not familiar with this booster pack. Do you know what kind of LCD it is? It may need some time to start after powerup -- I don't see any delays for that. (20-50ms wouldn't be surprising.)

    More generally: If you still have access to the P1.0 LED, you might try blinking it in your home loop so you can distinguish between LCD-not-running and MCU-not-running.

  • Thank you for looking into this Bruce. The LCD is a Sitronix ST7032 and I have a few of these circuitco boosterpacks from my teaching days and I was hoping to put them to use somehow.

    I put a third delay just after setting up the Timer1A. You can see that there were already two others in the beginning of the main routine associated with setting up this LCD. Adding this additional delay did not change the behavior. When debugger is active the system behaves as it should by printing on the upper line the difference between the two timer values in TA1CCR2 (the inverse of the spindle speed). When I quit the debugger, the display shows what was most recent before I quit and no updates to spindle speed. If I hit the reset button the initial screen shows up ("0123456789012345testing testing!") and that remains even when the spindle is turning and generating a signal on P2.5.

    At your suggestion, I put a toggle for the P1.0 LED in the timerA overflow ISR and it indicates that when the board is being debugged, it flashes, but when I quit the debugger, no more LED flashing and when I hit reset, the LED never flashes (even though the LCD displays the initial splash screen as previously described). Could I put a scope across the watch crystal (pins 18, 19 XOUT, XIN) or would that mess with the running of the ACLK?

    I welcome any additional suggestions. Thanks again,

    Nick

  • In your description I read two separable symptoms: (1) Program (often/always) hangs when a debugger session is disconnected (2) Program does not start properly on power-up, requiring a separate Reset. I don't know the answer for (1); I've seen it many times, but it didn't bother me enough to investigate. I've been focused on (2), since this really needs to work. (Also case (1) where Reset doesn't fix it.)

    A) I've had mixed results with scope-probing a crystal circuit (results might be ambiguous, but you won't hurt anything). You can get ACLK on P1.0, but I understand you're already using that. In the absence of captures, it will take 8*2=16 seconds for the overflow to happen, which is kind of tedious. As an experiment, you can try setting SCS=0, which will allow captures even if the timer isn't running (akin to a GPIO interrupt). 

    B) The ST7032 datasheet (v1.4) seems to suggest waiting 40ms after powerup before trying to talk to it. This would mostly be significant for case (2).

  • You are correct to focus on the LCD. I simplified the app by taking out any code related to it and removed the boosterpack. The remaining board and code work as intended. While debugging, the registers and variables change appropriately and after debugger is terminated, the heartbeat LED on P1.0 continues every 16 sec.

    I also tried your suggestion of removing SCS from the timerA configuration and moved my LED toggle from the heartbeat TA1IV rollover into the TA1IV_TACCR2 ISP. That did work. As spindle rotates, the LED toggles. So, it looks like the clock is not running after I quit the debugger and that it doesn't start when I power the board separately.

    Now some thoughts on the boosterpack with the ST7032. The clock is running much slower when the BP device and code for LCD is included. It is more like 120 seconds (while the debugger is running, not paused) for the TA1IV to rollover. I thought that was due to the fact that the debugger was running not because of anything associated with the LCD.

    One other thing about this boosterpack. The engineers who designed it believed that they could leave the SPI chip select pin floating and for the most part it works. That is pin 2 in the ST7032 datasheet (see below). Occasionally, however it doesn't bc it gets out of synch. I saw somewhere that people were reconnecting this pin and this hack does work reliably (I am using a different board for a different project).

    So, as far as the LCD connections go.

    9      |    8     |     7        |     6     |     5     |      4    |    3     |     2     |   1    |  0        ST7032 LCD pin

    C1-  |  C1+  |  VOUT  |  VDD  |   G      |     SI   |  SCK  |  CSB  |  RS  |  RST   from ST7032 datasheet

    NC  |   NC  |      NC     |  VCC  |  GND  |  P1.7  |  P1.5  |  P2.0  |  P2.3 |  NC   current configuration

    I noticed that I had set P1SEL2 = (EBP_CLK | EBP_MOSI) in my InitSPI routine and changed that to |= with no change in behavior.

    Thanks again for any thoughts they are really helpful.

    Nick

  • I neglected to mention that with this new configuration of not setting SCS, when I exit the debugger or power the board with external power supply (and take the emulator out of the circuit), the LCD does report a value of 0 for timerDiff as described in the for loop in main function. So the LCD does accept values. Also, as I think I've mentioned before, powering up the board shows a blank screen and I have to hit the reset button to see the splash screen and get the value for timerDiff printed.

    N

  • Another experiment: Try setting

    > BCSCTL3 |= LFXT1S_2; // ACLK=VLOCLK

    VLOCLK runs at something vaguely resembling 12kHz, so your timings will be off by a factor of ~3, but if the system otherwise behaves reasonably, that points very much at the crystal oscillator.

  • Replacing the oscillator with the VLO does get the board to behave. I can get by with a less accurate clock and would be happy to move on (close this thread) unless it would be helpful to others for me to get to the bottom of this issue. When I would need a more accurate clock (if ever), I could revisit this. Do you think trying a different board with a different 32khz watch crystal would be a good next step to solving this?

    N

  • You might consider fiddling with the drive strength (XCAP) in BCSCTL3. It's a long shot, but there are only 4 possibilities. 

  • Ok, I gave those other cap settings a try--no joy. I'll leave this thread open for a little bit and see if I can come up with what is causing the ACLK to work with the watch crystal while in debug mode but not otherwise and close this thread if I cannot come up with anything. At least this project will work with VLO! Thank you for all your help. One last question can you recommend a small LCD that works with SPI that is more commonly used in the MSP430 microcontroller community?

    Cheers,

    Nick

  • As I understand it (?), you have (a) G2 ("old") Launchpad, Rev 1.4 or 1.5 (b) an Education Booster Pack (mkI, though they don't call it that), the one with the 2x16 character LCD.

    I think I found a schematic for (b) [Doc "BP-EDUC-01"], which shows that P2.6 (XIN) is connected to a buzzer (FET), with no jumper disconnect. Is this still connected?

    [Edit: For the archaeologists: There's a Github repository here:

    https://github.com/CircuitCo/Educational-BoosterPack-RevA2

    ]

**Attention** This is a public forum