2

I'm implementing a pascal library to deal with RPI3 peripherals. My goal is to control GPIO pins' functions, pins' logical levels, pins' pull resistors, I2C and PWM, at least.

To achieve this I'm studying some well known C libraries, like WiringPi and examples available at http://abyz.me.uk/rpi/pigpio/examples.html

Everything seems fine, but I'm not sure about the way I'm doing the mapping. Following the Tiny GPIO example I understand that, using /dev/gpiomem, I do not need to use any offset, because /dev/gpiomem is at zero offset of GPIO already (?):

fd = open("/dev/gpiomem", O_RDWR | O_SYNC) ;
gpioReg = (uint32_t *)mmap(NULL, 0xB4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

Using this approach I'm able to control GPIO pins' functions, the pins' logical levels and pins' pull resistors perfectly.

Now I will try to implement the PWM and to do so, I'm studying the WiringPi way. Again I'm looking how the WiringPi does the mapping and It is different from the Tiny GPIO example:

fd = open ("/dev/gpiomem", O_RDWR | O_SYNC | O_CLOEXEC) );

// Set the offsets into the memory interface.

GPIO_PADS     = 0x00100000;
GPIO_CLOCK_BASE = 0x00101000;
GPIO_BASE     = 0x00200000;
GPIO_TIMER    = 0x0000B000;
GPIO_PWM      = 0x0020C000;

// Map the individual hardware components

gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);
pwm = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PWM);
clk = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_CLOCK_BASE);
pads = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PADS);
timer = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_TIMER);

(The above is the resulting code used by WiringPi. Some conditions and constants was removed to ensure readability)

As you can see, even using /dev/gpio mem, the WiringPi implementation is using offsets. Even to access the gpio there are one offset and my question is: how could this work?

Sumarizing, I have two implementations:

// The Tiny GPIO way (and the way I'm using)
(uint32_t *)mmap(NULL, 180, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

The WiringPi way
(uint32_t *)mmap(NULL, 4096 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x00200000);

(Again, above, some constants was replaced by its values to ensure readability)

Both implementations works, but I don't know why. I'm not sure of the behaviour of mmap function, because the offset seems to be irrelevant to GPIO but relevant to another peripherals.

OBSERVATIONS:

I got the WiringPi sources from git and I'm compiling and debugging it step by step to see what is being done. By debugging I could see that running my example program without root privileges leads the WiringPi to load and map the /dev/gpiomem using an (unnecessary?) offset. And worst, after that, it is maping the PWM and another things that could not be done from /dev/gpiomem

1

/dev/gpiomem only gives access to the GPIO register addresses.

To gain access to the PWM registers you need to use /dev/mem which requires root access.

If you try to access hardware PWM with wiringPi you need to be running as root. If you run the program without being root it will crash.

Have a look at Minimal GPIO Access for an example of accessing the other hardware registers. That will be similar to your wiringPi example. It also requires root access.

  • Hi @joan, I'm using these examples. In fact, I'm using the Tiny GPIO example that uses /dev/gpiomem and it is working very well without root access. Thanks for your answer! Now I know that I cannot use the /dev/gpiomem to access PWM, but unfortunatelly, this is not the answer for my current main question: why the WiringPi way of mapping, even using the /dev/gpiomem, uses an offset and it works? Form me, on using /dev/gpiomem, the offset used on mmap would be zero. And this is correct, cuz all my current implementations using /dev/gpiomem with zero offset is working perfectly! – Carlos Feitoza Filho Jun 20 at 21:17
  • I answered the topic question. You can't use /dev/gpiomem to access the other peripherals. As to the mmap the difference seen to be the tiny GPIO example maps the minimal needed amount of register memory. There are only 180 bytes (45 longs) of GPIO register memory. – joan Jun 20 at 21:24
  • Please see my last edit (Observations) and try to explain that. In fact, using the "stock" WiringPi library, I CAN use PWM without any root access. You said one thing, but another is occurrying. Despite this, however, I insist, my question is about how could the mapping of /dev/gpiomem works with an offset if my implementation do not uses it and works perfectly. Read the entire question text. – Carlos Feitoza Filho Jun 20 at 21:39
  • 2
    No you can't use hardware PWM in wiringPi without root privileges. You are using software PWM. – joan Jun 20 at 21:56
  • about pwm, my apologies. You was right. I'm so upset about these memory offsets and its using with the mmap function that I ended confusing the things. No HW-PWM without root privileges. Now, I only want to know about the use of offsets when using /dev/gpiomem, just like my text explains. – Carlos Feitoza Filho Jun 21 at 2:09
0

As Joan said on Raspberry Pi Forums:

mmap expects you to be using the /dev/mem device where offsets mean something.

The /dev/gpiomem device (as written) ignores any offset and always grants access to the GPIO register area

I would to read this mmap exceptional behaviour directly on its man pages :/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.