Thought Leadership

Device registers in C

Mentor Graphics has historically been dedicated to providing tools for electronic hardware designers and that still represents a very large proportion of the business. Ever since I was acquired into the company, I have found that the hardware focused guys have a healthy interest in software – embedded software in particular. Often, they are specifically concerned with the boundary between software and hardware …

The broad issue is quite straightforward. A peripheral device is likely to have a number of internal registers, which may be read from or written to by software. These normally appear just like memory locations and can, for the most part, be treated in the same way. Typically a device register will have bit fields – groups of bits that contain or receive specific information. Such fields may be single bits, groups of bits or a whole word. There may also be bits that are unused – reading from them or writing to them has no effect.

For example, a serial interface might have an 8 bit register, with the bits used like this:

  • Bits 0-2: baud rate, where the values [0-7] have specific significance.
  • Bits 3-4: parity, where 0=none, 1=even, 2=odd and 3 is an illegal setting.
  • Bits 5-6: unused.
  • Bit 7: interrupt enable.

Writing code to access such a device need not be hard, but there are at least 4 areas where care is needed:

1) The word size of the register. It is essential that the data type used in C corresponds correctly. Fortunately, C99 addressed this matter satisfactorily.

2) If the register is wider than 8 bits, there is a question about the endianity of the CPU. Some processors are fixed, others have their endianity locked in their hardware implementation and others may be changed in software. You just need to know.

3) Careful use of the keyword volatile is essential when accessing device registers to prevent over-enthusiastic optimization by the compiler removing repeated references to the address.

4) At first sight, bit fields in C structures look perfect for this application. You simply need to map the structure onto the register and then each of the fields can be accessed with ease. However, this is unwise for a couple of reasons: First, the layout of bit fields in a C structure is compiler dependent; even if your code works it would be non-portable. Second, the code which accesses a bit field to write a value would also need to read the data which is already there; some hardware does not allow read back, so a shadow copy of the register needs to be maintained in RAM.

For something that is apparently quite simple and straightforward, there are a surprising number of pitfalls. What is even more surprising, given that this is a matter of concern to developers of almost all embedded systems, is that no “standard” way to approach this issue has emerged.

Colin Walls

I have over thirty years experience in the electronics industry, largely dedicated to embedded software. A frequent presenter at conferences and seminars and author of numerous technical articles and two books on embedded software, I am a member of the marketing team of the Mentor Graphics Embedded Systems Division, and am based in the UK. Away from work, I have a wide range of interests including photography and trying to point my two daughters in the right direction in life. Learn more about Colin, including his go-to karaoke song and the best parts of being British: http://go.mentor.com/3_acv

More from this author

Comments

0 thoughts about “Device registers in C
  • It is at this low level that plain C tends to be used, even in C++ projects. This is a pity. As you say, C bit-fields are frought with hidden dangers and also the generated access code is typically sub-optimal. However, their use does promote more readable and less error-prone coding at application level.

    The dangers and portability issues of C bit-fields can be avoided completely in C++ by instead devising suitable classes to implement them. These can be designed with particular hardware idiosyncrasies in mind (including the possible need for shadow registers). Also, using templates and some template meta-programming, it is possible to offer better performance, sometimes, than is typically available with the standard bit-field arrangement.

    Such classes must be designed carefully by someone experienced with using C++ at low level, but the effort is worth it in order to give application programmers a straightforward, uniform and robust interface to bit-fields within registers.

    Anyone wanting to discuss the details is welcome to contact me through Software Integrity’s website:
    http://software-integrity.com/

Leave a Reply

This article first appeared on the Siemens Digital Industries Software blog at https://blogs.stage.sw.siemens.com/embedded-software/2011/03/28/device-registers-in-c/