Sign In
Forgot Password?
Sign In | | Create Account

Write-only ports in C++

Colin Walls

Colin Walls

Posted Jan 28, 2013
2 Comments

I recently wrote about write-only ports and discussed how they worked and the challenges presented to software developers who need to program them. The solutions proposed were quite straightforward, but the challenge remained to ensure that all the code utilizing the ports complied with the requirements.

I commented at the time that there are several ways to mandate the correct handing of write-only ports, but an approach that interested me was the use of C++ …

In C++, the power of object oriented programming can be very useful for embedded developers. Complex, hard to understand code may be hidden inside objects, which can then be used safely by applications programmers. In this case, I am going to create a class [in effect, a new data type] called write_only_port which deals with all the necessary usage of a shadow copy of the port data. Here is my first shot at it:

class write_only_port
{
unsigned shadow;
volatile unsigned* address;
public:
write_only_port(unsigned);
~write_only_port();
void operator|=(unsigned);
void operator&=(unsigned);
};

This needs the 4 member functions defined too [but I will skip the destructor for the moment]:

write_only_port::write_only_port(unsigned port)
{
address = (unsigned*) port;
shadow = 0;
*address = 0;
}
void write_only_port::operator|=(unsigned val)
{
shadow |= val;
*address = shadow;
}
void write_only_port::operator&=(unsigned val)
{
shadow &= val;
*address = shadow;
}

This enables write_only_port objects to be created and assigned an address [and initialized to 0]. The applications programmer then has [only] the |= and &= operators available, which are quite sufficient to set and clear bits. Application code using this class may look like this:

main()
{
write_only_port myport(0x10000);
myport |= 0x30;
myport &= ~7;
};

This sets bits 4 and 5 and clears bits 0, 1 and 2. The applications programmer needs to have no knowledge of how a write only port works, but can use them safely.

The next job would be to make the member functions reentrant, but I will save that for another day …

device drivers, drivers

More Blog Posts

About Colin Walls Follow on Twitter

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. Learn more about Colin, including his go-to karaoke song and the best parts of being British: http://go.mentor.com/3_acv Visit The Colin Walls Blog

More Posts by Colin Walls

Comments 2

Post a Comment
Hate to be finicky, but I will, anyway! (1) The long representing the port address should be unsigned long. To be really finicky, casting from any integer type to a pointer is theoretically unsound, but we all have to do it! C++ junkies would prefer to see a reinterpret_cast, though, instead of a C-style one. (2) The various ints should probably be unsigned, as well; signed ports are very uncommon, and if this is indeed one, it shouldn't be having bit-logic operations done on it! (3) I'd write... volatile unsigned int * address even though the port is write-only. It may be the input to a FIFO, for example, which might sometimes require successive writes of the same value. Having said that, the encapsulation of the write in its own non-inline function should ensure that the compiler always codes each write, anyway, when asked to. But I'm paranoid about these things. (4) These member functions will never be reentrant because they must access variables external to themselves! I assume what you meant was that the operations must be serialised by some kind of locking mechanism (e.g. disabling interrupts or using an OS mutex). (5) I was going to suggest a constructor initialisation list for the member variables. However, I guess you've set these up within the constructor body so that you can bracket them with the said locking mechanism, when you return to the topic.

Peter Bushell
12:51 PM Jan 28, 2013

Hi Peter I have to agree 100% with (1), (2) and (3). My coding was rather sloppy. I was just trying to illustrate my point, but that's no excuse. I have, I believe, address the points by editing the posting. I am assuming a 32-bit architecture, where type unsigned will serve. (4) and (5) are anticipating a future posting, as you guessed.

Colin Walls
10:05 AM Jan 29, 2013

Add Your Comment

Please complete the following information to comment or sign in.

(Your email will not be published)

Archives

Tags

 
Online Chat