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.

Preparing Recommendations

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.

More Blog Posts

About Colin Walls

Colin WallsI have over twenty-five 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. Visit The Colin Walls Blog

Follow on Twitter

More Posts by Colin Walls

Preparing Recommendations

Comments (↓ Add Your Own)

2 Comments on this Post

Commented on 10:56 AM, Mar 28, 2011
By Peter Bushell

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/

Commented on 12:54 PM, Mar 28, 2011
By Colin Walls

I agree 100% Peter. Unfortunately, we have yet to reach a point where C++ is the dominant language for embedded programming. IMHO, this alone is a strong reason to consider its use.

Add Your Comment

Please complete the following information to comment or sign in.

(Your email will not be published)

Archives

Tags

RSS