Raspberry Pi IoT In C - Pi 5 Memory Mapped GPIO
Written by Harry Fairhead   
Wednesday, 10 January 2024
Article Index
Raspberry Pi IoT In C - Pi 5 Memory Mapped GPIO
Registers
RIO
A Fast Pulse

Each register has the same format for each GPIO line. For example, the status register is:

Bits

Name

Description

Type

Reset

31:30

Reserved

 

-

-

29

IRQTOPROC

Interrupt to processors, after override applied

RO

0x0

28

IRQCOMBINED

interrupt to processors, after masking

RO

0x0

27

EVENT_DB_LEVEL _HIGH

Debounced input pin is high

RO

0x0

26

EVENT_DB_LEVEL _LOW

Debounced input pin is low

RO

0x0

25

EVENT_F_EDGE_H IGH

Input pin has seen a filtered rising edge. Clear with ctrl_irqreset

RO

0x0

24

EVENT_F_EDGE_LOW

Input pin has seen a filtered falling edge. Clear with ctrl_irqreset

RO

0x0

23

EVENT_LEVEL_HI GH

Input pin is high

RO

0x0

22

EVENT_LEVEL_LOW

Input pin is Low

RO

0x0

21

EVENT_EDGE_HIGH

Input pin has seen rising edge. Clear with ctrl_irqreset

RO

0x0

20

EVENT_EDGE_LOW

Input pin has seen falling edge. Clear with ctrl_irqreset

RO

0x0

19

INTOPERI

Input signal to peripheral, after override applied

RO

0x0

18

INFILTERED

input signal from pad, after filtering is applied but before override, not valid if inisdirect=1

RO

0x0

17

INFROMPAD

Input signal from pad, before override applied

RO

0x0

16

INISDIRECT

input signal from pad without filtering or override

RO

0x0

15:14

Reserved

 

-

-

13

OETOPAD

Output enable to pad, after override applied

RO

0x0

12

OEFROMPERI

Output enable from selected peripheral, before override applied

RO

0x0

11:10

Reserved

 

-

-

9

OUTTOPAD

Output signal to pad after override applied

RO

0x0

8

OUTFROMPERI

Output signal from selected peripheral, before override applied

RO

0x0

7:0

Reserved

 

-

-

 

You can see that many of the 32 bits in the register are not used, but bit 9 is OUTTOPAD which is the final state of the GPIO line after register overrides have been applied.

You can read its current value using:

 

    uint32_t *PERIBase = map;
    uint32_t *GPIOBase = PERIBase + 0xd0000 / 4;
    
    int pin = 0;
    volatile uint32_t *addrGP0Status = 
GPIOBase + pin * 8 / 4; uint32_t value = *addrGP0Status; printf("status 10987654321098765432109876543210\n"); printf("status %032b\n", value);

This prints the current status of GP0 in binary. You can read the value of the bits to check that they correspond to what you would expect from the known status of the line.

In most cases it is better to associate more familiar C data types with the memory area referenced. For example, the set of GPIO registers in which each status register is followed by the corresponding control register – is like an array of structs. For example:

typedef struct{
    uint32_t status;
    uint32_t ctrl; 
}GPIOregs;
#define GPIO ((GPIOregs*)GPIOBase)

This allows you to treat GPIO as an array of register structs and it allows the previous program to be written as:

    uint32_t *PERIBase = map;
    uint32_t *GPIOBase = PERIBase + 0xD0000 / 4;      
    int pin=2;
    volatile uint32_t *addrGP0Status = 
GPIOBase + pin * 8 / 4; uint32_t value = *addrGP0Status; printf("status 10987654321098765432109876543210\n"); printf("status %032b\n", GPIO[pin].status);

The expression:

GPIO[pin].status

expands to:

((GPIOregs*)GPIOBase)[pin].status

This is the general way you work with peripheral devices such as the PWM units or I2C hardware, but the GPIO is special in that it has another set of registers that control it.



Last Updated ( Wednesday, 10 January 2024 )