Colin WallsColin Walls has 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, Colin is an embedded software technologist with Mentor Embedded [the Mentor Graphics Embedded Software Division], and is based in the UK.
« Less
Colin WallsColin Walls has 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, Colin is an embedded software technologist with Mentor
… More »
Device registers in C
September 19th, 2016 by Colin Walls
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 each different value (0-7) has a 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:
- The word size of the register. It is essential that the data type used in C corresponds correctly. Fortunately, C99 addressed this matter satisfactorily.
- 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.
- 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.
- 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.
Related
This entry was posted
on Monday, September 19th, 2016 at 5:05 am.
You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.