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.

LPM macros and intrinsics: usage guidelines?

Other Parts Discussed in Thread: MSP430WARE, MSP430G2412

There seem to be many ways to manage LPM modes when programming MSP430 in C. There are LPM0-LPM4 macros, _BIC_SR and _BIS_SR macros, _bic_SR* and _bis_SR* intrinsics, and some books recommend using __low_ power_mode_*() and __low_ power_mode_off_on_exit().

Assuming I'm not writing throwaway code, but something which will be published as an open-source library and I do care about code quality — which ones do I use? Are there any official guidelines on which macros/intrinsics are "canonical" and which are just patchwork for legacy requirements?

I'm also slightly confused: does the LPM0_EXIT macro only exit from LPM0? Or does it clear all SR bits related to LPM and just exits active? (if so, why isn't it called ACTIVE_EXIT or something similar?)

  • Jan,

    i would suggest to go for the following intrinsic functions which are currently supported by IAR, CCS (and i think also MSPGCC):

    unsigned short _bic_SR_register(unsigned short mask);
    unsigned short _bic_SR_register_on_exit(unsigned short mask);
    unsigned short _bis_SR_register(unsigned short mask);
    unsigned short _bis_SR_register_on_exit(unsigned short mask);

    together with the LPM bits definitions:

    #define LPM0_bits (CPUOFF)
    #define LPM1_bits (SCG0+CPUOFF)
    #define LPM2_bits (SCG1+CPUOFF)
    #define LPM3_bits (SCG1+SCG0+CPUOFF)
    #define LPM4_bits (SCG1+SCG0+OSCOFF+CPUOFF)

    These are the most used in MSP430 example codes at the moment.

    Regarding your question about the LPM0_EXIT macro, if i look into CCS header files, the LPM0_EXIT is defined as:

    #define LPM0_EXIT _bic_SR_register_on_exit(LPM0_bits) /* Exit Low Power Mode 0 */

    So this shall only clear the LPM0_bits as defined above.

  • Leo Hendrawan said:
    i would suggest to go for the following intrinsic functions

    I disagree. (See below...)

    Leo Hendrawan said:
    These are the most used in MSP430 example codes at the moment.

    So what? I find most code examples to be horrible in the general sense, and promulgate some bad practices that lead to a lot of questions here that we answer over and over and over....

    The OP stated that the intent is to create an open-source library. In that regards I would suspect that it is for functions that others would find useful and perhaps maybe want to port to other processors.

    In that case, I would love to start with code that masks all the product-specific compiler directives behind macros that are #define -d in a header file.

    I am of the camp that you should use the LPM0, LPM0_EXIT, _ENIT(), _DINT() etc macros. They make the code easier to read, understand, maintain and port.

    Using your example of LPM0_EXIT being equivalent to _bic_SR_register_on_exit(LPM0_bits), which is easier to type?

  • The upper-case versions of the intrinsics, _BIC_SR(), were provided by version 1 of the IAR compiler.

    As of version 2 (released many years ago), the longer lowercase names, __bic_SR_register(), were introduced. However, for backward compatibility, the older names are still being recognized, but I would strongly advice against using them in modern code.

        -- Anders Lindgren, IAR Systems

  • Anders Lindgren said:
    The upper-case versions of the intrinsics, _BIC_SR(), were provided by version 1 of the IAR compiler.

    Sure, but I was referring to the standard, supported by all MSP compilers, macros. The ones found in all the current device-specific header files.

  • Brian,

    this is a good opinion from you, maybe i'm brainwashed by the example codes :)

    Yes, after thinking it further, for most people who maybe starts with MSP430, the macros like LPM0, LPM0_EXIT might be more intuitive, but if you add comments to the code such this:

    // enter LPM0

    __bis_SR_register(LPM0_bits);

    it can be understandable too, IMHO. Plus you also know that in the background that actually it is setting some bits in SR register which makes the device to go in/out to/from sleep modes.

    But again, i think this is just a matter of taste.

  • Leo,

    But in your case, to port the code (even to another TI microcontroller family) requires searching through all the source code and replacing whole lines of code. In my case, you change the definitions of the macros in 1 header file.

    I'm of the opinion that compiler-specific and device-specific constructs go into header file macros. Portability between families and maintainability becomes much easier. And remember, the framework of the OP's question was in regards to an open-source library that others could use.

  • Well, it seems I caused a bit of a stir and there doesn't seem to be much agreement as to what is the "canonical" way of doing things.

    It is true that in430.h contains this set of intrinsics:

    void _enable_interrupts(void); 

    void _disable_interrupts(void); 

    unsigned short _bic_SR_register(unsigned short mask);

    unsigned short _bic_SR_register_on_exit(unsigned short mask); 

    unsigned short _bis_SR_register(unsigned short mask); 

    unsigned short _bis_SR_register_on_exit(unsigned short mask);

    unsigned short _get_SR_register(void); 

    unsigned short _get_SR_register_on_exit(void); 

    unsigned short _swap_bytes(unsigned short src); 

    void _nop(void); 

    void _never_executed(void);

    but I'd agree with some of you that those are not necessarily the most intuitive and readable constructs. On a related note, having taken a quick look at some of the header files: I believe if your function name begins with an underscore, it had better be an intrinsic, and if it begins with two or more underscores, you have failed at naming things.

    Brian Boorman said:

    I'm of the opinion that compiler-specific and device-specific constructs go into header file macros. Portability between families and maintainability becomes much easier. And remember, the framework of the OP's question was in regards to an open-source library that others could use.

    Actually, I'm not that big on writing portable code when it comes to microcontrollers. Once you start trying to write portable code, it quickly grows and becomes a nightmare to maintain. I'd much rather have a number of small, well-written MSP430 libraries. Which is exactly where I'm coming from — I started writing MSP430 code, looked around for small, nice libraries, and found almost none. I also found a lot of bad examples and horrible code online. It seems people think it is OK to design hardware and then write crappy code for it, as long as they eventually get it to work in their setup. (And by the way, I was disappointed in the code quality of TI examples)

    So I started writing code that I intend to eventually publish — and most of it is very device-specific. As an example, I just finished an USI I2C module that I use on the G2412. It should be usable on any MSP430 that has an USI and is of no use anywhere else. And since the code is interrupt-driven and has an option of waking up the CPU when the transmission is done, I wanted to know what is the best way to do that.

    Thanks for you advice. I think I'll stick to intrinsics instead of macros for now.

  • Brian,

    another nice point from you. I couldn't agree more that nowadays, portability is a very critical aspect to consider when writing software for embedded system.

    However i believe that in this case, the call to low power mode will be encapsulated in low layer HAL modules used by the higher layer-hardware independent modules. And if you need to port this to another platform, you need mostly to change the whole functions and not only the macros.

    I basically don't want to prolong the debate :) and i believe our opinions can be differ from case to case.

  • Jan Rychter said:
    (And by the way, I was disappointed in the code quality of TI examples)

    +1

    Jan Rychter said:
    So I started writing code that I intend to eventually publish — and most of it is very device-specific. As an example, I just finished an USI I2C module that I use on the G2412. It should be usable on any MSP430 that has an USI and is of no use anywhere else. And since the code is interrupt-driven and has an option of waking up the CPU when the transmission is done, I wanted to know what is the best way to do that.

    I will point out that the MSP430Ware has a driver library for the 5xx-6xx series devices that sees to be shaping up pretty well. You may want to look at that for some inspiration and perhaps basis for what you are doing on 4xx series.

  • Brian Boorman said:

    I will point out that the MSP430Ware has a driver library for the 5xx-6xx series devices that sees to be shaping up pretty well. You may want to look at that for some inspiration and perhaps basis for what you are doing on 4xx series.

    I think my approach is quite different. I'm targeting mostly the cheapest devices (hence the MSP430G2412) and the free version of CCS, so I'm very code-size constrained. Also, I'm writing code that is very specific (usi_i2c, max31855, hd44870, debouncing, etc). You could think of it as code examples, except they are usable in actual applications. Kind of what I expected from TI examples, really. You should be able to take a bunch of .c/.h file pairs out of the library and just drop them into your project to use a particular device/protocol.
    I think we already have enough all-encompassing huge-library projects around, but I found none of them useful for practical work, hence a different approach.
  • Jan,

    Jan Rychter said:

    Actually, I'm not that big on writing portable code when it comes to microcontrollers. Once you start trying to write portable code, it quickly grows and becomes a nightmare to maintain. I'd much rather have a number of small, well-written MSP430 libraries. Which is exactly where I'm coming from — I started writing MSP430 code, looked around for small, nice libraries, and found almost none. I also found a lot of bad examples and horrible code online. It seems people think it is OK to design hardware and then write crappy code for it, as long as they eventually get it to work in their setup. (And by the way, I was disappointed in the code quality of TI examples)

    Actually there is one which i know (but i haven't tested it myself) called BSP430. It is developed by one of the open source MSP430 guru, Peter Bigot. Would recommend you to look at it, since I believe it is written in high quality standard.

    Jan Rychter said:

    So I started writing code that I intend to eventually publish — and most of it is very device-specific. As an example, I just finished an USI I2C module that I use on the G2412. It should be usable on any MSP430 that has an USI and is of no use anywhere else. And since the code is interrupt-driven and has an option of waking up the CPU when the transmission is done, I wanted to know what is the best way to do that.

    I made a small USI I2C library also a while ago, and you can find it here. Perhaps you can also link your code later on to the wiki page? The wiki is also open for everyone, you just need to create an account to be able to modify.

  • Let me join here, from the view of a forum observer (seeing what people actually do, not what they should do)

    Brian Boorman said:
    I am of the camp that you should use the LPM0, LPM0_EXIT, _ENIT(), _DINT() etc macros. They make the code easier to read, understand, maintain and port.

    For _EINT() and _DINT(), well, this is mostly true, even though _disable_interrupts or _enable_interrupts() are also commonly used and say the same. However, these macros show the same potential problems as the others. At least they are portable.

    But I consider the LPMx/LPMx_EXIT macros to be really dangerous. And not portable at all (except between different MSPs, and even then not always).

    While other MCUs may have low power modes too, and use the same macro, the mechanism is usually totally different, so portability is non-existent.
    But besides this, they hide what's going on.
    I've seen people trying to migrate from LPM3 to LPM0 by calling 'LPM0;' inside the ISR. They simply didn't know what these macros really do (setting and clearing bits in the status register, or on the stack).

    Also, there is no macro to migrate from one LPM to another.
    But you can easily change from LPM4 to LPM3 by using _bic_SR_register_on_exit(~(LPM4_bits&LPM3_bits)); Something you wouldn't even imagine when all you have is LPMx_EXIT.

    Using the _bis/_bic intrinsics with a proper comment makes clear what's going on. And if you don't know what i tmeasn in detail, all you have to do is to look in the users guide what these bits in the status register do. As the intrinsic shows clearly what it does: modifying the status register.
    So it actually provides hints for porting (or even understanding) the code where the LPMx macros won't.
    Especially if you want to port code from the MSP to a different MCU and have no specific MSP knowledge. Porting code should only require target system knowledge, and not also in-depth source system knowledge. Seeing the intrinsics, you can easily figure out what's happening wihtout prior MSP knowledge. With the LMPx macros, you're lost and have to dig much, much deeper.

    Brian Boorman said:
    Using your example of LPM0_EXIT being equivalent to _bic_SR_register_on_exit(LPM0_bits), which is easier to type?

    Easier to type is spaghetti-code without any comments. Is this a justification to write such code?

  • Jens-Michael Gross said:

    But I consider the LPMx/LPMx_EXIT macros to be really dangerous. And not portable at all (except between different MSPs, and even then not always).

    While other MCUs may have low power modes too, and use the same macro, the mechanism is usually totally different, so portability is non-existent.
    But besides this, they hide what's going on.
    I've seen people trying to migrate from LPM3 to LPM0 by calling 'LPM0;' inside the ISR. They simply didn't know what these macros really do (setting and clearing bits in the status register, or on the stack).

    I find this very convincing, especially after being fooled by LPM0_EXIT myself. There is no way around it: you have to understand what is going on to write correct code. And if you do, you might as well spell out the bits you're setting/clearing.

    Thank you for the interesting discussion, I will be using intrinsics from now on.

**Attention** This is a public forum