Forums

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

Started by Wouter van Ooijen December 4, 2013
(posted to comp.lang.c++, comp.arch.embedded, yahoo-groups/lpc2000)

I am working on a portable C++ hardware library for real-time 
applications on small (but still 32-bit) micro-controllers. My typical 
(and current only) target is the Cortex M0 LPC1114FN28 (4k RAM, 32K 
Flash) using GCC. Efficiency is very important, in run-time, RAM use, 
and ROM use. The typical restrictions for small microcontrollers apply: 
no RTTI, no exceptions, and no heap (or at most just an allocate-only heap).

So far I have found nice and efficient abstractions for I/O pins and I/O 
ports (using static class templates), implemented those on the LPC1114, 
and used these abstractions to implement protocols (I2C, SPI) and 
interfaces for some external chips like 74HC595 and MCP23017.

Like any would-be author of a serious piece of work I am looking for an 
adience to read, test, critisize (ridicule if necessary), maybe even 
contribute, and eventually use my work.

To get a idea of what I want to make, a very initial version can be 
found at http://www.voti.nl/hwlib

Any takers?

If this is all too abstract, I have a more concrete question, mainly for 
C++ architects. For I/O pins and ports I use class templates with (only) 
static functions. This matches well with reality (the hardware circuit 
is generally fixed), and is much more efficient than using inheritance 
and virtual functions.

However, I am now working on graphics for small LCD screens. At the 
lowest level (configuring an LCD driver for the size of the LCD and the 
pins used) the static-class-template approach is fine. But at some level 
the higher abstractions using the screen (for instance a subscreen, 
button, etc.) must be more dynamic and created ad-hoc. So somewhere 
(probably at multiple levels in the abstraction tree) I must make a 
transition from static class templates to the classic objects in an 
inheritance tree with virtual functions. Does anyone have any experience 
with such a dual hierarchy? One very stupid but basic problem is naming: 
a template and a class can't have te same name, so when the natural name 
would for instance be 'subframe', who gets that name, the template, the 
class, or neither?

Wouter van Ooijen


{ Multi-posted clc++ and cae, follow ups set to comp.lang.c++ }

On 04.12.2013 19:45, Wouter van Ooijen wrote:
> > At the > lowest level (configuring an LCD driver for the size of the LCD and the > pins used) the static-class-template approach is fine. But at some level > the higher abstractions using the screen (for instance a subscreen, > button, etc.) must be more dynamic and created ad-hoc.
Is it the case that the same /compiled/ software has to be used with different hardware? If not then simply using separate compilation (sort of "indirection at compile time") should suffice for the necessary decoupling, at the cost of needing a specific build for each supported hardware mix. You then link with the compiled classes that are specific to the relevant hardware items.
> So somewhere > (probably at multiple levels in the abstraction tree) I must make a > transition from static class templates to the classic objects in an > inheritance tree with virtual functions. Does anyone have any experience > with such a dual hierarchy?
The Java approach where the compiled code is used with various hardware, is to have an object factory and then using an object with virtual member functions. That can still be done without a heap. But (1) it implies needlessly having available all the "drivers" (whatever, name) that will not be used for this HW, and (2) chances are that you can avoid this, as outlined above.
> One very stupid but basic problem is naming: > a template and a class can't have te same name, so when the natural name > would for instance be 'subframe', who gets that name, the template, the > class, or neither?
Use namespaces? But again, you can probably avoid all that. Cheers & hth., - Alf
On 12/4/2013 12:45 PM, Wouter van Ooijen wrote:

> I am working on a portable C++ hardware library
1. Portable hardware is myth. 2. Universal solutions and modular designs don't work. 3. Trying to cover everything instead of doing particular task is waste of time and effort.
> So far I have found nice and efficient abstractions for I/O pins and I/O > ports
Useless. Abstract not I/O operation but function that it does.
> (using static class templates),
#define RED_LED_ON SETBIT(PORTA, 7)
> Like any would-be author of a serious piece of work I am looking for an > adience to read, test, critisize (ridicule if necessary), maybe even > contribute, and eventually use my work.
No problem. Everyone been there and done that. It is just the need for discipline and formality in low level code that you realized.
> To get a idea of what I want to make, a very initial version can be > found at http://www.voti.nl/hwlib > > Any takers? > > If this is all too abstract, I have a more concrete question, mainly for > C++ architects. For I/O pins and ports I use class templates with (only) > static functions. This matches well with reality (the hardware circuit > is generally fixed), and is much more efficient than using inheritance > and virtual functions.
How about life without C++ ?
> However, I am now working on graphics for small LCD screens. At the > lowest level (configuring an LCD driver for the size of the LCD and the > pins used) the static-class-template approach is fine. But at some level > the higher abstractions using the screen
QT 5.x has ~100M runtime. And it is slow, too. This is price of GUI portability.
> One very stupid but basic problem is naming: > a template and a class can't have te same name, so when the natural name > would for instance be 'subframe', who gets that name, the template, the > class, or neither?
Accept whatever style and stick to it. It doesn't matter as long as you are consistently following your design rules.
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++. Not looking so smart now, are you Vladimir? A tool is only as good as the people who use it. Especially a sharp tool.
On 12/8/2013 12:35 AM, 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
Good for you. So what? [...boast snipped...]
> > The entire engine fit in 1MB, even though it was written in C++. > Not looking so smart now, are you Vladimir? > A tool is only as good as the people who use it. Especially a sharp tool.
What are you arguing to? What point are you trying to make? VLV
>> I am working on a portable C++ hardware library > > 1. Portable hardware is myth.
I have a lot of hardware that I can carry if I want to :) Seriously (I am not sure you are, but I'll be), a lot of hardware-related code can be portable, except for the frustrating aspect of accessing the I/O pins (and dealing with timing).
> 2. Universal solutions and modular designs don't work.
I don't think any comment is needed.
> 3. Trying to cover everything instead of doing particular task is waste > of time and effort.
First part is true, second part is nonsense, otherwise no libraries would exist or be used. Library design is the art of balancing between doing everything and doing a specific task well.
>> So far I have found nice and efficient abstractions for I/O pins and I/O >> ports > > Useless. Abstract not I/O operation but function that it does. > > #define RED_LED_ON SETBIT(PORTA, 7)
I've been there, check for instance http://www.voti.nl/rfm73/. It works up to a point. It runs into problems - when setting a pin involves more than a simple operation (BTW, PORTA hints that you use a PIC, in which case this is plain wrong due to the RMW problem!) - when you need more than one instance of your library (like interfacing to two identical radio modules) - it uses macro's, which are evil (according to some they are THE evil)
> How about life without C++ ?
Been there, ran up against the limitations of an assembler, even wrote a compiler. Happy with C++ now. A pity concepts did not make it (yet).
> QT 5.x has ~100M runtime. And it is slow, too. This is price of GUI > portability.
That's not the kind of GUI I am targeting. I'm mainly into microcontrollers, the thingies that count their memory in kilobytes, not megabytes.
>> One very stupid but basic problem is naming: >> a template and a class can't have te same name, so when the natural name >> would for instance be 'subframe', who gets that name, the template, the >> class, or neither? > > Accept whatever style and stick to it. It doesn't matter as long as you > are consistently following your design rules.
The two styles I mention (static class templates and (traditional) classes with virtual functions) are both needed to get a balance between (code and data) size and run-time flexibility. (to the rest of the word: sorry if I am feeding a troll) Wouter
>> I am working on a portable C++ hardware library > > 1. Portable hardware is myth.
I have a lot of hardware that I can carry if I want to :) Seriously (I am not sure you are, but I'll be), a lot of hardware-related code can be portable, except for the frustrating aspect of accessing the I/O pins (and dealing with timing).
> 2. Universal solutions and modular designs don't work.
I don't think any comment is needed.
> 3. Trying to cover everything instead of doing particular task is waste > of time and effort.
First part is true, second part is nonsense, otherwise no libraries would exist or be used. Library design is the art of balancing between doing everything and doing a specific task well.
>> So far I have found nice and efficient abstractions for I/O pins and I/O >> ports > > Useless. Abstract not I/O operation but function that it does. > > #define RED_LED_ON SETBIT(PORTA, 7)
I've been there, check for instance http://www.voti.nl/rfm73/. It works up to a point. It runs into problems - when setting a pin involves more than a simple operation (BTW, PORTA hints that you use a PIC, in which case this is plain wrong due to the RMW problem!) - when you need more than one instance of your library (like interfacing to two identical radio modules) - it uses macro's, which are evil (according to some they are THE evil)
> How about life without C++ ?
Been there, ran up against the limitations of an assembler, even wrote a compiler. Happy with C++ now. A pity concepts did not make it (yet).
> QT 5.x has ~100M runtime. And it is slow, too. This is price of GUI > portability.
That's not the kind of GUI I am targeting. I'm mainly into microcontrollers, the thingies that count their memory in kilobytes, not megabytes.
>> One very stupid but basic problem is naming: >> a template and a class can't have te same name, so when the natural name >> would for instance be 'subframe', who gets that name, the template, the >> class, or neither? > > Accept whatever style and stick to it. It doesn't matter as long as you > are consistently following your design rules.
The two styles I mention (static class templates and (traditional) classes with virtual functions) are both needed to get a balance between (code and data) size and run-time flexibility. (to the rest of the word: sorry if I am feeding a troll) Wouter
On 04/12/13 18:45, Wouter van Ooijen wrote:
> (posted to comp.lang.c++, comp.arch.embedded, yahoo-groups/lpc2000) > > I am working on a portable C++ hardware library for real-time applications on small (but still 32-bit) micro-controllers. My typical (and current only) target is the Cortex M0 LPC1114FN28 (4k RAM, 32K > Flash) using GCC. Efficiency is very important, in run-time, RAM use, and ROM use. The typical restrictions for small microcontrollers apply: no RTTI, no exceptions, and no heap (or at most just an > allocate-only heap). > > So far I have found nice and efficient abstractions for I/O pins and I/O ports (using static class templates), implemented those on the LPC1114, and used these abstractions to implement protocols > (I2C, SPI) and interfaces for some external chips like 74HC595 and MCP23017. > > Like any would-be author of a serious piece of work I am looking for an adience to read, test, critisize (ridicule if necessary), maybe even contribute, and eventually use my work. > > To get a idea of what I want to make, a very initial version can be found at http://www.voti.nl/hwlib > > Any takers? > > If this is all too abstract, I have a more concrete question, mainly for C++ architects. For I/O pins and ports I use class templates with (only) static functions. This matches well with reality (the > hardware circuit is generally fixed), and is much more efficient than using inheritance and virtual functions. > > However, I am now working on graphics for small LCD screens. At the lowest level (configuring an LCD driver for the size of the LCD and the pins used) the static-class-template approach is fine. But > at some level the higher abstractions using the screen (for instance a subscreen, button, etc.) must be more dynamic and created ad-hoc. So somewhere (probably at multiple levels in the abstraction > tree) I must make a transition from static class templates to the classic objects in an inheritance tree with virtual functions. Does anyone have any experience with such a dual hierarchy? One very > stupid but basic problem is naming: a template and a class can't have te same name, so when the natural name would for instance be 'subframe', who gets that name, the template, the class, or neither?
Presume you complete that proposal to your satisfaction. When I start new designs, my thought processes are along the lines of: 1) what needs to be done at the hardware level, e.g. turn LED on/off, sleep, write text, draw rectangle, PWM an output to control a motor, read an ADC 2) what is the level of abstraction that I want to use in my application, e.g. setMotorSpeed, illuminateTarget, measureTemperature displayTemperature 3) what hardware do I have to use, both individual devices and /combinations/ of devices 4) what documentation, code examples and libraries are available that I can more or less cut-and-paste into my code 5) does the library contain complex algorithms or is it merely a indirect access to the peripherals And then, most critically: 6) what has the shortest learning+implementation curve 7) when something doesn't work as expected, how easy will it be to debug In my experience, 6&7 mean: - for specific peripherals that have a complex interaction with the main code or where I expect to repeat the task, /and/ there is a specific library available for that peripheral then it is worth my spending time learning how to use it - more frequently I'll just cut the code if /any/ of these are true - if another project would use different peripherals, or - the interaction with the peripheral is simple, or - the library doesn't support that specific peripheral, - the library documentation is worse than the peripheral documentation - the library is merely an "abstract framework" in which I would have to write the low-level guff for the specific peripheral It is /very/ difficult to pass that filter for devices that have kilobytes rather than gigabytes of memory. It can be done, e.g. a networking stack, but it isn't easy.
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. A few orders of magnitude higher would be my guess (I don't use these compilers so my guess is based only on the results I see as new software etc.). Would it be practical to run your sources through something like that just for the sake of some fun?
> A tool is only as good as the people who use it. Especially a sharp tool.
The tool user, the tool itself or both can be the limiting factor. I have yet to encounter someone to match my efficiency using any tool compared to me using my (own) tools, for example (because of my tools, not because of me being that better, obviously). Dimiter ------------------------------------------------------ Dimiter Popoff, TGI http://www.tgi-sci.com ------------------------------------------------------ http://www.flickr.com/photos/didi_tgi/sets/72157600228621276/
> When I start new designs, my thought processes are along the lines of: > 1) what needs to be done at the hardware level, e.g. turn LED on/off, > sleep, write text, draw rectangle, PWM an output to control a motor, > read an ADC > 2) what is the level of abstraction that I want to use in my > application, e.g. setMotorSpeed, illuminateTarget, measureTemperature > displayTemperature > 3) what hardware do I have to use, both individual devices and > /combinations/ of devices > 4) what documentation, code examples and libraries are available > that I can more or less cut-and-paste into my code > 5) does the library contain complex algorithms or is it merely a > indirect access to the peripherals > 6) what has the shortest learning+implementation curve > 7) when something doesn't work as expected, how easy will it be to debug
Thanks, though nothing concrete it reminds me of how a potential user probably looks to my library :)
> - if another project would use different peripherals, or
This is a point were an common interface might be an advantage. (Simple example: an A/D output can have the same interface for an on-chip A/D, an off-chip SPI or I2C A/D, or even a PWM.)
> - the library documentation is worse than the peripheral > documentation
:)
> It can be done, e.g. a networking stack, but it isn't easy.
If it were easy I guess it would alrady be done a 100 times. Wouter