Advertisement

Better even at the lowest levels

November 01, 2008

Dan_Saks-November 01, 2008

For the past several years, I've been presenting a talk at the Embedded Systems Conferences called "Writing ISRs in C++." The talk is aimed at programmers who've already written interrupt-handling code in C and would like to see how to use the features of C++ to make such code even better. More recently, I started presenting a talk at the Software Development Conferences entitled "C++ on Bare Metal", which presents ways to use C++ features such as classes, inheritance, and templates to model memory-mapped devices as tidy, yet efficient, abstractions.

This fall, both conferences took place at the Hynes Convention Center in Boston during the same week. I was one of two or three lecturers who spoke at both conferences, and I presented both talks. This time, I was struck by the number of attendees at each talk who were not so much interested in how to write such low-level code in C++, but rather why you'd want to write it in C++ rather than in C.

Ten or twelve years ago, C++ was still a novelty in the embedded world. Most of the developers at my conference lectures were as interested in why as in how, so I typically devoted time to both. Over the years, more and more programmers came to my talks already sold on why and were just interested in how. For the past few years, I've focused on how because that's what I thought my audiences wanted to hear. That's why this recent uptick in concern about why caught my attention.

So the question is "Why would you prefer to write low-level code that directly manipulates hardware and handles interrupts in C++ rather than in C?" If C and C++ were different languages, as different as say C++ and Ada, or even C++ and Java, this might be harder to answer. But C++ is essentially C with a bunch more stuff. I believe the only substantive features in C that aren't also in C++ are some built-in support for numerical computing. Device drivers and interrupt handlers don't do much number crunching.

C++ provides all the facilities of C for controlling hardware efficiently. At times, controlling hardware can be tricky and error prone. C++ has features that C lacks, principally classes and templates, that let you bundle device controls into components that are, as Scott Meyers would say, "easy to use correctly and hard to use incorrectly."1

For example, many processors have an interrupt controller with an interrupt-pending register. That register has a bit for each interrupt-generating device that indicates whether an interrupt is pending for that device. An interrupt handler for a given device should clear that device's interrupt-pending bit after handling the interrupt.

In C, you might represent the interrupt-controller register as a struct, such as:

struct interrupt_controller
{
    device_register INTMOD;
    device_register INTPND;
    device_register INTMSK;
};

and access the device via a pointer:

interrupt_controller *const ic
    = (interrupt_controller *)0x3FF4000;

With most control registers, you clear a bit using a masking operation, such as:

ic->INTPND &= ~button;

Here, button is presumably a one-bit mask that corresponds to the interrupt-pending bit for a push button. However, interrupt-pending bits should be cleared atomically, and few, if any, processors implement the &= operation so that it's atomic. Thus, many interrupt controllers are wired so that you clear an interrupt-pending bit by assigning rather than and-ing to the register, as in:

ic->INTPND = button;

< Previous
Page 1 of 2
Next >

Loading comments...