GPIO set/clear with mmap

88 Views Asked by At

Because sysfs is too slow I tried set/clear with direct memory access. It is a IMX6. The gpios used are here

cat /sys/kernel/debug/gpio

gpiochip4: GPIOs 128-159, parent: platform/20ac000.gpio, 20ac000.gpio:
 gpio-136 (                    |sysfs               ) out lo    
 gpio-137 (                    |sysfs               ) out lo    
 gpio-138 (                    |sysfs               ) out lo    
 gpio-139 (                    |sysfs               ) out lo    
 gpio-140 (                    |sysfs               ) out lo    
 gpio-141 (                    |sysfs               ) out lo    
 gpio-142 (                    |sysfs               ) out lo    
 gpio-143 (                    |sysfs               ) out lo    
 gpio-144 (                    |sysfs               ) out lo    
 gpio-145 (                    |sysfs               ) out lo  

So I map the physical 0x020ac000 into the virtual address space.

#define GPIO_BASE_ADDR_4    (0x020ac000)
volatile unsigned *gpio_reg; 
void* gpio_map;
int mem_fd;

mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
if(mem_fd < 0) {
    printf("ERROR could not open gpio mapping");
    exit(1);
}

gpio_map = mmap(NULL, 
                getpagesize(), 
                (PROT_READ | PROT_WRITE), 
                MAP_SHARED, 
                mem_fd, 
                GPIO_BASE_ADDR_4);

close(mem_fd);

if(gpio_map == MAP_FAILED) {
    printf("ERROR could not open gpio mapping");
    exit(1);
}

gpio_reg = (volatile unsigned *)gpio_map;

and set/clear the value. e.g. gpioNr is 137 -> (gpioNr-128) = 8. This would be the 8th line in the gpiochip4.

void clear(int gpioNr) {
    *(gpio_reg+0x190) = 1<<(gpioNr-128);
}

void set(int gpioNr) {
    *(gpio_reg+0x194) = 1<<(gpioNr-128);
}

The program is executed with root privileges. GPIO are exported and set to output at start with sysfs.

  • is the mapping correct? did I miss some additional spacing or alignment issues
  • is the data register not correct?

Edit 2023-07-05 11:30

Output is now working better. GPIOs are used for a NHD-14432WG LCD display. Some areas are correctly displayed (about 50-70%) the rest is filled with artifacts. Before I used sysfs, there the output was correct but very slow refresh rates.

void clear(int gpioNr) {
    int reg_index = (gpioNr - 128) / 32;
    int bit_pos = (gpioNr - 128) % 32;
    gpio_reg[reg_index] &= ~(1 << bit_pos);

} 
void set(int gpioNr) {
    int reg_index = (gpioNr - 128) / 32;
    int bit_pos = (gpioNr - 128) % 32;
    gpio_reg[reg_index] |= (1 << bit_pos);
}
0

There are 0 best solutions below