Modifying registers from user space

Madhura Gandhi
I want to write to a physical address to change the voltage of a pin using
an ARM board- but in order to write to a physical address, I need to take a
virtual address, and map it to the physical address using mmap. So I did
that, in this way:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

int main(void) {
int fd;
int *map_base_c,*map_base_d, *map_base_p, *virt_addr;
off_t target,control,data,pullup;

control=0x56000050;

if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;

map_base_d = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd,data
& ~MAP_MASK);

printf("Memory mapped at address %p.\n", map_base_d);

virt_addr = map_base_d; //+ (data & MAP_MASK)
*virt_addr = 0x00;  //This is where it goes off. find out why!!!
printf("Value at address 0x%X (%p): 0x%X\n", data, virt_addr,(*virt_addr));

close(fd);
return 0;
}

But, The pin didn't get a high voltage as I'd expected. Is there something
wrong with the way I'm changing the address? 

Also, is there a way to see the physical address which was mapped to the
virtual address? Thanks!

Juergen
Seems you want to write to the GPFCON register at the physical address
0x56000050.

What about:

static uint32_t read_reg32(const void *p)
{
    const uint32_t *r = (const uint32_t*)p;
    return *r;
}

static void write_reg32(void *p, uint32_t v)
{
    uint32_t *r = (uint32_t*)p;
    *r = v;
}

int main(....)
uint32_t gpfcon:
void *map_base_d;
[...]
gpfcon = read_reg32(map_base_d + 0x56000050);
write_reg32(map_base_d + 0x56000050, gpfcon);

Madhura Gandhi
It is giving me a segmentation fault when I reach this particular line : 

    gpfcon = read_reg32(map_base_d + 0x56000050);

Why have you added 0x56000050 to the map_base_d? 
I am not getting any warnings or errors at compile time so I am not sure
where the problem is.

Madhura Gandhi
The problem seems to be at this step :

gpfcon = read_reg32(map_base_d + 0x56000050);

This gives me a segfault when I run it

What I had done in the previous code that didn't work was

gpfcon = map_base_d + (0x56000050 & MAP_MASK)

where MAP_MASK was 0xfff. Actually, I am not sure why this would even work.

This doesn't give a segfault but it doesn't work either!

Madhura Gandhi
I got the GPIO access. Thanks!
Here's the code if anyone is interested.
I'm controlling port GPF0 and making it blink.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>


#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n",
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)
#define USR1_LED (1<<22)

int main(int argc, char *argv[]) {
  volatile void *gpio_addr_c = NULL;
  volatile void *gpio_addr_p = NULL;
  volatile void *gpio_addr_d = NULL;
  volatile unsigned int *gpio_oe_addr_c = NULL;
  volatile unsigned int *gpio_oe_addr_p = NULL;
  volatile unsigned int *gpio_oe_addr_d = NULL;
  unsigned int reg;
  off_t control,data,pullup;  
  int fd = open("/dev/mem", O_RDWR);
  
  control  = 0x56000050;
  data     = 0x56000054;
  pullup   = 0x56000058;

  printf("Mapping %x \n", control);

  gpio_addr_c = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
(control& ~MAP_MASK));

  gpio_oe_addr_c = gpio_addr_c + (control &MAP_MASK);

  if(gpio_addr_c == MAP_FAILED) {
    printf("Unable to map GPIO\n");
    exit(1);
  }
  printf("GPIO mapped to %p\n", gpio_addr_c);
  printf("GPIO OE mapped to %p\n", gpio_oe_addr_c);

  reg = *gpio_oe_addr_c;
  printf("GPIO1 configuration: %X\n", reg);
  reg = reg & (0xFFFFFFFF - USR1_LED);
  *gpio_oe_addr_c = 0x5555;
  printf("GPIO1 configuration: %X\n", *gpio_oe_addr_c);



  gpio_addr_p = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
(pullup & ~MAP_MASK));

  gpio_oe_addr_p = gpio_addr_p + ( pullup &MAP_MASK);

  if(gpio_addr_p == MAP_FAILED) {
    printf("Unable to map GPIO\n");
    exit(1);
  }
  printf("GPIO mapped to %p\n", gpio_addr_p);
  printf("GPIO OE mapped to %p\n", gpio_oe_addr_p);

  reg = *gpio_oe_addr_p;
  printf("GPIO1 configuration: %X\n", reg);
  reg = reg & (0xFFFFFFFF - USR1_LED);
  *gpio_oe_addr_p = 0xff;
  printf("GPIO1 configuration: %X\n", *gpio_oe_addr_p);



  gpio_addr_d = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (
data& ~MAP_MASK));

  gpio_oe_addr_d = gpio_addr_d + ( data &MAP_MASK);

  if(gpio_addr_d == MAP_FAILED) {
    printf("Unable to map GPIO\n");
    exit(1);
  }
  printf("GPIO mapped to %p\n", gpio_addr_d);
  printf("GPIO OE mapped to %p\n", gpio_oe_addr_d);

  reg = *gpio_oe_addr_d;
  printf("GPIO1 configuration: %X\n", reg);
  reg = reg & (0xFFFFFFFF - USR1_LED);
  *gpio_oe_addr_d = 0xfe;
  printf("GPIO1 configuration: %X\n", *gpio_oe_addr_d );

  
  printf("Start blinking LED USR1\n");
  while(1) {
    printf("ON\n");
    *gpio_oe_addr_d= 0xfe;
    sleep(1);
    printf("OFF\n");
    *gpio_oe_addr_d = 0xff;
    sleep(1);
  }
  
  close(fd);
  return 0;
}