Hello, world

This is my first post, and the topic is (of course) “Hello, world.”

Raspberry Pi

I’ve been working with Raspberry Pi (RPI) these days. The motivation is to acquire the sense of how OS is composed of and how it works. On the course of my learning, the first thing I did was to lit a LED, which is attached to the board –– so to speak Hardware Hello World. Here I used Raspberry Pi model B+, which has a ARMv6 processor.

There are two steps to go:

  1. Configure the LED pin to be output mode
  2. Turn the output pin for LED on

I only focus on relevant codes, and omit entire topics about how to build and run. Please refer the following sites to follow them.

How to handle hardware

Before diving into the practice, I want to introduce how we can control hardwares first.

Each hardware has its own memories called “registers”. There are two types of registers: data register which holds actual data, and control register; the aggregation of flags which changes hardware’s behaviours.

What we want to do is control these registers by coping only with CPU. There seems to be several approaches for this, and the RPI’s way is to map hardware registers to its memories so called Memory Mapped IO. By this way, we can manage the state of hardware registers by reading/writing memory as we usually do with load/store instructions against CPU. The biggest advantage of this method is its simplicity; we don’t need to learn another instructions only to manage hardwares. Thus, the question we need to answer to turn the LED on is “What are the addresses of these registers on memory?”

As RPI is very versatile and can handle various kinds of hardware resources, there is general pins, 53 in total, called GPIO. LED is assigned one of these pins, and its number is 47 (for RPI B+). So, the above question is paraphrased to another question: “Where are the 47th GPIO registers on memory?”

The answer can be found by looking up the ARM’s peripheral references, which states all the hardware specs. The topics about GPIO start from page 89, and according to it, its address starts from 0x20200000¹. The registers we want to use to lit the LED is called GPSEL to set pin mode and GPSET to turn on the light. Now, let’s get started.

Hello, world

I put the entire codes first.

void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags)
{
(void) r0;
(void) r1;
(void) atags;

*(volatile uint32_t *) 0x20200010 = (1 << 21);
*(volatile uint32_t *) 0x20200020 = (1 << 15);

while (1) {
}
}

1/ Configure the LED pin to be output mode

GPIO has registers to manage pin mode called GPSEL. Each pin on GPIO is given three bits. Because there are 53 pins in total on GPIO as I said, and one register has only 32 bits, these bits are separated into six registers (GPSEL0 ~ GPSEL 5), and each of them manages ten pins. Here, our target pin is 47th, which means they’re GPSEL4 register’s 21st ~ 23rd bits, and we want to set 47th pin output mode: the value is0b001. As GPSEL4 is on 0x20200010 according to the reference, the code should look like this:

*(volatile uint32_t *) 0x20200010 = (0b001 << 21);

(volatile is used to tell the compiler NOT to change this value for optimisations.)

2/ Turn the output pin for LED on

We use GPSET registers to hoist the output bit of GPIO pins. There are two GPSETs; GPSET0 is for pins 0 ~ 31, and GPSET1 is for pins 32 ~ 53. Again, our pin is 47th, which is GPSET1’s 15th bit.

*(volatile uint32_t *) 0x20200020 = (1 << 15);

If you build and run it on a device, you’ll be able to see the LED is on.

References

Extra: Flashing

You may want to turn OFF the light as well. It’s pretty much the same as turning on the light, and the only difference is the register to work with. We use GPCLR register to switch off the light, and the address for GPCLR1 is 0x2020002C.

*(volatile uint32_t *) 0x2020002C = (1 << 15);

With delay function which loops CPU for specified cycles:

// FROM https://jsandler18.github.io/tutorial/boot.html
void delay(int32_t count)
{
asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n"
: "=r"(count): [count]"0"(count) : "cc");
}

you can see the flashing light. The entire codes would be as follows.

void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags)
{
(void) r0;
(void) r1;
(void) atags;

*(volatile uint32_t *) 0x20200010 = (1 << 21);

while (1) {
*(volatile uint32_t *) 0x20200020 = (1 << 15);
delay(500000);
*(volatile uint32_t *) 0x2020002C = (1 << 15);
delay(500000);
}
}

¹ You may wonder because it says 0x7E200000 not 0x20200000. The trick is it’s in the different memory space, and we have to use the value on physical address. (see the diagram on the references’ page 5.)

--

--