As mentioned in the last Wideband Transmission, I recently viewed a presentation from CppCon 2016 which convinced me that a lot of my preconceived notions about the (lack of) suitability of C++ for use in microcontroller applications might be misplaced.
The standard lore (go ask Wes Hayward W7ZOI his opinion of lore) states that C++ is inefficient in generating the compact binaries that are required when using a device with very limited program storage and RAM space, as you will find with microcontrollers (especially 8-bit controllers). Given that C is a probably fairly categorized as a mid-level language, and that C++ easily falls into the high-level language category with its much larger feature set, it seems natural to believe that there has to be an overhead cost to pay when using C++ over C. Yet, if you take the time to watch that video, you can see that it is possible to use advanced features of C++ and incur little to no overhead in the binary.
Not to say that you can just blithely use C++ without the possibility of incurring an overhead penalty. I've tried it and had some horrible results, and chalked my experience up to the old lore being correct as a general case. But that's obviously not true.
What I intend to do with this series is to look into ways that the features of C++ (mostly C++11 at this point) can be leveraged in the Arduino environment to take advantage of the advanced features of the language (and perhaps even things such as the Standard Template Library) while incurring no or perhaps a very small penalty in flash and RAM usage.
As most of you are probably aware, Arduino is based on C++, and every Arduino library coder has to use at least minimal C++ functionality in order to create a library. However, in the name of abstracting away much complexity, Arduino sketches are written more in C-style than modern C++. That being the default case, there's no reason we can't incorporate more C++ coding techniques into our Arduino sketches, as long as doing so serves our purposes of being able to use the higher-level abstractions without paying a penalty.
Before seeing the above presentation, I had already been thinking about this topic because good old Hackaday has been running a series of articles about it. While I may cover some areas previously addressed by said articles, I notice that many (but not all) of the previously mentioned posts don't delve into making the measurements of how implementing the C++ coding patterns affect code and RAM size (or perhaps execution speed). Data is king, so I intend to provide as much of it as possible so that you can see actual proof of the effects of migrating to C++ coding.
Just so you know where I'm coming from, let me tell you about where I'm at in my journey as a coder. I've been writing C for microcontrollers for a fair bit of time now, and I think I'm at least proficient at it, but not an expert by any means. I've dabbled in C++, but never really written any major programs in it, so I'm on a learning journey here as well. I'm sure I probably won't do everything perfectly or the most efficiently, but by holding to what the data tells me, I think I can provide some useful information to all while I learn some new things for myself.
Areas of Investigation
At this point, I don't have a list of topics for this series that is set in stone. I do have some initial ideas for investigation, but plan to follow other leads as they present themselves and as I learn more about this topic. From my initial notes, here are some potential topics you may see in future posts:
- Using constexpr
- C++ Standard Library and Standard Template Library usage
- Using lambda functions/inline functions
- Variable declaration: auto vs explicit
- Other C++11 features, such as the new for loop syntax that functions as a foreach
Please feel free to comment below if you have some other topics of potential interest.
In order to maintain consistency across the series, I intend to use the same microcontroller platform in all articles. The controller of choice will be my Empyrean Alpha board, which is basically an Arduino Zero minus the debugging circuitry on a form factor that can be plugged into a solderless breadboard, just like the Arduino Nano and related products. The Empyrean Alpha uses an Atmel ATSAMD21G18A microcontroller, which runs with a 48 MHz clock speed and has 256 kB of flash program memory and 32 kB of RAM, which is ample for many types of projects.
Hopefully in the near future, I'll be selling the Empyrean Alpha and its little brother Beta through Etherkit, so stay tuned for further news on that.
The Arduino environment for ATSAMD microcontrollers uses the arm-none-eabi-gcc toolchain, which has a variety of very nice tools that are available in addition to the compiler. One of those is arm-none-eabi-size, which can give a breakdown of the flash and RAM usage of a sketch simply by feeding it the file name of the ELF file that the compiler generates. For example:
jason@oberon /tmp/arduino_build_994621 $ arm-none-eabi-size -B foreach_test.ino.elf text data bss dec hex filename 9732 256 1780 11768 2df8 foreach_test.ino.elf
From the above, you can see the text section, which indicates size of the program in flash memory, the data section, which is the initialized variable storage in RAM, and the bss section, which is allocated but uninitialized variable storage in RAM. Pretty easy to use and interpret. We'll talk about this tool a bit more in the first investigation so that we have a good understanding about it.
Most likely, I'll also be using the Compiler Explorer tool, as was used in the video above. It looks like a very handy way to quickly and roughly demonstrate how code changes affect the assembler output from the compiler.
Now that we have the preliminaries out of the way, I'm ready to start tackling this series. Watch this blog for the first installation, which will be coming soon. My patrons will have early draft access to articles in the series, and will have a chance to chime in there with suggestions to help me with the final article on nt7s.com. See you soon!