Guidelines for using C++ as an alternative to C in embedded designs: Part 2
Click here to see Part 1.
An object oriented language such as C++ enables data and code to be encapsulated into objects, which can then be utilized without any knowledge of their internal workings.
This approach is particularly attractive when a large software team is used for a project. Different members of the team will have different knowledge and capabilities and it is the encapsulation of that expertise which is so useful.
This perspective is strongly emphasized in embedded software development, where there may be a wide spread of expertise from the "embedded expert", who is used to working close to the hardware with drivers etc., to the applications specialist, who knows little about the ways that embedded systems differ from desktop computers.
If the expertise of the embedded expert can be encapsulated into C++ objects, the applications specialists can proceed efficiently and safely. In the case study that follows, a classic embedded system problem will be addressed: the handling of a write-only port.
Case Study: A Write-only Port
It is not uncommon for an embedded system to have a device (a port) to which a data value may be written, but from which no data may be read " a write-only port.
Although this sounds like a joke played upon software engineers by the hardware designers, it is really just a design which makes economic use of hardware design elements. Handling a write-only port in software is reasonably straightforward " it is just a matter of keeping a "shadow" copy of the last data written.
The matter becomes more complex when, as is often the case, the bits in the port have a selection of functionally unconnected purposes. This means that a number of parts of the software need to use the port correctly, which presents some challenges.
A Solution in C It is entirely possible to implement a solution for write-only ports in C. Here is some possible code:
extern int ports;
void wop_set(int port, int bit)
val = 1 << bit;
shadow[port] |= val;
ports[port] = shadow[port];
void wop_clear(int port, int bit)
val = ~(1 << bit);
shadow[port] &= val;
ports[port] = shadow[port];
Although this code will do the job, it suffers a number of shortcomings:
1) There is no provision for initializing the data. Something (the linker probably) would need to map ports onto a sequence of write-only ports. At some point, an initial values need to be written to the ports and to shadow.
2) There is no mechanism compelling programmers to use these functions " accessing ports and shadow directly is a possibility, even if it is ill-advised.
3) The code is not reentrant, which would be a problem if a real-time operating system (RTOS) is in use or even if interrupt service routines might need to access the ports. Reentrancy could be implemented, but would be very application specific.
4) This bundle of code and data is not encapsulated, so distribution is not readily controllable.