Switching a 5V DC motor with a microbit.

This post shows how to use a BBC microbit to control a 5V fan or DC motor using a FET switch. The circuit shows how we can use a transistor to control a device that needs more current than the microbit can supply.

A demo showcasing the microbit’s sensor technologies was set up in the office I’m lucky enough to loiter in when not working offshore. One of the demos showed how the microbit can detect temperature. When the microbit is heated up above a certain temperature with a hair dryer, the microbit turns on a  fan to cool itself down. The fan is  turned off the fan when the microbit detects that the temperature has fallen below a pre-set threshold. I don’t have much use for a hair dryer nowadays (baldy matt), but I lashed up a little circuit to enable a fan to turn on when a pin on the microbit goes high. I passed this over to the rest of the team who were setting up the demo to add the temperature sensing code.

The problem is that the fan operates at 5V and needs a fair whack of current compared with what we can squeeze out of a microbit pin. The microbit operates from a 3V battery pack. So how do we use the microbit to turn on a device that operates at 5V and enable enough current for the fan?

Short answer, we use a transistor switch. In this case, I used an N-channel FET, specificially a 2N7000. There are other types of transistor that can be used and different arrangements of circuitry, but this is one of the simplest and most reliable setups for this example.

As we are using 5V battery pack for the fan, we can use the same 5V battery pack to connect with the micro USB connector on the microbit. We could use independent 5V and 3V battery packs, so long as the grounds on the battery packs are connected. Being able to have separate battery packs for the microcontroller and the device being powered is an important idea which allows us to switch e.g. 12V devices using the microbit, where you couldn’t share the same power supply between the microbit and the device. The device being powered is often called a ‘load’, as it loads the power supply.

 

Circuit layout of the fan controller. The pins on the FET are labelled.

A drawing of the circuit can be seen above. I used Fritzing to make this. The three pins of the transistor are called ‘source’, ‘gate’ and ‘drain’. The source and drain are named as they are the source and drain for the charge carriers inside the transistor that allow the current – in this case electrons. The gate, is well, a gate, that enables a current through the transistor when it is held at a higher voltage than the drain

The source of the transistor is connected to the negative of the battery pack, as this supplies the electrons that are the charge carrier in this type of transistor. This negative pin on the battery pack is also connected to the ground of the microbit through the USB connector. The drain on the transistor is connected to the negative pin on the DC motor. The positive pin of the motor is connected to the positive pin on the battery. The positive pin on the battery is also connected to the microbit through the USB connector, as the battery pack supplies +5V, which is the same as USB supplies.

Here’s a photo of the device in real life. The blue oblong is a 5V rechargeable USB power pack. The fan is on in the photo. The transistor can be seen as the tiny black think on the breadboard. A green clip connects pad 0 on the microbit to the gate of the transistor. The wiring connecting all the pins between the USB connectors is hidden underneath the connectors as about the only area I am in any way tidy is with wiring.

So how does this the transistor switch work? Many people better than myself have written on this. I’d recommend having a play on the excellent Falstad circuit simulator. Go to ‘circuits’ ‘MOSFETS’ ‘switch’ and click on the little open switch symbol to close it. Watch the flow of charge (the current). I modified and labelled the example circuit to show how the microbit circuit is laid out and put a screen grab below. In the Falstad simulation, the switch connects to the gate pin on the FET to a 3V power rail. This represents pin 0 on the microbit. Pin 0 going high is simulated by closing the switch and connecting the gate of the FET to 3V. Pin 0 going low is simulated by opening the switch and having the gate of the FET go to 0V.

When the gate is connected high, the FET switch is on and allows a current from the drain to the source. When it is not high, the FET will not allow charge to flow. The 5 Ohm resistor represents the load on the circuit, in my case the fan. I don’t know what the resistance of the fan is, but 5 Ohm is good enough for the simulation.

The battery pack is simulated by the +5V power rail which connects to the positive side of the 5 Ohm resistor. So, using a switch from a lower voltage rail, we can control the current supplied by a higher voltage supply. This idea is used in industrial controllers to allow little microcontrollers to operate machinery that runs at a far higher voltage than the microcontroller and used far more current than a microcontroller can supply from its output pins. I put the Falstad code at the bottom of this page. You can copy and paste it into Falstad. Go to ‘File’ ‘Import from text’ and paste in the code.

Falstad simulator FET switch layout.

The +ve on the fan motor is connected to the battery pack’s +ve rail. The -ve on the fan motor is connected to the drain on the FET. When a high voltage is applied to the gate on the FET (3V from the microbit pad 0), the semiconductors inside the FET are put in a state that allows a current through the drain to the source. As the source is connected to ground, there is now a current from the battery through the fan and to ground. So with the gate voltage high, the circuit is complete and the fan can operate. When the gate voltage is not high (pulled to ground by pad 0 on the microbit), the FET’s semiconductors are in a state that will not allow a current through the FET and the fan, so the fan does not operate.

I wrote some micropython code to test it all out. Please find this below. Button A toggles pad 0 on the edge connector high and low. Note that when the microbit is powered on, I set the pad to a known state, in this case low. You should always configure the state of pins that are being used to control devices to a known state at power up. Sometimes when you start up a microcontroller, the pins will go to a state you didn’t anticipate whatever the data sheet says, which could cause whatever you are controlling to turn on or off when you didn’t expect it to. How do you think I found this out?

Here’s the micropython code I used to test the circuit with.

''' Toggle pin0 on button A press. '''

from microbit import *

TOGGLE = False

def display_leds(toggle_flag):
    if toggle_flag:
        display.show(Image.TARGET)
    else:
        display.show(Image.ASLEEP)

def setup():
    write_pin0(0)
    display.show(Image.ASLEEP)

def write_pin0(toggle_flag):
    if toggle_flag:
        pin0.write_digital(1)
    else:
        pin0.write_digital(0)

setup()
while True:
    if button_a.was_pressed():
        TOGGLE = not TOGGLE
        write_pin0(TOGGLE)
        display_leds(TOGGLE)

Here’s the Falstad simulator code. Copy and paste it into the box you get when you click on ‘File’ ‘Import from text’ in Falstad.

$ 1 0.000005 10.634267539816555 50 5 50
s 288 224 288 304 0 0 false
w 288 128 400 128 0
r 400 128 400 288 0 5
w 400 320 400 336 0
f 288 304 400 304 0 1.5 0.02
R 288 128 240 128 0 0 40 5 0 0 0.5
g 400 336 400 352 0
x 432 213 465 216 4 24 fan
x 416 310 534 313 4 24 2n700\sFET
x 139 195 281 198 4 24 microbit\spin\s0
x -7 284 267 287 4 24 switch\sclosed\s\q\spin\s0\shigh
x -6 258 242 261 4 24 switch\sopen\s\q\spin\s0\slow
x 121 112 251 115 4 24 battery\spack
R 272 208 224 208 0 0 40 3 0 0 0.5
w 272 208 288 208 0
w 288 208 288 224 0

Measuring the BBC micro:bit LED current draw

Summary: I looked at the voltage and current supplied to the BBC micro:bit for different numbers of active LEDs. The voltage to the LEDs is pulsed at about 55Hz, with each LED on about 1/3 of the time at maximum intensity. The frequency is high enough that the LED appears continuously lit. The current draw from a single pin is in spec for the microcontroller. The current supplied to each LED decreases as the total number of LEDs being sourced from the same microcontroller pin increases. If the LED ntensity is decreased in code, then the LED is active for a smaller fraction of each voltage cycle.

An interesting question at stackexchange asked how the pins to the microcontroller on the microbit could handle the current to and from all 25 of the LEDs on the board. At first glance, it looks like there are too many LEDs being supplied by too few pins to stay within the 5mA current limit for a single pin on the Nordic nRF51822 microcontroller.

There is a schematic for the microbit board on github. A screenshot showing how the microcontroller pins are connected to the LEDs, taken from sheet 1 and 5 of the github site is shown below.

Microbit schematic showing how the LEDs are connected, taken from the microbit Github site.
Nordic nRF51822 pinout on the microbit from Github, with the pins that connect to the LEDs indicated.

There are three pins called ROW1-ROW3 that supply current to the anodes (the left of the LED symbol) of all 25 LEDs. Pin PO.13 on the microcontroller is connected to ROW1 and supplies 9 LEDs. Pin PO.14 connects to ROW2 and supplies 7 LEDs. Pin PO.15 connects to ROW3 and supplies 9 LEDs. According to the datasheet for the microcontroller, up to 3 pins can supply or sink up to 5mA in 'high-drive' mode. The rest can source or sink 1.5mA each.

The cathode (the bit of the LED connected to the resistor) of each LED is connected to one of nine 220 Ohm resistors. Upto 3 LED cathodes are connected to each resistor. Each of the nine resistors is then connected to a single microcontroller pin, to sink the LED current.

A limit of 5mA from a single pin to source current to 9 LEDs is not a lot. So what is happening? Are the pins being overloaded?

I pulled the C++ microbit compiler code from the lancaster university github. It looks like one row of the microbit display is illuminated at a time and the display constantly scans through the rows.

Anything that turns on and off at a frequency greater than about 15Hz appears as if it is constantly on.

Using a power supply, I measured the current draw with different numbers of LEDs active. The voltage applied was 3.00V from a TTi EX345RD power supply.

The results surprised me:

LEDS current in mA
0         4.74
1         5.79
5         8.63
10      11.31
15      12.75
20      13.45
25      14.01

So about 14.01-4.74 = 9.27mA extra current is being used to supply 25 LEDs.

I used an Analog Discovery 2 with its Wavefroms software to both power the board and as a 'scope. A Fluke multimeter measured the current and was used to verify that the supply voltage stayed constant.

The Analog Discover 2 supply pins were connected to the ground and 3V pin on the edge connector for the microbit. With a supply voltage of 3V from the Analog Discovery 2, I measured 3.001V across the ground and 3V edge connector pins for 1 LED on and 2.994V with all 25 LEDs on, so the voltage drop across the supply pins is 0.2% while increasing the number of active LEDs. Not much of a voltage drop.

With the 'scope, I can see that the voltage to each LED is indeed pulsed. The screen shot taken from the Waveform software below shows what I saw 'scoping the anode of an LED. The red vertical lines show where I measured time intervals. I am fairly sure that I am 'scoping the LED's anthode as I could count 9 of the pins connected to this side of the LED and 3 at the other end. Which agrees with the schematic. Plus I used my Fluke to verify the LED polarity. Matty likes to double check what he is measuring after having made so many, many mistakes over the years.

Voltage on a single LED anode, red lines show where I measured time intervals.

Clearly the current draw I measured from the power supply was showing the average current. The current through the LEDs will vary with the voltage. The resistor is 220 Ohm. The current will be V^2/R, where V is the voltage across the resistor.

The LED voltage at the anode is high for 5.8824ms out of 17.914ms = 32.83% duty cycle. So the pin is high for about 1/3 of the time. This makes sense - one pin out of the three that supply current to the LEDs is active at a time. The pulse frequency is 55.821Hz. So the pulsing is invisible to the eye.

The frequency and pulse widths do not change with the number of LEDs that are on. What does change is the anode and cathode amplitude. This drops as the number of LEDs on increases. The supply voltage to the microbit stayed almost constant though.

The image below shows the anode voltage on two separate supply pins, showing that they are indeed turned on at different times. Should I have three probes, the gap would be filled in by 'scoping the pin supplying the third row of LEDs.

Voltage on the anodes for two LEDs supplied by different pins.

With no LEDs on, the voltage rail was 3.0200 on the 'scope. Fair enough. That's pretty much the supply rail. With all LEDs on, I measured two voltages, 2.0896V and 2.1640V. If you've been paying attention, it won't be a suprise that the higher voltage occurs on 7 LEDs (ROW2 on the schematic) and the lower on the remaining 18 (ROW1 and ROW3 on the schematic).

Let's look at the cathode of one of the LEDs. A screen grab is shown below. With a single lit LED, the cathode is at 3V for 2/3 of the time as the sink pin goes high to prevent current, from, well, being sinked. When it goes low, current can flow from through the LED and the resistor and back to ground through the microcontroller pin. Thus completing the circuit and allowing the LED to light up. When the current is flowing, the voltage drops at the cathode. In this screen grab, with only 3 LEDs active, I measured 912.34mV at the cathode of the lit LED. Which makes for a current of 0.91234^2/220 = 3.78mA through the single LED and resistor. Note: I had the LEDs set on maximum intensity.

Voltage on an LED cathode when only one LED is active. Maximum LED intensity. x-axis: one square is 5ms.

What is interesting, is that the low value of the cathode voltage decreases with an increasing number of lit LEDs. So the current flowing through the LED must similarly decrease. So the voltage and thus current decreases with increasing lit LEDs, which means that the brightness also decreases. Similarly, the fraction of time that the cathode is high also decreases as the number of active LEDs increases, which makes sense, as for a greater fraction of the time the multiplexed cathode will be sinking current.

With all LEDs on, I measure 356.81mV for 1/3 of the time and 292.46mV for 2/3 of the time. Can you guess why the voltage is stepped between the two values? I suspect it as the voltage switches between supplying 9 and 7 LEDs. Please see the two 'scope grabs below.

Cathode voltage, all LEDs active. Maximum intensity. x-axis: one square is 5ms.
Cathode voltage, all LEDs active. Maximum intensity. zoomed. x-axis: one square is 5ms.

The human eye is not so good at discerning different light intensities. I think that having a bunch of LEDs not so brightly lit as a single one also helps fool the eye in judging their individual brightness.

With all LEDs on, the maximum current flow through the 220 Ohm resistor for the pin supplying 7 LEDs is 0.35681^2/220 = 0.5787mA. So for 7 LEDs, the total draw is 4.05mA.

For the 9 LED pins, the current per LED is 0.29246^2/220 = 0.3888mA. So for 9 LEDs, this is 3.499mA, again inside the 5mA spec for a single 'high-drive' pin to supply. However, the pin is only active for about 1/3 of the time. So the average current flow per LED will be 1/3 of the above values.

The current sinking into the pins that sink current is within the 1.5mA spec for a non 'high-drive' pin.

Lets look at all 25 LEDs active. About (7 x 0.5787 x 1/3)+ (9 x 0.3888 x 2/3) is being drawn at any instant. Which is 4.125mA. I measured an increase of around 9mA with all LEDs active. Hmmm, where does the extra current go? I'm open to suggestions. I've gone down the rabbit-hole with this. Time to move onto something else.

Ta-daaaaaaa.

An obvious question is: How do the traces look when the intensity changes? I edited the code shown at the end of the article to have the minimum LED intensity. Prior to this, I'd had everything set at maximum intensity.

Looking at the 'scope, the anode voltage stayed the same as for when we have maximum intensity - it is high for about 1/3 of the time for any given LED. Below see the cathode voltage for minimum intensity, all LEDs lit and a repeat of the image for when the LED intensity is maximum. We can see that the cathode voltage goes low, which allows current to flow, for much less of the cycle when the intensity is at a minimum. Which makes sense. At maximum intensity, current flows for almost all of the time that the anode voltage is high (about 1/3 of the time). I measured the cathode coming low for only 32.637us at minimum intensity, which is only about 0.18% of the illumination cycle, compared with the roughly 32% of the time when at maximum intensity.

Microbit LED cathode voltage, all LEDs lit, minimum intensity. x-scale: one square is 5ms.
Microbit LED cathode voltage, all LEDs lit, maximum intensity. x-scale: one square is 5ms.

I work at sea for half of the year, on a six week on, six week off rota. I first looked at this while I was on a survey ship, with limited test equipment and time as I am paid to do 12 hour shifts, that usually over run. Obviously, the ship would stop operating if Little Matty was not at his station when he is supposed to be.

I found a voltage supply on the ship, lashed this up to the microbit with a set voltage of 3.00V and measured the current draw through a Fluke multimeter for different numbers of LEDs. What I did not have access to was a 'scope. So I finished off my investigations when I was back home.

Looking at the display through a digital camera - I could see that the LED brightness is not constant. The frame rate of the digital camera is not synced with the refresh rate of the display, so as the rows are switched on and off, this is picked up as a variation in intensity in the camera display.

So even without a 'scope, I was pretty sure that the rows were being pulsed on and off. Actually, there is a 'scope on the ship, but as it is connected to the recording equipment to monitor all is well, I figured I should leave it in place.

Here's my micropython script to turn on/off one LED at a time using the A/B buttons:

#
''' Light LEDs using A and B buttons. '''
from microbit import *

# intensity of LED
BRIGHT = '9'
# how many LEDs to turn on at a time
INCREMENT = 1
# maximum number of LEDs allowed on at once
MAX_BRIGHT = 25
# how many LEDs on at boot
START_BRIGHT = 3


def decrease(num_bright, inc):
    num_bright = limit(num_bright-inc, MAX_BRIGHT)
    return num_bright


def increase(num_bright, inc):
    num_bright = limit(num_bright+inc, MAX_BRIGHT)
    return num_bright


def leds_string2(bright):
    ''' return led string '''
    bright = limit(bright, MAX_BRIGHT)
    leds_string = BRIGHT*bright + '0' * (MAX_BRIGHT-bright)
    leds_string = ":".join(leds_string[i:i+5]
                           for i in range(0, len(leds_string), 5))
    leds_image = Image(leds_string + ':')
    return leds_image


def limit(val, limit):
    ''' limit <val> between 0 and <limit>'''
    if val > limit:
        val = 0
    if val < 0:
        val = MAX_BRIGHT
    return int(val)


num_bright = START_BRIGHT
while True:
    if button_a.was_pressed():
        num_bright = (decrease(num_bright, INCREMENT))
    if button_b.was_pressed():
        num_bright = (increase(num_bright, INCREMENT))
    display.show(leds_string2(num_bright))
    sleep(0.1)
Experimental kludge.

Real time accelerometer display from three BBC Micro:bits

I submitted an article to Circuit Cellar magazine on how I get real time data display from three BBC Micro:bits real time. Please find a video showing this in action below. On the screen to the right of the juggling clown, you can see the accelerometer data. Each BC Micro:bit has a three axis accelerometer in it. For each Micro:bit I get the average from all three axis as a single value. On the screen three are three traces, one for each Micro:bit. As the boards are juggled, the accelerometer values are sent by radio to a receiver Micro:bit connected to the computer. This Micro:bit acts as a go-between for the juggled Micro:bits and the computer. The accelerometer data is plotted real time using a script I wrote in Python, using the pyqtgraph library.

Using udev to remove the need for sudo with the BBC Micro:bit

A comment on this post hinted that there is a way to remove the need to use ‘sudo’ when interacting with the BBC Micro:bit on Linux. So I left a comment asking how to do this, which the author kindly answered:

The way to make sure there is no need for root permissions to access USB device (like connected MicroBit) is by creating a file into `/etc/udev/rules.d/` directory with proper config. For Microbit this could be like this:

SUBSYSTEM=="usb", ATTR{idVendor}=="0d28", ATTR{idProduct}=="0204", MODE="0666"
and then restarting udev system with:
sudo udevadm control --reload-rules

So I created the file /etc/udev/rules.d/microbit.rules with the above code and it works!

I fired up pyocd to enable command line programming of the BBC Micro:bit without needing to use sudo. See this page for more details on programming the BBC Micro:bit from the command line and using pyocd to help with this.

Zombie BBC Micro:bit serial ports created when using pyocd-gdbserver –persist

So I was happily using pyocd-gdbserver to program and enter debugging mode on a BBC Micro:bit attached to one of my laptop’s USB port, as described here. Then I stopped being able to read data through the USB port… Long story short, multiple ‘zombie’ ports were created and my Python script was connecting to a zombie instead of the live one.

setserial -g /dev/ttyACM*

output:

/dev/ttyACM0, UART: unknown, Port: 0x0000, IRQ: 0, Flags: low_latency
/dev/ttyACM1, UART: unknown, Port: 0x0000, IRQ: 0, Flags: low_latency

Sometimes for fun, I would also see a ttyACM2. Why would two ports have the same Port number? The answer is they don’t. They are the same port. Connecting to /dev/ttyACM1 got me nothing. Connecting to /dev/ttyACM0 got me connected to the BBC Micro:bit. I had set the pyocd-gdb utility running using:

sudo ~/.local/bin/pyocd-gdbserver -t nrf51 -bh -r --persist

I think that the –persist flag does the damage. Run the script without this and I think we are good to go. I altered my serial port script to flag up when more than one Micro:bit is found. For good measure, I sort the ports into reverse order and connect to the first one with the PID and VID for the Micro:bit, which will be the lowest numbered ttyACM port. This is a work around when zombies appear.

Please find my Python 3 serial_port.py script for finding and returning a serial port connection to a BBC Micro:bit below.

import logging
import serial
import serial.tools.list_ports as list_ports
from time import sleep

BAUD = 115200
PID_MICROBIT = 516
VID_MICROBIT = 3368
TIMEOUT = 0.1

logging.basicConfig(level=logging.DEBUG, format='%(message)s')


class SerialPort():
    def __init__(self, pid=PID_MICROBIT, vid=VID_MICROBIT, baud=BAUD, timeout=TIMEOUT):
        self.serial_port = self.open_serial_port(pid, vid, baud, timeout)


    def count_same_ports(self, ports, pid, vid):
        ''' Count how many ports with pid and vid are in <ports>. '''
        return len([p for p in ports if p.pid==pid and p.vid==vid])


    def get_serial_data(self, serial_port):
        ''' get serial port data '''
        inWaiting = serial_port.inWaiting()
        read_bytes = serial_port.readline(inWaiting)
        if not read_bytes:
            return
        return read_bytes.decode()


    def get_serial_port(self):
        ''' Return the serial port. '''
        return self.serial_port


    def open_serial_port(self, pid=PID_MICROBIT, vid=VID_MICROBIT, baud=BAUD, timeout=TIMEOUT):
        ''' open a serial connection '''
        print('looking for attached microbit on a serial port')
        # serial = find_comport(pid, vid, baud)
        serial_port = serial.Serial(timeout=timeout)
        serial_port.baudrate = baud
        ports = list(list_ports.comports())
        print('scanning ports')
        num_mb = self.count_same_ports(ports, pid, vid)
        logging.info('{} microbits found'.format(num_mb))
        if num_mb>1:
            logging.info('**** check for false connections ****')
        ports.sort(reverse=True)
        for p in ports:
            print('pid: {} vid: {}'.format(p.pid, p.vid))
            if (p.pid == pid) and (p.vid == vid):
                print('found target device pid: {} vid: {} port: {}'.format(
                    p.pid, p.vid, p.device))
                serial_port.port = str(p.device)
        if not serial:
            print('no serial port found')
            return None
        try:
            serial_port.open()
            serial_port.flush()
            print('opened serial port: {}'.format(serial))
        # except (AttributeError, SerialException) as e:
        except Exception as e:
            print('cannot open serial port: {}'.format(e))
            return None
        # 100ms delay
        sleep(0.1)
        return serial_port


if __name__ == '__main__':
    print('instatiating SerialPort()')
    serial_port = SerialPort()
    print('finished')

Eclipse, yotta, C/C++ and the BBC Micro:bit

With the help of the excellent instructions at the link below I set up Eclipse with yotta to compile C code for the BBC Micro:bit under Linux:
http://flames-of-code.netlify.com/blog/microbit-cpp-3/
I get the debugger window to come up, but have not yet used this feature in anger.
The writer, achary, clearly knows more about Eclipse and embedded programming than I do. I got a little stuck at a couple of stages so created this page to pass on my solutions.

The offline C compiler for the BBC Micro:bit is developed at Lancaster University. Installing the yotta compiler and downloading example files is explained here.

The rest of this article assumes you followed the instructions on this installation guide and have cloned the microbit-samples directory. I assume that you have Eclipse installed, either the C/C++ installation or you have installed the C/C++ development environment.

Installing yotta

Instructions for installing yotta can be found in the yotta documentation here. Note that yotta is designed for Python2.7 only. I used pip to install yotta to my user directory, using the –user flag. Then I started getting errors:

‘module’ object has no attribute ‘X509_up_ref’

I faffed around upgrading my cryptography library as mentioned in the yotta documentation. Long story short, the recently installed ‘yotta’ and ‘yt’ commands in ~/.local/bin/yt and ~/.local/bin/yotta both referred to python 3. I probably did something sometime to cause this. To fix the error I changed ~/.local/bin/yt and ~/.local/bin/yotta from:

#!/usr/bin/python3.6

import yotta
yotta.main()

To:

#!/usr/bin/python2.7

import yotta
yotta.main()

Get yotta to work in debug mode

Using yotta with the –debug-build flag allows for easier debugging. By default, the code is compiled in an optimised mode which makes debugging harder. I need all of the help that I can get, so would like to use this flag. The command to run yotta with the –debug-build flag  is:

yotta build --debug-build

However, this will throw an error and the last line of the build will give the erro:

ninja: build stopped: subcommand failed.

I am not sure what a ninja is doing in my system. If I could see him, I would probably already be dead.

To fix this error, the ‘-fomit-frame’ flag needs adding at two places in the file yotta_targets/mbed-gcc/CMake/Platform/mbedOS-GNU-C.cmake in your microbit-samples directory.

The two changes to mbedOS-GNU-C.cmake are:

line 21 from:
set(CMAKE_C_FLAGS_DEBUG_INIT “-g -gdwarf-3”)
to:
set(CMAKE_C_FLAGS_DEBUG_INIT “-g -gdwarf-3 -fomit-frame-pointer”)
line 28 from:
set(CMAKE_ASM_FLAGS_DEBUG_INIT “-g -gdwarf-3”)
to:
set(CMAKE_ASM_FLAGS_DEBUG_INIT “-g -gdwarf-3 -fomit-frame-pointer”)

Then remove the build directory in the microbit-samples directory and rebuild using:

yotta build --debug-build

If you don’t remove the old build directory directory, then the command will still fail. I know this.

Install pyOCD

We use the pyOCD tool to help debug and program the microbit. Details of this tool are on its github page.

‘pyOCD is an Open Source python 2.7 based library for programming and debugging ARM Cortex-M microcontrollers using CMSIS-DAP. Linux, OSX and Windows are supported.’

Note the ‘python 2.7’ bit. Initially I pip installed it, which defaulted to a python 3 install. The install worked, but when I came to try running pyocd, I got a  bunch of assertion errors. So I read the instructions…

To ensure that pyocd is installed using python2.7, I used:

pip2 install --pre -U --user pyocd

–pre # ‘Include pre-release and development versions. By default, pip only finds stable versions.’ from https://pip.pypa.io/en/stable/reference/pip_install/#install-pre
-U # same as –upgrade ‘Upgrade all specified packages to the newest available version.’
–user # libraries go to the user directory. In linux, this removes the need for sudo to install, which is a security issue.

Plug in your microbit.

Now we fire up a gdbserver using the newly installed pyocd. What is a gdbserver? This wikipedia page explains that ‘gdbserver is a computer program that makes it possible to remotely debug other programs.’

sudo ~/.local/bin/pyocd-gdbserver -t nrf51 -bh -r

-t # target (nrf51 is the chipset used on the microbit).
-bh # replace software breakpoints with hardware breakpoints.
-r # halt the target when reset.

I get this output:

INFO:root:DAP SWD MODE initialised
INFO:root:ROM table #0 @ 0xf0000000 cidr=b105100d pidr=2007c4001
INFO:root:[0]&amp;lt;e00ff000: cidr=b105100d, pidr=4000bb471, class=1&amp;gt;
INFO:root:ROM table #1 @ 0xe00ff000 cidr=b105100d pidr=4000bb471
INFO:root:[0]&amp;lt;e000e000:SCS-M0+ cidr=b105e00d, pidr=4000bb008, class=14&amp;gt;
INFO:root:[1]&amp;lt;e0001000:DWT-M0+ cidr=b105e00d, pidr=4000bb00a, class=14&amp;gt;
INFO:root:[2]&amp;lt;e0002000:BPU cidr=b105e00d, pidr=4000bb00b, class=14&amp;gt;
INFO:root:[1]&amp;lt;f0002000: cidr=b105900d, pidr=4000bb9a3, class=9, devtype=13, devid=0&amp;gt;
INFO:root:CPU core is Cortex-M0
INFO:root:4 hardware breakpoints, 0 literal comparators
INFO:root:2 hardware watchpoints
INFO:root:Telnet: server started on port 4444
INFO:root:GDB server started at port:3333

There is a way to set up a file in udev to remove the need to use sudo to run pyocd. Please see this link on how to do this.

The guide I read recommended using the –persist flag with the pyocd-gdbserver command. I found my serial port communication with the Micro:bit stopped working. Instead of there being a single serial port connection to the Micro:bit, there were several. I suspect the –persist flag kept ‘zombie’ connections alive, causing my code to connect to a dead connection that only existed in the OS’ imagination.

–persist # keep GDB server running even after remote has detached.

As awac explains, this shows that we have access to 4 hardware breakpoints. The server is started at port 3333. This port will be entered into the Eclipse debugger setup, which is explained below.

Set up Eclipse

http://flames-of-code.netlify.com/blog/microbit-cpp-3/ covers setting up a C/C++ Eclipse project with the microbit-samples code downloaded from the Lancaster University github. I am using Eclipse Oxygen at the time of writing this post.

A new project is set up by using File, New, Makefile Project with Existing Code.

Alter the default build command from ‘make’ to ‘yotta build –debug-build’. Get to this by right clicking on the microbit-samples project and selecting ‘Properties’.

Use control-B to build the code. I get a bunch of depreciation warnings that can be ignored.

dynamic exception specifications are deprecated in C++11 [-Wdeprecated]

Configuring the Eclipse C/C++ debugger for use with yotta

The pyOCD site mentions that the plugin ‘Eclipse Embedded Systems Register View’ should be installed. This took me a little while to figure out how to install, so I created a separate post on how to do this here. This plugin is not yet of use for the microbit. I hope to get CMSIS-SVD configuration files from Nordic for the microbit’s microcontroller to be able to make use of the plugin.

I came a little unstuck when setting up the debug session as I could not find the ‘GDB Hardware Debugging’ option when editing my debug configuration. To get that option we need to install the GNU MCU Eclipse plugin from the Eclipse Marketplace. Go to the Help menu and click on ‘Eclipse Marketplace’. Put ‘gnu mcu’ as the search term to find the plugin. This plugin adds the ‘GDB Hardware Debugging’ option to your run configurations which we use when setting up Eclipse.

This allows me set up for the GDB debugger as shown in the screen shots below. Go to Run, Debug configurations.

Double clicking on the heading ‘GDB Hardware Debugging’ and set up the Main, Debugger and Startup tabs as shown below. The C/C++ application is found in the ‘build’ subdirectory, in the microbit-samples directory at:

microbit-samples/build/bbc-microbit-classic-gcc/source/microbit-samples

The Debugger tab specifies the path to the GDB :

/usr/bin/arm-none-eabi-gdb

Enter port ‘3333’, which we noted earlier when starting the gdb server.

In the Startup tab, click on ‘Load image’ and ‘Use File’. Enter

${workspace_loc:/microbit-samples/build/bbc-microbit-classic-gcc/source/microbit-samples-combined.hex}

Initially I had some errors:

Reset command not defined for device 'Generic TCP/IP'

Looking at this Stackoverflow question, I fixed this by also unchecking Reset & Delay and Halt options in the debugger configuration:

Running the Eclipse debugger

Run the command ‘yt clean’ from the command line in your microbit-samples directory to clean out the last build. Then ‘control-b’ in Eclipse to create a fresh build. I feel I should be able to click on the little bug icon on the menu bar to get to the debugger, but this gives me a ‘launch failed. Binary not found.’ window. So I right click on the project and select ‘Debug As’,’Debug Configurations’, ‘microbit-samples Default’ then click on the ‘Debug’ button on the bottom right. I get offered the chance to go to the debug screen, which is a result.

Bash script to mount and unmount a BBC Micro:bit

I develop using the BBC Micro:bit (which I’ll call a microbit from now on) using Linux. To get a new hex file on to the microbit, the microbit has to be mounted on to the file system. Which may seem obvious. But the microbit has a habit of unmounting itself after being programmed. Or not mounting when it is plugged in. So I wrote a script to make things easier. Because I can. To be more accurate, I copied a script from Stackoverflow and made a few minor modifications. Don’t pretend this isn’t how you have written a lot of your scripts.
Find the code at the bottom of this post. Copy and paste it to a file called microbit_manage.sh. Make the file executable (chmod +x ./microbit_manage.sh) and run using either ‘mount’ or ‘unmount’ as an argument. I’ve got these aliased to ‘mm’ and ‘md’ in my .bashrc.

Example usage:

bill@bill ~ $ microbit_manage.sh mount

found one MICROBIT, device: /dev/sdb
MICROBIT was unmounted
Mounted /dev/sdb at /media/bill/MICROBIT.

bill@bill ~ $ microbit_manage.sh unmount

found one MICROBIT, device: /dev/sdb
MICROBIT was mounted
Unmounted /dev/sdb.

Comments and improvements welcome. The script is:

#!/bin/bash
# microbit_manage.sh
# mount and unmount microbit
# modified from https://askubuntu.com/questions/342188/how-to-auto-mount-from-command-line
# v1.0 matt oppenheim October 2017

BASEPATH="/media/$(whoami)/"
MICRO="MICROBIT"

if [ $# -eq 0 ]
then
    echo "no argument supplied, use 'mount' or 'unmount'"
    exit 1
fi

if [ $1 == "--help" ]
then
    echo "mounts or unmounts a BBC micro:bit"
    echo "args: mount - mount the microbit, unmout - unmount the microbit"
fi

# how many MICRO found in udiksctl dump
RESULTS=$(udisksctl dump | grep IdLabel | grep -c -i $MICRO)

case "$RESULTS" in

0 )     echo "no $MICRO found in 'udkisksctl dump'"
        exit 0
        ;;

1 )     DEVICELABEL=$(udisksctl dump | grep IdLabel | grep -i $MICRO | cut -d ":" -f 2 | sed 's/^[ \t]*//')
        DEVICE=$(udisksctl dump | grep -i "IdLabel: \+$DEVICELABEL" -B 12 | grep " Device:" | cut -d ":" -f 2 | sed 's/^[ \t]*//')
        DEVICEPATH="$BASEPATH""$DEVICELABEL"
        echo "found one $MICRO, device: $DEVICE"

        if [[ -z $(mount | grep "$DEVICE") ]]
        then
            echo "$DEVICELABEL was unmounted"
            if [ $1 == "mount" ]
            then
                udisksctl mount -b "$DEVICE"
                exit 0
            fi
        else
                echo "$DEVICELABEL was mounted"
                if [ $1 == "unmount" ]
                then
                    udisksctl unmount -b "$DEVICE"
                    exit 0
                fi
        fi
        ;;

* )     echo "more than one $MICRO found"
        ;;

    esac

echo "exiting without doing anything"

Prior to mounting the microbit, running the command:

gvfs-mount –list
Should return a bunch of stuff, with a block like this in it:

Drive(1): MBED DAPLINK VFS
  Type: GProxyDrive (GProxyVolumeMonitorUDisks2)
  Volume(0): MICROBIT
    Type: GProxyVolume (GProxyVolumeMonitorUDisks2)

This shows that the microbit is connected, but not mounted or usable by the file system.

After mounting the microbit using the above script, running:

gvfs-mount --list
Should return something like:

Drive(1): MBED DAPLINK VFS
  Type: GProxyDrive (GProxyVolumeMonitorUDisks2)
  Volume(0): MICROBIT
    Type: GProxyVolume (GProxyVolumeMonitorUDisks2)
    Mount(0): MICROBIT -&gt; file:///media/bill/MICROBIT
      Type: GProxyMount (GProxyVolumeMonitorUDisks2)

Showing that the microbit is now mounted

Getting the BBC Micro:bit radio to work with the mbed online C/C++ compiler

This blog explains how to get the example programs for working with the non-Bluetooth radio on the BBC Micro:bit to compile correctly using the Mbed online C/C++ compiler.

Short story

Two options:

1 Place the line:

#define MICROBIT_BLE_ENABLED 0

in the MicroBit.h library and forget about the config.json file.

Or

2 Create an mbed_app.json file instead of the config.json file with this content:

{
"macros": [ "MICROBIT_BLE_ENABLED=0" ]
}

Long story

 
The Mbed online compiler and the yotta offline compiler for the BBC Micro:bit are explained at the Lancaster University github site here:

https://lancaster-university.github.io/microbit-docs/

I couldn’t get the example radio programs supplied with the online Mbed C/C++ compiler to work with the BBC Micro:bit. These programs did work with the yotta offline compiler. It took a while to figure out that the config.json file supplied with the examples is being ignored by the Mbed online compiler. The BBC Micro:bit has a custom radio setup which does not work when Bluetooth is enabled. The compiler needs to be told that Bluetooth is disabled. In the examples supplied for both the yotta offline compiler and for the mbed online compiler this is done using a config.json file containing:

{ 
    microbit-dal:{
        bluetooth:{
            enabled: 0 
        } 
     } 
}

The example programs are called simple-radio-rx and simple-radio-tx. For the Mbed online compiler, these can be found at:

https://os.mbed.com/teams/microbit/code/microbit-simple-radio-rx/

https://os.mbed.com/teams/microbit/code/microbit-simple-radio-tx/

For the offline yotta compiler the same programs and config.json files can be found at:

https://github.com/lancaster-university/microbit-samples/tree/master/source/examples

The hex files created using the Mbed online compiler resolutely refused to do anything when I loaded them onto the microbits. I figured out that the the config.json file was being ignored by the Mbed online compiler. To disable the Bluetooth through code, place this line:

#define MICROBIT_BLE_ENABLED 0

in the MicroBit.h library. After doing this, the hex files produced by compiling the example programs using the Mbed online compiler ran correctly.

I posted this on the Mbed questions site and an Mbed moderator said that the issue will be fixed:

https://os.mbed.com/questions/79592/BBC-Microbit-how-to-use-the-radio/?compage=1#c29069

A while later, a helpful guy on Stackoverflow advised me to use an mbed_app.json file instead of the config.json file with this content:

{
    "macros": [ "MICROBIT_BLE_ENABLED=0" ]
}

Setting up yotta and C with the BBC Micro:bit by modifying the examples directory

I set up to program the BBC Micro:bit (which I’ll call the microbit from now on) in C/C++ under Linux. I’ve been using micropython to program the boards up to now, but want to leverage the increased performance that using C can give and some of the C libraries that are available for e.g. encryption.

There is good documentation on the Lancaster University microbit github page:

https://lancaster-university.github.io/microbit-docs/

I installed the offline tools as I spend a lot of time working at sea where you can’t always rely on having an internet connection. I got a demo compiled and loaded by following the instructionso n the Lancaster University github site. Now it was time to write my own code. I had a little trouble getting this going, so here’s what I had to do to get my first program compiled and loaded. I did this by modifying the structure of the examples directory that was created by following the github instructions.

I downloaded the github repository linked above into

~/git/microbit-samples

Initially I made a new directory under:

~/git/microbit-samples/source/my_code

Whenever I ran ‘yt build’, I got a weird error referring to one of the bluetooth example programs. Plus yt build took longer than I thought it ought to. So…..

Move

~/git/microbit-samples/source/examples

out of:

~/git/microbit-samples/source/

Put these folders one level above this folder. Only put the main.cpp file into

~/git/microbit-samples/source/

Then run:

yt clean

and

yt build

I copied the file:

~/git/microbit-samples/build//bbc-microbit-classic-gcc/source/microbit-c-combined.hex

to the microbit. After waiting for the flashing LEDs to stop, it worked!

The microbit unmounts itself each time that you load a new hex file. So using the bash script that I detailed in an earlier blog to quickly mount the microbit is a time saver.

This is a quick way of getting started by building on top of the examples directory that most folk will start with.

disclaimer: I loiter in the same department as the authors of the C/C++ BBC Micro:bit repository.

Enabling the analog to digital converter (ADC) on the BBC Micro:bit using C/C++

To get the example ADC code to work on the Lancaster Github site, change the line:

MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);

To:

MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ANALOG);

I tested this using both the online Mbed compiler and the yotta compiler.