Accessing peripheral registers - the next version

Johannes Pfau via D.gnu d.gnu at puremagic.com
Sun Aug 28 01:34:15 PDT 2016


Am Sat, 27 Aug 2016 08:05:08 +0000
schrieb Timo Sintonen <t.sintonen at luukku.com>:

> [...]
> I did some simple tests and this seems to work.
> 
> My question is: is this the way we should go?

Yes, I think this is the best way to implement a volatile type. It is a
natural replacement for volatile variables as it can be used in exactly
the same way:

1) For variables, used e.g. in interrupts and in the normal program
code:

Volatile!bool dataAvailable;

2) For memory mapped registers:

(cast((Volatile!uint)*)0xABCD)* += 1;


The alternative is a type which also internally handles the address of
the 'data'. However, then you have one template instance per
address. With your solution there's one template instance per type
which is more reasonable IMO.

The Volatile!T code you posted does not show how to map such a
Volatile!T instance to a certain address. The code in 2) could be placed
into a @property, but some stuff might still not work correctly (like
using & to get the address). I think I'll add a @attribute("address",
0xABCD) to GDC which can be used for all extern variables. Then you
could simply do this:

extern Volatile!int PORTA @address(0xABCD);

> If it is, what would be the preferred name for this type? Also 
> what would you think should be the module and file name?
> 

As Mike already posted, Volatile!T is a good name (as this exactly
explains what the type does for anyone already knowing the C volatile
meaning).

However, for accessing peripheral registers I'd use something more high
level and name it Register!(...) or something like that. Here's a proof
of concept:
https://github.com/D-Programming-microD/avr-playground/blob/master/src/test.d
https://github.com/D-Programming-microD/avr-playground/blob/master/src/util/mmio.d

// using enums for fields
DDRB.pin1 = Direction.out_;
PORTB.pin1 = Level.low;
PORTB.toggle!"Pin1";
PORTB.set!("Pin1", "Pin2");
PORTB.clear!("Pin1", "Pin2");
PORTB.set!("Pin1", Level.low,
           "Pin2", Level.high);

// classic, c-style usage
DDRB |= (0b1 << DDRB.shiftPin1) | ( 0b1 << DDRB.shiftPin2);
DDRB = 0b1;


More information about the D.gnu mailing list