title: WRITE and READ memory mapped device registers in Linux on ARM
body: <p>I am trying to read and write registers on my ARM9 (SAM9X25) following those steps : <a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3750.html" rel="nofollow noreferrer">http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3750.html</a><br>I ended with the following code :</p>
  
  <pre><code>#include "stdio.h"
  
  #define PIO_WPMR_BANK_D                     0xFFFFFAE4  // PIO Write Protection Mode Register Bank D
  #define PIO_PUER_BANK_D                     0xFFFFFA64  // PIO Pull-Up Enable Register Bank D
  #define PIO_PUSR_BANK_D                     0xFFFFFA68  // PIO Pull-Up Status Register Bank D
  
  #define MASK_LED7                           0xFFDFFFFF  // LED7 Mask
  #define DESABLE_WRITE_PROTECTION_BANK_D     0x50494F00  // Desable write protection Bank D
  
  int main(void) {
      printf("test");
      unsigned int volatile * const register_PIO_WPMR_BANK_D = (unsigned int *) PIO_WPMR_BANK_D;
  
      unsigned int volatile * const register_PIO_PUSR_BANK_D = (unsigned int *) PIO_PUSR_BANK_D;
  
      unsigned int volatile * const port_D = (unsigned int *) PIO_PUER_BANK_D;
  
      *register_PIO_WPMR_BANK_D = DESABLE_WRITE_PROTECTION_BANK_D;
  
      *port_D = *register_PIO_PUSR_BANK_D &amp; MASK_LED7;
  
      return 0; }
  </code></pre>
  
  <p><br>I cross compiled my code in Ubuntu 16.04 like so <code>arm-linux-gnueabi-gcc gpio.c -o gpio</code> <br>But I have a <code>Segmentation Fault</code> just after the <code>printf</code> during the execution of the program on my board. <br> I know the addresses are right... So why do I have this error?<br>Is it the good way ?<br>Thank you for your help !</p>
  
  <p><strong>SOLUTION :</strong><br>
  Thank you to @vlk I could make it work ! Here is a little example for toggling a LED :</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;sys/mman.h&gt;
  #include &lt;fcntl.h&gt;
  
  
  #define handle_error(msg) \
             do { perror(msg); exit(EXIT_FAILURE); } while (0)
  
  #define _PIOD_BANK_D                            0xA00
  
  #define _PIO_OFFSET                             0xFFFFF000
  
  /* When executing this on the board :
      long sz = sysconf(_SC_PAGESIZE);
      printf("%ld\n\r",sz);
     We have 4096.
  */
  #define _MAP_SIZE                           0x1000  // 4096 
  
  #define _WPMR_OFFSET                        0x0E4   // PIO Write Protection Mode Register Bank D
  
  #define _PIO_ENABLE                         0x000
  #define _PIO_DISABLE                        0x004
  #define _PIO_STATUS                         0x008
  #define _OUTPUT_ENABLE                      0x010
  #define _OUTPUT_DISABLE                     0x014
  #define _OUTPUT_STATUS                      0x018
  #define _FILTER_ENABLE                      0x020
  #define _FILTER_DISABLE                     0x024
  #define _FILTER_STATUS                      0x028
  #define _OUTPUT_DATA_SET                    0x030
  #define _OUTPUT_DATA_CLEAR                  0x034
  #define _OUTPUT_DATA_STATUS                 0x038
  #define _PIN_DATA_STATUS                    0x03c
  #define _MULTI_DRIVER_ENABLE                0x050
  #define _MULTI_DRIVER_DISABLE               0x054
  #define _MULTI_DRIVER_STATUS                0x058
  #define _PULL_UP_DISABLE                    0x060
  #define _PULL_UP_ENABLE                     0x064
  #define _PULL_UP_STATUS                     0x068
  #define _PULL_DOWN_DISABLE                  0x090
  #define _PULL_DOWN_ENABLE                   0x094
  #define _PULL_DOWN_STATUS                   0x098
  
  #define _DISABLE_WRITE_PROTECTION           0x50494F00  // Desable write protection
  
  #define LED_PIN                                 21
  
  int main(void) {
  
      volatile void *gpio_addr;
      volatile unsigned int *gpio_enable_addr;
      volatile unsigned int *gpio_output_mode_addr;
      volatile unsigned int *gpio_output_set_addr;
      volatile unsigned int *gpio_output_clear_addr;
      volatile unsigned int *gpio_data_status_addr;
      volatile unsigned int *gpio_write_protection_addr;
  
      int fd = open("/dev/mem", O_RDWR|O_SYNC);
      if (fd &lt; 0){
          fprintf(stderr, "Unable to open port\n\r");
          exit(fd);
      }
  
  
      gpio_addr = mmap(NULL, _MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, _PIO_OFFSET);
  
  
      if(gpio_addr == MAP_FAILED){
          handle_error("mmap");
      }
  
  
      gpio_write_protection_addr = gpio_addr + _PIOD_BANK_D + _WPMR_OFFSET;
  
      gpio_enable_addr = gpio_addr + _PIOD_BANK_D + _PIO_ENABLE;
  
      gpio_output_mode_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_ENABLE;
  
      gpio_output_set_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_SET;
  
      gpio_output_clear_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_CLEAR;
  
      gpio_data_status_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_STATUS;
  
  
      *gpio_write_protection_addr = _DISABLE_WRITE_PROTECTION;
  
      *gpio_enable_addr = 1 &lt;&lt; LED_PIN;
      *gpio_output_mode_addr = 1 &lt;&lt; LED_PIN; // Output
  
  
      // If LED
      if((*gpio_data_status_addr &amp; (1&lt;&lt;LED_PIN)) &gt; 0){
          *gpio_output_clear_addr = 1 &lt;&lt; LED_PIN;
      }else{
          *gpio_output_set_addr = 1 &lt;&lt; LED_PIN;
      }
  
      return 0;
  }
  </code></pre>
  
  <p><strong>EDIT :</strong><br>
  Answer for the <strong>3)</strong> in the comments. You have to change the mmap and the assignations like so if you want it to work with all the offsets (i.e : <a href="http://man7.org/linux/man-pages/man2/mmap.2.html" rel="nofollow noreferrer">mmap example</a>):</p>
  
  <pre><code>#define _PIO_OFFSET                         0xFFFFFA00 // Instead of 0xFFFFF000
  #define _MAP_SIZE                           0x1000  // 4096 
  #define _MAP_MASK                           (_MAP_SIZE - 1)
  #define _PA_OFFSET                          _PIO_OFFSET &amp; ~_MAP_MASK
  </code></pre>
  
  <p>And the mmap :</p>
  
  <pre><code>gpio_addr = mmap(NULL, _MAP_SIZE + _PIO_OFFSET - _PA_OFFSET, PROT_READ | PROT_WRITE, MAP_SHARED, fd, _PA_OFFSET);
  </code></pre>
  
  <p>And for the assignation :</p>
  
  <pre><code>gpio_enable_addr = gpio_addr + _PIO_OFFSET - (_PA_OFFSET) + _PIO_ENABLE;
  </code></pre>