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 v6, msp430 and gcc

Other Parts Discussed in Thread: MSP430F5438A

There is a strange behaviour related to the interpretation of DINT instruction on msp430f5438A (and probably on others msp430) in a debug session (I suppose)

With the CCS debugger I observe that when DINT is executed PC increments by 2 if the GIE bit is 0, and by 4 if is set to 1.

so the following simple code wont work as expected when stepping with the debugger, because the instruction after dint is not executed:

/*
 * main.c
 */
#include <stdint.h>
#include <msp430.h>

#define LEDS_PxDIR P4DIR
#define LEDS_PxOUT P4OUT
#define LEDS_CONF_RED       BIT0

#define LED_RED_ON          LEDS_PxOUT &=~LEDS_CONF_RED
#define LED_RED_OFF         LEDS_PxOUT |= LEDS_CONF_RED


int main(void) {

	WDTCTL = WDTPW | WDTHOLD;

	LEDS_PxDIR = LEDS_CONF_RED;
	LED_RED_OFF;

	__eint();
	__no_operation();

	__dint();
	//__no_operation();

	LED_RED_ON;

	return 0;
}

A no_operation has to be inserted after dint()  to fix the problem in debug mode.

When the fw runs (not in debug mode) the code executes correctly the LED_RED_ON instruction.

Does someone know the rational or it is a bug?

greetings

Attilio

  • Hello,
    Sorry for the delayed response. The issue seems related to the one mentioned in this thread:
    http://e2e.ti.com/support/microcontrollers/msp430/f/166/t/53319

    That thread does refer to a fix but that is with the TI compiler. I'm not sure about GCC. I will move this thread to the MSP430 forum where hopefully the experts there will have more information.

    Thanks
    ki
  • Setting and clearing GIE is, technically seen, a register write like any other. The MSP has no dedicated DINT or EINT instructions (other processors do).
    If the target of an operation is a register, the MSP fetches the next instruction during the write (prefetch/pipelining). So when clearing GIE, the next instruction is already fetched, but an interrupt may have been granted during execution of DINT. As a result, an ISR will be called after the instruction after the DINT. For this reason, some implementations of the DINT macro have an implicit NOP, to avoid interrupting an atomic operation. Something similar happens when you enter LPM: while the LPM entry instruction is executed (again a simple write to a a processor register), the next instruction is fetched (even though it won't be executed) and this will trigger a break if there was a breakpoint on it. This is why many code examples have a NOP after LPM entry, with the (somewhat ambiguous or even misleading) comment 'for debugging' (should rather read "don't put a breakpoint here")

    It is possible that your single-step experience is related to the debugger intentionally stepping over the implicit NOP.
    However, I don't see why the instruction after the DINT shouldn't be executed. I'd just expect the debugger not stopping on it. If the debugger really skips this instruction this is, well, unexpected. I can only guess that this was done to hide the unexpected side-effects of the prefetch (for those who didn't read about the processor inner workings or didn't get the implications), but now exposing an unexpected behavior for code that wasn't designed as expected.
    BTW: there is a silicon bug that leads to unexpected behavior when DINT and EINT follow immediately. It normally makes no sense doing this, but it might happen for explicit and implicit manipulations of the GIE bit (e.g. by multiplications which need to be shielded from ISR interruption)
  • gcc 4.9.x defines __dint as _disable_interrupt (in430.h):

        #define _disable_interrupts() __asm__ __volatile__ ("dint")

    so it not include an implicit NOP instruction. Following the theory explained above I think an implicit NOP operation inserted into the macro definition will add robustness.

    If not the programmer has to insert explicity the NOP.

    I dont know how mspgcc managed this but could be also a porting problem.

    The other problem I noticed, with a TrxEB board in particular and not with others boards, is that when executing a DINT (with the debugger) the PC get incremented by 4 if and only if when GIE bit is set to 1:

    this cause the next instruction to be skipped. Obviously this behavoir manifests clearly only because gcc 4.9 does not insert implicity a NOP after DINT.

    The code that I posted above is clearly not correct but necessary to point out the problem.

    Greetings

    Attilio

  • I agree that including the NOP would add robustness. However, in some cases you don't want this NOP. Being forced to have it would be not the best. And in most use cases, it would be not needed, adding unnecessary size and execution time. There is no clear winner.
    Does the skip happen when free-running the code or only when single-stepping through it?
    I just checked the errata sheet for the 54xxA and it lists CPU39 erratum. This exactly describes what you're seeing. And applies to single-stepping in debug mode only. Apparently a bug in the EMM that is used to execute single instructions under debugger control. The recommended workaround is to insert a NOP.
    You could do so by making a conditional NOP that only gets compiled if in debug configuration.
    #ifdef __DEBUG
    #undef _disable_interrupts()
    #define _disable_interrupts() { __asm__ __volatile__ ("dint");__asm__ __volatile__ ("nop") ;}
    #endif
  • I confirm,

    It is exactly the behavoir reported by CPU39 erratum, the bug is only in debug mode, the free-running is not affected.

    Thanks for your support!
    Attilio

**Attention** This is a public forum