# Segmentation fault on mmio to raspberry pi's gpio pins



## RalfPeg (Mar 7, 2019)

Hello!

using this program


```
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdint.h>

int main()
{
        volatile void *gpfs0; //general purpose function select 0
        int memfd;
        volatile uint32_t *gpfsr; //general purpose function select register
        volatile uint32_t *gposr; //general purpose output set register
        volatile uint32_t *gpocr; //general purpose output clear register

        //open fd to physical memory
        memfd = open("/dev/mem", O_RDWR|O_SYNC);
        if(memfd == -1)
        {
                printf("error opening /dev/mem\n");
                return 1;
        }

        //mapping into memory
        gpfs0 = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_WRITE, MAP_SHARED, memfd, 0x7E200000);
        if(gpfs0 == MAP_FAILED)
        {
                printf("map failed: %d\n", errno);
                return 1;
        }

        gpfsr = gpfs0; //GPIO Function select 0
        gposr = gpfs0 + 0x1c; //GPIO Output Set 0
        gpocr = gpfs0 + 0x28; //GPIO Output Clear 0

        *gpfsr = 0x40; //Pin 2 to Output
        *gposr = *gposr | 0x4; //high signal to Pin 2

        usleep(1000000); //Wait a second

        *gpocr = *gpocr | 0x4; //low signal to Pin 2


        return 0;
}
```

causes a sementation fault message on my raspberry pi 3 b.

`dmesg | grep gpio` says


```
gpio0: <BCM2708/2835 GPIO controller> mem 0x7e200000-0x7e2000b3 irq 23,24 on simplebus0
gpiobus0: <OFW GPIO bus> on gpio0
gpioc0: <GPIO controller> on gpio0
gpioled0: <GPIO LEDs> on ofwbus0
gpioled0: <led0> failed to map pin
gpioled0: <led1> failed to map pin
```

using the code on raspbian (with different memory address) works fine. what could be wrong there?


----------



## acheron (Mar 7, 2019)

Why don't you use gpioctl?


----------



## RalfPeg (Mar 7, 2019)

Because I won't understand how to use mmio then......


----------



## Emrion (Mar 7, 2019)

Just a thought: have you tried to add PROT_READ permission on your mmap() call?
`gpfs0 = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_WRITE | PROT_READ, MAP_SHARED, memfd, 0x7E200000);`


----------



## RalfPeg (Mar 7, 2019)

yes adding PROT_READ worked. but the pins still don't have a high level.


----------



## SirDice (Mar 7, 2019)

```
*gposr = *gposr | 0x4; //high signal to Pin 2

{snip}

*gpocr = *gpocr | 0x4; //low signal to Pin 2
```

Both _set_ bit 3 to 1.


----------



## RalfPeg (Mar 7, 2019)

yes that's correct. setting a bit in  the "set register" sets the pin level to "high" and setting a bitt in the "clear register" sets the pin level to "low". or am i wrong?


----------



## SirDice (Mar 7, 2019)

You may be right, my dyslexia got the better of me and I didn't notice one was gposr and the other gpocr. So both looked to be doing the same thing while the remarks metioned one should be pulled low and the other pulled high.


----------



## RalfPeg (Mar 7, 2019)

could there something be wrong with mmap?


----------



## Emrion (Mar 7, 2019)

I propose you to use another API, as acheron suggested, just for testing purpose. It could be a problem of communication between the hardware and the kernel.

```
gpioled0: <led0> failed to map pin
gpioled0: <led1> failed to map pin
```

Because if it is, you waste your time trying to make a proper code functioning while the hardware doesn't respond.


----------



## RalfPeg (Mar 8, 2019)

Well I reported a bug yesterday, because it should work, shouldn't it?


----------



## Emrion (Mar 8, 2019)

You didn't understand what I meant. I advised you to try with gpioctl API. If it works, it's a bug in your current code. Otherwise, it's maybe a problem at kernel level.

Better is to make a PR only when you have well identify the bug if bug there is (and even wrote a patch if possible). The FreeBSD staff is very busy people...


----------



## SirDice (Mar 8, 2019)

Don't rush to claim that you have found a bug


----------



## RalfPeg (Mar 8, 2019)

like i said: on raspbian linux this code does work. the only difference between raspbian linux and freebsd is that dmesg tells different memory base addresses (0x3f000000 respective 0x7e200000). and i think that this code should work on freebsd, too.


----------



## SirDice (Mar 8, 2019)

FreeBSD is not Linux. So what works for Linux is not guaranteed to work for FreeBSD. You assume things are the same when they could be vastly different.


----------



## RalfPeg (Mar 8, 2019)

well i would assume that mmap on /dev/mem does work on freebsd, because afaik mmap is "the" way to access the hardware directly by mmio on unix systems, isn't it? if there are problems the developers should know that there are problems and then they can decide if they care about it or not. or am i wrong?


----------

