Im Standard-Header lpc17xx.h ist der Zugriff auf die Register über
structs realisiert. Wahrscheinlich ist dir das nicht geläufig. Man macht
sich dabei die Tatsache zu Nutze, dass die Register für die jeweiligen
Hardware-Blöcke im Controller (z.B. GPIO oder UART) unmittelbar
nacheinander im Adressraum liegen, eben wie Variablen einer struct. Das
hat den Vorteil, dass man beispielsweise für die 4 GPIO-Ports nicht
jedes Register einzeln mit Adresse definieren muss. Stattdessen
definiert man bloß ein einziges mal das "Layout" der Register für einen
GPIO-Block allgemein als struct und braucht dann nur noch die
"Startadressen" der 4 Blöcke zu hinterlegen.
Mal ein Beispiel aus dem Header für die drei I2C-Blöcke des μC:
1 | // Als erstes die allgemeine Definition der struct für einen I2C-Block
|
2 | typedef struct
|
3 | {
|
4 | __IO uint32_t I2CONSET;
|
5 | __I uint32_t I2STAT;
|
6 | __IO uint32_t I2DAT;
|
7 |
|
8 | // usw...
|
9 |
|
10 | } LPC_I2C_TypeDef;
|
11 |
|
12 | // ...
|
13 | // Jetzt kommen die Startadressen der drei Blöcke
|
14 | #define LPC_I2C0_BASE (LPC_APB0_BASE + 0x1C000)
|
15 | #define LPC_I2C1_BASE (LPC_APB0_BASE + 0x5C000)
|
16 | #define LPC_I2C2_BASE (LPC_APB1_BASE + 0x20000)
|
17 |
|
18 | // ...
|
19 | // Und anschließend die "Verknüpfung" - Hier steht im Prinzip:
|
20 | // Interpretiere die Speicherstellen LPC_I2C0_BASE bis LPC_I2C2_BASE
|
21 | // als Zeiger auf structs vom Typ LPC_I2C_TypeDef
|
22 | #define LPC_I2C0 ((LPC_I2C_TypeDef *) LPC_I2C0_BASE )
|
23 | #define LPC_I2C1 ((LPC_I2C_TypeDef *) LPC_I2C1_BASE )
|
24 | #define LPC_I2C2 ((LPC_I2C_TypeDef *) LPC_I2C2_BASE )
|
Dadurch kann man dann im Code über LPC_I2C0->I2STAT auf das
Statusregister vom I2C-Block 0 zugreifen. Die Adresse wird dann vom
Compiler indirekt berechnet (Startadresse des Blocks LPC_I2C0 + 4 Byte
Offset). Ansonsten ist die Verwendung exakt so wie bei den
Registerdefinitionen aus dem AVR-Bereich.