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.

Code execution stopping for no reason. Unsupported assembly generated by compiler. MSP430x

Other Parts Discussed in Thread: MSP430F2274

Ok, this is my first time posting something, but I have a time-critical application and this issue is holding up all of my testing. I will try to be as detailed as possible so that anyone who knows anything about this issue can help. Here is a little background:

I have taken over this project from someone else.  My role is really just supposed to be a supporting role because the boards are already made and the firmware is already written and tested.  However, I get a new batch of boards for the first time and am trying to load the firmware on them.  The code loads just fine, but "main" is never reached, and I never have the option to push "play".  I turned off the debug option that makes the code run to main (Debug>Auto Run and Launch Options), looked at the disassembly, and I saw something very odd.  In all of the places where there should have been an assembly "RETA" instruction (return from subroutine), there was a ".word 0x0110" instruction.  Basically my compiler was not recognizing the assembly instructions that were being generated.  So, instead of returning, like it should, code execution just fell through to the next function that the linker had placed consecutively in memory.  I found out that the RETA instructions, which were causing the problem, are part of an extended instruction set called MSP430X.  After digging through the project settings, I found a setting called "Silicon Version" which had two options: "msp" and "mspx" (Build > MSP430 Comiler > Processor Options).  When I changed this from "mspx" to "msp", the compiler no long tries to generate the RETA instruction and code flow is back to normal.  I thought all my problems were solved.

However, I'm afraid I may have messed other things up by changing this setting in the project properties.  What's happening now is that CCSv5 no longer lets me set breakpoints in the code. Also, at predictable spots in the code, execution will simply pause (as if I had a breakpoint set there), even though there is no breakpoint. The code where it pauses is always a simple loop for write out a character array over UART.  This is the code:

unsigned int i = 0;
while(s[i] != NULL)  {
    while(UCA0STAT & UCBUSY);
    UCA0TXBUF = s[i];
    i++;
}

Every time code flow reaches this point, the whole program will stop running as if I set a breakpoint.  This happens even when I am not debugging.  I know that because I turn on an LED before I write this message over UART.  The message is triggered by an external button press.  When I load and run the code, then disconnect the debugger and press the button, the LED comes on and everything freezes.  The system no longer responds to other interrupts....nothing.  The funny thing is that it will write several characters before pausing.  When I am debugging and I look at the disassembly, the specific instruction that it always halts on is the UCA0STAT & UCBUSY line in the C code. 

So, this is where I'm at now.  I don't know why it's pausing at that one spot all the time.  I don't know why it won't let me set break points in the code.  This has happened on several boards that I've tried; it's not limited to just one. I talked to the previous guy on the project and he said that he never had anything like this happen.  He was always able to set break points and his code never paused for no reason.  My first suspicion is that it has something to do with the CCSv5 project settings, because that seems to be the only variable here.  I even tried loading code from my computer onto earlier sets of boards that were working fine: same problem.

I appreciate any suggestions.  I'm *this* close to just re-installing code composer.

Help!

P.S.  My microcontroller is an MSP430F2274.  I've also tried it on an earlier revision with an F2234 (which is pin compatible with the 2274) with the exact same results.

  • The MSP430F2274 can only execute its native machine code. It cannot execute c statements. The c statement while (UCA0STAT & UCBUSY); is compiled into a sequence of machine code and includes a conditional jump to repeat that sequence. When that condition does not go away, it keeps repeating and cannot finish. This appears to you that the the specific c-instruction halts. In reality, the underlining machine code is effectively an endless loop.

  • @old_cow_yellow:

    I know that the MCU can only execute its specific machine code instructions.  The original problem appeared to be that the MCU didn't recognize the machine code instructions generated by the compiler.  That's why I changed the project properties.  However, the odd stopping problem and the fact that I can't set breakpoints makes me believe that I might have affected other things by changing the project properties.

    Now let me address your looping response.  At the time of posting my original question I did not have the hardware on-hand so I couldn't give you the specific assembly instruction where execution would halt. This is the specific assembly instruction where the code halts taken from the disassembly that CCS provides during execution:

    f23e: B3D2 0065 BIT.B #1,&USCI_A0__UART_Mode_UCA0STAT

    Now, your response makes me think that you have understood my problem incorrectly.  It's not that the code is stuck in a loop. The loop only causes a brief pause while the UART buffer is emptying. Whenever this instruction is reached, it is as if I pressed the "pause" button in my debugger.  Execution halts completely.  The code is no longer running. Code composer highlights the current line of execution as if I had paused at a break point.  It's NOT like I press the pause button myself, only to discover that I'm stuck in a loop.  An infinite loop is easy enough to take care of.  The problem is that something actually halts code execution completely.  Maybe something in the underlying architecture of the MCU is throwing some sort of "halt" exception?  I have to physically press the "play" button again in code composer to get execution to resume, even though I (and I'm repeating myself) NEVER pressed the pause button.  

    In summary, I don't think that this is just an average coding problem. I've spoken with several other engineers who have never seen something like this happen before. I think that something subtle is happening that code composer doesn't know how to deal with. 

    I'm more than open to any other ideas though!  :-)



  • The c-statement while (UCA0STAT & UCBUSY); should have been compiled into at least two assembly code instructions, such as:

    f23e: B3D2 0065 BIT.B #1,&USCI_A0__UART_Mode_UCA0STAT
    f242: 2FFD      JC    Location_f23e

    where the second assembly code is a conditional jump.

    I do not know how CCS did it. I heard that it even assign variables in Flash memory.

  • The RETA instruction is the mirror of the CALLA instruction. It is used for calling functions that are located in 20 bit address range (and returning to a memory location in 20 bit address range).

    It is mandatory that all code either uses CALL/RET or CALLA/RETA, including all linked libraries.

    While using CALL for a 20 bit destination causes a linker error, returning with RET after being called by CALLA will not cause an error, but leave 2 bytes on stack where they don't belong, crashing the MSP then.

    This is also called 'large' and 'small code model'. Large code model is the default for mspx, but can be disabled separately by specifying small code model.

    However, mspx core has other instructions that are useful. Independently of the code model. Like multiple-bit shifting, multiple register push/pop etc. By forcing msp core usage, you have disabled them as well, making the code slower.

    In 2x family, MSPs with >64k flash have mspx and those with less code usually have msp core. And in 5x family, all CPUs have mspx2 core (same instructions, but some are faster)

    0x0110 is a MOVA @SP+,PC instruction. The same as a RETA. But if the processor doesn't understand MSPX instructions (has only a 16 bit core), this is a NOP.

    However, the 2274 does not have an extended core, so your "msp" core setting is correct. And explains the problems.

    About the lock in your code: the inner while waits for the USCI not being busy anymore. That means, the last byte has been sent. You should instead wait for UCTXIFG being set, indicating that TXBUF is empty (which happens when the last byte starts sending). This allows faster throughput.

    However, it shouldn't freeze as it is. How does your USCI init code look like?

  • All of that is very good information, and that very clearly explains the initial problems I was having.  Thank you.

    Now, about the current problems I'm having.  Here is my USCI initialization code:

    void UART_init (void) {
    	UCA0CTL1 |= UCSWRST;	        //disable USCI while configuring module
    	UCA0CTL1 |= UCSSEL_2;	//Select SMCLK as UART clock source
    	UCA0BR0 = 0x45;			//Set baud rate prescaler to 138
    	UCA0BR1 = 0x00;			//Set baud rate prescaler to 138
    	UCA0MCTL = 0xaa;		        //Value found using daycounter's baud rate calculator
    	IE2 |= UCA0TXIE | UCA0RXIE;  //Enable Rx and Tx interrupts
    }

    All this does (or should do) is initialize the UART module with the baud rate set to 115200.  For some reason, the line where I turn on Rx and Tx interrupts is not working.  I check the IE2 register and those bits are not set after that instruction.

    Here's another thing, my code is now halting in a different place (the exact same way that it was before). It is always whenever I call a function to print out a string over UART. Here's the code for it:

    void report_str( char s[] ) {
    	WDTCTL = HOLD_AND_RETAIN_WDT; //halt WDT while broadcasting stats
    	P4OUT &= ~BIT0;		//wake up xbee radio 
    	_delay_cycles(90000); //delay 11.25ms to allow radio to wake up.
    
    	int str_index = 0;
    	while(s[str_index] != NULL){
    		str_index++;
    	}
    	int str_length = str_index;
    
    	int print_index = 0;
    	while(print_index < str_length){
    		UCA0TXBUF = s[print_index];
    		while(UCA0STAT & 0x1);
    		print_index++;
    	}
    	P4OUT |= BIT0; //put xbee radio to sleep to conserve power 
    	WDTCTL = START_AND_RETAIN_WDT; //restart WDT after broadcasting stats
    }

    Now, I didn't write this code, and I know it could be a lot more efficient, but let's not focus on that right now. This code was working fine previously (before I took over the project), so I'm trying not to change anything that I don't have to. The code execution is now halting every time it gets to the "str_indexx=++;" line in the first loop where it is basically counting the size of the string.  When looking at the disassembly, it is stopping on an INC instruction. I hope this sheds more light on the situation.

    In the beginning I was thinking that this might be due to some sort of stack or heap error, where the microcontroller was running out of space when trying to print out long strings, but that doesn't seem to be the case here.  I increased the stack and heap size anyway, just in case, but it didn't seem to have any effect.  I don't know what else it could be.  Maybe it has something to do with passing the strings that are being printed to the report_str function?

    I appreciate the help so far, as well as any additional help.  This is driving me nuts! I'm gonna be ticked when, at the end of all this, it was just something simple that should have been obvious the whole time.

    :-)

  • Steven Deshazer said:
    it is stopping on an INC instruction

    How it can be? - Please explain what you mean. CPU clock stops or what? Or you are trying to tell that while loop can't find end of the string?

    Steven Deshazer said:
    void report_str( char s[] ) {

    You pass '\0'- terminated string, right? - Then to NOT confuse other developers - use report_str(char *s) instead.

    Steven Deshazer said:
    while(s[str_index] != NULL){

    You shall search for '\0' char here, not NULL pointer which is defined as ((void *)0). I would simply write something like this:

    while(s[str_index++]) {

    }

  • Ilmars said:
    How it can be? - Please explain what you mean. CPU clock stops or what? Or you are trying to tell that while loop can't find end of the string?

    That's a great question! If you will refer to my previous posts, you will see that it has nothing to do with being stuck in the loop. The loops are terminating just fine.  What happens is as if I had set a breakpoint at that line.  Code execution actually stops and I have to hit the "Play" button in the debugger in order to get code execution to resume.  Once I get past this point in the code, execution continues normally.  However, I have no breakpoints set and I never hit the "Pause" button, but my code pauses as if I had hit the "Pause" button.

    Ilmars said:
    You pass '\0'- terminated string, right? - Then to NOT confuse other developers - use report_str(char *s) instead.

    As I mentioned before, I did not write this code, but it has been working before.  I will rewritten the function to be more efficient below:

    void report_str(char * s){
        int print_index = 0;
        while(s[print_index] != 0){
            while(UCA0STAT & 0x1);
            UCA0TXBUF = s[print_index++];
        }
    }

    The code still pauses on the INC instruction as before.

     

  • Steven Deshazer said:
    However, I have no breakpoints set and I never hit the "Pause" button, but my code pauses as if I had hit the "Pause" button.

    Can't be. How it behaves when you run it without debugger?

    Maybe what you call "code pauses" is actually microcontroller crash or watchdog reset?

  • Steven Deshazer said:
     I check the IE2 register and those bits are not set after that instruction.

    The IE bits are reset when the USCI is in reset (SWRST set). You'll need to set them after you cleared SWRST.

    This prevents interrupts being fired by TXIFG (set by default) while the USCI is not working and writing to TXBUF won't clear TXIFG, causing an eternal ISR loop.

    About the other lock, it is probably looping eternally in the while loop before the increment. You shouldn't check for UCBUSY in UCA0STAT, but rather for check IFG2 for TXIFG before you write to TXBUF.

**Attention** This is a public forum