Cannot set Pin in Navio+ with Raspberry Pi 4 + Ubuntu 18.04 arm64

Hi guys,
After completing with success the test with the combo Navio+ raspberry pi 3 with Ubuntu 18.04 arm64, I got the new raspberry pi 4 and I tried to run the demo code in your Navio2 C++/Python GitHub repository.

ADC works;
IMU works;
GPS works;

LED and Servo are now working and I tried to understand the problem… So fai i suspect that your Pin class is not ready for raspberry pi 4 (or at least you didn’t released the patch as the new Navio2 uses rcio instead).

Could you give me some hint although probably could be better to add a few lines of code into the example repo to fix for all the people out there.

Waiting for your help,


Hi Vincenzo,

May I ask you to clarify what examples you had issues with? Have any of the examples worked incorrectly?

Hi Polina,
thanks for the reply. Please refer to the following case:

Board: Navio+
Raspberry Pi version: 4 / 4Gb

After running the example code fetched from Navio2 Repo, I noticed that every example using the class Pin was not working. After a little bit of digging into the Raspberry Pi details I noticed the following error:

In the file gpio.cpp

the function Pin::getRaspberryPiVersion() does not support raspberry pi v.4, why?

if you cat the file /proc/cpuinfo in my case, the result yields to:

Hardware	: BCM2835
Revision	: c03112
Serial		: 10000000e0b3d26d
Model		: Raspberry Pi 4 Model B Rev 1.2

which selects in your code the wrong platform… in particular, v3. There is also another issue, which is the base peripheral address for raspberry pi 4, which is:

#define BCM2711_PERI_BASE   0xFE000000

here the changes I implemented to fix the issue:

bool Pin::init()
    int mem_fd;
    if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
        warn("/dev/mem cannot be opened");
        return false;

uint32_t address = 3;
int version = getRaspberryPiVersion();
if (version == 1) {
    address = GPIO_BASE(BCM2708_PERI_BASE);
} else if (version == 2) {
    address = GPIO_BASE(BCM2709_PERI_BASE);
} else if (version == 3) {
    address = GPIO_BASE(BCM2835_PERI_BASE);
} else if (version == 4) {
    address = GPIO_BASE(BCM2711_PERI_BASE);

void *gpio_map = mmap(
    NULL,                 /* any adddress in our space will do */
    BLOCK_SIZE,           /* map length */
    PROT_READ|PROT_WRITE, /* enable reading & writting to mapped memory */
    MAP_SHARED,           /* shared with other processes */
    mem_fd,               /* file to map */
    address               /* offset to GPIO peripheral */

if (gpio_map == MAP_FAILED) {
    warn("cannot mmap memory");
    return false;

/* No need to keep mem_fd open after mmap */
if (close(mem_fd) < 0) {
    warn("cannot close mem_fd");   
    return false;

_gpio = reinterpret_cast<volatile uint32_t *>(gpio_map); // Always use volatile pointer!

return true;

and then I also modified the

int Pin::getRaspberryPiVersion() const
    char buffer[MAX_SIZE_LINE];
    const char* hardware_description_entry = "Hardware";
    const char* v1 = "BCM2708";
    const char* v2 = "BCM2709";
    const char* v3 = "BCM2835";
    const char* v4 = "BCM2711";
    char* flag;
    FILE* fd;

    fd = fopen("/proc/cpuinfo", "r");

    while (fgets(buffer, MAX_SIZE_LINE, fd) != NULL) {
        flag = strstr(buffer, hardware_description_entry);

        if (flag != NULL) {
            if (strstr(buffer, v4) != NULL) {
                return 4;
            } else if (strstr(buffer, v3) != NULL) {
                return 3;
            } else if (strstr(buffer, v2) != NULL) {
                return 2;
            } else if (strstr(buffer, v1) != NULL) {
                return 1;
    return 3;

    /* defaults to DEFAULT_BOARD_VER */
    fprintf(stderr, "Forcing RPi version to <%d>\n", DEFAULT_BOARD_VER);

then you can build the library and the examples with the compiler option


to get everything working for the Raspberry Pi 4 case.

I hope this post can help some other developer who need your product to work without your raspbian image…

I would like also to mention that, the example code you released in full of warnings and small bugs, which can be highlighted by removing all the warning filters you establish in your make files… which I friendly recommend as best practice.

Hoping to be helpful to improve robustness and compatibility,

with my best regards,


1 Like

Hi Vincenzo,

Sorry for the much-delayed response!

Thank you for the putting your time into improving the code. We’ll double-check the examples and correct them accordingly :slightly_smiling_face: