EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

C++ hardware library for (small) 32-bit micro-controllers

Started by Wouter van Ooijen December 4, 2013
> Your fully template-based approach looks neat and appropriate for things > with as little "meat" as an I/O pin, but for more complicated things > like "SPI transaction", "parallel NOR flash", "NAND flash" I'd like to > know where in the object files my code ends up.
You mean that it is a problem that you can't see which parts use how much ROM?
> Plus, an I/O pin may end up to be more than just read-bit-from-register: > for applications that occasionally read a pin, I've got an > implementation of the InputPin interface that performs a remote > procedure call into the driver, saving the application from having to > map physical memory.
I don't see why a templatetized implementation could not do that too?
> "The hardware circuit is generally fixed" is one of the biggest lies of > embedded software development :-) > > At least I didn't yet encounter a project where hardware assignments > didn't change over time. Pins get moved, get inverted, new flash chip, > etc. So it's good I'm able to adapt by changing a (runtime) initialisation.
Would it be a problem to re-compile?
> I'm paying one virtual dispatch per access. So, I wouldn't want do to > bit-banged SPI or IIC with my drivers. Thank god I don't have to :-) > It's probably not appropriate for 8-bitters, but it's efficient enough > to be useful in production bootloaders with a few k code.
I started on such a class/object/vtable approach 2 years ago, but found a number of problems: - it is slow for very simple operations - it hinders optimization - it requires an object, which takes RAM, of which there is preciously little on small micro-controllers - compilers seem to be bad at eliminating virtual functions that are never used About optimization and speed: suppose I have a LED on a certain pin: typedef gpio_1_0 LED; LED::set( 0 ); // LED off OOPs, the LED is connected to Vcc, not to ground! So I change this to typedef invert< gpio_1_0 > LED; LED::set( 0 ); // LED off With the template approach the second version generates exactly the same amount of code, and is exactly as fast, as the first version. Wouter
Hey gasbag
Which functions are thread safe?
How about interrupt safe?



On 12/8/2013 3:36 PM, Wouter van Ooijen wrote:
>> Your fully template-based approach looks neat and appropriate for things >> with as little "meat" as an I/O pin, but for more complicated things >> like "SPI transaction", "parallel NOR flash", "NAND flash" I'd like to >> know where in the object files my code ends up. > > You mean that it is a problem that you can't see which parts use how > much ROM? > >> Plus, an I/O pin may end up to be more than just read-bit-from-register: >> for applications that occasionally read a pin, I've got an >> implementation of the InputPin interface that performs a remote >> procedure call into the driver, saving the application from having to >> map physical memory. > > I don't see why a templatetized implementation could not do that too? > >> "The hardware circuit is generally fixed" is one of the biggest lies of >> embedded software development :-) >> >> At least I didn't yet encounter a project where hardware assignments >> didn't change over time. Pins get moved, get inverted, new flash chip, >> etc. So it's good I'm able to adapt by changing a (runtime) >> initialisation. > > Would it be a problem to re-compile? > >> I'm paying one virtual dispatch per access. So, I wouldn't want do to >> bit-banged SPI or IIC with my drivers. Thank god I don't have to :-) >> It's probably not appropriate for 8-bitters, but it's efficient enough >> to be useful in production bootloaders with a few k code. > > I started on such a class/object/vtable approach 2 years ago, but found > a number of problems: > > - it is slow for very simple operations > - it hinders optimization > - it requires an object, which takes RAM, of which there is preciously > little on small micro-controllers > - compilers seem to be bad at eliminating virtual functions that are > never used > > About optimization and speed: suppose I have a LED on a certain pin: > > typedef gpio_1_0 LED; > LED::set( 0 ); // LED off > > OOPs, the LED is connected to Vcc, not to ground! So I change this to > > typedef invert< gpio_1_0 > LED; > LED::set( 0 ); // LED off > > With the template approach the second version generates exactly the same > amount of code, and is exactly as fast, as the first version. > > Wouter > >
Hi Dimiter,

On 12/8/2013 2:29 PM, dp wrote:

>>> We got switched from a mild autumn into a harsh winter >>> overnight by the end of November... It is not a worst case >>> winter yet (-10 to -20) but way harsher than last year. >> >> Yeah, but you *expect* The Cold!<grin> (I actually miss >> it -- when I am prepared for it! -- especially the fruits) > > Oh expecting it does not make it any nicer.
Aw, c'mon... I just *know* you love those (lethal) 3 ft icicles! <grin>
> When we see > the apples go reddish in August we are reminded that "winter is coming",
Yup. I miss *good* apples.
> you know. We both hate it, how can you possibly miss the cold :-) .
I always enjoyed clearing the driveway/sidewalk with the snow blower. Of course, as I work at home, I never had to *go* anywhere *in* the snow -- unless I wanted to do so. That "option" makes the world of difference in how you regard the cold ;-)
>>> A may be less obvious one is that having to maintain/remember all >>> that stuff you wrote last 20 years all the time (a few tens of megabytes >>> of sources, about 1.5M lines (non multilined as C :-) in my case) >>> tends to keep you alert and in good shape; I am not sure if this is >>> any less important than anything else really. >> >> "Inertia". Keeps you from straying too far, too fast! :> > > Hmm, I guess this is useful only up to a point :D . Once inertia becomes > too dominant in what we do it gets obvious why we have the lifespan > timer designed to tick inside us :D :D .
Yes, but inertia can be great -- if you are aware of it! It tells you that your thinking "may be in a rut" and, if you're "aware", challenges you to challenge yourself, more. Some "habits" are good and helpful. Others can be restrictive and crippling.
On 08/12/13 21:18, dp wrote:
> On Sunday, December 8, 2013 8:35:31 AM UTC+2, Clifford Heath wrote: >> On 08/12/13 16:33, Vladimir Vassilevsky wrote: >>> QT 5.x has ~100M runtime. And it is slow, too. This is price of GUI >>> portability. >> >> In the late 80's I designed OpenUI, a cross-platform UI toolkit with >> interpreter for an embedded language, and asynchronous rich messaging IO >> both internally and across the Internet. It ran the new international >> trading system of NASDAQ for ten years, initially on 486/66 PCs with 8MB >> ram, with Windows 3.11. Equivalent versions ran the exact same apps on >> character terminals, X11/Motif, Macs, OS/2, Windows NT, etc, on large >> enterprises around the world, including some of the first Internet (pre >> web-browser) banking and share trading apps. >> The entire engine fit in 1MB, even though it was written in C++. > Well the obvious question is in how much the same sources would > compile today, using todays compilers/libraries etc.
Given that the same code-base compiled on more than twenty different vendor's C++ compilers, just one of those being different versions of gcc on a further twenty different platforms (16, 32 and 64 bit) I'd guess it wouldn't be hard at all to get it building again. We had all our own portability infrastructure (for build and runtime) and didn't use any templates nor STL (which were broken or unimplemented on some compilers back then). But I don't have time or inclination to do it. Of course, the result would only support the GUI widgets that were current at the time - newer ones would require new work. These days, you'd rip out the Java-esque compiler/interpreter and put the V8 Javascript engine in instead, too. Clifford Heath.
> Hey gasbag
Who are you adressing? I did not notice anyone with that name in the discussion. Wouter
Wouter van Ooijen wrote:
>> Hey gasbag > > Who are you adressing? > I did not notice anyone with that name in the discussion.
Pot, kettle? Please don't snip attributions! -- Ian Collins
On 09/12/13 07:24, Wouter van Ooijen wrote:
>> Hey gasbag > > Who are you adressing? > I did not notice anyone with that name in the discussion.
Don't feed the troll!
Wouter van Ooijen wrote:
>> Your fully template-based approach looks neat and appropriate for things >> with as little "meat" as an I/O pin, but for more complicated things >> like "SPI transaction", "parallel NOR flash", "NAND flash" I'd like to >> know where in the object files my code ends up. > > You mean that it is a problem that you can't see which parts use how > much ROM?
Yep. It probably depends a lot on the toolchain and its configuration, but having two-pass template compilation and linkonce sections doesn't actually make writing linker script files easier unless you can get the compiler to inline everything.
>> Plus, an I/O pin may end up to be more than just read-bit-from-register: >> for applications that occasionally read a pin, I've got an >> implementation of the InputPin interface that performs a remote >> procedure call into the driver, saving the application from having to >> map physical memory. > > I don't see why a templatetized implementation could not do that too?
It could do that, but assuming that the RPC operation is more than just dereference-a-pointer-and-set-a-bit, it would risk duplicating more code, see below.
>> "The hardware circuit is generally fixed" is one of the biggest lies of >> embedded software development :-) >> >> At least I didn't yet encounter a project where hardware assignments >> didn't change over time. Pins get moved, get inverted, new flash chip, >> etc. So it's good I'm able to adapt by changing a (runtime) >> initialisation. > > Would it be a problem to re-compile?
Yes. Our software usually has to run on half a dozen board versions at least.
>> I'm paying one virtual dispatch per access. So, I wouldn't want do to >> bit-banged SPI or IIC with my drivers. Thank god I don't have to :-) >> It's probably not appropriate for 8-bitters, but it's efficient enough >> to be useful in production bootloaders with a few k code. > > I started on such a class/object/vtable approach 2 years ago, but found > a number of problems: > > - it is slow for very simple operations > - it hinders optimization > - it requires an object, which takes RAM, of which there is preciously > little on small micro-controllers > - compilers seem to be bad at eliminating virtual functions that are > never used > > About optimization and speed: suppose I have a LED on a certain pin: > > typedef gpio_1_0 LED; > LED::set( 0 ); // LED off > > OOPs, the LED is connected to Vcc, not to ground! So I change this to > > typedef invert< gpio_1_0 > LED; > LED::set( 0 ); // LED off > > With the template approach the second version generates exactly the same > amount of code, and is exactly as fast, as the first version.
Now imagine you have a flash driver, and want do drive two flashes. typedef spi_flash<spi<gpio_1_0, gpio_1_1, gpio_1_2> > Left_Flash; typedef spi_flash<spi<gpio_2_0, gpio_2_1, gpio_2_2> > Right_Flash; This would duplicate the flash driver. Sure, each one would have incredible speed. I decided to rather pay the virtual dispatch than the code space, because speed is good enough for the things I do. Your mileage will probably vary. Stefan
> It could do that, but assuming that the RPC operation is more than just > dereference-a-pointer-and-set-a-bit, it would risk duplicating more > code, see below.
When the code is small and/or has substantial possibility for optimization due to inlining the template approach wins. When the code is large and needs to be used with two or more sets of pins (or run-time configurable pins or other resources) the OO approach wins. Inbetween the contest is on. Hence my quest for a good way to make a dual hierarchy.
> Now imagine you have a flash driver, and want do drive two flashes. > > typedef spi_flash<spi<gpio_1_0, gpio_1_1, gpio_1_2> > Left_Flash; > typedef spi_flash<spi<gpio_2_0, gpio_2_1, gpio_2_2> > Right_Flash;
One approach here is the template-inherits-from-non-template-class approach. Put the bulk in the non-template, and the few fast things in the template. I think in this case the template should be the SPI part, the flash driver should not be a template. Separating the SPI makes sense anyway, beacuse you want to be able to use the flash driver over a bit-banged SPI, a hardware SPI, and tomorrow over yet something else. Wouter

The 2024 Embedded Online Conference