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.

MSP430G2452: Access SR location on stack.

Part Number: MSP430F2013

Due to limited amount of flash on MSP430F2013 my bootloader (located in upper 1K of flash) handles some of low level I2C functionality and passes the execution to the application (located in lower 1K of flash). The execution is passed using a regular function call.

1. To change the power state on interrupt exit, the application needs to change the state of SR register on exit for an interrupt. For that, I have allocated a variable sr_address_on_exit (address 0x027C) that is shared between the bootloader and the application. Before the bootloader calls the application it would write the address of "stacked" SR register to 0x027C. If the application needed to change the power state on exit, it would get the address of where the SR is stored from 0x027C and update it as needed.

The problem is figuring out the location of SR on stack. Calling __get_SR_register_on_exit() returns the "interrupt exit" value of SR register.

Calling __get_SP_register() returns the current value and does not account for the frame size (PUSH.W calls at the beginning of the interrupt).

One way is to write the ISR in assembly language which at this point is not feasible.

Would be nice to have an intrinsic function __get_SP_on_exit() that would return the value of SP + "whatever is added by PUSH.W calls".

Is there any way to get the address of SR on stack with the current tools without writing the whole ISR in assembly?

2. An alternative is to call __get_SR_register_on_exit() and save the SR value in a shared location. If needed, the application would update the value at a shared location. Upon return to the bootloader, the value from a shared location should be written over the SR value on stack. In assembly, it could be done with one instruction. Since __set_SR_on_exit(val) does not exist, I have to make two calls:

__bic_SR_register_on_exit(~sr_value_on_exit);
__bis_SR_register_on_exit(sr_value_on_exit);

These unroll into four instructions:

MOV.W &sr_value_on_exit+0,r15
INV.W r15
BIC.W r15,10(SP)
BIS.W &sr_value_on_exit+0,10(SP)

Any way to get the compiler to generate an instruction:

MOV.W &sr_value_on_exit+0,10(SP)

automatically? This would replace 4 instructions with just 1 (save some flash space and execution time).

  • Hello,

    Seems like you have already been digging deep into this issue, although I didn't follow it fully.  Are you trying to modify the value on stack so that when you return from the interrupt/function, it is automatically loaded?  

    As for #1, it seems like you are fully aware, but all available intrinsics are listed in the MSP430 Compiler UG and there isn't a function like you asked.

    For #2... Doing some digging, it does seems like the intrinsic you listed listed are the only option as well, but I understand that you need to fully copy so have to call both and it adds a few lines of assembly.    

    I wasn't able to come up with any better solutions for you so far.  We do have an app note for mixing C and Assembly, but it would require writing the assembly in a separate file and calling it via it's own function call... So I think it would only really help if you wrote the whole function as you mentioned.

    Is the 4 lines or assembly to much from a code space standpoint, or are you just to save those instructions? 

    Thanks,

    JD  

  • Implementing I2C capabilities on MSP430F2013 takes a significant portion of the available flash. Because of that, adding I2C to the bootloader and the application is not practical. I have a low level I2C functions implemented in the bootloader, and application only contains high level handlers char rxbyte(void) and void txbyte(char). To change the power state on exit, the application has to change the return SR value on the stack. For that to happen the bootloader can pass the address of the location to the application via a reserved address in memory. Another way is for the bootloader to copy SR exit value to a reserved memory location that application can update if needed. Upon return to the bootloader, the value would be copied back to the stack space. As of now, the latter is the only way to implement it in C.

    4 lines is not too bad. It is just something that could be improved. If there was a "local frame size" macro in the assembly, I would write something like this to update the SR value on stack:

    asm("MOV.W &sr_value_on_exit,FRAMESIZE(SP)");

    I think TI should expand the list of intrinsic functions by adding __get_SP_register_on_exit() and __set_SR_register_on_exit().

    Thank you.

  • Hey Gennadiy,

    Thanks for the feedback.  I will pass it on the compiler teams.  To be clear, the 4 line workaround is sufficient for you currently?  

    I also looked for a way to insert Assembly directly into the C code, but that also isn't supported by the compiler, although I believe I saw that the MSP430 GCC compiler does support inserting ASM instructions in the code directly.  So in this case, you could just enter your one line, and continue on with C.  

    It is an interesting use case.  Thanks for sharing. 

    JD

  • Yes, the two line C instructions (4 line assembly) is sufficient.

  • When you say that Assembly in C is not supported, are you referring to a particular compiler? I am able to insert asm("") instructions into my C code. For example, the bootloader is using these lines to pass WDT interrupt to the application:

    #pragma location=0xFBFC
    const unsigned int __WDT_AISR;
    #pragma vector = WDT_VECTOR
    __interrupt void wdt(void)
    {
    __asm("\t MOV.W\t &__WDT_AISR, PC");
    }

    The compiler I use is TI v.18.12.7.LTS. running from Code Composer Studio v9. It also worked in CCS v8 with previous versions of the compiler.

  • Hello Gennadiy,

    I apologize.  I just double-checked the compiler UG and you can use inline asm() functions as you are already.  (which is what I was expecting.) 

    I had just come across some old E2E posts yesterday saying it wasn't supported, but looking closer, that user was trying to use asm() in a very specific way that wasn't supported, not the inline assembly support itself. 

    You are all good!

    JD 

**Attention** This is a public forum