Where Are The Registers?

The only question we have to answer now is where are the registers?

This turns out to be a difficult question to answer because the processor implement memory mapping which essentially means that any physical address can appear almost anywhere in the memory map of a running program. 

All of the peripheral registers including the GPIO registers we have been describing are in a block of memory  0x2000 0000 to 0x20FF FFFF acording to the documentation but this has been changed to 0x3F00 0000 for the Pi 2 and 3 which is a source of much confusion. 

So in the PI 1 the peripheral registers start at 0x2000 0000. For a Pi 2 and later the registers start is indicated by the contents of a file setup by the Linux Device Tree. So to find out where the registers are you have to read:

/proc/device-tree/soc/ranges

which contains three four byte values the address of the start of the memory, the second byte and its size,. the third byte. In practice reading the file returns 0x3F00 0000 for a Pi 2 and 3 but this could change in the future.

The best way to discover where the perhiperhal registers are located is to try to read the file and use the default 0x2000 0000 if it isn't present. For example:

bcm2835_peripherals_base=  0x20000000;  
int fp;
if ((fp = fopen("/proc/device-tree/soc/ranges" , "rb")))
{
  unsigned char buf[8];
 if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf))
 bcm2835_peripherals_base = 
  (uint32_t *)(buf[4] << 24 |
               buf[5] << 16 | 
               buf[6] << 8  | 
               buf[7] << 0);
    fclose(fp);
    }

 

In practice it is easier to rely on the bcm2835 library and the 

bcm2835_peripherals_base 

variable which is set to the start of the peripherals area when you initialize the library - i.e. it is set correctly for all Pis. 

The register addresses can be specified as offsets from bcm2835_peripherals_base but it is easier to take the offsets from where the first register belonging to the device is.

So for the GPIO the first GPIO register is at 0x20 0000, which is BCM2835_GPIO_BASE  in the bcm2835 library

That is the starting address of the GPIO registers is given by:

gpio address  =bcm2835_peripherals_base +
                               BCM2835_GPIO_BASE

‚ÄčThe offsets for each of the registers from this address is

0x0000 GPFSEL0 GPIO Function Select 0 
0x0004 GPFSEL1 GPIO Function Select 1 
0x0008 GPFSEL2 GPIO Function Select 2 
0x000C GPFSEL3 GPIO Function Select 3
0x0010 GPFSEL4 GPIO Function Select 4
0x0014 GPFSEL5 GPIO Function Select 5
   
0x001C GPSET0 GPIO Pin Output Set 0
0x0020 GPSET1 GPIO Pin Output Set 1
   
0x0028 GPCLR0 GPIO Pin Output Clear 0
0x002C GPCLR1 GPIO Pin Output Clear 1 32 W
   
0x0034 GPLEV0 GPIO Pin Level 0
0x0038 GPLEV1 GPIO Pin Level 1
   
0x0040 GPEDS0 GPIO Pin Event Detect Status 0
0x0044 GPEDS1 GPIO Pin Event Detect Status 1
   
0x004C GPREN0 GPIO Pin Rising Edge Detect Enable 0
0x0050 GPREN1 GPIO Pin Rising Edge Detect Enable 1
0x0058 GPFEN0 GPIO Pin Falling Edge Detect Enable 0 
0x005C GPFEN1 GPIO Pin Falling Edge Detect Enable 1
0x0064 GPHEN0 GPIO Pin High Detect Enable 0
0x0068 GPHEN1 GPIO Pin High Detect Enable 1
0x0070 GPLEN0 GPIO Pin Low Detect Enable 0
0x0074 GPLEN1 GPIO Pin Low Detect Enable 1
0x007C GPAREN0 GPIO Pin Async. Rising Edge Detect
0x0080 GPAREN1 GPIO Pin Async. Rising Edge Detect 1
0x0088 GPAFEN0 GPIO Pin Async. Falling Edge Detect 0
0x008C GPAFEN1 GPIO Pin Async. Falling Edge Detect 1
   
0x0094 GPPUD GPIO Pin Pull-up/down Enable
0x0098 GPPUDCLK0 GPIO Pin Pull-up/down Enable Clock 
0x009C GPPUDCLK1 GPIO Pin Pull-up/down Enable Clock

 

The only registers missing from this list are the PAD control registers and these are located in a different area of memory at:

BCM2835_GPIO_PADS=bcm2835_peripherals_base+BCM2835_GPIO_PADS
                 =0x20100000 or
                 =0x3F100000 for Pi2

And the offsets are:

0x002c PADS0 (GPIO 0-27)
0x0030 PADS1 (GPIO 28-45)
0x0034 PADS2 (GPIO 46-53)

You can work out the address of any register listed in the documentation by finding the base address for the registers and adding its offset. 

It is worth knowing that you can use

cat /proc/iomem

to discover where devices are in memory. On a Pi 2 you will see:

00000000-3affffff : System RAM
  00008000-007e641f : Kernel code
  0085e000-0098c1ab : Kernel data
3f006000-3f006fff : dwc_otg
3f007000-3f007eff : /soc/dma@7e007000
3f00b840-3f00b84e : /soc/vchiq
3f00b880-3f00b8bf : /soc/mailbox@7e00b800
3f200000-3f2000b3 : /soc/gpio@7e200000
3f201000-3f201fff : /soc/uart@7e201000
  3f201000-3f201fff : /soc/uart@7e201000
3f202000-3f2020ff : /soc/sdhost@7e202000
3f980000-3f98ffff : dwc_otg