Write-only ports
I often joke that my job puts me in a difficult position, as I am a software guy and a very large proportion of Mentor Graphics employees are hardware design specialists; I am consorting with the “the enemy”. Although I am making a light-hearted comment, there is, sadly, something of an “us and them” attitude between software and hardware teams in many companies. It is in everybody’s interest to make this a thing of the past.
Sometimes, it seems as if this view is reasonable, when hardware seems to be designed specifically to make life hard for software developers …
The issue of hardware being challenging to control from software is well known. The whole idea of device drivers was conceived, as much as anything, to hide the nastiness of such interfaces from non-experts. My favorite example of hardware that seems to have designed for intentional aggravation is a write-only port.
This type of interface has a register, to which data may be written, but from which the current value may not be read back. This may be problematic because the 8-, 16- or 32-bit port may consist of a number of single- or multi-bit registers with unrelated functionality. This means that different parts of the software may need to access the port and there are plenty of opportunities for unintentional interference. For example, to set the bottom 2 bits of the port without affecting the other bits, the following code would seem obvious:
WOPORT |= 0x03;
However, this construct will not work, as the |= operator generates code which will read the port [and get invalid data or trigger an exception] before writing an updated value. The solution is simple enough: keep a “shadow” copy of the port data and use that each time an update is required, like this:
woport_shadow |= 0x03;
WOPORT = woport_shadow;
This is quite straightforward, but there are a few things to take care of:
- The port and the shadow data must be correctly initialized.
- Code which accesses the port must always utilize the shadow.
- Re-entrancy may be an issue. If an interrupt occurred between the updating of the shadow and the writing to the port, another thread [task or ISR] might utilize the port and the shadow could get out of synch.
All of these issues may be addressed by careful code design. Probably the best approach is to encapsulate the access to a port inside a function, thus providing a common API. Another approach might be to use C++ to encapsulate the details of write-only port access. I will look at that approach on another occasion.
Incidentally, the code above might be an ideal application for my approach to binary constants, which I wrote about some time ago; instead of 0x03 you would use b00000011.
This topic (write only ports) also exposes another one of the hazards of bit fields. Seductive as they are, they obscure what’s really going on behind the scenes. Typically, writing fields via bit fields involve reading, shifting and/or masking bits, and then writing back. Particularly when only some of the bits are write-only (it happens), it’s easy to review the bit-field code and assume everything will work.
I believe you (Colin) wrote about bit fields in your book (haven’t seen the updated version released earlier this year), and maybe even mentioned something like this?
Don’t mean to hijack the thread topic & rant against bit fields, but… well, I really feel the need to rant against bit fields. They have their place, but they’re too easy to use incorrectly, and their lack of portability can really cause trouble.
Finally, I agree about using C++ to encapsulate the details of hardware complexity like this. Looking forward to your follow-up post down the road.
Good input. Thanks Dan.
I did not even touch on the idea of a port where just some of the bits are write-only, but the approach would be identical.
This is, indeed, a topic that I discuss in greater detail in my book – “Embedded Software: The Works”
Incidentally, in defence of hardware designers, a write-only port is not [just] designed to make programming hard. It does eliminate the extra electronics that would be required to support read back. As is so often the case, a saving on hardware has a cost in the software. It was for ever thus.