setting up a to program a SAM device in C++ - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: February 20, 2025, 12:54:36 pm
content: OK, so I got the C++ bug. I think some C++ features will make it easier for me get stuff done on a micro controller, so I opened the can of worms.I started by setting up a blank C++ project in Microchip studio. And then I decided to use the map container from the standard library, at which point the world of error message rained down due to lots of stuff not being available. So with the help of a colleague I set up a C++ project with the ASF "stuff" and so now creating a map container does not break the universe as my project knows it.But this leaves me uneasy. So far I have only used the bare CMSIS header files and written everything myself. Now I have the CMSIS plus a ton of stuff that can set up my hardware. Must I use this? can I simply continue with my existing code? OK, I know that of course I can but is it worth giving this ASF thing more use or should I just keep it as my C++ libraries bolt on and carry on as I always have. If I am not mistaken microchip want to obsolete the ASF.

author: ataradov
author_rank: Super Contributor
timestamp: February 20, 2025, 02:39:29 pm
content: ASF is obsolete. It was declared obsolete years ago and all development has been stopped for a long time. There is no ASF for newer MCUs, so if you even want to switch MCUs you will be in a real pain.

author: Simon
author_rank: Unknown
timestamp: February 20, 2025, 04:34:46 pm
content: OK, so what is the best way to get the required C++ libraries into the project? I can only assume that the default M0+ C++ compiler does not have all of the libraries.

author: ataradov
author_rank: Super Contributor
timestamp: February 20, 2025, 04:46:10 pm
content: I have no idea. Never used C++ for embedded work. I personally think think it is a bad idea and will never do it, so I have not looked into it.

author: westfw
author_rank: Super Contributor
timestamp: February 21, 2025, 02:52:42 am
content: Quote from: Simon onTodayat 09:34:46 amWell, there's Arduino...While the Arduino AVR environment doesnotinclude the C++ STL, it is there for SAM...I'm not sure why the support isn't there in Atmel Studio. You can probably copy over the C++ includes and libraries from an Arduino install...

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 21, 2025, 02:56:08 am
content: There is this major issue of "hidden" heap allocation in C++.You have to be aware of it and in particular, avoid a ton of std containers which do use heap allocation by default. Or make damn sure you can track your heap allocations so that you don't run out of heap memory. Problem is that it can't be determined at compile-time by the compiler. So, that's extra burden for small targets IMO.std::map is no exception, as far as I'm aware. Now with reasonably recent C++ versions, most std containers can be used with a custom allocator, but that's something you may not want to get into.I don't think std::map can be used only with "static" storage.In terms of MCU resources, you should probably stick to using CMSIS as you did before.

author: Simon
author_rank: Unknown
timestamp: February 21, 2025, 07:42:09 am
content: Sounds like I best stick to C then on micro controllers.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 21, 2025, 08:01:12 am
content: If you still want to give C++ a go, I can suggest the following library:https://www.etlcpp.com/home.htmlIt's a replacement for the standard STL, with no dynamic allocation. It appears to implement maps (with a max size defined at compile time), so that could fit your bill.

author: hans
author_rank: Super Contributor
timestamp: February 21, 2025, 09:20:06 am
content: I know this is not going to help achieve your intended goal, but make strong considerations which part of the STL to use.The use of embedded C++ doesn't mean that memory fragmentation issues will disappear if your application continuously makes malloc and free calls. Some STL classes will do this for you, for example std::vector, but also std::map. Typically these classes will allocate a certain initial array to store element, and once thats full, will allocate a new one with a certain grow factor, and then move every element over.Some other classes are safer to use such as std::array or std::function if properly used (the latter in a template is usually quite safe).There are some static STL variants on Github and such that try to achieve a (as much) function complete STL library without memory allocation. For example:https://github.com/rukkal/static-stlBut unfortunately it doesn't contain the map class.edit: or see @SiliconWizard 's linkAVR-GCC has the same woes by the way, as it doesn't include any STL at all.I've using embedded C++ for almost 10 years on MCUs, and I do think there are some clear advantages.For example, better code structuring with classes. If a project implements structs with function pointers in C, then thats just a vtable (which in C++ is all taken care for you.Another advantage is templates. No more macros that 'write code' and cannot be debugged. Macro's are banned in some code bases for good reasons.Finally stronger type system to allow for more constexpr/consteval expressions.Two disadvantages: hidden use of malloc as I said (STL), and blown up code size because of all the templating. A good compiler with LTO can get rid of a lot, but if you want to debug code you may need to squeeze it in with optimization level Og in GCC.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 21, 2025, 10:23:36 am
content: I've seen many hit the same disappointment as Simon has, both in C and C++, when they realized that in the embedded environments, using freestanding C or C++, youdo nothave all of the standard library and utility libraries available. It feels like a new, different programming language altogether. In a sense, it is; the difference to normal hosted environments and their libraries is that big.I wish I knew which resources and books to point to as a good way to learn freestanding C or C++ programming, but I do not. :'(The good news is that if you do wrap your mind around the ideas and limitations, the coding part isn't that difficult, justdifferent. It is realizing how this limited environment differs from the one described online and tutorials and books, that is the big hard part of it.At the very core, assuming you use either GCC or Clang toolchains, and start from a freestanding C environment, the initial change is to just switch your compiler from a C one to a C++ one. That's it. If the C development environment has been set up, it should just work. (This is also how Arduino cores do it: they have a base C library, on top of which they add their own C++ preprocessor and libraries.) Then, depending on how much of C++ you want to use, you add the necessary libraries and base functions that the C++ libraries you want to use need.That starting point is what I call the C/C++ freestanding environment: you rely on the C standard definition for a freestanding environment for what is available by default, but a C++ compiler to compile your code, carefully only using the subset of C++ features you have runtime support for.

author: Simon
author_rank: Unknown
timestamp: February 21, 2025, 02:17:53 pm
content: Well my coding experience has been exclusively C on embedded so rather this miss things I have to work out what to ignore in a text book that relates to an OS environment. Having started to look at C++ I do think that things like classes would help to write code that is easier to use later. Obviously using every wizz bang feature of C++ will end in disaster.

author: voltsandjolts
author_rank: Unknown
timestamp: February 22, 2025, 02:53:09 am
content: IIUC this is commercial work for your employer. IME it's hard enough to hire a fw eng with good experience in C, my impression is it would be an order of magnitude more difficult to hire a good C++ fw eng.

author: Simon
author_rank: Unknown
timestamp: February 22, 2025, 09:08:16 am
content: Most programmers work from a PC with an OS background, so particularly with C++ they don't understand how to deal with the very limited resources and direct contact with the hardware. Then you get the manufacturers various configurators and library systems that try to make a 48MHz cpu with mere kB of RAM that try to cater to these people. That's why I never use them as the reason I do not get them is because I learnt starting from flipping IO pins rather than writing programs on a PC that are rather complex with graphics etc. Now that i try PC programming myself I am lost.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 22, 2025, 09:22:44 am
content: Yes, from that perspective, using C++, if the project is likely to be maintained by people from various backgrounds, is a trap.Many devs will be tempted to use convoluted class architectures and lots of STL containers, making the whole thing bloated and using a lot of hard-to-spot heap allocation, with the consequence of not knowing if there's even enough RAM to run it.Using C++ for embedded dev is an "art" that takes serious knowledge of both C++ and embedded dev and while it can have some benefits, I'm still not sure the benefits are worth the trouble in practice.constepxr functions are nice, though. You can easily create fixed arrays at compile time, something that can't be done with C (for which you have to create them with another tool such as as scripting language). But again, you can usually do that with a few lines of Python or Lua instead, so. Nice, but not a game changer.

author: Simon
author_rank: Unknown
timestamp: February 22, 2025, 09:49:57 am
content: I'm thinking I use C++ with the STL, just so that I can organize code better, I would be statically creating an class objects.

author: hans
author_rank: Super Contributor
timestamp: February 22, 2025, 10:18:00 am
content: I have seen embedded projects that remove malloc symbols and set heap size to zero at linker time. If any STL uses heap allocation, the linker cannot find malloc and fails to build.If you then are so inclined to use dynamic allocations for some objects, you can always write your memory allocator on a small pool of RAM. A simple slot based system is not that hard to write. Chances are you can also better control the chunk sizes that are allocated within the same pool, meaning if you only use 1 chunk size, heap fragmentation because much less of an issue.(Obviously the program can still run out of memory if object lifetime is not taken care off)In my opinion modern embedded processors will be shifting more to high-level software. I have a STM32H7 chip on my bench that runs 550MHz, attached to 16MB of HyperRAM at 100MB/s+ and can read/write SD cards that are literally 1TiB big. That is much much faster than the first home PC we got in '98. You'll obviously need good people writing a BSP for the hardware, but then a project may also need to implement high-level firmware for e.g. server communication, webservers, Sqlite databases, etc. Given enough time one can learn both, but as time progresses these jobs will grow more distinct (much like "PC programming" and "bare metal" was always seen as such -- but now we need both running on the same chip).

author: nctnico
author_rank: Super Contributor
timestamp: February 23, 2025, 03:49:46 pm
content: Quote from: SiliconWizard on February 22, 2025, 09:22:44 amI don't think this is a valid reason not to use C++. In the end you can make this claim for any programming language. C programs are typically littered with malloc/free and the same goes for other languages (scripted or not). The bottom line is that a developer needs to be aware of the limits the platform has.

author: voltsandjolts
author_rank: Unknown
timestamp: February 23, 2025, 05:29:28 pm
content: Quote from: nctnico on February 23, 2025, 03:49:46 pmC programs running on what?PCs, then quite likely.For smaller mcu's like the SAMs being discussed here, then nope, no way.

author: nctnico
author_rank: Super Contributor
timestamp: February 23, 2025, 06:47:14 pm
content: Quote from: voltsandjolts on February 23, 2025, 05:29:28 pmThe context was having generic developers (using C / C++ or other languages) coming from larger systems (not specific PC BTW) working on embedded systems with limited resources. That always means going through a learning curve. And it is not uncommon to find malloc in software intended to run on microcontrollers. Most typically when an OS is involved.

author: xvr
author_rank: Frequent Contributor
timestamp: February 24, 2025, 02:53:07 pm
content: QuoteEven just switching from C to C++ (still on PC) could be a disaster.I was involved in the development of the Sun Pro compiler (in the 90's). The compiler itself was written in C, but SUN Microsystem decided to switch from C to C++. So they first rewrote the code generator in C++. They took the C sources, converted every struct to a class, made all the members private, and created read/write access functions for all of them. All the functionality was still outside the class. It was a disaster - the source code grew tenfold in size. The funniest thing was the AST debug print function. Each operation in the AST was implemented as a separate class (derived from the base one), and the print function was defined in the base class with a huge switch on the opcode. The comment on this function says:QuoteFurther transition was cancelled

author: JPortici
author_rank: Super Contributor
timestamp: February 24, 2025, 03:52:37 pm
content: Quote from: xvr on February 24, 2025, 02:53:07 pmwtf did i just read? It's like when ASM programmers start using C without treating it as a completely different language

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 24, 2025, 04:24:43 pm
content: The funny thing with C++ is that there are people who are delusional enough to believe they understand C++.

author: Simon
author_rank: Unknown
timestamp: February 24, 2025, 06:14:18 pm
content: Quote from: SiliconWizard on February 24, 2025, 04:24:43 pmUnfortunately there are people delusional enough to force you to use it if you want to use their graphics library.

author: eutectique
author_rank: Frequent Contributor
timestamp: February 24, 2025, 07:56:54 pm
content: Quote from: Simon on February 24, 2025, 06:14:18 pmThis doesn't mean you have to have your whole system be written in C++. Just the interface with the said library.

author: nctnico
author_rank: Super Contributor
timestamp: February 24, 2025, 08:29:45 pm
content: IMHO there is certainly an advantage of using C++ over plain C as object oriented programming using a language which has the support for it (instead of using the crutches you find in C programs so often) is a good approach to organise the structure of software. C++ also allows to pass variables by reference (made constant if you like) so you can get rid of most of the pointers.As with any tool: point the sharp end away from you.

author: JPortici
author_rank: Super Contributor
timestamp: February 25, 2025, 05:50:37 am
content: Quote from: SiliconWizard on February 24, 2025, 04:24:43 pmbut there is a universe of possibilities between "understanding C++", failing to grasp the concept, and outright refusing to write itthere *are* some concept we can understand and use for our benefit in order to make the code more optimized/more readable/more mandainable.- virtual functions are not hard to understand, see java override (which is even more funny for the story thinking the guy was working at SUN), instead of function pointers everywhere- private members are better the moment you have to share code with someone, protected is good when you expand a base class, instead of two, three, four include files, some you can share, some you can't- const, constexpr and their optimizations- operating on references instead of pointers- classes, instead of having to "pass the context"- default constructors- function polymorphism- strings.- templates *can* be useful like for lists and iterators, but it's more syntactic sugar.we don't even have to throw in the allocator, we can statically allocate everything and still keep whatever's good and sane from the language

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 25, 2025, 06:37:58 am
content: It is expected and normal that there are people who are delusional enough to believe they understand and know all of C++.It happens with everything else, too, until one discovers they don't. Just look at obfuscated C code contest entries.

author: Simon
author_rank: Unknown
timestamp: February 25, 2025, 07:39:15 am
content: That is basically what I want to do. I find that programming in C it is hard to separate things and provide a good interface to reusable code. I find this even more so with the lower level stuff like setting up peripherals. Function overloading would be a godsend in writing setup functions that can cater to different use cases of the peripheral. I also tend to have a few little functions of my own that I end up writing for both integer and float numbers.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 25, 2025, 08:41:58 am
content: Quote from: Simon on February 25, 2025, 07:39:15 amI hear you. I use a very similar subset of C++ for similar reasons. I'm less interested in reusable code, as I nowadays tend to adapt the implementation to the exact needs in embedded use cases. (Instead of reusable-as-is libraries, I have tested implementations in embryonic form I can quickly adapt, with my own READMEs describing the gotchas to avoid, details to check, main benefits over alternatives.)You do need to be careful about exactly which subset of C++ you use, though. Like mentioned above, that depends on the C++ implementation, and varies from base C++ library to another. But understanding that in an embedded environment we're using a subset, is the major point here. Be prepared to look up the support requirements first, when you discover a new useful C++ thing (like you did withstd::map). Really, it's not that different to freestanding C: you wouldn't expectfopen()to work on a microcontroller with just the basic libraries available.(Most C and C++ compilers except for Microsoft's also provide some POSIXisms, describedhereunder volumeBase definitions, 14.Headers; and under volumeSystem interfaces, 3.System interfaces. Many times the base C/C++ libraries you'll use also includes some of those, likealphasort()for example. The exact set depends on your compiler and libraries. Even if you're not interested in those, I do recommend you theBase definitions, 4.General concepts, paragraphs 4.3Default initializations, 4.13Host and Network Byte Orders, and 4.15Memory Ordering and Synchronization(skipping 4.15.2), because the compilers usually tend to these behaviours for stuff that the C and C++ standards leaveImplementation Defined. For the same reason, if you use GCC, do read theGCC C implementation defined behaviourandC++ implementation defined behaviour. I do not mean you need to memorize any of this: just read through so that when you encounter something related in practice, you vaguely remember coming across it and can look it up.)

author: JPortici
author_rank: Super Contributor
timestamp: February 25, 2025, 08:46:44 am
content: Or, in case Simon's compiler is XC32, so the documentation is XC32 User Guide for PIC32C (which describes many of the gotchas!) and the Microchip Unified Standard C Library (yes, they named it MUS(C)L) for the rest

author: Simon
author_rank: Unknown
timestamp: February 26, 2025, 07:18:15 am
content: Not wanting to start a war, but which compiler am I best using? When I did setup the ASF I had ARM GCC and I got duplicate #defines warnings until I went back to "native". Obviously without any other libraries etc this is not the case.

author: JPortici
author_rank: Super Contributor
timestamp: February 26, 2025, 08:54:45 am
content: I honestly don't know.I don't actively use SAM devices, last time i did they were still atmel, but if it was me i would probably use XC32 (i'm much more used to Microchip's quirks than vanilla GCC quirks)Also new parts are exclusively PIC32C, with microchip's peripherals etc so i don't know if they are officially supported in GCC (but don't quote me on that!)

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 26, 2025, 11:47:19 am
content: Quote from: Simon on February 26, 2025, 07:18:15 amNo war. It's just a compiler.I nowadays use only GCC and Clang, because they're free and maintained by the distributions I use, so I don't need to.I've happily used commercial compilers from Metrowerks, Portland Group, Pathscale, and Intel, but for normal application and HPC software development, not embedded work. For me, embedded stuff simply came later on, and is only a hobby. Overall, I get more out of the hobby if I use open source tools, but that's all, and only applies to hobbyists in a similar situation as I am.For commercial work, the vendor support can make a big difference. Microchip xc32 for PIC32C/SAM and PIC32M are based on GCC anyway, and have an ELF-based toolchain, which is what matters most to myself (due to linker scripts and section tricks that allows). For Microchip stuff, it means the board support packages and such should be up to date so you don't need to hunt those down, I assume.The only "war" I've associated with these was Microchip requiring a paid compiler license and telling users that modifying the compiler to remove the license check is a copyright violation or a violation of the user EULA with Microchip. Neither is true, because GCC derivatives are licensed under the GPL license. It does permit requiring a payment, that's fine. It does not allow adding any further contractual limits on what the user can do with the bought copy, not even limit modifications and publishing those modifications under GPL. Users always were allowed to remove the license checks, and Microchip was always required to provide the modified GCC sources to the users if they asked. If any EULA limited what the user is allowed to do, or if Microchip didn't provide the sources, Microchip itself would no longer be permitted to distribute that GCC derivative. It's a plain copyright and licensing issue, that many, many humans don't understand correctly. If you build your product on top of copyleft licensed stuff like GCC, it will be forever bound to that copyleft license, unless you rewrite it yourself from scratch, no matter how much effort and money you pour in, or how large and appreciated company you are; it's that simple. Fortunately, we now have LLVM to compete with GCC, benefiting everyone; and LLVM has a much more permissive, non-copyleft license.

author: cv007
author_rank: Frequent Contributor
timestamp: March 05, 2025, 06:24:09 pm
content: The advantage of using the GCC compiler is its wide usage, which means problems/solutions/questions have already been discussed/resolved on the web and not that hard to find when needed. It also means when you jump from mcu to mcu you have essentially the same compiler options/pragmas/attributes/etc. and even if its all hidden behind an ide you will know how its works under the hood. I think using a toolchain at the command line is a good way to understand what an ide is doing, which is essentially the same thing in a more automated way, at least for enough time to get a handle on the sequence of toolchain usage and where the options come in to play.What MCHP does, at least with xc8 but not sure of xc32, is to modify the compiler for its own use where you start to diverge from the 'normal' gcc. New/changed attributes start to make the compiler become mcu specific and when it comes time to move to another mcu you have a new compiler to learn even though it may be mostly similar. If you never leave the MCHP 'ecosystem' then probably doesn't matter that much, but with the available mcu choices eventually you will exit that ecosystem even if just briefly. Not an insurmountable problem but the case is there to just stick to the 'normal' gcc toolchain that everyone else is using. I don't follow what MCHP has been doing, but I imagine they will eventually move to a compiler with a license it prefers (llvm) where you will most likely not have access to its source code.Using C++ on an mcu is not that much different than using C, in terms of what an mcu can use. I doubt most mcu users are searching the standard C library for solutions to all their problems. You use what you can, but you cannot use everything and your mcu is not a pc. The same thing applies to C++. Its foremost a language, not a library, and you can easily put that language to use without having to dig into its standard library at all. If there are things in the C++ standard library (no longer referred to as STL) that are useful to an mcu, and are lightweight enough to use, then use them. If not, don't. There are probably more useful things in the library usable by an mcu than one realizes, but the mcu user is not primarily digging around the library for things to use. Instead, you will typically stumble on various things in the library that you realize may be useful to an mcu- a few examples- array, string_view, chrono, which are all lightweight and usable on an mcu.You will not learn to use C++ well on an mcu quickly, but you can gradually ease yourself into it as you still have access to all of C. Its a long term goal, and whether you end up using it exclusively or not the learning process will improve your C coding and overall code organization.The online compiler is useful for learning C++. I typically use it to test ideas, and the fast feedback works well. The following simple example is not typically what I do in the online compiler (complete projects) as I usually test/try ideas just in a single file, but it shows some C++ ideas in use and is complete (makefile, linker script, startup code, etc.)-https://godbolt.org/z/qrYx9qfejprobably not helpful to leave a couple errors showing (renamed a function, didn't factor all uses)https://godbolt.org/z/K7vx375We(note that in the makefile I 'wrap' _malloc_r so anything that attempts to use the heap turns into an error)This was for an stm32g031k8 nucleo32 board, where programming takes place via a virtual drive (makefile copies file to target). A windows 11 pc is used, but is portable to a Linux pc with only a few changes in the makefile (target path and compiler path), plus the os specific arm gnu toolchain. I am using whatever text editor I prefer (vs code) and for the Windows pc the make.exe came from a TCC download (busybox for Windows is in the downloads, where you can compile just make.exe).

author: voltsandjolts
author_rank: Unknown
timestamp: March 05, 2025, 06:46:30 pm
content: Quote from: cv007 on March 05, 2025, 06:24:09 pmJust to clarify for others...What Microschip calls "XC8" is actually two compilers:(1) their version of avr-gcc for the AVR stuff(2) 'xc8' for the PIC 8-bits stuff (which is proprietary and not related to gcc).

author: Simon
author_rank: Unknown
timestamp: March 07, 2025, 12:28:31 pm
content: OK, I caved in and tried to use the ETL, it's only for strings I promise.How different is the ETL from the STL in use? I can't use a string type as a function argument. I can however:Code:type value(char* input){text = input;value_type = st_type;return value_type;}

author: cv007
author_rank: Frequent Contributor
timestamp: March 07, 2025, 03:46:34 pm
content: What exactly do you want to do with strings on an mcu?Maybe someone here can answer your question about the ETL, but I would suggest that starting out using some library which you cannot understand is not going to simplify things. In my opinion skip any fixation on C++ libraries and use the language as-is (its the same language all these library writers use). You can create solutions to your own specific problems, and in the case of strings which you seem to desire- maybe think about what it is you really want to do with strings. It could be you want something that would be simple to do on your own, with the added benefit that you will understand what the code is doing.I tend to think that for an mcu, trying to solve specific problems using libraries that want to solve every problem usually becomes more complex than it needs to be. You end up with complexity when the goal was simplification.

author: Simon
author_rank: Unknown
timestamp: March 07, 2025, 06:54:18 pm
content: Well How much should I resort to C? I could use itoa() to convert numbers to ascii. Strings have an equivalent. No I am not about to write my own itoa() etc. I actually did once.I am writing code to put stuff on a monochrome screen, these could be integers, floats or text. So it makes sense to have an object that will hold one item. if I put an integer in it will automatically create the text equivalent. Then I can put the text into the screen buffer when I choose. Various properties are obviously stored in the class such as position (x, y) whether or not I want the value to flash, be inverted right aligned etc.Yea I can write a load of stuff myself but really this was half the point of getting into C++, more machinery to mess with rathor than having to constantly make my own.

author: cv007
author_rank: Frequent Contributor
timestamp: March 08, 2025, 02:29:12 am
content: QuoteI don't use the Strings class from the C++ standard library, but I'm curious how a string object is going to get you an integer to string conversion. The class has string to number conversions, but is reverse of what you want.Getting numbers into a string format is easy enough, and you have a lot of options. You pointed one out already, but a better C option is sprintf which is much more powerful (it gets linked in for a single use, so use it everywhere). Even in C++ sprintf is a good option for an mcu, and can be put to use inside a C++ class as well. If you look at my example linked in a previous post, I created my own Print class which mimics the stream class 'cout' style of formatting which anyone can inherit and use however they want (in this case a uart). Whether that was worth the effort or not, I now have it, understand it, and can use it on any mcu with a C++ compiler and no longer need to deal with printf. Before that was created I used sprintf/printf to do formatting where the C++ class hid the details so usage was like- uart.print("the number is%d\n",n);A simple example of extending the Print class to an Sbuf class which inherits the formatting Print already provides and becomes sprintf-likehttps://godbolt.org/z/EcqePfchdwhether that Sbuf example is useful or not, it shows its quite easy to extend classes as needed,

author: Simon
author_rank: Unknown
timestamp: March 08, 2025, 08:36:38 am
content: Yes sprinf also sounds like an option. Can it handle floating point numbers as well? Admittedly I'm yet to consider numbers of decimal places etc. another option is to round a float and cast it to int for conversion to characters.

author: cv007
author_rank: Frequent Contributor
timestamp: March 08, 2025, 04:57:03 pm
content: Printf and sprintf end up at the same code to do conversions, with different destinations. For mcu's, there can be different library versions of the printf family such as with/without float support, so it may require specifying the float library version if by default its not provided. Depending on the capabilities of your mcu, it may or may not be a big deal to eliminate the use of float.Simple example using snprintf-https://godbolt.org/z/1Ts7cb91bthis is compiled for x86 so that output can be seen in the online compiler (using printf), but would easily transfer to an mcu without changes provided you had some output destination for the strings.The online compiler is a great place to test ideas as it has instant feedback. Its also a great place to learn C++.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 08, 2025, 05:34:57 pm
content: Also, while I understand the rationale of not reinventing the wheel, sometimes it's pretty useful to, when the constraints are not a "generic" platform (like small embedded stuff), especially considering that finding an existing and satisfactory solution may take hours while writing your own, only minutes. Just a thought.I've seen so many people waste days or sometimes weeks trying to find an "off-the-shelf" solution that they would otherwise have implemented themselves in a matters of a few minutes to a few days.

author: nctnico
author_rank: Super Contributor
timestamp: March 08, 2025, 07:36:27 pm
content: Well, that argument can go both ways. I've also seen people waste lots of time while they could use something off-the-shelve.IMHO the best approach is to adhere to standards and if there are standard, well documented libraries to do a certain task, then it is better to go for the standard library instead of re-inventing yet another square wheel. But choosing the right library can be tricky as there is a lot of crap out there.The situation becomes worse when people optimise for the sake of optimisation before looking at whether something off-the-shelve which leads to simple & maintainable code, fits the bill. If you don't know, try first. 9 out of 10 times it saves time & effort.

author: Simon
author_rank: Unknown
timestamp: March 12, 2025, 01:13:26 pm
content: well I tried sprintf(): Error undefined reference to `_sbrk'So looks like I am "itoaing"

author: eugene
author_rank: Frequent Contributor
timestamp: March 12, 2025, 03:30:09 pm
content: No reason to give up so quickly. The first hit of a duckduckgo search was this:https://stackoverflow.com/questions/5764414/undefined-reference-to-sbrkI'm not saying that the same solution will work for you, but I'd be surprised if there isn't a simple solution that will work.OTOH, _sbrk implies runtime memory management, which is exactly the type of C++ feature that I try to avoid in embedded code.

author: nctnico
author_rank: Super Contributor
timestamp: March 12, 2025, 04:02:00 pm
content: Quote from: eugene on March 12, 2025, 03:30:09 pmThe solution from the article is the right one. BTW, keep in mind that the stack itself is a form of runtime memory management as well.

author: cv007
author_rank: Frequent Contributor
timestamp: March 12, 2025, 06:44:28 pm
content: You may get different results depending on toolchain version, as the newlib libraries seems to have changed what was included in nano.a at some point.I'm not an expert on this, and is one of the reasons why I switched (on the cortex-m at least) from using snprintf to creating my own C++ print replacement, so that I can understand what is happening and also eliminate the use of malloc. I will give you what I know from what I have tried just now.edit- I have removed the previous contents as it does not seem to be needed.Simple answer- add the missing _sbrk function-Code:int _sbrk(int){ return -1; }Even though the _sbrk function is simple enough in its real form, it seems to me from testing that you never reach _sbrk using snprintf. So simply returning a fail is the simplest code to remove the error, and if it does get called a fail value is returned and I suppose wherever the call originated will deal with this error (and you see a failure in missing output I suppose).My previous post contents showed a complete _sbrk function, but I forgot in the linker script I had the heap section set to use no memory so even if the code was reached it would have returned a fail. I also then doscovered that _sbrk was never called so just used the small code above and snprintf still was working fine. I guess that could change and a real _sbrk function may be needed at some point, but maybe not.

author: Simon
author_rank: Unknown
timestamp: March 13, 2025, 08:35:12 am
content: So there are options that need turning on? obviously as I am coming up from bare metal programming as opposed to down from OS programming I'm unaware of the options and where I need to add these explicitly. I use an IDE in the hope that as much as possible is set up until I figure it out and become a command line guru.In the case of itoa I have writen my own myitoa now and included the facility to put in a decimal point a nominated amount of digits in. So I would simply supply an int that is the float value multiplied by pow(10, dec_plages). I am already storing "fixed point ints" in my C++ class anyway.The other reason is that as this is an M0+ it has no divide or modulo instruction. But there is a divide and square root module on the chip so myitoa() makes use of this rather than being generic and having a software library do divisions and modules.When using the ETL I hit the no _sbrk error so maybe this solution was what I needed to get that to work before abandoning it.

author: cv007
author_rank: Frequent Contributor
timestamp: March 13, 2025, 01:38:51 pm
content: QuoteWhich can also change toolchain options via its gui interface. The ide has to deal with running the toolchain at a command line level, so if you want specific options the ide user has many settings they can change from the project settings, and if the ide does not provide a specific option it does provide a way for you to specify additional options to pass to the toolchain .Whether your itoa is all you need for your specific needs is up to you, but where something like snprintf becomes nice is when it comes time to 'assemble' a grouped output (strings. numbers, formatting) where the use of itoa requires that you deal with everything separately.snprintf( buf, 32, "Temp: %3d.%uF\n", tempF/10, __builtin_abs(tempF%10) ); //note spacing resulting from %3d keeps any temp value right aligned//tempF = -56Temp: -5.6F//tempF = 725Temp: 72.5F

author: nctnico
author_rank: Super Contributor
timestamp: March 13, 2025, 01:46:09 pm
content: Which circles back to 'replace printf if the libary provided one is not suitable'. Don't re-invent the wheel.

author: Simon
author_rank: Unknown
timestamp: March 13, 2025, 01:47:31 pm
content: Yes sprinf() is certainly useful. What I am doing at the moment is a C++ class that will handle one value to be put on a graphical display. The class holds various details such as if I want it printed right justified, the coordinates on screen, will it flash, will it be colour inverted, how fast it will flash ect.So my itoa is to simply put the value into a string that will then be put into the display buffer.I'll try the options suggested in the IDE - microchip studio, if I do end up wanting the ETL or any other library that needs _sbrk dealing with I will need to sort this out anyway.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 13, 2025, 02:53:52 pm
content: Anything calling sbrk means that there are heap allocations. That's something you may or may not want. I think getting rid of the STL was a way of avoiding heap allocations. But using anything related to printf (at least from the newlib library that ships with the compiler) will use heap allocation.If you manage to get rid of all heap allocations, sbrk shouldn't be necessary.

author: cv007
author_rank: Frequent Contributor
timestamp: March 13, 2025, 09:25:54 pm
content: If you dig into the newlib source, even if confusing and easy to get lost trying to decipher it, it appears that the use of sprintf/snprintf sets the __SWR and __SSTR FILE flags (FILE struct on stack in sniprintf function), and with those flags set you do not reach any call to malloc. No malloc call, no heap used and no need for _sbrk to do anything useful.simply providing the _sbrk function that always returns a failure-int _sbrk(int){ return -1; }will allow the use of sprintf/snprintf, which WILL also bring in _malloc_r whether it actually gets used or not (and _sbrk_r which calls _sbrk). Since we know the heap is not used for sprintf/snprintf, but to satisfy the potential call from _malloc_r to _sbrk_r and ultimately _sbrk (user provided in the case of the current newlib nano library) that _sbrk function must exist.This simple single line of code for the _sbrk function will satisfy the requirements to get snprintf working without the need to get into details of using the heap. If the heap is later wanted, or it starts being used without your knowledge (with the resulting malloc failures), then the _sbrk function will need to change to allow it.