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.

General library for MSP430

Other Parts Discussed in Thread: ENERGIA, MSP430F2013

I know this is a tough concept, for people used to electronics and microcontrollers, and I have to admit I don't have specific background in this fields.

The problem is that when talking about 'generality', people immediately think to 'performance loss', 'big code size', and so on... But this is a different problem: since we are programmers, we must be used to think in terms of problems to solve, assigning priorities, and finding the best solution we can. Only then we can understand if that solution is good enough for us.

Having said this, and specifying that I have what I think a strong background in C/C++/C#, but not specific in this field, and having started to program MSP430 Value Line chips, I soon realized what are MY personal problems that I have to solve, and that maybe are common to other programmers.

The general objective is to have a general libray to simplify coding solutions for these chips, and these are the priorities I have in mind.

1 - Details are overwhelming! If, for example, I write a program that uses Timer_A, the very next time I have to use Timer_A again, I forgot everything about TACTL, TACCTL0, and so on... The best thing I can do is to search through the program I already wrote, finding the place where I used the timer, trying to remember why I set those particular registers in that way, copy and paste some code, and adapting to the new needs. GOAL: write this code once, in a library, and use that in a more readable way.

2 - Good performance. Compiled library must give me a performance in the 90-95% range of the hypothetical hand-written code. Since we are at second level priority, we must be ready to accept a little degradation, in performance, according to my (and maybe everybody's) needs.

3 - Compact code size. With 16Kb chips available, I place this need in third position. Apart from particular cases, I think that microcontroller programs can easily stand inside this size. Nevertheless, we must check that executable size doesn't explode: I would say that executable code size should stand in the 110% range of the hypothetical hand-written equivalent program.

From the next post, I will try to start my search of the right solution, together with my own personal thoughts about it.

I choose to post all of this in the forum, because I really need observation, thoughts, critics, from expert people, that can drive me along the right way, if there's one... :-)

Andrea

  • Hi Andrea,

    this could be nice :) I guess you are trying to obtain similar libraries than the ones in the Arduino world, aren't you? :)

    I think if you are only contemplating Value Line chips, it is feasible.

  • ...absolutely NOT!!! :-)

    I'm joking, but the point is: Arduino HIDES technical details, giving you a high level abstraction over the underlying technical world. It's true that you can go downstairs, but the original goal is to make life SIMPLE to programmers.

    My case is opposite: I want to give maximum power in programming MSP430 chips, without the complexities of the technical details.

    Thanks for giving me the chance to clarify this.

    ...and in just two minutes, here is the first CODE post...

    Andrea

  • Ok, I think I did enough small talk: it's time to code! :-)

    Let's only give some background: I will use CCS 5.2, and target generically MSP430G2xxx chips: we'll see later what we can do to eventually expand to other chips.

    This post is about I/O ports, so let's forget for a moment the whole concept of an MSP430 (correct) program, and let's see if we can create some generic, readable and performant reusable code...

    The simplest program to write, just to have a reference code size, is simply

    void main()
    {
        WDTCTL = WDTPW | WDTHOLD;

        while (1)
        {
            __delay_cycles(50000);
        }
    }

    that gives us a code size of 160+2 bytes. We'll use this value as a reference base value.

    Since the first program is usually a blinking led program, let's go in this direction, even if I want immediately eliminate that terrible row about watchdog.
    Since we don't want to lose efficiency calling a function, we'll use a macro to make code more readable:

    #define WATCHDOG_STOPPED() WDTCTL = WDTPW | WDTHOLD;

    This one was not difficult. Rewriting the program in this way cannot give a different result from any point of view:

    void main()
    {
        WATCHDOG_STOPPED();

        while (1)
        {
            __delay_cycles(50000);
        }
    }

    To blink the led, we have first to configure it.
    Maybe I'm lazy, but I cannot even think to bother with ^, ~, | operators, that are so error prone if you just forget one little detail, in operations, so I want to write code fragments once for all, and rely on those from here on:

    #define SETLOW(REG, PIN) REG &= ~(PIN)
    #define SETHIGH(REG, PIN) REG |= PIN

    If we know that a particular pin must go high or low, we can just make that operation (please note that in this case too we are not losing any single clock cycle, or a single byte in code size, since the generated code is just equal to what we should write 'by hand'. Parenthesis are necessary for cases where we use more than one bit: BIT0 + BIT3, for example.

    If we don't know in advance which value that pin must get, we need a generic function with one more parameter:

    typedef enum PINVALUE_VALUES {PINLOW = 0, PINHIGH = 1} PINVALUE;

    #define SETVAL(REG, PIN, VALUE) \
        if (VALUE == PINLOW) \
            SETLOW(REG, PIN); \
        else \
            SETHIGH(REG, PIN);

    Just to clarify, '\' symbol makes the macro go on to the next line, so this fragment of code is one only macro.

    Last, we need a way to toggle a pin:

    #define TOGGLE(REG, PIN) REG ^= PIN

    With this, we can be sure that we have not to deal anymore with any single low-level symbol (binary operator).

    Before writing to a pin, however, we have to configure it, and this can be obtained through registers P1OUT. for the first port, P2OUT for the second, and so on...

    Hm. I don't like to remember technical details (and this is not the first time I tell it... :-)), so we have to find a way to hide these. Look at this code:

    #define SETDIRIN(PORT, BIT) SETLOW(PORT##DIR, BIT)

    As I said, I don't want to deal again with low level bit operation, so I leverage the SETLOW macro we already wrote. Moreover, I make use of 'token concatenation' macro operation to 'adapt' the port name to the correct configuration register.
    If you don't know about token parsing operators in macro definitions, here is the reference: http://en.wikipedia.org/wiki/C_preprocessor#Special_macros_and_directives.

    Since this can be a little confusing, let's make a simple example:

    SETDIRIN(P1, BIT0)
    -> translates in SETLOW(P1DIR, BIT0)
    -> translates in P1DIR &= ~(BIT0)

    that is exactly what we should write 'by hand'.

    At this point, we have an instrument to generate a lot of other 'primitive' but complex functions, like:

    #define SETDIROUT(PORT, BIT) SETHIGH(PORT##DIR, BIT)
    #define TOGGLEVAL(PORT, BIT) TOGGLE(PORT##OUT, BIT)
    #define ENABLEINT(P1, BIT3) SETHIGH(PORT##IE, BIT)

    I hope that translation steps are really and immediately comprehensible.

    Now we can write the whole led blinking program:

    void main(void)
    {
        WATCHDOG_STOPPED();

        SETDIROUT(P1, BIT0);

        while (1)
        {
            TOGGLEVAL(P1, BIT0);
            __delay_cycles(50000);
        }
    }

    Considerations:

    - Code size is 174+2 bytes. We added 14 bytes to the base program, but we have to remember that in a 16bit environment, instruction can take up to 6 bytes each (when with two 16bit operands), so we can stand with it, even without looking at the disassembly for this code. Moreover, at least at this level, we can assert that this generates exactly the same code, row by row, that we would write 'by hand'.
    - Performance. Same comment.
    - Readability. It's surely improved. Even a programmer NOT used to MSP430 programming can tell what this program do, with just a quick look.
    - Maintainability. Here we can do much better: if I change port or bit, I have to go through the code to change each and every occurrence (in our case, just two, but we know things get very complex very quickly, in programming).
    - Library complexity. If we go on using macros, we'll get a library with one only level of functionalities, the usual nightmare, in programming. We need a way to categorize functions, and group together the ones related each other.

    The next (obviuos) step is hence to use classes, to obtain results in these last two arguments.

    AAARGH: how much performance I lose, using *CLASSES* in a microcontroller program?

    ...in the next chapter, we'll see some surprise... stay tuned! :-)

    Andrea

  • When creating a library, usually good programmers start from the code that USES the potential library: after all, we write the library once, but we want to use it a lot of times, don't we? :-)

    So, my first guess was to write sample code like this:

    Pin p10(P1, BIT0);
    ...
    p10.SetDirOut();
    ...
    p10.Toggle();

    and so on.

    Readibility and maintainability are very high, but performance will surely suffer for the code we have to write to support this code.

    Where could P1 come from? How much memory are we wasting saving those values in the constructor? How can I understand, from there, and ultimately generate, code that writes in the register P1DIR after having *saved* some 'P1' value?

    So, my reflections were: I cannot *save* values in the class (I would waste a lot of memory, since potentially we want to handle many pins). This leads directly to a static class (unfortunately for readers, you need some background in C++).

    Not saving the parameters of the pin, however, doesn't give us the chance to handle different pins, with one only static class.

    To solve this further problem, we can only state that we will need one different class for each pin we want to handle, with parameters already hardwired in the class itself. Remember that this solution doesn't automatically lead to memory occupation, since this depends only on data members or virtual functions.

    Let's write some code that follows our ideas:

    class _Pin10
    {
    public:
    inline void SetDirOut() { SETHIGH(P1DIR, BIT0); }
    inline void Toggle() { TOGGLE(P1DIR, BIT0); }
    // ...
    } p10;

    class _Pin11
    {
    public:
    inline void SetDirOut() { SETHIGH(P1DIR, BIT1); }
    // ...
    } p11;

    Here I used, and it's not coincidental, the syntax that let me create a class and, at the same time (right after the class definition), an instance of the class itself.

    If we include this code in our program, we are then free to write code like:

    ...
    p10.SetDirOut();
    ...
    p10.Toggle();
    ...

    I already said I'm really lazy :-), so I don't want to write all the classes for all the pins by hand, so I wrote a macro that automates this job, too. It's a little bit long, but maybe it's worth to read and understand:

    #define DEFINE_PIN(PINNAME, PORT, BIT) \
        class _Pin##PINNAME \
        { \
        public: \
            inline void SetDirIn() { SETLOW(PORT##DIR, BIT); } \
            inline void SetDirOut() { SETHIGH(PORT##DIR, BIT); } \
            inline void SetDir(PINDIR dir) { if (dir == PININPUT) SetDirIn(); else SetDirOut(); } \
            \
            inline void SetOutLow() { SETLOW(PORT##OUT, BIT); } \
            inline void SetOutHigh() { SETHIGH(PORT##OUT, BIT); } \
            inline void SetOut(PINVALUE val) {if (val == PINLOW) SetOutLow(); else SetOutHigh(); } \
            inline void Toggle() { TOGGLE(PORT##OUT, BIT); } \
            \
            inline void EnablePinResistance() { SETHIGH(PORT##REN, BIT); } \
            inline void DisablePinResistance() { SETLOW(PORT##REN, BIT); } \
            \
            inline void EnableInt() { SETHIGH(PORT##IE, BIT); } \
            inline void DisableInt() { SETLOW(PORT##IE, BIT); } \
            inline void EnableIntFromLowToHigh() { SETLOW(PORT##IES, BIT); } \
            inline void EnableIntFromHighToLow() { SETHIGH(PORT##IES, BIT); } \
            inline void ClearIntFlag() { SETLOW(PORT##IFG, BIT); } \
            \
            inline void InitPullupButtonFromLowToHigh() \
            { \
                SetOutHigh(); \
                EnablePinResistance(); \
                EnableIntFromHighToLow(); \
                ClearIntFlag(); \
                EnableInt(); \
            } \
            \
        } PINNAME;

    This generates the sketch code we just saw before, but in an automated manner, as said.
    At this point, to declare a pin is just a matter of:

    DEFINE_PIN(p10, P1, BIT0);

    With this, the whole led blinking program becomes now:

    DEFINE_PIN(p10, P1, BIT0);

    void main(void)
    {
        WATCHDOG_STOPPED();

        p10.SetDirOut();

        while (1)
        {
            p10.Toggle();
            DELAY_CYCLES(50000);
        }
    }

    that, when compiled, gives us a code size of 174+2 bytes. Do you know this number? It's EXACTLY the same that we got with the previous version of the program (see the other post), so we can state, even without studying the generated assembly, that we didn't lose anything in terms of performance and code size, but we gained in readability and maintainability, since, for example, if I want to change the output pin, I have only to change it in one place for all my program.

    Moreover, readability is greater because we have way less parameters, in the code, that lowers error chance, too.

    I think I can conclude that, at least until now, we had only improvements, in writing the program in this way, compared to the 'traditional' way.
    The fear of losing what's important in microcontroller (speed, code size, low level control of the chip) is vanished.

    In the next chapter, we'll approach interrupt control: we'll see smart solution even to that problem, but since I still have to clean the code, I need some day, so don't wait for quick updates (I do all of this on my spare time...).

    Andrea

  • Admittedly I haven't actually pulled the code yet to check it out but there is a port of an Arduino IDE with supporting libraries for the Launchpad here: https://github.com/energia/Energia If this interests / works for you I would suggest contributing rather than starting from scratch.

  • I have to repeat that we are talking about two totally different approaches: in Energia case, or any other porting, there will be a layer that hides the underlying chip. This can be perfect for a hobbyist point of view, but is far from ideal for who wants to exploit the real processor power.

    Just to make an example, timer implementation in MSP430 is very different from arduino implementation: trying to make things compatbile can only be done at the expense of performance, code size and capabilities... If you have to create an optimized and powerful solution form MSP430 you cannot use such a library. I'm trying to give support to who has to do this second activity.

    Andrea

  • I just gave a look at the Energia source code, and for example, this is their implementation of digitalWrite, the function the sets a pin high or low:

    void digitalWrite(uint8_t pin, uint8_t val)
    {
        uint8_t timer = digitalPinToTimer(pin);
        uint8_t bit = digitalPinToBitMask(pin);
        uint8_t port = digitalPinToPort(pin);
        volatile uint8_t *out;

        if (port == NOT_A_PIN) return;

        // If the pin that support PWM output, we need to turn it off
        // before doing a digital write.
        if (timer != NOT_ON_TIMER) turnOffPWM(timer);

        out = portOutputRegister(port);

        uint8_t oldSREG = SREG;
        cli();

        if (val == LOW) {
            *out &= ~bit;
        } else {
            *out |= bit;
        }

        SREG = oldSREG;
    }

    I have nothing to say about this code: surely it integrates perfectly on Energia point of view, and surely it makes life easy for the programmer, particularly if he/she has a background in Arduino programming.

    You will agree with me, though, that the performance (and partially code size too), even if we don't look at the implementation of digitalPinToTimer, digitalPinToBitMask and digitalPinToPort, shouldn't be so ideal: in Energia this is not a problem, of course, since these are not project goals.

    Andrea

  • Well, thank you for clarifying this :)

    Some time ago I read about a similar project with MSP430, but I cannot remember the name and it was not very mature (yet).

    Good luck Andrea!

  • My code is growing, so I recognize the need to publish it in a usable form, for who wants to give it a try.

    Since I've never done it before, can you suggest what is a good repository, and why?

    Thanks in advance.

    Andrea

  • Andrea Bioli said:

    My code is growing, so I recognize the need to publish it in a usable form, for who wants to give it a try.

    Since I've never done it before, can you suggest what is a good repository, and why?

    Thanks in advance.

    Andrea

    I use github mainly as a backup for some bits and pieces and have not had any issues with it. I think its probably best to chose a VCS you are comfortable with, Git, Mercurial etc then choose one of the big sites which support it.

    If you have no preference in VCS I would suggest giving Git a go and if you like it look into github or bitbucket.

  • Maybe five minutes are few, to understand well what is needed to use Git service... but it looked a mess, to me! :-(

    I will give a shot to the others...

    Thanks, anyway! :-)

    Andrea

  • Hi Andrea,

    did you have a look at TI's MSP430Ware driver library for the x5xx and x6xx devices? The source code is even provided with CCS v5.2. What do you think about it?

    Best regards

    Christian Steffen

  • Yes, I looked at it, and it's a full fledged (real) library, but just because of this, it's oriented only to higher processors, that do have a lot of memory, compared to the (inferior) Value Line MCUs.

    The challenge is just this: to make life easier for developers in the need of squeezing bits and bytes from their code. A 'normal' library is of very little use, from this point of view.

    When I have a first (reasonable) release, I will give out some samples together with the source code.

    Andrea

  • Without going into detail with all teh posts in this thread, I want to add my own experience abotu this topic.

    Originally, a library was a place where people could lookup for information someone else has collected, and then use this information to build their own individual solution. But today, a library (or more precisely the internet, that is used as a replacement) is used as a place where one can pick up a solution and copy it into his own project without understanding it at all.

    The typical code library has been of the second type most of the time. People do not know how it works, they only know that it serves a specific purpose and use it, either dynamically linked or statically included into their programs.

    This is fine as long as the library 'does the job' and the executing compiler has the resources to hold it and execute it and still 'do the job'.

    However, in case of a prebuilt library, neither the user nor the compiler knows how the library is designed. So the library needs to handle all possible cases for all possible targets. And decide at runtime what to do.
    This makes the library code larger and slower (in many case MUCH larger and slower) than necessary. Still not a problem if the executing processor has the resources.

    But on microcontroller applicaitons, size and speed matter. The best code is code that exactly fits to the problem and does not contain any checks and cases for situations that are not part of the application scope.

    This leads to a different type of library, where only the required code is generated and as much as possible is resolved at compile-time.

    In our company, we work with MSPs (1232, 1611 and 5438) and ATMega128. All devices share specific high-level funcitonality. Over time, I developed a set of 'library' code files for the high-level functions but as well for the low-level stuff, that can be included in any project and will do the job, and still be highly efficient.

    All those code files contain a lot of #ifdef and #infdef precompiler instructions. Whenever soemthing is processor specific, an #ifdef ensures that the proper code is compiled based on global settings. Sometimes, the funcitons contain more #ifdefs than normal code lines.

    What is to be compiled is controlled by a global settigns header file that is specific for a project and included by all code files.

    Let's assume there is need for an RS232 communication. The global settings file contains
    #define RS232_UART 1

    The code file rs232.c then contains

    #include <uart.h>
    #ifndef RS232_UART
    #error RS232_UART not defined
    #elif RS232_UART > UART_MAX_UARTS
    #error target device does not have requested UART
    #endif

    UART_STATE RS232_Init(long int baudrate, int timeout)
    {
      UART_STATE state = 0;
      state = UART_Init(RS232_UART);
      state |= UART_SetBaudrate(RS232_UART,baudrate);
      state |= UART_SetTimeout(RS232_UART,timeout);
      return state;
    }

    int putchar (int char) // for link compatibility with printf library code, this must be a function
    {
      return uart_putch(RS232_UART, char);
    }
    #define putch(x) uart_putch(RS232_UART, x)
    #define puts(x) uart_puts(RS232_UART, x)
    [...]

    uart.c then contains the low-level code. Based on the target CPU, UART #1 may e a software UART or a hardware UART. Other global settings may control the size of the ringbufer, whether an ISR is used for the data transfer of busy-waiting code etc. It also contains the UART_STATE type and the different state definitions.

    As a result, the compiler can eliminate all unused code at compiletime. If done properly, there will not be any code that relates to UART #0 when no part of the project uses UART#0. Not even an IF check whether UART 0 or 1 is to be used.

    However, this type of library is difficult to maintain if the number of target devices increases. Not that a 'generic' library code is less complex, but using the precompiler makes the code less readable. The compiler sees a different (already filtered) code than you see.
    However, if you have to fight for every byte in ram and flash, it really pays.

    Well, there is an RS485.c module that is almost identical to the RS232.c module. Of course it uses RS485_UART and has some additional code around the lowest-level UART calls for the diretion control. And a global define for the port pin that controls the direction :)

    Over the years, quite a lot of modules have been added to the collection. An LED module that controls signal LEDs based on timer interrupt. You simply set the on-time or off-time in a global variable and the LED goes on (or off) for the specified amount of ms. Een a PWM-like output (blinking with configurable on and off time) is supported, and the global settigns control whether the LEDs are on separate port pins or connected through a serial shift register. If you don't use the LEDs, the main tiemr interrupt will not even hold a check whether to call the LED code. All is eliminated at compile time.
    Modules for short-time delays, multhreading, SPI (hardware or software), I2C (hardware or software), DMA, MMC card access (with or without DMA), external RTC, and, and, and.

    And while all modules will interact with each other, you won't find a trace of unused modules in the compiled code. Not even for the (inactive) interactions between one module and an unused other module. Everything is sorted out at compiletime based ont he global configuration.

    However, the documentation for all this is way more complex than for a generic 'all-in-one' library. But it pays.

  • TI does supply some bits and pieces like the USI I2C Master/Slave library. I used this in a simple I2C communication project with a MSP430F2013.

    http://www.ti.com/litv/pdf/slaa368a

    Is that the kind of thing you are looking for?

  • I try to answer both last messages.

    Jens-Michael, I *totally*, and I mean TOTALLY, agree with you, most of all for the first part of your message: this is what pushes me to write code like I'm doing right now. If you browse back the messages, you can see that the macros and functions I'm writing often don't even add a SINGLE byte to the executable, still I think they are by far more readable than original TI *basic* code.

    But, coming to Timothy, I have another thought that gives me the spin for my library, and that is (how can I call it?): 'time to grasp the functionalities', or 'effort to be able to use the MCUs'.

    I cut & paste e sample of the code contained in the document he just pointed to:

     

    /* Initialize USI module, clock ~ SMCLK/128 */

    TI_USI_I2C_MasterInit(USIDIV_7+USISSEL_2+USICKPL, StatusCallback);

    __disable_interrupt();

    TI_USI_I2CWrite(0x50,9,0,TxData0);

    __bis_SR_register(LPM0_bits + GIE);

    /* Acknowledge polling function - loops continuously until slave device

    provides an ACK */

    while(TI_USI_I2CSelect(0x50));

    /* Transmit data to the EEPROM device, prefixed by page address 0x08

    TI_USI_I2CWrite(SlaveAddress, Length, Multi, TxData)*/

    __disable_interrupt();

    TI_USI_I2CWrite(0x50, 3, 0, TxData1);

    __bis_SR_register(LPM0_bits + GIE);

    Now I obviously agree that a programmer has to know what we are talking about (in this case, I2C), but really is there someone that can understand from this code, what it does, why it's written in this way, and how he can modify it to suit his needs??? So I'm sorry, Timothy, but that kind of code is just what I'm NOT looking for! :-) Still, it's interesting for who, like me, wants to write a library... yes, on this, I strongly agree!

    So, the approach of Jens-Michael is the right one, if you want to squeeze bytes and performance (I'm using the same approach, for the Value Line MCUs), but I add another motivation: simplifying the distance between the theory, that must be known in advance, and it's effective use in real code.

    I like this thread: it's always important to know what other think, and to receive ideas to elaborate from... (and I thank you all for the support you are giving me!)

    Andrea

  • Andrea Bioli said:
    Now I obviously agree that a programmer has to know what we are talking about (in this case, I2C)

    You'd be surprised how many people do not even know that 1) I2C is an open-collector bus and 2) needs a common GND. Not to mention protocol internals.

    I agree that much of the TI code mroe or less does what it shall do, but kepps the 'how' in thw shadows. Especially 'smart' workarounds for problems.

    So there are basically two approaches:

    First the one-in-all approach. You call 'send' and it sends. And you call 'receive' and it receives. No limitiations , 'telling' return codes etc.
    However, this will likely be much more than needed. And less efficient.
    Or the problem is stripped down into small mid-level steps.

    'send start condition', 'send byte', 'receive byte'  etc. Then one can construct a chain of events exactly fitting the requirements. Strictly following the diagram in almost every I2C slave device datasheet I've ever seen.
    This is basically what I've done for a non-interrupt-driven I2C implementation OF both, hardware I2C and software I2C (with configurable port pins): Other than with my first try with the USART I2C on the 1611, it worked from the first try. Well, I had some experience with software I2C: I implemented one on the C64 datasette bus many years ago. :)

  • It's all true, even if I didn't want to go in these particular details (of the I2C, for this example).

    I was trying to give a general point of view, that regarding your message, can be summarized as follows:

    The one-in-all approach gives you a fast start, but probably is not so useful when you want to control the details. There must be, as you call them, those mid-level steps that are still very efficient, but relaxing the programmer to remember all the flags, all the very low level functions that are seldom used (but that must be there, for such particular cases... :-)).

    On those, I'm working right now.

    Andrea

  • Hi Andrea,

    What was the outcome of this exercise? Can you please share the details?

    Thanks,

    Anand

  • ...I think all of this is totally superseded by Energia... :-)

    AB

  • Andrea Bioli1 said:
    ...I think all of this is totally superseded by Energia... :-)

    Maybe. I haven’t worked with energy yet. But from what I’ve seen in some forum posts, it is more like a ‘one-in-all’ solution. Simple to start with (‘fire-and-forget’, that's why people are using it) but when you need more control…

     

    Edit: I'm pretty sure I typed 'Energia' but now it read 'energy' above. So much for auto-correction :)

  • Jens-Michael Gross said:

    ...I think all of this is totally superseded by Energia... :-)

    Maybe. I haven’t worked with energy yet. But from what I’ve seen in some forum posts, it is more like a ‘one-in-all’ solution. Simple to start with (‘fire-and-forget’, that's why people are using it) but when you need more control…

    [/quote]

    I second that. We are moving towards too much dependence on tools rather the focusing on accomplishing the task at hand and building/innovating on top of existing knowledge. To move towards that aim, abstraction and re-usability are important but not at the cost of lower-level control.

    In my research, I found following to be more helpful:

    - Board support package based on C https://github.com/pabigot/bsp430

    - Peripheral Template Library based on C++ https://github.com/pfalcon/PeripheralTemplateLibrary

    I've started my own effort to port mbed API to MSP430 https://github.com/atamariya/mbed . Though mbed is primarily targeted towards ARM, the API is still useful.

    - The C++ API is very clean promoting understanding and re-usability (e.g. SPI example here https://mbed.org/handbook/SPI)

    - Good documentation and community involvement in developing libraries.

    - Code size and performance are important. However, the first focus is functionality. The good thing is - once performance improvement is done at HAL or API layer, it is immediately available to all the programs using it with just one re-compile.

**Attention** This is a public forum