Raspberry Pi CM5 IoT In C - GPIO Registers
Written by Harry Fairhead   
Tuesday, 04 November 2025
Article Index
Raspberry Pi CM5 IoT In C - GPIO Registers
Registers
PAD
PAD Control

PAD Control

Using the RIO we can read and write the GPIO lines, but there is a further step we have to complete before we can actually make use of them. Each GPIO line has its own PAD which is a set of components that control the physical connection of the line to the outside world. To make a GPIO line work you have to configure the pad to act as input or output and set its electrical characteristics. You can see the CM5’s PAD structure in the diagram below:

This is very similar to the PAD design found in other members of the Pi family. The PAD registers for the GPIO bank we are using is at 0x400f0000 which means its offset is 0xf0000:

uint32_t *PADBase = PERIBase + 0xf0000 / 4;

The only complication is that the first register is a VOLTAGE_SELECT register which sets the voltage that all of the GPIO lines in bank 0 work with. A zero sets 3.3V and a one sets 1.8V. The default is 3.3V and you can ignore this register unless you need to work at 1.8V.

After the VOLTAGE_SELECT register there is a PAD register for each GPIO line:

Bits

Name

Description

Type

Reset

31:8

Reserved

7

OD

Output disable. Has priority over output enable from peripherals

RW

0x1

6

IE

Input enable

RW

0x0

5:4

DRIVE

Drive strength.
0x0 → 2mA
0x1 → 4mA
0x2 → 8mA
0x3 → 12mA

RW

0x1

3

PUE

Pull-up enable

RW

Varies

2

PDE

Pull-down enable

RW

Varies

1

SCHMITT

Enable Schmitt trigger

RW

0x1

0

SLEWFAST

Slew rate control. 1 = Fast, 0 = Slow

RW

0x0

 

We can access the PAD registers using:

uint32_t *pad = PADBase + 1;

For example, if we want to set the PAD to output with a default drive, no pull-up/down, no Schmitt trigger and slow slew rate we would use:

pad[pin]= 0x10;

Notice that output is set by not enabling input.

A Fast Pulse

Now we can re-write a Blinky-style program to find out how fast the CM5 can toggle a GPIO line. We first have to map the peripherals area into user space and set up all of the addresses we want to use. Next we configure the pin as an output and start a loop that toggles the line using the XOR register:

The complete program is:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
typedef struct{
    uint32_t status;
    uint32_t ctrl; 
}GPIOregs;
#define GPIO ((GPIOregs*)GPIOBase)
typedef struct
{
    uint32_t Out;
    uint32_t OE;
    uint32_t In;
    uint32_t InSync;
} rioregs;
#define rio ((rioregs *)RIOBase)
#define rioXOR ((rioregs *)(RIOBase + 0x1000 / 4))
#define rioSET ((rioregs *)(RIOBase + 0x2000 / 4))
#define rioCLR ((rioregs *)(RIOBase + 0x3000 / 4))
int main(int argc, char **argv)
{
    int memfd = open("/dev/mem", O_RDWR | O_SYNC);
    uint32_t *map = (uint32_t *)mmap(
        NULL,
        64 * 1024 * 1024,
        (PROT_READ | PROT_WRITE),
        MAP_SHARED,
        memfd,
        0x1f00000000
    );
    if (map == MAP_FAILED)
    {
        printf("mmap failed: %s\n", strerror(errno));
        return (-1);
    };
    close(memfd);
    uint32_t *PERIBase = map;
    uint32_t *GPIOBase = PERIBase + 0xD0000 / 4;
    uint32_t *RIOBase = PERIBase + 0xe0000 / 4;
    uint32_t *PADBase = PERIBase + 0xf0000 / 4;
    uint32_t *pad = PADBase + 1;   
    
    uint32_t pin = 2;
    uint32_t fn = 5;
    GPIO[pin].ctrl=fn;
    pad[pin] = 0x10;
    rioSET->OE = 0x01<<pin;
    rioSET->Out = 0x01<<pin;
    
    for (;;)
    {
        rioXOR->Out = 0x04;
    } 
    return (EXIT_SUCCESS);
}

I
f you try this out you will find that it produces 24ns pulses.

 

 In Chapter but not in this extract

  • The Gpio5 Library
  • Initializing GPIO
  • Get and Set
  • PAD Configuration
  • Working with Gpio5
  • Examples
  • Interrupts? 

Summary

  • The CM5 has its peripherals implemented by the custom RP1 chip and this makes it incompatible with all previous versions of the Raspberry Pi.

  • The memory map and the register configurations are different to other Pis and more like those found in the Pico.

  • You can still work with the CM5’s registers using the standard memory-mapping techniques.

  • The /dev/mem device accesses all of the memory, but needs root privileges.

  • The /dev/gpiomem0 device only provides the GPIO registers, but it can be used without root privileges.

  • The CM5 uses the same RIO-based GPIO implementation as the Pico. To use the GPIO lines you first have to select RIO mode.

  • Each GPIO line also has a PAD and a PAD control register.

  • The RIO registers are used to control and read the state of the GPIO line.

  • Using direct register access, the CM5 can produce well-formed 25ns pulses

  • Although using the registers directly is a good way to get started, creating functions, and hence a library to do the same job, is a good idea.

  • The Gpio5 library is based on the Pico SDK GPIO functions and it allows you to run Pico GPIO programs with little modification.

  • Working with raw interrupts under Linux is not easy and best avoided.

 

Raspberry Pi Compute Module 5
IoT In C
Using Linux
Drivers and Gpio5

By Harry Fairhead

CIoTCM5360
Buy from Amazon.

Contents

  1. The CM5 For The IoT
  2. Setting Up the CM5
  3. C and Visual Studio Code
  4. Drivers: A First Program
  5. The GPIO Character Drive
  6. GPIO Using I/O Control
  7. GPIO Events
  8. GPIO Hardware With Gpio5 
          Extract:  GPIO Registers ***NEW!!!
  9. Some Electronics
  10. The Device Tree
  11. Pulse Width Modulation
        
    Extract: PWM Using GPIO5
  12. SPI Devices
  13. I2C Driver and Gpio5
  14. Sensor Drivers – Linux IIO & hwmon
  15. 1-Wire Bus
  16. The PIO
        
    Extract: Getting Started With PIO
  17. Going Further With Drivers
  18. Almost Real-Time Linux
  19. Appendix I Gpio5

 <ASIN:1871962951>

 

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

Banner


PostgreSQL 18 Released - What's New?
13/10/2025

PostgreSQL 18 was released on September 25, boosting a
many great features. If you check out the official release statement you'll find that there's a lot to digest, so we'll focus on just a  [ ... ]



Visualize The Inner Workings Of An LLM
17/10/2025

Simply referred to as "LLM Visualization" this web site 
with interactive and intuitable graphics explains how an LLM actually works.


More News

pico book

 

Comments




or email your comment to: comments@i-programmer.info

 



Last Updated ( Saturday, 08 November 2025 )