Article Index

The framework makes working with the GPIO and other devices as easy as it can be but there are many layers of software to go through before you get to the hardware. Writing directly to the hardware can make things up to ten times faster and give you access to things that their framework doesn't. It is also an educational experience to deal with the raw hardware directly.

Now On Sale!

You can now buy a print edition of micro:bit IoT in C.

You can buy it from:

USA and World


 The full contents can be seen below. 

Chapter List

  1. Getting Started With C/C++
    Anyone who wants to use the BBC micro:bit to its full potential as an IoT device needs to look outside the coding environments provided by its own website. As an mbed device, however, the micro:bit  is capable of being programmed in C/C++. Here we look at how to use the mbed online compiler for a simple demo program.

  2. Offline C/C++ Development  
    We have already discovered how to use the online editor to create a C/C++ program. Now we are going to move to the desktop with an offline approach. This has the advantage that we can use any tools we care to select and no Internet connection is needed.
  3. First Steps With The GPIO 
    The most basic task when working with the micro:bit is controlling the I/O lines. This isn't difficult if you use the framework provided but there some subtle points to watch out for. This chapter looks a the basics of using the GPIO.

  4. Working Directly With The Hardware - Memory Mapping. 
    The framework makes working with the GPIO and other devices as easy as it can be but there are many layers of software to go through before you get to the hardware. Writing directly to the hardware can make things up to ten times faster and give you access to things that their framework doesn't. It is also an educational experience to deal with the raw hardware directly.

  5. Pulse Width Modulation, Servos And More
    In this chapter we take a close look at pulse width modulation PWM including, sound, driving LEDs and servos.

  6. I2C
    The I2C bus is one of the most useful ways of connecting moderately sophisticated sensors and peripherals to the any processor. The only problem is that it can seem like a nightmare confusion of hardware, low level interaction and high level software. There are few general introductions to the subject because at first sight every I2C device is different, but here we present one.

  7. I2C Temperature Measurement
    Using I2C devices is fairly easy once you have successfully used one - and hence know what information you need and what to look for in a working system. In this chapter we use the HTU21D temperature and humidity sensor as a case study of I2C in action. It also happens to be a useful sensor.

  8. A Custom Protocol - The DHT11/22

  9. The DS18B20 - One Wire Bus

  10. The SPI Bus
    The SPI bus can be something of a problem because it doesn't have a well defined standard that every device conforms to. Even so if you only want to work with one specific device it is usually easy to find a configuration that works - as long as you understand what the possibilities are. 

  11. SPI MCP3008/4 AtoD   
    The SPI bus can be difficult to make work at first but once you know what to look for about how the slave claims to work it gets easier. To demonstrate how its done let's add eight channels of 12 bit AtoD using the MCP3008.

  12. Serial Connections
    The serial port is one of the oldest of ways of connecting devices together but it is still very, very useful. The micro:bit has a single serial interface but it can be directed to use any of the GPIO piins as Rx and Tx. 

  13. WiFi 
    The micro:bit has a radio that works in Bluetooth LE and point-to-point ad-hoc mode, but at the moment it lacks WiFi connectivity. The solution is to use the low cost ESP8266 to make the connection via the micro:bit's serial port. 

  14. LED Display 
    The micro:bit's LED display may only be 5x5 but it is very versatile. If you want to make use of it directly then you are going to have to master some lower level functions.


All of the peripherals that are directly connected to the processor are memory mapped. What this means is that there are a set of addresses that correspond to "registers" that control and give the devices status. Using these is just a matter of knowing what addresses to use and what the format of the registers is. 

Easy to say - slightly more difficult to get right. 

However after you have got it right you can't understand what the fuss was about.

The best way to understand how all of this works is to find out about a particular peripheral - the GPIO.

The GPIO Registers

If you look at the manual for the RF51 series processor you will find a long section on the registers that are connected to the GPIO lines. This looks very complicated but in fact it comes down to a very simple pattern.

There are 32 GPIO lines, not all usable on the micro:bit. For each GPIO line there is a single configuration register i.e. 32 registers one for each line. 

There is also a single 32 bit OUT register that is used to set each output line to high or low - each bit corresponds to the state of one line. 

There is a single 32 bit IN register that will read the state of all 32 GPIO lines i.e. one bit per line. 

In theory these are the only registers you need to know about to use the GPIO lines but there are five more provided to make things easier. 

There is an OUTSET and OUTCLR register. If you write to either register then the lines that correspond to one bits are set or cleared according to which register you write to. 

Why is this useful?

The simple answer is that you can use OUTSET and OUTCLR to set or clear any GPIO lines without changing the state of the others. 

For example suppose you want to set GPIO Pin0 to a one then you would write 0x01 to the OUT register. However this has also set all of the other 31 pins to zero. If you write 0x01 to the OUTSET register then you set Pin 0 high and leave all of the others in their current state. Similarly writing 0x01 to OUTCLR sets Pin 0 low and leaves the other in their current state. 

You can see that OUTSET and OUTCLR make things much easier. 

There is also a 32 bit DIR register which can be used to set any combination of pins to input or output depending on whether you write a zero or a one to the corresponding bit location. 

Similar to the case of the OUT register there is a DIRSET and DIRCLR register. These either set the GPIO line to output or input when you write a one to the corresponding bit location. 

The reason for the existence of DIRSET and DIRCLR is just to make it easier for you to set lines to input or output without altering what the remaining lines are set to. The situation is exactly the same as the OUT, OUTSET and OUTCLR registers. Writing 0x01 to DIR will set Pin 0 to output but all of the remaining 31 pins to input. Writing 0x01 to DIRSET will set only Pin 0 to output and writing it to DIRCLR will set only Pin 0 to input. 

This will all become clear after a few examples. 

To summarize the registers controlling the GPIO lines are

OUT   set the any combination of GPIO lines high or low
OUTSET set any combination of GPIO lines high
OUTCLR set any combination of GPIO lines low

IN  read the state of all GPIO lines

DIR     set the I/O direction of any combination of GPIO lines
DIRSET set any combination of GPIO lines to output
DIRCLR set any combination of GPIO lines to input

PIN_CNF[n] 32 configuration registers one for each GPIO line

Of course we need to know which bits in the configuration register controls what aspect of the GPIO line. 

0         DIR          0=input 1=output
1         INPUT     0=disconnect input  1=connect input
3,2      PULL       00= No Pull, 01=Pull Down, 11=Pull Up
10,9,8 DRIVE    000 S0S1
                          001 H0S1
                          010 S0H1
                          011 H0H1
                          100 D0S1
                          101 D0H1
                          110 S0D1
                          111 H0D1
17,16   SENSE  00=diabled, 01=High, 11= Low

Most of these will be easy to understand. You already know about DIR and PULL from the previous chapter and DRIVE was mentioned in passing. To understand DRIVE all you really need to know is that there are two possibilities for the pushpull transistor arrangement:

The two transistors can either be Standard drive i.e. 0.5mA or High drive 5mA. The bottom transistor pulls the output low to give a zero and the top transistor pulls the output high to give a one. Hence a DRIVE or S0H1 has a high drive for the top transistor and a standard for the bottom. That is the GPIO line can sink 0.5mA and supply 5mA to a load. The D in the specification simply means Disconnected i.e. there is no transistor in that position in the drive. So H0D1 has the pull up transistor missing giving an open collector drive. 

In most cases you either want S0S1 or H0H1 - the others are for special situations. 

The INPUT bit simply disconnects the input buffer is you set it to one. The reasons for wanting to do this are to reduce the loading and decouple input from output. 

The SENSE bits control when the pin will contribute to generating a DETECT signal. This is used to bring the processor out of power saving mode and in more complex ways to automatically trigger other actions. You can ignore this for the moment. 

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

The answer is surprisingly well spaced out in memory - the processor has a very big address space. The GPIO registers occupy a block of memory starting at 0x50000000 and the register addresses are specified as offsets from this starting point in two blocks:

OUT              0x504
OUTSET       0x508
OUTCLR       0x50C

IN                  0x510

DIR               0x514
DIRSET        0x518
DIRCLR        0x51C

PIN_CNF[n]  0x700 +4*n