Logic level converter between an Arduino Uno and micro:bit using a FET transistor


We can use a single FET transistor with two resistors to make a two way logic level converter to interface e.g. Arduino Uno and a micro:bit.

The problem

I need to interface a micro:bit to an Arduino Uno, connecting the RX and TX pins of the Arduino to tabs on the edge connector of the micro:bit. The Arduino Uno has 5V logic levels. The micro:bit has 3V logic levels. The 5V signals from the Arduino Uno may damage the micro:bit.

The setup may well work without the logic level converter. However, the input pins on the micro:bit are not rated for more than 3.9V. So, applying the 5V signal levels from the Arduino is out of spec, meaning that the micro:bit could fail at any time. Or fail a little bit, just enough to corrupt your data occassionally, leaving you chasing Heisenbugs.

A solution

I need a logic level converter. This sits inbetween the Arduino Uno and the micro:bit boards and converts the signal levels so that each board receives the logic levels it works at.

How a logic level converter works

I learned about how logic level converters work from an excellent article in Circuit Cellar by Robert Lacoste. You can read this article for free by opening a free account on the website here. The simplest bi-directional logic level converter in the Lacoste article uses a single field-effect transistor with two 2.2K Ohm resistors. This circuit is simulated below.

Simulation of the FET based logic level converter using Falstad

I use the free online circuit simulation tool Falstad to simulate the device. Go to the site, then click on File, Import from Text. Copy and paste this text in to the text box and click OK.

$ 1 2e-8 21.593987231061412 50 5 50 5e-11
r 256 272 256 352 0 2200
r 464 272 464 352 0 2200
f 368 320 368 368 32 1.5 0.02
w 256 352 256 368 0
w 256 368 352 368 0
w 464 352 464 368 0
w 464 368 384 368 0
w 256 272 256 256 0
w 256 256 368 256 0
w 368 256 368 320 0
R 160 368 96 368 0 2 10000 2.5 2.5 0 0.5
w 160 368 256 368 0
R 256 256 176 256 0 0 40 3 0 0 0.5
R 464 256 560 256 0 0 40 5 0 0 0.5
w 464 256 464 272 0
403 640 352 768 416 0 6_64_0_4099_5_0.003125_-1_2_6_3
w 464 624 464 640 0
R 464 624 560 624 0 0 40 5 0 0 0.5
R 256 624 176 624 0 0 40 3 0 0 0.5
R 496 736 544 736 0 2 10000 2.5 2.5 0 0.5
w 368 624 368 688 0
w 256 624 368 624 0
w 256 640 256 624 0
w 464 736 384 736 0
w 464 720 464 736 0
w 256 736 352 736 0
w 256 720 256 736 0
f 368 688 368 736 32 1.5 0.02
r 464 640 464 720 0 2200
r 256 640 256 720 0 2200
w 496 736 464 736 0
403 32 672 160 736 0 26_64_0_4099_5_0.0015625_-1_2_26_3
207 464 368 528 368 4 High\slevel\slogic
207 256 736 176 736 4 Low\slevel\slogic
403 32 288 160 352 0 11_64_0_4099_5_0.00625_-1_2_11_3
403 512 656 640 720 0 30_64_0_4099_5_0.00625_-1_2_30_3
x 157 222 687 225 4 24 Low-level\slogic\sinput,\shigh-level\slogic\soutput
x 131 587 658 590 4 24 High-level\slogic\sinput,\slow-level\slogic\soutput

You should see this circuit:

One note about Falstad - the app can suck up a lot of the CPU and ramp up the CPU temperature.

The 'scopes shows voltage in green and current in brown at the same time. We are interested in the green voltage levels.

There are two circuits shown. These show the same logic level converter circuit but with the inputs and outputs reversed.

The top circuit shows a 3V signal, simulated by a 10kHz square wave, from the simulated low-level logic device converted to a 5V signal.

The bottom circuit shows a 5V signal input to the right side of the circuit and a 3V signal output from the left.

So the logic level converter simulates correctly for an input signal to either side.

I use 2.2K resistors in the simulated circuit as this is what the boards I received use. Lacoste uses 2.2K resistors in his example.

Explanation of the simulated FET circuit

The FET is called an n-type FET as it uses an n-type semiconductor channel to transmit charge through the component. This channel is incomplete unless the gate has a positive bias compared with the source. Then current can flow along the completed channel. This current flow is shown as animated dots in Falstad. If you hover your cursor over the FET symbol, the gate, drain and source terminals show up as G, D and S. This gate-source bias needs to be above a threshold level for the semiconductor channel to complete and for current to flow. This is a pretty sketchy summary. There are lots of good YouTube videos explaining how a FET works with great animations I wish I'd had access to in the Chibanian when I studied this.

The FET gate is permanently held high by the low level side of the logic converter, in this case 3V. The source and drain of the FET are both weakly held high by 2.2K resistors.

If we slow down the simulation, we see that current flows when the source is held low by the low-level logic driver in the top simulation. Similarly, in the bottom simulation, current flows when the drain is held low by the high-level logic simulation. In both cases, a path to ground is created when the FET starts to conduct. This means that the output level also sees ground.

Have a play with the simulation to get your head around how the device works.


I bought a logic level converter board from eBay. The board has four logic level converter channels. A photo of the board with four converter channels can be seen below. The top pins are labelled HV1..HV4 - these are the connections for the high logic values. In my use case, these connect to the RX and TX pins on the Arduino Uno. So I only need two of the four channles. The pin labelled HV is connected to the high logic level voltage rail (5V in the case of the Arduino Uno). There is a ground pin connection on both the top and bottom rows, labelled GND. Similarly, the bottom row of connections has LV1..LV4 for each of the four low voltage signals. In my use case, the low level logic channels connect with pads 0 and 1 of the micro:bit's edge connector. I only need two channels. The unused channels are left unconnected.

Logic level converter.

I set the logic level converter up on some breadboard. I hooked a micro:bit to one side and an Arduino Uno to the other. The TX pin from the Arduino goes into the high-level logic side on HV1. Pad 0 of a micro:bit is connected to the low-level logic side on LV1. I connect to pad 0 on the micro:bit using a pin on a Kitronix edge connector that the micro:bit slots into.

A photo showing this arrangement can be seen below.

Testing a logic level converter.

I set up the Arduino Uno to send a signal from the TX pin and scoped the input to the micro:bit on my pocket oscilloscope, a DS213. This may not be a high-spec oscilloscope, but it is good enough for this application. One advantage of the DSO213 'scope is that it is battery powered, so there is no danger of creating ground loops. A close up of the oscilloscope display showing input and output serial data can be seen below:

High level logic input, low level logic output DSO213 display.

The green trace is the low level logic, the yellow the high level trace. I can see that the signal going to the micro:bit is shifted to the expected 3V logic level. The time axis is set to 10us per square. The square waves can be seen to occupy about one 'scope square for each high and low, which gives a baud rate of approximately 1/(10*10^-6) = 100kHz. I set the baud to be 115200, so this all looks about right.

The screen shot shows that the output signals are not the crisp square waves shown on the simulation. This is due to the capacitance in the circuit which was not part of the simulation There is also some ripple and noise on the signals. This is from other real-world artefacts of building circuitry, such as inductance. As the input frequency increases, the capacitance will have an increasing effect on the output signal, causing the edges to become more rounded. We can add capacitors and inductors to our simulated circuits to get more accurate outputs. That is a topic to deal with in another blog one day.

Once I was happy that the setup worked to convert from a high level voltage to a low level voltage, I tested the opposite signal direction. I connected pin 1 from the micro:bit edge connector to a second channel on the low logic level side of the converter board (LV4) and the RX pin of the Arduino Uno to the same channel on the high voltage side (HV4). I generated 3V signals with the micro:bit as the input to the logic level converter. The output was at the 5V logic level of the Arduino Uno. The output signals showed a similar rounding of the signal edges due to capacitance as the high level to low level conversion did.

Low level logic input, high level logic output DSO213 display.

Difference between the converter board and the simulated circuit

The transistors on my boards have 'J1Y' marked on the backs. The only transistor I can find with this marking on the back is the KSA1298Y, which is a bipolar transistor, not a FET. I don't see how the circuit will work with a single bipolar transistor per channel, but I'm open to suggestions. My conclusion is that the transistor is an unidentified FET. The converter board I bought uses 10K Ohm resistors, but this is a minor difference with the 2.2K Ohm resistors used in the simulation. A wide range of resistance values can be used for the resistors in the circuit.


The logic level converter works as expected. The real world implementation has effects from the inherent capacitance present in the circuitry. I'm not sure what model of transistor is used in the circuit boards that I purchased. Using a printed circuit board may reduce the rounding of the signal corners. I'm not sure how well the converter board would work in the MHz range - the rounding may become so severe that the output signals don't reach the necessary logic voltage levels. However, for passing data between serial ports at 115200 baud, the board is adequate.

Using the micro:bit to detect electrical current

This blog is an ongoing record of using the micro:bit to detect electrical current.


The micro:bit has a magnetometer on the board. When a current flows through a wire, a magnetic field is produced. We can use the magnetometer to detect this.

This is part of an energy conservation project for classroom use.


The magnetometer on the micro:bit is used to detect the change in magnetic field produced in the mains cable to a hair dryer when it is turned on and off.

(max-min) magnetometer data for 1000ms windows, sampling at 15ms, hair dryer turned on and off

I tried two methods. The first uses the unprocessed magnetometer data from the micro:bit. The second method looks at the deflection of the compass direction reported by the micro:bit. The compass direction is calculated by the micro:bit using internally processed magnetometer data.

Both methods gave positive indications of when a hairdryer drawing 3A is turned on and off.


The magenetic field strength around a wire varies with the current through the wire and the distance from the wire as:

B = μ0 I/(2π r)

Where B is in Tesla, A is in Amps and r is in metres. There are, as always with Physics, quite a few assumptions with deriving this equation.

For our purposes, it is ‘good enough’.

μ0 is the ‘permeability of free air’ and is 1.2566 x 10-6 m kg s-2 A-2.

If we take 2mm as the distance from the middle of the power cable to the sensor, r=2x10-3m.

This gives:

B = 9.9997 x 10-5 A ≈ 10-4 A

So, with 1A of current, we get 10-4 T of magnetic field strength at 2mm from the centre of the wire core.

So, 0.1mT per Ampere of current. An Ampere is quite a lot of current in today’s world.

Turning a device on and off can cause an inductive spike, so the momentary current can be higher than the steady state current through the load.


The micro:bit v1 has separate 3-axis accelerometer and magnetometer sensors. The 3-axis magnetometer is the MAG3110.

The micro:bit v2 has an integrated accelerometer and magnetometer, each 3-axis, the LSM303AGR.

I will assume micro:bit v1 is in use. The data sheet does not go into details on how the magnetometer works. It could well use the Hall effect.

The sensitivity of the MAG3110 is stated as 0.10μT with a range of ± 1000μT.

The maximum sample rate of the sensor is 80Hz. This becomes important when we start using it to measure AC devices (mains powered), as the frequency of mains current is 50Hz where I live.

One other piece of information: ‘Noise down to 0.25 μT rms’. I think that this means that if we put the magnetometer in a shielded box, so that the Earth’s magnetic field is absent, then the minimum magnetic field that the sensor could reliably measure is 0.25μT rms.

The Earth’s magnetic field intensity on the surface varies from 25 to 65μT.

Working with the results from the Theory section:

0.1 mT per Ampere is the same as 100μT per Ampere. So far, so good. We should be able to detect this. With one Amp of current. Which is a lot of current. How about 100mA? This gives 10μT of magnetic field strength in addition to the background magnetic field strength.

We should be able to detect this.

How about 10 mA? Should still be good.

How hard could it be? What could go wrong? The answer to this is that we need to consider:

Alternating Current

In the Real World, we are probably trying to monitor energy consumption from devices that run from alternating current (AC), not direct current (DC). There will be an alternating magnetic field from the wires that transfer the AC to and from our devices. But... there are two wires current carrying wires connected to the device, one for current going in to the device (the live wire), one for current out (the neutral wire). There may also be a third wire, the earth wire, which does not carry current unless a fault occurs in the device. These wires are twisted together in the power cable.

The currents flow in opposite directions in the live and neutral wires. The magnetic fields that are produced will be equal and opposite, so will cancel out to some degree.

Geomagnetic field

The reason that the micro:bit has a magnetometer is to use it as a compass. The magnetometer measures the Earth's magnetic field. This field is pretty stable for a given location, but does vary geographically. You can find out what the field is at your location at this website. Where I live, the magnetic field strength is quoted as 49588.2nT, which is 49.5882μT. So we should always measure some magnetic field on the magnetometer, unless you somehow shield it from the geomagnetic field.

AC Testing

The AC current to a device drawing current varies sinusoidally with a 50Hz cycle rate (where I live). I am looking for variation in the magnetic field as the current builds and decays during each cycle. There should be a difference in the max-min magnetic field. Ideally, when the device is off and no current is drawn, there is no variation between the max and min magnetic field strength.

There are, of course, several Real World limitations.

Real World Limitations

Noisy data

In the Real World, the magnetometer sensor data is noisy. There is a variation in the magnetometer readings from one sample to another even when the device it is monitoring is switched off. This is a combination of internal noise in the electronics and external noise from the environment. You could look at this experiment as adding another source of external noise. In our case, the noise is the data we want to measure. One person's noise is another person's data.

Sensor sample rate limit

The magnetometer has a maximum sampling rate of 80Hz according to the data sheet. I don't know what the max sample rate is when using the programming platform provided for the micro:bit. It clearly can't be more than 80Hz though, as the sensor cannot transmit at a higher rate. So I need to get data over a number of 50Hz mains cycles to have any chance of picking up the max and min magnetic field strength. Ideally, we would sample at least 10 times the frequency of the data set that we are trying to characterise. Instead, we sample over a number of cycles and hope to catch values that approximate the max and min for each cycle.

micro:bit v1 limitations

During testing, I regularly ran out of memory on the micro:bit v1. I am using Micropython for development so that the code can be easily re-used and improved by the target end users of this project. It may well be that the Micropython implementation is creating the memory limitation. I may move to C if Micropython is too limiting.

Ideally, we choose the hardware to fit the project. In this case, I am mandated to use the micro:bit. Which is fair enough. The end product is to be lesson plans that use the micro:bit to teach about energy conservation.

AC Testing Setup

The maximum 80Hz sample rate for the magnetometer equates to a maximum sample interval of 12.5ms. I set the sample interval to 15ms. Nobody likes being pushed to their theoretical limit.

The results presented below are for a hair dryer, which has a current of about 3A when on, according to my 'Plug-in Power & Energy Monitor'.

Please find the elegant and sophisticated experimental mounting arrangement presented below. The power cable is fixed over the top of the magnetometer, which is labelled as 'COMPASS' on the micro:bit.

micro:bit attached to the power cord of a hair dryer

I collected samples for the x, y and z magnetometer axis every 15ms for 1000ms time windows. I tried a longer window and had a memory allocation error. Then I calculate the max-min for each of the three windows. This max-min is called the 'delta'. This is plotted automagically using the mu editor. I am trying to stick to tools that are readily available for the class room. If I don't have success, then I'll log data to a file and hammer at it with data analysis software.

The power to the hair dryer is turned on and off using the power switch on a socket switch. Please find a photograph of this below, which also shows the 'Plug-in Power & Energy Monitor' used to measure the current. I use the switch on the socket strip to turn the power on and off to the hair dryer to avoid disturbing the power cable position. Moving the power cable causes noise on the magnetometer data.

Plug-in Power & Energy Monitor used to measure the current going to the hair dryer


Please find a graph from the Plotter tool in Mu below. This graph automatically scales. I added the labels. This shows the max-min (delta) values for each of the x, y, z axis. The time window is 1000ms and the sensor sample rate is 15ms. So there are about 66 samples in each time window.

(max-min) magnetometer data for 1000ms windows, sampling at 15ms, hair dryer turned on and off

We can clearly see that the delta for two of the axis spike when the dryer is turned on and off, then remain higher while the dryer is on. The spikes are due to induction, which causes the current to spike high when the appliance is turned on or off. This leads to protection circuitry needing to be added to appliances to protect from damage from these spikes. But I digress.

Why do we see this marked effect on only two axis? My hypothesis is that as the magnetic field is circular around the wire, the magnetometer axis that is parallel to the wire will not see as much variation as the other two that are at right angles to the wire.

Direct current (DC) Testing

With DC, the magnetic field strength should not vary as the current does not fluctuate. So I intend to measure the absolute magnetic field strength and look for an increase when there is a DC current flowing through the wire to the device under test (DUT).


I used a USB powerbank connected to a mobile phone. I am not sure how much current it draws as my fancy USB power monitor is at the University and I am working from home due to the ongoing pandemic. I'll add this data when I have it. I attached the micro:bit to the USB cable in much the same manner as with the AC power cord. Sophisticated, advanced rubber band technology. I may have to patent this tech. The current along the cable will vary as the mobile phone battery charges up. This variation changes over a time scale of tens of seconds, compared with the 20ms cycle rate from AC 50Hz mains.


I can measure a 20% increase in the average total magnetic field strength when the phone is connected, compared to when the phone is disconnected.

Historical method - compass deflection

After completing the above experiments, I read that in the early 1800s, current was measured by looking at the amount that a magnetic compass was deflected near to the wire carrying the current. The article about this is here.

The micro:bit uses the magnetometer to get compass readings. So I tested seeing if there is a deflection to the compass reading of the micro:bit when the hairdryer is turned on or off, using the same setup as in the previous experiment, with the hairdryer drawing 3A.

I used the makecode editor to quickly lash up a program to poll the compass. I trid to poll the compass at 4Hz, but I think it maxes out at about 1Hz. The reading is plotted using the Mu editor. Please see the results below. The higher, stable line, is the compass bearing when the hairdryer is off, the lower noisy readings are when it is on.

Clearly, the magnetic field from the wire deflects the compass reading. I now have a digital version of the galvanoscope, a mere 200 years after the invention of the original.

Compass reading from a micro:bit attached to a hairdryer cable as the hairdryer is turned on and off

Each time I reflash the micro:bit with code that uses the compass, the compass demands to be recalibrated. This means that the board has to be twisted around until all the LEDs fill on the screen. It takes maybe 20 seconds to do this. This slows down trying out new ideas with the compass.

Where's the code

I will put it up on a GitHub site.

Anticipated 'why didn't you...'

I tried to stick to tools that are easily available for classroom use, such as Micropython and the Mu editor.

I would like to put a space between numbers and units, as is recommended by journals. I couldn't figure out how to stop the units splitting from the numbers across lines in my markdown editor. I've looked for 'markdown non breaking spaces'. So far none of the suggested fixes work for me. Life is short.

Setting up a micropython editor with the BBC micro:bit v2 on Linux

This post follows on from my blog post that shows how to set up the mu-editor in Linux for v1 of the micro:bit. This blog post is here:


I couldn't get the mu-editor to work with micro:bit v2. This was frustrating as I wanted to check some existing code ran on v2 of the micro:bit as well as start to use some of the new feautures on board.

I solved this by following a tip from a comment on my first post. This recommended using a different editor and following some setup instructions for that editor.

I will call this editor the PythonEditor as this is the name of the project's GitHub site:


The PythonEditor can be used online at:


Python Editor can also run offline. Initially, the editor would not recognise any micro:bits that were attached to my laptop. The information that I needed to follow to get PythonEditor working is here:


In case this site is removed, I replicate this information below and add one or two tips of my own.

I use <user> to represent whatever user name you are using. I use Debian 10 on a Lenovo X260 and X230.

Create a udev rule to get the micro:bit to be recognised

Create the file:


with this content:

SUBSYSTEM=="usb", ATTR{idVendor}=="0d28", MODE="0664", GROUP="plugdev"

To create this file you need to be root or use the sudo command. I created and edited the file using vim:

sudo vim /etc/udev/rules.d/50-microbit.rules

Add <user> to plugdev group

To add your username to the plugdev group:

sudo usermod -aG plugdev <user>

To have this change recognised by the system, we need to restart the udev rules:

sudo udevadm control --reload-rules 

The webpage I followed to get this far says to log out and back in. I did not do this and things worked out.

Using PythonEditor online.

The online PythonEditor only works in Chrome for me. The editor now connected with micro:bit v1 and v2 and would program them. The first time that I flashed code to the micro:bit v2 took a while, with a message saying that the initial flash could take a while, but subsequent flashes would be faster. This is the case. I suspected that the first flash copied a micropython hex file to the micro:bit.

Using PythonEditor offline

The PythonEditor source code can be downloaded from GitHub and run offline. The instructions on how to do this are on the GitHub site, linked at the start of this post. This is how I run the PythonEditor. If we look in our downloaded GitHub repository, in the folder:


we find two .hex files:


I suspected that copying the v2.hex file to the micro:bit v2 was necessary before it would work with either of the editors.

So I took my spare micro:bit v2, connected it and tried to look at it with the serial connection on the PythonEditor. Nothing - a blank screen. I dragged and dropped the microbit_micropython-v2.hex file onto it using the Nautilus file explorer. After the requisite 10 seconds or so of flashing on the micro:bit as it loaded the hex, I tried again with the serial connection on PythonEditor and saw this:

PythonEditor serial connection with micro:bit v2

I see something similar when I click the REPL button on the mu-editor. I also get a REPL when I use the cu command I talked about in my earlier blog:

cu -l /dev/ttyACM0 -s 115200

So copying over the .hex file is a necessary step. PythonEditor does this for us if we haven't done it already.

So now I have some tools to program micropython on the micro:bit v2.

mu-editor with micro:bit v2

I can get this working with v2 of the micro:bit after getting PythonEditor up and running. But it is not stable for me. Sometimes it works, sometimes it doesn't. If I can figure out a reliable way of making this run, I'll edit this post.

There is some cryptic information in this post, which says that the UART buffer needs to be cleared to get the mu-editor to work.


I like the mu-editor and hope that I can get it up and running. Right now, I am relying on a single tool to program the micro:bit v2.

Summary of how to get micro:bit v2 working with a micropython editor

  • Create the udev rule.
  • Add <user> to plugdev group.
  • Add .hex file to the micro:bit

To do

I use the uflash or pyboard scripts with v1 of the micro:bit to enable me to use e.g. vscode to edit micropython and have a script automagically load updated code to the micro:bit. So far I have not gotten anything like this set up for the micro:bit v2. I would like this. I've gotten used to the idea that setting up programming environments requires tenacity.

micro:bit c toolchain explained, part 2. yotta, file locations

December 2020: I wrote this post when only v1 of the micro:bit existed. I haven't yet checked to see if the contents are still valid for the toolchain used to program v2 of the micro:bit.

This article follows on from part 1 of my attempt to explain the chain of tools used to build your C code into something that can run on the BBC micro:bit. In this part, I will cover the yotta build tool and how the make build tool is used as the top level component.

Here's the final tool chain. Admire the beauty.

Offline tool chain for building an executable from C code for the micro:bit

So what is yotta and why do companies choose names like 'yotta' and 'ninja' for their products when this will make it hard for us to find them on the web?


Yotta is another build tool. Yotta takes the build file module.json and the configuration files target.json and config.json. Yotta produces the build file for cmake called CMakeLists.txt. If you read part 1 of this explanation of the micro:bit C tool chain, you will be getting used to the idea that one build tool creates the build file for the build tool underneath it. It took me a while to get my head around this. The reason for using these layers of build tools is that there are many other files than the ones that we write to pull into the project to enable our C code to be built to run on the micro:bit hardware.

In your yotta examples directory, which I represent with <yotta_examples> below, have a look in the file <yotta_examples>/yotta_targets/bbc-microbit-classic-gcc/target.json. Almost at the end of the target.json file, you will see where yotta tool is configured to produce a build file for CMake:

"toolchain": "CMake/toolchain.cmake",
  "scripts": {
    "debug": [

Here ends the description of build tools used to create the hex file that goes onto your micro:bit from the source C code.


This section is a bit of an extension/digression. The 'make' tool is not used in the programming stack for micro:bit. I use it to automate building and loading a hex file to a micro:bit.

Make is the Grandad of build tools. I often use this tool for building C projects outside of micro:bit programming. ninja may be faster for large C projects, but make is fast enough for my projects and has proven reliability.

The build file for make tool is called makefile, or sometimes Makefile. Linux does not distinguish between the two names, but Windows will. Typing 'make' at the command line will cause the contents of makefile to be processed by the make tool. You will be used to the idea of a build file being processed by a build tool by now.

I use make to automate building the binary and loading it onto my micro:bit. Here's a listing of a typical makefile for one of my projects:

	yt build
	# script to mount a microbit
	~/data/infolab2/progs/scripts/microbit_mount.sh mount
	cp ./build/bbc-microbit-classic-gcc/source/microbit-c-combined.hex /media/bill/MICROBIT/

yt build obviously builds the project. The line after the comment checks to see if the micro:bit is mounted and if not, mount it. The final line copies the newly generated hex file to the mount point for the micro:bit, which is specified in the script microbit_mount.sh.

I use a script to mount the micro:bit, as this is unmounted after flashing the new code. I use Linux; this may not be necessary with Windows. Details on the script I use can be found on my blog post. The micro:bit is mounted at /media/bill/MICROBIT. You need to change the mount point in the makefile to the location that you choose to mount your micro:bit.

Using a microbit to control a servo motor

Subtitle: Making things move a microbit at a time

In this post I explain how I set up and operated a small servo motor that runs directly from the same 2xAAA battery pack that powers my microbit. I then explain how to operate a servo motor that requires a 5V power supply from the same microbit, using a transistor as a voltage level converter for the control signal.


I set up a small servo motor for a project to make an automated guinea pig feeder. Details on how to use this are here. Naturally, mistakes were made. I will detail the hardware setup, explain the control signals for the servo and show where the software can be found.

Hardware: SG51R servo motor

I used a Tower Pro SG51R servo motor, which runs from the same 2xAAA battery pack as the microbit. The battery pack, microbit and servo motor can be seen in the photo below. I slotted the microbit into a Kitronik edge connector.

2xAAA battery pack, microbit in a Kitronik edge connector and a SG51R servo motor

I got my SG51R servo motor from the Pi Hut here.

Why use this servo motor?

The SG51R works using a 2xAAA battery pack as the power supply, while many other servo motors require a higher voltage than 2xAAA batteries produce. This means it can run direct from the same battery pack used to power your microbit.

The manufacturer's website says that this servo motor requires 4.8V to operate. However, it works fine with the 2.4V or so that we get from the 2xAAA rechargeable battery supply I use to power the microbit. This is great, as it means I don't need to use a different voltage supply to power the servo motors with.

The servo has three wires for power and control. The black wire is for ground, the red wire for the voltage supply and the orange wire is the control signal.

The wires from the Kitronik edge connector to the servo motor connector can be seen in the photo below. I used D0 as the pin to output the servo motor control pulses on. The labels on the microbit are guides as how to use the microbit for the guinea pig feeder project.

The photo below shows how the wires from the microbit connect to the servo motor plug. Black is ground, red is positive voltage, yellow is the signal, from pin D0 on the microbit.

Wires from the microbit on the left, servo motor connector on the right

A servo typically responds to a control signal of a pulse between 1 ms and 2 ms long within a 20ms period. 180° needs a 1 ms pulse.

So what does that look like? The software I wrote to drive the servo motor is at the end of this article. I put an oscilloscope onto the signal pin. Here's what it looks like:

Servo motor controller pulses

We see a positive pulse every 20 ms. Remember that these pulses go from ground to the battery voltage (about 2.4 V in this plot). We will revisit this polarity when we talk about driving a 5 V servo motor later in this post. The width of this pulse sets the angle of the servo motor. The pulse must occur within the same 20 ms window, just how much of this window it takes up changes.

From the data sheet for the SG51R:

This servo is pulse controlled. This means that supplying a pulse will move it to a particular angle. In this case 0° is a 1.5 ms pulse, 90° a 2 ms pulse and -90° is a 1ms pulse. This may not be set by your controller by default or give you the full range of movement as such you may wish to try up to 2.25 ms and as low as 0.75ms. Be aware that if you go to far you can break the servo.

Using my 'scope, I could see that the servo motor responds to pulses with a width from 0.57 ms to 2.58 ms. Remember that the window that these pulses occur in remains as 20 ms wide. Just the width of the control pulse changes to take up more or less of this 20 ms.


Initially I carefully crafted beautifully structured micropython code in classes. Then ran out of memory, so ripped out all of the classes and bludgeoned the code to fit into the memory of the microbit.

I did, of course, find example software elsewhere on the 'net to get started and apologise that I can't remember which site I found this on to give proper credit.

The code can be found in the file called feeder.py on my GitHub site at: https://github.com/hardwaremonkey/microbit_projects

5V servo motor MG90D

Maybe you need a more powerful servo motor for your application. In this case, you will probably need one that requires a higher voltage than we get from the battery pack for the microbit. This section explains how to control a servo motor that is running from a separate power supply using a battery-powered microbit.

The mg90d is a servo motor that requires a higher voltage than the microbit can supply to operate. I ran it at 5V from a power supply. So how do we set up our microbit to control this?

I used a 2n2222 transistor to interface the microbit with the servo motor control wire. The control signal from the microbit goes to the base of the transistor. There is a 1K Ohm current limiting resistor in between this signal from the microbit and the base of the transistor. The signal going to the base of the transistor switches the transistor on and off.

The collector of the transistor connects to the 5V power supply through a 100 Ohm resistor.

Remember: We are only using the transistor to change the voltage level of the control signal. The voltage for the servo motor comes directly from the +5V power supply.

When the control signal from the microbit goes high, the transistor turns on. When the control signal goes low, the transistor turns off.

Find the wiring diagram below. The images come from Fritzing, though I made the diagram in Inkscape.

Circuit layout showing how to power and control a 5V servo using a microbit and a 2N222 npn transistor

There is one catch with this circuit - the control signals become inverted. You might ask - why not tap the signal from the emitter of the transistor, not the collector, then the signal would not be inverted. However, doing this produces an output signal going to the servo motor of lower voltage than the signal coming into the base of the transistor. Which defeats the object. There is about a 0.6V drop between the base and emitter of a typical bipolar transistor.

The simple answer is to invert the control signal coming from the microbit. I did this. See the oscilloscope grab below, showing the inverted control signal from the microbit in yellow and the non-inverted control signal going to the servo motor in blue. Note the different voltage levels. The signal from the microbit is around 2.4 V in amplitude and the signal going to the servo is about 5 V in amplitude.

Inverted controller signal from microbit is yellow, signal from transistor emitter to servo is blue

I put the micropython code needed to generate both a non-inverted and an inverted pulse below so you can see the simple trick needed to invert the pulse.

   def set_ms_pulse(self, ms_on):
        # pin.write_analog(1023) is constant on pulse
        # (1023 * ms_on / 20) gives a pulse of length ms_on
        self.pin.write_analog(1023 * ms_on / 20)

    def set_ms_pulse_invert(self, ms_on):
        ''' Gives inverted logic servo control pulse. '''
        self.pin.write_analog(1023 - 1023 * (ms_on / 20))

This worked to operate the 5V servo motor. The transistor allows us to drive the servo motor using the output of a battery powered microbit.

Another component that allows us to drive a device requiring a voltage that is not compatible the part that generates the control signal is an opto isolator. This is a story for another day.

As always, comments are welcome.

BBC micro:bit guinea pig timed feeder instructions

This blog post is the instructions on how to use a timed servo motor circuit that I lashed up as part of a guinea pig feeder for a friend.

The hardware details can be found here: here

Software is on my GitHub site here

The need

A friend wanted something to open a box of food to feed his guinea pigs. The box needs to open after an adjustable time.

I can think of no more noble cause to focus on than feeding our furry friends.

After a period of procrastination and confusion I supplied the hardware and software detailed in this post. The mechanical components that the device will operate are up to my friend to make. He is a highly experienced mechanical engineer. I am but a lowly electronics tech.

Between the two of us, the guinea pigs will be fed!


The microbit counts down for a preset amount of time. The remaining time is indicated on the LEDs on the microbit. At the end of the pre-set time, the servo motor lever moves 90 degrees. The two positions of the servo motor are shown in the pictures below.

The timer is adjusted using the A and B buttons as detailed in the Instructions section below.

Servo motor position while the timer is in operation
Servo motor position once the timer completes the countdown

Instructions for use

The A button adds 12 minutes to the timer. An extra LED will light up for each press of the button. The B button decrements 12 buttons from the timer. An LED will turn off for each press of the button. The photograph below shows two lit LEDs on the microbit, indicating 24 minutes or less are left on the timer.

The two lit LEDs indicate that 24 minutes are left until the servo motor is activated

The last timer setting is recorded to the memory on the microbit. When the board is reset, it will start counting down from this time. So, if you set the timer to 2 hours (10 LEDs lit), on resetting, you will see 10 LEDs lit up and the board will take 2 hours to trigger the servo motor.

The reset button on the back of the board restarts the board. Please see the photograph below which shows the position of this button.

Underside of the microbit with the rest button indicated, next to the battery connector

Hardware description

The components of the system are shown in the picture below. On the left is a AAA battery pack containing 2 x AAA batteries. I use battery packs with a switch, which I get from eBay. The microbit is in the centre, slotted into a kitronik microbit edge connector. This edge connector allows the signal pins of the microbit to be connected to the servo motor using female to male jumper cables . The cables are designed for the 0.1" pins and sockets found on the edge connector and the cable connected to the servo motor.

AAA. battery pack, microbit, servo motor

The full assembly including cabling is shown in the photo below.

AAA battery pack (right), microbit and edge connector board (centre), servo motor (top), connectors (right)

A close up photo showing how the cables from the edge connector and the servo motor connector are connected is shown below. The black/brown wires are ground, the red wires are the battery voltage and the yellow wire is the PIN0 signal line.

Pins from cables connected to the Kitroniks edge connector on the left, sockets connected to the servo motor on the right

The photo below shows how the cables connect to the pins on the Kitronik edge connector.

Cables connected to the Kitronik edge connector. Yellow goes to 0, black to 0V, red to 3V.

BBC micro:bit wrist holders

With my handshake project, a microbit and AAA battery pack need to be worn on the wrist. They can be vigorously shaken. I don't want the equipment flying off! So what can I use that will hold the microbit and batteries safely in place and is comfortable and safe to wear?

I tried a couple of armband holders aimed at iPods recently. Both of them are suitable for housing a BBC microbit and a AAA battery pack. Prior to this, I used a wrist holder that I made myself.

The advantages of repurposing an iPod arm band holder instead of making one yourself are:

  • Saves you the time of making one.
  • The clear plastic cover makes it easy to clean.

Please find photographs of the armband holders I tried out as wrist holders containing a microbit and AAA battery holder below. First a top-tip!

Velcro tabs to secure armband straps

Whichever armband you re-purpose to be a wrist holder, as the wrist is narrower than your arm, the end of the strap will no longer stick down. The end will flap free. As this end of the strap has the hook velcro on it and the rest of the strap is the loop kind, the strap will no longer stick down to itself. You need to make some double sided hook velcro tabs. See the photo below.

Double sided hook velcro tabs

These are lengths of sticky back hook velcro, stuck back to back. Place them on the loop velcro to enable the strap to stick to itself when used on the wrist.

TuneBelt Armband for iPod touch 4G

The TuneBelt iPod touch 4G armband holder can be used to hold a microbit and AAA battery pack as shown in the photo below. Use some double sided velcro hook 'gender bender' strips to allow the strap to stick to itself when used on the wrist.

iPod touch 4G arm band in use as a microbit and AAA battery pack wrist holder
TuneBelt iPod touch 4G used as a microbit and AAA battery pack holder, front view

arm band in use as a microbit and AAA battery pack wrist holder

TuneBelt Sport Armband iPod touch 4G box

igagdgitz iPod classic armband holder

Larger than the iPod touch 4G holder. Costs about twice as much - about £10 from eBay. The build uses thicker neoprene. The rear panel folds down to allow easy installation and removal of the microbit and battery holder. This is made from a decent thickness of neoprene and is held securely in place with velcro on three sides.

The strap is longer and bulkier than the iPod 4G holder . If you know you are going to use this arm band as a wrist holder, it would be worth trimming the strap down. Then you would rely on the velcro double-sided tabs to stick the strap down unless you sewed some hook velcro on to replace the tab that you had cut off when shortening the strap.

iPod classic arm band in use as a microbit and AAA battery pack wrist holder
igadgitz iPod classic holder, front view, containing BBC microbit and AAA battery holder. There are two velcro tabs near the plastic to enable the strap to latch onto itself when worn on the wrist.

Rear view, showing fold down flap which allows acccess to the interior

Automating loading micropython code to the BBC micro:bit in Linux


When I edit micropython for a microbit project, I want the code to automagically load onto the microbit each time that I save the code. Then I want to see any messages from the microbit displayed. I worked out a toolchain that does this under Linux.

I summarise the toolchain in the next section, then go through each step in more detail.

For the examples in this post, I am editing a file called 'feeder.py'.


Use your favourite editor for creating your code with. The toolchain to load the code to the microbit kicks off when you save the file.

There are four tools needed to automate the process.

  • A script to locate and mount the microbit. I wrote a blog post about this script here.
  • The uflash utility to write the micropython file to the microbit.
  • screen terminal to display messages from the microbit
  • inotifywait command to monitor the micropython file being edited


Use pip to install this. Details are in the link given earlier in this post. To load a_file.py to an attached microbit, simply type:

uflash a_file.py

Using virtual environments makes my life easier, so I use one for my microbit programming. There are plenty of blog posts detailing how to set up and use these.

script to attach a microbit

I wrote a blog post on how to create a script that automatically locates and mounts a microbit here. This script is aliased to mm and md in my .bashrc file to mount a microbit and dismount a microbit.


screen is built in to most Linux distros, so I use it here. This connects to the port that is in use by the microbit and displays any output from the microbit.

You need to know what port your microbit is attached to though. On my laptop this is often /dev/ttyACM3, which I use in the example below.

I present a script in the next section to automatically find the port that the microbit is connected to and fire up a screen connection using this.

To fire up the connection manually, if you know the port (in this example /dev/ttyACM3) use:

screen /dev/ttyACM3 115200

Remember to kill screen without leaving it running in the background by using:

control-a k

One potential problem with screen, is that it is easy to 'detach' from screen instead of ending the process, which leaves an instance of screen running invisibly which is attached to the same port as the microbit. When you come to try and run screen or connect to the microbit again, you will see an error like the one below:

can't open device "/dev/ttyACM3" 

To find and kill the errant screen instance:

lsof | grep /dev/ttyACM3

If you get something like:

screen  8610  elm    5u   CHR  166,3      0t0 5599015 /dev/ttyACM3

You still have a screen instance attached to the port. The PID is the second value in the list, in this case 8610. Kill it using e.g.

kill 8610

One way to prevent this potential problem is to replace screen with another terminal display tool such as gtkterm.

script to automate finding and connecting to the microbit

The python3 script below automates finding a connected microbit. The script starts a screen session on the port that the microbit is connected to.

Find pyboard or microbit and open a terminal.
Created on 4 Nov 2015.
From http://wdi.supelec.fr/boulanger/MicroPython/
Usage: find_device [device]
Calls screen on "device". If device is not given, looks for /dev/ttyACM* devices
then /dev/tty.usbmodem* devices (for MacOS).
import sys
import os
import fnmatch

BAUD = 115200

def main():
    if len(sys.argv) > 1:
        ttymodems = [sys.argv[1]]
        ttymodems = fnmatch.filter(os.listdir('/dev'), 'ttyACM*')
        if len(ttymodems) == 0:
            ttymodems = fnmatch.filter(os.listdir('/dev'), 'tty.usbmodem*')
        if len(ttymodems) == 0:
            print('Error: no pyboard found.')
        ttymodems[0] = '/dev/' + ttymodems[0]
        print('connection at: {}'.format(ttymodems[0]))
    os.system('screen '+ttymodems[0] + ' {}'.format(BAUD))

if __name__ == "__main__":


inotifywait is a command line tool that can be configured to watch a file for a change, then trigger an action. Here we use it to watch for a change in the micropython file being edited. When this file is saved, inotifywait mounts the microbit and flashes the file to it.

If infotifywait is not already installed, then you need to install inotify-tools.

The command to watch a file called feeder.py for a change, then run the alias mm (to mount the microbit) and to flash the file to the microbit is:

while inotifywait -e modify feeder.py ; do mm && uflash feeder.py ; done

I would have formatted the above line as the other code in this post but found that the syntax highlighter plug-in refuses to show the ampersand symbol correctly.


Some editors have the 'feature' of 'kind of' saving the file you are editing while you are editing it. This creates a new timestamp for the file and activates inotifywait without your saving the file. mu is one of these editors. In this case, I do not use inotify and run the following command from the command line each time I want to flash the updated file. In this example the updated file is called feeder.py:

mm && uflash feeder.py

but why not use a Makefile

Makefiles are typically used to build programming projects, detailing the dependencies of each component. The file is run when 'make' is typed on the command line.

The one-liner command using inotifywait is fine for this simple example where we are editing a single file. Which is most of what I do with the microbit and micropython. Makefile comes into its own for more complex builds involving multiple files. It allows for extra run-time options to be added, e.g. to clean files created by earlier builds.

For completeness, I present a simple Makefile below for this project. Makefile is a useful tool that is worth learning to use for when we have larger projects to build.


I created a Makefile containing commands to mount the microbit to the Linux filesystem, then flash a micropython file to the attached microbit.

An example Makefile is below. Note: Use tabs to create the indents after the line 'run:'. Or the World Ends. The supporting file microbit_mount.sh is in the same directory as feeder.py to keep it simple.


	./microbit_mount.sh mount

In this example, microbit_mount.sh is the script to attach a microbit, detailed above.

uflash is the tool used to write the .py file to the microbit. This is detailed above.

To automate the Makefile being run each time that we save new code, we can use the inotifywait command below:

while inotifywait -e close_write feeder.py ; do make; done

Powering the BBC micro:bit with a 5V power bank

I had an interesting question to a blog post I made about running a DC motor from a microbit. The blog post is here. I am pleased that anybody reads my blogs.

Doesn't applying 5V to the microbit board exceed the voltage spec?

When we connect the board to our laptops or PCs, we apply 5V to the board through the USB connector. Sometimes I run the board from a USB power bank. This supplies 5V to the microbit. The advantage of using the power bank over AAA batteries is that I can use the power bank to also run e.g. a DC motor. So far I have not cooked off a microbit doing this.

But I still only measure 3.2V on the pads on the board edge connector.

Why is this?

Let's look at the board circuit schematics. Please find a screengrab showing the USB connector on the left and the microcontroller on the microbit on the right.

BBC micro:bit schematic fragment, showing USB connector and the microcontroller.

Let's zoom in on the connector:

Schematic showing the USB connector.

The 5V input voltage on the USB connector is given the net label VBUS_IF. This label reappears next to the little number 5 - which means this is where the track connects to on the PCB. The zener diode to the left of the number 5 and the 10 Ohm resistor R31 to the right combine to protect the board in the case of reverse polarity - if somehow the voltage is applied to the USB connector backwards, the current flows to ground, not into the microcontroller.

The capacitor C31 and C33 are there to act as little charge stores for the microcontroller for when it needs a sudden 'oomph' of charge that the USB power supply cannot supply quickly enough. These are called decoupling capacitors.

The +5V signal is renamed VBUS_IF_2 to the right of R31. Lets look at where this goes into the microcontroller. I labelled the net VBUS_IF_2:

So our +5V USB voltage connects to the microcontroller on a dedicated pin VREGIN. This is the input to a regulator inside of the microcontroller. The output of this regulator is a DC voltage called +3.3V_IF. This output supplies the +3.3V seen elsewhere in the board and on the board edge connector pads.

Now, if the input to VREGIN is below 3.3V, we are not going to see 3.3V on the output pads. In fact, I see 3.2V with an input of 5V, so there is a 0.1V drop somewhere on the board.

So, in summary, we can apply 5V through the USB connector.

One last schematic fragment. This shows the battery connector and where this supply connects with the voltage generated by the internal regulator on the microcontroller:

Microbit schematic showing the battery connector and how it connects to the board voltage tracks.

The battery voltage goes through a low drop BAT60A schottky diode labelled D2. This then connects to V_TGT. This is the main voltage rail for powering most of the board components, such as the magnetometer and accelerometer. This is also the rail that connects to the board edge connector on the pad labelled '3V'.

Both the output from the microcontroller regulator, labelled 3.3V_IF and the voltage from the battery labelled VBAT connect to this rail through BAT60A schottky diodes. The diodes mean that the battery voltage and the regulator output voltages are isolated from each other, but either can produce V_TGT.

What if both a battery and a USB connector are connected? Whichever is the higher of VBAT or 3.3V_IF, minus a small voltage drop created by the BAT60A diode, will produce V_TGT. The voltage drop across the diode is around 0.1-0.2V according to the datasheet for the BAT60A.

It would be dangerous to the board to apply 5V to the battery connector. I am not about to try this. The battery connector bypasses the regulator in the microcontroller, so applying a high voltage to this connector applies the same high voltage to the components on the microbit board, minus a small drop across the BAT60A diode. Many of these are not rated to work at 5V.

The board is designed to take 5V only through the USB connector.

Running handShake in administrator mode to operate Grid 3

Sensory Software's Grid 3 is a popular communication software package, running in Windows. Naturally, I would like handShake to be able to operate this software through the software keystrokes that handShake generates.  To get Grid 3 to respond to a software keystroke, I have to 'elevate' the base.py script which runs on the communication device to run as an Administrator.

There is a second solution. I can use a Freetronics Leostick USB dongle as a pretend keyboard and have this generate keystrokes that appear as coming from a physical keyboard. I did this for a while, but this adds a layer of complexity and expense to the project. The simplest solution is to run handShake as an Administrator when using Grid 3, or other software that requires software keystrokes to come from an elevated source.

I tested out adding the functionality for handShake to detect when Grid3 was running, then automatically try to elevate the base.py script to run in Administrator mode. I got this running. Then removed the functionality. Why? Security. Software running as Administrator can damage your system if incorrectly or maliciously written.

Now handShake detects if Grid 3 is running and advises that this requires the software to be restarted as an Administrator, but does not try to automate this restart. The decision is left to the user.

The Grid 3 software is detected using the code shown below. The code looks through the titles of the windows for any that match the ones in the list called ADMIN_SOFTWARE. At the moment there is only one title to check for - 'grid'. This is the title for a window running Grid3. As I find other packages that demand that my script runs as Administrator to have the ability to interact with it, then I will add their titles to the ADMIN_SOFTWARE list.


def target_admin_sware(software=ADMIN_SOFTWARE):
    ''' Check if target software requires this script to run as Administrator. '''
    toplist, winlist = [], []
    logging.info('Looking for software that requires elevation to Aministrator: {}'
    def _enum_cb(hwnd, results):
        winlist.append((hwnd, win32gui.GetWindowText(hwnd)))
    win32gui.EnumWindows(_enum_cb, toplist)
    for sware in software:
        # winlist is a list of tuples (window_id, window title)
        for hwnd, title in winlist:
            if sware in title.lower():
                logging.info('found software requiring Administrator mode {}'
                return True
    return False

Running handShake as Administrator is a choice that the user makes and implements if he or she deems necessary.  As all of the code is on the project GitHub site, the code can be reviewed to check that it is safe to run as an Administrator.

One of the advantages of open source projects is that they are open to this kind of scrutiny to find security flaws.

For interest, I detail the code I added and then removed from the base.py script to enable it to detect if it is running as an administrator and if not, request to be restarted as an Administrator.

I added the option to run the script as an Administrator from the command line using the click library.


@click.option('-a', '--admin', default=False, 
    help='Run as administrator. Required for Grid 3.')

@click.option('-k', '--keystroke', default='F1',
     help='Keystroke to send. Default is F1.')

def main(admin, keystroke):
    logging.info('software keystroke is {}'.format(keystroke))
    logging.debug('admin flag is {}'.format(admin))
    if is_admin():
        logging.info('running as administrator')
        logging.info('not running as administrator')
        if admin:
            logging.info("restarting as administrator")

To test if the script is running as an administrator I added this method:

def is_admin():
    ''' Is the script running as an Administrator? '''
        return windll.shell32.IsUserAnAdmin()
        return False