Some more tips for embedded software developers. Today I am looking at real time programming, using the C language and some advice on transitioning into the world of embedded software …
To maintain real time integrity, keep ISRs as short as possible
A real time system is one that responds to external events and may initiate events in a predictable fashion. Often real time systems are fast, but that need not necessarily be the case. One system may need to be fast enough, but another may need to be slow enough; they are both real time. Although it is possible – and sometime best – to poll for external events, it is much more usual to use interrupts. The trouble with interrupts is that, when one occurs and the interrupt service routine [ISR] code starts running, interrupts are disabled and not enabled again until the code does so. This is likely to be at the end of the ISR. The problem is that, while interrupts are disabled, the system’s ability to be responsive – i.e. exhibit real time behavior – is inhibited. It is, therefore, very good practice to keep ISRs as short as possible. Just respond to the event source and line up the data processing or further actions for a task to perform when it is scheduled.
Never use global variables in C instead of function parameters
Normally, a C function can have a number of input parameters – an indefinite number or maybe none. It can return a single value. This covers most eventualities, but there are a couple of situations when this architecture may seem inadequate:
- the function needs to return more than a single item of data
- one or more parameters almost always take the same value
The obvious way to address each of these situations is to use global [extern] variables. However, it is very hard to write clear, maintainable code that uses globals. If they can be localized to a module [i.e. static], some careful commenting can make matters easier, but this is still challenging. But there are better solutions.
For (1), to return more than a single item of data, pass pointers to variables to receive the data. Typically, functions that do this reserve their actual return value for a status [success or failure] response. This approach is typically used by real time operating system APIs.
C does not offer a simple solution to (2), but C++ has default parameter values. For example you could declare a function like this:
float process(float input_value, int power=2, int magnitude=10);
and then make calls like these:
x = process(val, 3, 11); x = process(1.5, 4); x = process(9.99);
To move from desktop programming to embedded, some hardware knowledge may be useful
I often have enquiries from people who are interested in becoming embedded software engineers. I am generally keen to encourage them, as it is an interesting area in which to work, IMHO. Many such enquires are from programmers who have worked on desktop software etc. That is fine, because programming is programming. However, I would generally suggest that some appreciation of hardware matters – particularly the software/hardware interface – would be beneficial.
I have been contemplating this matter recently and I think my advice would now be a little different. Although this hardware knowledge would be useful, if you wanted to work at the “sharp end” – i.e. close to the hardware, doing drivers etc. – many developers work on embedded systems without really understanding anything about the underlying platform. They are simply concerned with the application-level code, which is really not much different from desktop software.