Hardware Abstraction

Hi,
I just wanted to solicit some feedback on creating some hardware abstraction classes. I am building a remote controller plane that I want to be able to control a lot of the subsystems in the plane (engine throttle, electric starter motor, etc). As I keep writing the objects I'm starting to realise that the arduino board might not have enough I/O for me.

There are different options to go if this ends up being the case, so I wanted to tackle this problem early... I may need a different MCU or I might just need a I2C I/O expander, but what I do want to be able to do is to be able to have a good hardware abstraction so if I do need to move to different hardware I'll be able to do so easily.

What do people do or suggest in this case?

Thanks,
Greg

If done correctly, I think any libraries written for the base Arduino (currently the Duemilanove) should port up or down gracefully to other boards based on AVR chips. I'm about to start digging into this deeper, and think it really depends on the support within the IDE.

There should be, if there isn't already, a well defined method to add support for boards with both less and more hardware features. Things such as maximum number of I/O pins, mappings to current Arduino pins, etc, should all be in hardware dependent files that are selected when a board is selected in the IDE. The same would be true for the type of pins (UARTTX, UARTRX, UARTCTS, I2CSDA, I2CSCL, etc). It should be possible to abstract all of this even if it involves a lot of rework of the IDE. If mappings are done right, it should be pretty intuitive to work with different boards, even if the hardware features are a real superset of what the Arduino has.

If the above is already true, then writing libraries to be hardware dependent should not be difficult. While I think the current Arduino IDE is a bit less than it really needs to be, it's in the right ball park for the targeted audience.

As for writing libraries, I believe each major hardware component should have support in a separate library that does not have any other dependencies. These hardware libraries should be able to stand completely alone unless some core routines are reasonable to share between things, such as UARTs, SSPs, etc for functions like I2C and SPI. Those core routines should be part of the native development environment that are included with it. This would allow different libraries thing such as I2C, SPI, serial communication, digital I/O, analog I/O, etc to be easily written, without worries of colliding with any other current user accessible library.

8-Dale

if done correctly, I think any libraries written for the base Arduino should port up or down gracefully to other boards based on AVR chips.

True in theory, but you will find that most libraries that use any of the many hardware resources not abstracted by the arduino will need work to port to other chips. This includes libraries that access timers and direct port I/O. And even the pin numbers will be different on different chips – for example the ATmega644 uses different Arduino pins for the hardware serial port than the ATmega168 so libraries and code using hardware serial that assumes this is on Pins 0 and 1 (or that pins 8 and 9 are free ) will not work.

I think writing the libraries so that they would easily port is possible but would be much more time consuming for the code author. I would be interested to see a proposal for writing code accessing all the low level stuff that was sufficiently abstracted to be chip independent, and sufficiently simple that it didn't make writing low level code a pain.

I enjoy writing libraries and making them available to the arduino community. It would be unfortunate if additional abstraction layers made this more work than fun.

@mem,

Yes, that would be true because the libraries deal directly with the hardware. Without a bunch of defines and #ifdef/#endif blocks in libraries, it would be more work to accomplish what I am proposing. However, this is how a lot of C/C++ is done in order to keep it portable to different architectures and systems. One only has to look at some of the GNU code to see this.

The whole idea of going to this extra effort is to make things easier for the end users. That is also one of the main reasons for the Arduino existing. If the software does not make things as easy as the hardware, then there is something wrong. In this case, I think it is the software that has to keep up with the hardware. There will continue to be new chips and new boards that use those chips, and it's important to make them as easy to use as possible.

Even though it is currently on hold, there has been quite an effort to port the Arduino environment to the ARM architecture. That's a whole new world, and I support this kind of effort fully. The Arduino is a wonderful concept and I am enjoying working with mine, but I need more features (hardware and software) to really accomplish things I want to do. It's wonderful that the Arduino is so easy to use, and it's the real reason I am getting back to tinkering with hardware and software after being away from it for many years.

The Arduino development environment has great potential to do the same for architectures like ARM and others that it is doing for AVRs now.

8-Dale

No doubt that having Arduino code more portable would be a good thing. One way to help make that happen is to find some like minded people and define and document some guidelines for handling hardware specific implementations in a more portable way. This could simply by recommendations for how to document hardware resources used in a library. It could also comprise suggestions for handling the conditional defines. My own experience in getting my hardware intensive arduino code working on different ATmega chips saw some pretty inscrutable code knotted with hash defines until I ended creating separate header files for each chip. Not saying that is the best way to go, just pointing out that to move this forward, you want to get some knowledgeable people together to think through the technical issues and put some practical and easily implemented recommendations down on paper.

Please don't forget that many providing code to the Arduino community have no commercial benefit from the effort, so to be successful, portable code should not be much more complicated to write and test.

Another approach is to port the core and libraries to new processors, creating appropriate abstractions as necessary. That way you know that any extra complexity is there for a good reason.

The solution I keep coming back to is bytecode. The bootloader (or surrogate) can interpret a bytestream, be it sent over the wire or in an eprom or in flash or ram, and perform the "generic" operations therein on the given chip. But it is a very large step with performance caveats, though it could mean you could pack more functionality on a given chip.

There is another thought, that is to leverage macros more, like Don K does here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1226257074/5#5

Basically folks would write to the mega168, and anyone else would provide a set of macros to redefine their own ports/pins/functions to mega168 terms. Then you just need to include the right macro definition file for your chip.

Of course not everyone likes macros :slight_smile:

Don't much like macro's much. Use 'em when I have to. But there's another way. That is, declare a C++ "interface" class, all of whose functions are pure virtual, and abstracted.

Then declare subclasses for the hardware you have. Within your "client" code, pass around pointers or references to the interface class.

Lastly, create instances of the hardware classes.

For example, I did this for A2D, and can use the same code to do PID loops and a Kalman filters, whether I'm using the arduino's A2D or an MCP3304.

"declare a C++ interface class"

If starting from scratch, arguably the ideal solution.

It gets a little messy if you have to rewrite everything (libraries, examples, forum code posts?) to use this interface though

Still messy if you leave the existing definitions alone and introduce the interface on top of everything.

Maybe the including of the interface disables the existing keywords in the current script? That way things would be a bit cleaner at the application level (it's converted or it isn't).

Why are we doing this again? :smiley: Oh, yah, more CPUs want to run with arduino and we don't rightly know how compatible they should be before declaring them compatible.

is %100 compatible asking too much? Assuming they implement the entire interface and the interface encompasses existing functionality? It would be for an attiny, but what about something with pins to spare? how about multi purpose pins?

Seems to be working for me. I'm not suggesting replacing anything, but building a layer above it.

one of the problems is going to be not only the number of pins available but also processing power and running all plane systems on one arduino is probably not going to work. Same goes for other uCPU's so I would think the one thing which would help would be to use an I2C mechanism for your module control interface and a messaging system such that one arduino is the master and puts the commands on the I2C bus and the arduino node containing the target module runs the command.

Abstract the comm API to modularize so many uCPUs can be used and spread the load. Abstract your routines so pin numbers, timers, etc are as generic as possible. Without a Java or bytecode like system, there will always be some form of porting to move to another platform.

Doug