Sunday, September 23, 2012

How to set GPIO on Raspberry PI in assembly

How to set GPIO on Raspberry PI in assembly.

While reading the nice free courses 'Baking Pi: Operating Systems Development by Alex Chadwick' that explain how to write your own OS for your raspberry Pi, I couldn't figure out how the setup of the GPIO pins was done. I was able to copy the code from the lesson and thus to make it work on my raspberry PI but I wanted to understand what I was doing. For the people who also want a better understanding of how you can use the GPIO pins on the raspberry PI I'll share my findings.

As explained in the OK1 course the GPIO pins our grouped by 10 and there are 3 bits per GPIO pin to select its function. On page 90 of the Soc_pheripherals manual you can see what these 3 bits do:

000 = GPIO Pin 9 is an input 
001 = GPIO Pin 9 is an output 
100 = GPIO Pin 9 takes alternate function 0 
101 = GPIO Pin 9 takes alternate function 1 
110 = GPIO Pin 9 takes alternate function 2 
111 = GPIO Pin 9 takes alternate function 3 
011 = GPIO Pin 9 takes alternate function 4 
010 = GPIO Pin 9 takes alternate function 5

(This is a small extract of the BCM2835 ARM Peripherals manual.  Copyright is property of Broadcom corporation). 

In the course we want to set the 16th pin to an output pin so we need to write 001 to the 3 bits corresponding with the 16th pin.

When we make a drawing of the bits (starting from the GPIO address, so our bit 0 is address 0x20200000 in the tutorial). We get the following layout:

The upper row denotes the bit numbers. The second row will number the bytes and in the 3th row we mark the pin that corresponds with the bits. As explained in the course lesson, there corresponds 10 pins with 4 bytes.

The 4th row illustrates what happens if we write value one to 0x20200000.

ldr r0,=0x20200000
mov r1,#1
str r1,[r0]

The 5th row illustrates what happens if we write the shifted register to 0x20200000

ldr r0,=0x20200000
mov r1,#1
lsl r1,#18
str r1,[r0]

The 6th row shows the bits that are written when we write to [r0+4]. Because ARM uses a byte aligned layout the word will be written to bytes 4-7. So the full code part from the course lesson will give the result shown in row 7. The code fragment from the lesson was:

ldr r0,=0x20200000
mov r1,#1
lsl r1,#18
str r1,[r0,#4]

Next we need to now how to set the pin on (LED OFF) and how to set it off (LED ON).

The pin is cleared by writing a 1 to the relevant bit This is done using address 0x 7E20 0028 [GPCLR0] ( see Soc-Peripherals page 90). This word will be used for setting pins 0-31 , the next word will be for pins 32-54.

As denoted in the course we need to set the pin to 0 to set voltage high (led ON). We write a 1<<16 to the address 0x7E200028. But 0x28 = 40 so this gives the following to activate the LED:

mov r1,#1
lsl r1,#16
str r1,[r0,#40]

GPIO Pin Output set Register to set the pin on (LED OFF). This is done using address 0x 7E20 001C [GPSET0] ( see Soc-Peripherals page 90). This word will be used for setting pins 0-31 , the next word will be for pins 32-54.

Now we will set the 16th bit for the address with offset 0x1C = 28. This results in the code

mov r1,#1
lsl r1,#16
str r1,[r0,#28]

So now that you know this, you should head back to http://www.cl.cam.ac.uk/freshers/raspberrypi/tutorials/os and continue the courses. I think they are very good and it is good that the authors are so generous to share them for free with the rest of the world!