Accessing GPIO through mmap


I am trying to control values of GPIO pins from C by writing into memory through mmap, but I reached a dead end and I don’t know what I could be doing wrong.

I read 8KB starting at 0x10005000 and I try to set mode to GPIO (0), direction to OUT (1) and value to 1, but when I try to read the values right after I set it, I get all zeroes, except for direction. When I started, I was successful at writing to values, but now I can’t even do that.

This is (part of) my code

#define BLOCK_SIZE 4096
#define MTK_GPIO_BASE_ADDR 0x10005000
#define MTK_GPIO_DIR 0x00
#define MTK_GPIO_PULLE 0x150
#define MTK_GPIO_DOUT 0x500
#define MTK_GPIO_DIN 0x630
#define MTK_GPIO_MODE 0x760

int pin = 25;
int fd;

if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) {
    printf("Unable to open /dev/mem\n");
    return -1;

if (((int32_t)gpio == -1) || ((int32_t)gpio == -1 )) {
    printf("Failed to initialize mmap\n");
    return -1;


volatile uint32_t *dirAddr = gpio + MTK_GPIO_DIR + 16 * (pin / 16);
*dirAddr = 0x20;

volatile uint32_t *valAddr = gpio + MTK_GPIO_DOUT + 16 * (pin / 16);
*valAddr= 0x20;

The result for this part of code is

direction address: 10005010
direction: 0000010000000000
value address: 10005510
value: 0000000000000000

I calculate address like this

memAddr = addr - gpio + MTK_GPIO_BASE_ADDR

Thanks for any help or hint!

first you write about bpi-r2, right? that matches with gpio-register…but i’m no expert to recalculate the memory address from physical to logical

imho it is not possible to read out values in direction-out-mode…imho only in can be read out can only be set…yes i see in dev-sheet, that the registers are RW…but afair it was not possible to read the value set before

just for (my) reference: starting at page 64

Yes, it is BPI-R2.

I am able to manipulate with the pin 25 through /sys/class/gpio. I need to export pin 257 (232 base + 25 pin) and I have full control, but I cannot read or write anything through the registers directly. I tried to set the pin HIGH and read the INPUT register with C code, but it didn’t show any change. Command cat /sys/class/gpio/gpio257/value showed the correct number (1).

I changed the memory allocation and now I have this.

#define BLOCK_SIZE 4096


Here is how I display (some) values (don’t really know what values these are

printInfo("GPIO Direction Control Register 2: ", *(gpio + (0x10005010U & BLOCK_MASK)));
printInfo("GPIO Mode Control Register 6: ", *(gpio + (0x100057B0U & BLOCK_MASK)));
printInfo("GPIO Pull-up/Pull-down Selection Register 2: ", *(gpio + (0x10005290U & BLOCK_MASK)));
printInfo("GPIO Data Input Register 2: ", *(gpio + (0x10005640U & BLOCK_MASK)));
printInfo("GPIO Data Output Register 2: ", *(gpio + (0x10005510U & BLOCK_MASK)));

GPIO Direction Control Register 2: 0000 0010 0000 0000
GPIO Mode Control Register 6: 0000 0000 0000 0000
GPIO Pull-up/Pull-down Selection Register 2: 0000 0000 0000 0000
GPIO Data Input Register 2: 0100 0000 0001 1101
GPIO Data Output Register 2: 0111 0111 0010 1111

But these values are not correct and don’t represent the pin state.

I don’t need answer, I would be more than happy for some reference, where how’s and why’s would be explained. I couldn’t find anything.

have you verified with devmem2 if the memory-address is right? this does the conversion between logical and physical memory

Thank you! ./devmem2 0x10005510U w 0x200 sets the pin HIGH.

Now I need to find what I am doing wrong…

I finally found the reason why it wasn’t working.

After whole day of trying, it came to this…

Had to change this…

volatile uint32_t *addr = gpio + (offset & BLOCK_MASK) + 16 * (pin / 16);
*addr |= (1u << (pin % 16));

… to this …

uint32_t addr = (uint32_t)gpio + (offset & BLOCK_MASK) + 16 * (pin / 16);
*((volatile uint32_t *)(addr)) |= (1u << (pin % 16));

Can anybody explain the difference please?

i guess difference is the handling of gpio…as it is pointer first uses its value, second uses gpio (the pointer-value itself) for calculate addr