Has anyone used C++ or any other non 'C' basic language with STM chips? - Page 1
Forum section: electronics / general

author: Acecool
author_rank: Regular Contributor
timestamp: May 09, 2018, 08:37:56 am
content: I'm looking into rewriting software for a hardware configuration I put together ( The Logitech G series USB Adapter for Pedals / Shifter ) and I want to go with an object oriented language but I haven't found libraries for it...I know C++ would increase the overhead, and the chip I use has 32KB memory, if I recall correctly, but the current implementation of C would require a rewrite anyway just because it's such a mess from the original author so if it does, I may as well use a different language... I don't really care if I use C++, Python, Java, or Lua for the project - I know all of them fluently. I would be open to C# as it seems cleaner than C++ but I'd need to learn it.. I don't really have a preference but I'd prefer object oriented over basic C ( and Lua would work for this purpose too )...Does anyone know of any libraries available for the STM32 chip to use another language for a USB HID adapter / plug and play for a game controller? I would also need the ability to edit the driver display page so allow combining axis, and reversing them.

author: newbrain
author_rank: Super Contributor
timestamp: May 09, 2018, 09:45:14 am
content: Quote from: Acecool on May 09, 2018, 08:37:56 amThere aren't that many C++ libraries for STM32, the ones I know of are:https://github.com/andysworkshop/stm32plusF0, F1 and F4andhttps://github.com/no111u3/stm32cclibL1, F3, F4The first one seems to be more "alive" and complete, especially for documentation and examples.From a quick look at the code and examples, the level of abstraction is also higher.I have used neither, though, so cannot vouch on their actual quality.The second part of your question puzzles me a bit: do you intend to also develop the Windows/Linux/MacOS driver and configuration or only the device part to emulate a known device?

author: andyturk
author_rank: Frequent Contributor
timestamp: May 09, 2018, 10:15:43 am
content: Oh! Another C++ question!Quote from: Acecool on May 09, 2018, 08:37:56 amNot really. Simply using C++ to compile your code won't cost anything. C++ often leads to more resource efficient code than straight C because the compiler has more information to work with.QuoteHmm. The fact that you're even asking this question combined with your "fluency" in several different dynamic/OO languages suggests that you probably haven't written much C or C++ in a microcontroller environment yet. The C++ features you use on Linux/Windows are going to be vastly different than what you can get away with on an mcu.Generally speaking, you won't want to use STL or Boost, and you probably won't be using "new" to create class instances either. You'll be writing a lot more code from scratch and spend a lot of time shimming to processor specific APIs.I think you can probably forget about Python, Java and C# on STM32. Lua maybe? The F7 parts can do double precision floating point in hardware.

author: brucehoult
author_rank: Super Contributor
timestamp: May 09, 2018, 10:31:51 am
content: Quote from: Acecool on May 09, 2018, 08:37:56 amC++ doesn't "increase the overhead" unless you're doing things that you can't do in C anyway.Well, that's not true .. you can do *anything* in C. But if you need some facility and it's built in to C++ but you'd have to tediously hand code it in C then any difference in overhead will be negligable, and quite possibly favour C++.As for Lua, Python, Java or C# ... none of those are likely to fit into a machine with 32 KB. *Maybe* Lua. I can't find figures on it.I was on a project a couple of years ago porting C# to phones and it was the goal of a year-long project with half a dozen people to get C# usage of small apps down to eight MEGABYTES.

author: DJohn
author_rank: Regular Contributor
timestamp: May 09, 2018, 01:48:01 pm
content: Lua won't enjoy having only 32KB of RAM. I'd avoid anything with garbage collection, which is pretty much everything except C and C++.As others have said C++ won't use any more memory than C, unless you start doing silly things with it.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: May 09, 2018, 03:33:40 pm
content: It should not be too hard to make C++ wrappers around existing C lib APIs. Only wrap what you need.Note that wrapping is not abstracting, so it will leak C lib details, although I generally try to minimize that.

author: hans
author_rank: Super Contributor
timestamp: May 09, 2018, 04:08:43 pm
content: Abstractions are useful and dangerous in the embedded world. They are useful because they save on time if reused, and can avoid typing errors. They are dangerous because an abstraction does not immediately reveal it's cost.For example most of the STL library functions are not very friendly for embedded, because they use dynamic memory allocation. You do have static STL variants available, which may be of use though.C++ metaprogramming is quite popular, and can be useful if you can spend the mental energy and time into it. In some cases it can lead to negative cost (speed or size, depending what you optimize for) code.What I don't think so nice of metaprogramming is that the code becomes incredibly slow (and large) to run if you don't use the optimizer. That could happen if you're debugging your code during development, which either means you got to use -Og (GCC) and hope it's good enough, or test as much higher level code as possible on a normal desktop PC.. (e.g. via unit tests - which is a big enabler in C++ over C IMHO that is worth utilizing!)

author: SiliconWizard
author_rank: Super Contributor
timestamp: May 09, 2018, 04:37:11 pm
content: Quite right.I'd be interested in seeing a real-world, non-trivial C++ codebase (not one explicitely written just to prove a point) for a small MCU (let's say a 32 KB or even 64 KB binary) that properly uses C++ constructs (and not just uses it as C with namespaces) and that really leads to similar or smaller code size and similar performance than an equivalent C codebase. We often hear or read about such claims, but it's often difficult to find real examples.The STL is a good point. Most people using C++ will want to benefit from the STL and similar libraries, and they can lead to bloated object code.The pervasive use of dynamic memory allocation would also be a potential issue, as we have discussed in another recent thread (https://www.eevblog.com/forum/microcontrollers/having-trouble-avoiding-malloc-on-embedded-arm-suggestions/).Anyway, if anyone can post a project or point to one, I'll be happy to investigate.

author: andyturk
author_rank: Frequent Contributor
timestamp: May 10, 2018, 04:36:28 am
content: Quote from: SiliconWizard on May 09, 2018, 04:37:11 pmThat might be a difficult comparison to make, since anything "non-trivial" is going to be somewhat costly to create and re-writing it for the purposes of the experiment probably doubles the expense.Jason Turner has talks about an interesting (but perhaps contrived) C++ example on small hardware here:I currently work on a commercial project that is C++11 top to bottom, except for one assembly file that implemented a custom scheduler. Code space is about 100kB with -O3 on a Cortex-M0. There are some non-trivial algorithmic pieces in there that were originally developed on OS X and are still unit tested there apart from the embedded build.While it's possible to use C++ to squeeze out more performance (probably by doing more computation at compile time than C would), that's not the main reason to use the language. IMO, using C++ often results in code with fewer bugs (a personal conclusion for sure, not a fact) and at a higher level of abstraction. I like C++ because I spend less time debugging code on the embedded platform than I would with straight C.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: May 10, 2018, 06:21:21 am
content: Quote from: SiliconWizard on May 09, 2018, 04:37:11 pmNot sure if this fits the criteria, but this is my Midi Mapper project on an AtMega 1284 (main is in Program.cpp).https://github.com/obiwanjacobi/Midi-Master/tree/master/Source/MidiMapperIt is based on a C++ templates using my ATL lib, and a catalist project for expanding ATL as well.The choice here is: rather more code than use more memory.Last I remember I had trouble abstracting all the different Timer functions in a sensible way...

author: Acecool
author_rank: Regular Contributor
timestamp: May 10, 2018, 12:44:18 pm
content: Yes, I am new to the micro-controller world of programming, but not with the languages themselves...Yes, I'm aware you can code anything with C but it is easier with C++ because of objects - making maintenance much easier along with readability... I did state the code is hideous and it'd be so much easier with C++ which is why I was asking for libraries, etc... From what I have read about using C++ or another language with microcontrollers, they stated C++ increases overhead quite a bit so the onboard 32KB may not be enough - if that's wrong then no problem..OR, it could be the library size is larger - I don't recall..My main reason for switching is human readability and ease of maintenance because right now everything looks thrown together with minimal comments and there is so much code which has been repeated which doesn't need to be...The device itself is open source, open hardware:https://hackaday.io/project/13456-logitech-g25g27-shifterpedals-usb-adapterI have been wanting to add new features and update the code - using C++ would help because of objects and less repeated code.I'll look through the responses so far - thanks, I really appreciate it!The driver itself is already made, or it is fully plug and play with no additional driver required - that's what I'm aiming for but if I need to write a driver to add the options to combine the axis, swap directions, etc... then so be it ( although I could do that in the software itself but I'd need a way to configure it - I haven't looked really at the gate configuration program which controls the axis positions when a gear is chosen or exited - so if it saves the data on the chip then great - but it means developing software to do that.. the big thing is ensuring the output is the same for the driver end which is why I'd prefer those options in the actual controller configuration so that may require a custom driver although those options should exist in default HID plug and play drivers / support so I just need to add the features )...

author: brucehoult
author_rank: Super Contributor
timestamp: May 10, 2018, 01:19:24 pm
content: Quote from: Acecool on May 10, 2018, 12:44:18 pmIf you use libraries then of course you'll end up with (some of) the library using space in your program.How much depends on the design of the library.There is one obvious area in which the usual C++ library gives smaller programs than the standard C library: printing or formatting to a string or buffer using printf and friends. Because the printf format string is parsed at runtime, there is no way to know whether you're going to be printing strings, or characters or integers or floating point or what. The result is that the code for ALL of them has to be present in your final program.With either standard C++'s streams library and << operator, or with something like the Arduino library's overloaded print() and println() functions your program binary should end up with formatting code for ONLY the actual datatypes you use.In C you could avoid printf() and write and use print_char(), print_int(), print_string(), print_float() functions, but the code becomes more tedious to write and most people just stick with printf() and friends.

author: rstofer
author_rank: Super Contributor
timestamp: May 10, 2018, 02:22:25 pm
content: Quote from: Acecool on May 10, 2018, 12:44:18 pmIt's possible to write crap code in any language. There's no reason to blame C for the lack of coding skill. Or design skill. At some point all programs begin to react like a balloon. Push a little here, it bulges a little there.The best Fortran programs were written after the programmer dropped the box of cards.

author: nctnico
author_rank: Super Contributor
timestamp: May 10, 2018, 02:56:41 pm
content: Quote from: brucehoult on May 10, 2018, 01:19:24 pmThe key to reducing code is not avoiding libraries but using smaller versions of them. The printf example is a classic one. The best solution is to use a smaller printf and not re-invent the wheel.

author: SiliconWizard
author_rank: Super Contributor
timestamp: May 10, 2018, 03:16:09 pm
content: Quote from: nctnico on May 10, 2018, 02:56:41 pmTrue, but it still depends. printf() is usually pretty slow due to its nature (interpreting formats during execution), so if you need really fast conversion of predefined types, you're usually much better off devising your own.This for speed considerations. As for code size, again it would depend. If all you ever need in your code is an int-to-string conversion, you'll end up with a much lower footprint (and again much faster) writing your own conversion (just a few lines of C). But if you need all the bells and whistles of printf(), of course you should use the standard printf().One thing to consider is that printf() is very flexible since it allows to modify the format itself at execution time (since the format is just a string), something you can't do with C++ streams.As for the variants of printf(), the most commonly seen when using GCC on ARM for instance, is one version (the default one) which doesn't support floating point conversion, and one with floating point support (with the "-u _printf_float" option). The floating point support makes printf() obese!

author: nctnico
author_rank: Super Contributor
timestamp: May 10, 2018, 03:46:30 pm
content: Quote from: SiliconWizard on May 10, 2018, 03:16:09 pmTry to compile something with GCC and you'll find out it won't allow to feed it a non-constant formatting string. For a good reason because it would impose a huge security hole.

author: SiliconWizard
author_rank: Super Contributor
timestamp: May 10, 2018, 04:29:02 pm
content: Quote from: nctnico on May 10, 2018, 03:46:30 pmI've done that quite a few times and never had any issue. Whether it's more or less dangerous than a constant format but incorrect following parameters is largely up to debate.Below is a very minimal example just to show what you can do:printf_ex1.c:Code:#include <stdio.h>int main(void){char szFormat;unsigned int i;for (i = 1; i <= 10; i++){sprintf(szFormat, "[%%0%uX]\n", i + 1);printf(szFormat, i);}}It compiles with GCC without any kind of warning with: "gcc -Wall -pedantic -o printf_ex1.exe printf_ex1.c" and executes properly.And I don't think you can make GCC more pedantic than with the -Wall and -pedantic options.You'll get the following output:Code:

author: westfw
author_rank: Super Contributor
timestamp: May 11, 2018, 05:06:20 am
content: Well, there's the STM32duino stuff - an Arduino "core" that runs on a bunch of the STM chips.Arduino makes use of some C++ constructs, to reasonable effect and without incurring a lot of overhead that could be blamed on C++.It's STL-free, libc++-free, pretty much template-free. It's probably a bit un-even - some libraries are better examples than others, and it may not be what you're looking for. But it's not a completely awful starting place.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: May 11, 2018, 06:27:16 am
content: I would start to refactor the code first.Write (successful) unit test for the code you are about to change, then refactor it. Make sure the tests still pass.Refactor towards the structure you think is better (carefully chosen words).When you're done you probably won't need to convert it to C++ or at least it will be a lot easier.Takes time though.

author: rstofer
author_rank: Super Contributor
timestamp: May 11, 2018, 03:27:46 pm
content: Quote from: nctnico on May 10, 2018, 02:56:41 pmI don't want a heap so I avoid the string functions and I also avoid printf().What I do is copy the string and conversion functions from "The C Programming Language" (K&R) and write up several functions that will output decimal, hex nibbles, bytes, shorts and ints. Then all I need is character and string IO over the serial port and I'm ready to go. I don't tend to do a lot of serial input. If any...The thing about this low level code is that it is easy to port from chip to chip. Just copy and paste!No, using these functions isn't as slick as printf() but I don't really need about 90% of what it can do. There are some lightweight printf() functions around the Internet and they basically eliminate the lesser used conversions. The ones I have seen also avoid using the heap.Here's one minimal implementation:https://github.com/mludvig/mini-printfApparently the search string is 'micro printf' to turn up this version and many others.

author: nctnico
author_rank: Super Contributor
timestamp: May 11, 2018, 03:48:14 pm
content: Quote from: rstofer on May 11, 2018, 03:27:46 pmI think you are misinformed here. Printf (and associated functions) don't use the heap at all! They use the buffer(s) you provide and perhaps a very small buffer which is allocated statically or on the stack. Especially C libraries which are written for embedded platforms have a very small memory footprint. If you write your own functions then you are re-inventing the wheel. The C library has been designed in an era when memory was very limited so way the functions are designed is very clever.

author: westfw
author_rank: Super Contributor
timestamp: May 11, 2018, 09:11:55 pm
content: QuotePeople keep saying that, but I don't think many have actually looked. I'd challenge you to write a "hello world" program that uses a standard printf() library and write to a UART on any ARM chip/environment you like, and check the linker output to see if malloc() is there or not. (if not, please post instructions on how to replicate!)It might not be printf() itself causing problems. But most ARM environments use newlib, and newlib treats printf() as bring a proper stdio call that writes to a file, and so it sucks in filesystem code as well as the formatting code. OTOH, it looks to me like printf() itself has a malloc or two as well.(at least in newlib.)https://community.atmel.com/comment/2374621#comment-2374621

author: rstofer
author_rank: Super Contributor
timestamp: May 11, 2018, 09:14:05 pm
content: Quote from: nctnico on May 11, 2018, 03:48:14 pmAs soon as I see the linker error that _sbrk() is not defined I KNOW there is a heap. As long as _sbrk() never gets declared as weak in the library, I'll know what to avoid. One of these days I'll look at the difference in size for a build using printf() and one that doesn't. I know my conversion routines are small with buffer space allocated on the stack and the serial IO is whatever it takes and has nothing to do with the library. Anecdotal remarks on the Internet suggest that printf() is huge in microcontroller terms. What I didn't see was numbers.Meanwhile, for me, printf() brings nothing to the dance. It's handy but not necessary.

author: nctnico
author_rank: Super Contributor
timestamp: May 11, 2018, 09:49:14 pm
content: Quote from: westfw on May 11, 2018, 09:11:55 pmCode:.data 0x1000000c 0x0 libcmini-arm-none-eabi-thumb2-os.a(atoi.o).data 0x1000000c 0x0 libcmini-arm-none-eabi-thumb2-os.a(printf.o).data 0x1000000c 0x0 libcmini-arm-none-eabi-thumb2-os.a(vuprintf.o).data 0x1000000c 0x0 libcmini-arm-none-eabi-thumb2-os.a(puts.o).data 0x1000000c 0x0 libcmini-arm-none-eabi-thumb2-os.a(memchr.o).data 0x1000000c 0x0 libcmini-arm-none-eabi-thumb2-os.a(strncmp.o).data 0x1000000c 0x0 libcmini-arm-none-eabi-thumb2-os.a(strncpy.o).data 0x1000000c 0x0 libcmini-arm-none-eabi-thumb2-os.a(memcpy.o).data 0x1000000c 0x0 libcmini-arm-none-eabi-thumb2-os.a(memset.o).data 0x1000000c 0x0 libcmini-arm-none-eabi-thumb2-os.a(strlen.o).data 0x1000000c 0x0 /usr/local/bin/arm-gcc/lib/gcc/arm-none-eabi/4.6.2/armv6-m/libgcc.a(_thumb1_case_uqi.o).data 0x1000000c 0x0 /usr/local/bin/arm-gcc/lib/gcc/arm-none-eabi/4.6.2/armv6-m/libgcc.a(_udivsi3.o).data 0x1000000c 0x0 /usr/local/bin/arm-gcc/lib/gcc/arm-none-eabi/4.6.2/armv6-m/libgcc.a(_divsi3.o).data 0x1000000c 0x0 /usr/local/bin/arm-gcc/lib/gcc/arm-none-eabi/4.6.2/armv6-m/libgcc.a(_dvmd_tls.o)The C library I use is the one which comes with MSP430 GCC but then compiled for ARM. It is very lean and I have been using it for over a decade. If a C library pulls in malloc then it is not suitable for embedded work but it is still not a reason to avoid printf. You just need to use the appropriate C library. I can't imagine an embedded environment providing an 'unsuitable' C library.

author: westfw
author_rank: Super Contributor
timestamp: May 11, 2018, 10:13:52 pm
content: QuoteWell, I guess we can add "bad printf implementation" to the list of complaints about 32-bit microcontroller development environments. Or maybe as a complaint about gcc.AFAIK, almost everyone is using newlib.QuoteHmmph. I'd been thinking about porting avr-libc to ARM for similar reasons, but it's full of AVR assembler. I may have to take a look at the MSP430 libs... (where do they come from?)QuoteIn the example I linked earlier (https://community.atmel.com/comment/2374621#comment-2374621) stdio filesystem stuff added about 7k and printf() added about 9k. That may not seem horrible if you're talking about an average CM3 with 128k or better of flash, but there are ARM chips being aimed at 8bit users that have 8k or less.

author: westfw
author_rank: Super Contributor
timestamp: May 11, 2018, 10:19:27 pm
content: QuoteIs that the one from the Peter Bigot days, or the current TI supported MSP430 gcc?

author: nctnico
author_rank: Super Contributor
timestamp: May 11, 2018, 10:21:23 pm
content: The printf + vuprintf in the library I'm using need less than 1kB.You can find the mspgcc library here but I don't know if it is still portable. Back then I just had to change the makefile a little bit and remove a minimum amount of assembler. I also changed the makefile to create various versions of the library for various Cortex Mx instruction sets and optimisations (size and speed).https://sourceforge.net/projects/mspgcc/files/msp430-libc/And yes that is the one from the Peter Bigot days.

author: westfw
author_rank: Super Contributor
timestamp: May 11, 2018, 10:57:42 pm
content: Thanks. It doesn't seem to have changed since 2012, so it probably hasn't become much less portable (and old versions still available!)This sub-discussion illustrates the problems with libraries and language features. No one really thinks that printf() should NEED to use malloc(), but by the time the library designers are done core printf functions invoke malloc() because the original caller MIGHT have been "asprintf()" (which I never noticed, until today), and making the printf parts understand dynamically allocating the results (by calling malloc) seemed like it would be more efficient, but it certainly isn't if that's the only place you'd call malloc().Similarly "obvious and useful" stuff in C++ bloats code in non-obvious ways (for instance, virtual functions defeat linker function garbage collection, so an arduino sketch that uses "Serial" ends up including a bunch of HWserial functions whether they're used or not...)

author: bson
author_rank: Unknown
timestamp: May 11, 2018, 11:19:50 pm
content: Just as a note, there's no need to link with libstdc++; it has a tendency to pull in undesirable bits and pieces. The following stubs out the runtime support needed for g++. (libstdc++ uses atexit() to register exit-time destructors, something not even remotely desirable in embedded systems.)Code:// ABI stuff (both ELF and EABI stubs, for simplicity, though only one is needed)extern "C" {#undef abortvoid abort() { panic("ABORT"); }int __cxa_atexit(void (*func) (void*), void* arg, void* dso_handle);int __cxa_pure_virtual();int __aeabi_atexit (void *object, void (*destructor) (void *), void *dso_handle);}int __cxa_atexit(void (*func) (void*), void* arg, void* dso_handle){return 0;}int __aeabi_atexit (void *object, void (*destructor) (void *), void *dso_handle){return 0;}int __cxa_pure_virtual() { abort(); return 0; }void* __dso_handle = (void*) &__dso_handle;And, if using a custom startup, make sure to run initializers:Code:// Call from startup.S with:// bl _Z10init_arrayv// Somewhere else define:// #define __weak gnu::weak for gcc// For other compilers use other attributes if available, or an empty definition and make the symbols weak in the link script.[] extern void (*__preinit_array_start []) (void);[] extern void (*__preinit_array_end []) (void);[] extern void (*__init_array_start []) (void);[] extern void (*__init_array_end []) (void);void init_array() {size_t count, i;count = __preinit_array_end - __preinit_array_start;for (i = 0; i < count; i++)__preinit_array_start();count = __init_array_end - __init_array_start;for (i = 0; i < count; i++)__init_array_start();}The symbols __init_array_start etc need to match the linker script. init_array needs to be called from the startup code.This removes all dependencies on standard libraries other than libgcc.a; but libgcc is a hard dependency, for arithmetic ops, floating point, and such.

author: pigrew
author_rank: Frequent Contributor
timestamp: May 11, 2018, 11:59:43 pm
content: I had a few students this semester using ARM's mbed platform to target a STM32F4. My feeling is that it was somewhat Arduino-esque, but a much better implementation. If you want some quick prototypes done, it's great. I didn't personally use it, so I don't know if I'd suggest it or not. My students used the web-compilation feature, and then downloaded and flashed the binary. It looks like you can also use their libraries through Eclipse.