Bitwise operations on device registers

A lot of embedded software is focused on the control of peripheral devices and this can present some interesting challenges. In particular, the developer must be quite comfortable “bit bashing” – i.e. manipulating individual bits or groups of bits within a register …

The first aspect of device programming that needs to be considered is working at the bit level – and that entails working in binary. As the C language does not directly support binary notation – I wrote about a way around this here – most programmers use hexadecimal. This is quite straightforward and it just takes practice to see the binary values represented by hex numbers.

For the purposes of this discussion, I am going to consider an 8-bit port, where only the least significant 3 bits are used [any values set in the top 5 bits are ignored]. So the only meaningful values are 0 to 7.

Screen Shot 2016-09-05 at 10.24.26

Most programmers, when learning C, encounter bit fields and, not unreasonably, conclude that they are the optimal way to manipulate bitwise data – single bits and groups. However, this is not a valid conclusion. For internal data structures, bit fields are a perfectly reasonable way to manipulate data. However, their implementation is entirely compiler dependent. This means that there is no guarantee that they will map on to a device register in the expected manner. If you use them and your code works OK, that is fine, but bear in mind that your code is entirely non-portable and even a compiler update might break it.

The only reliable way to work with the bits in a register is to use the OR and AND operators: | and &. In simple terms, you use OR to set one or more bits, without affecting the others, and you use AND [with the ones-complement – the inverse – of the bit pattern] to similarly clear bits. Here are some simple examples:

device_reg = device_reg | 0x01;    // set bit 0
device_reg = device_reg & ~0x06;   // clear bits 1 and 2

I would probably use the compound assignment operators and write the code like this:

device_reg |= 0x01;    // set bit 0
device_reg &= ~0x06;   // clear bits 1 and 2

but it amounts to the same thing – just a matter of style.

If you want to toggle/flip a bit, the XOR operator in C is ^ which works in the same way.

An additional challenge with some device registers are “write-only”. In other words, unlike a normal memory cell, you can write a value into the register, but it is not possible to read it back. As the code shown above entails read/modify/write sequence, such write-only ports would be problematic. It is only a matter of coding and I have written on this matter in detail here, here and here.

Want to stay up to date on news from Siemens Digital Industries Software? Click here to choose content that's right for you

Comments

0 thoughts about “Bitwise operations on device registers
  • Hi Colin,

    I have seen folks using shift operators to manipulate bits. So which way is better, shift operators or by using ‘|’ and ‘&’ ? Or does it matter on the context ? If you’re going to have to manipulate more than one bit than AND/OR might be more efficient.

  • @Jenson – It is not generally a question of which is better. Each approach may be best in some situation. Most CPUs have instructions to directly perform all the operations, so efficient code is always likely.

Leave a Reply

This article first appeared on the Siemens Digital Industries Software blog at https://blogs.sw.siemens.com/embedded-software/2016/09/05/bitwise-operations-on-device-registers/