This guide will show you how to interface a BBC micro:bit with the 1.44″ colour LCD display provided by AdaFruit and to implement a basic Lunar Lander game.
I’ve not written a complete library to drive the display, but the code includes line drawing, rectangle filling, some very basic text support (roll your own fonts), and some very basic “sprite” support. There’s enough here, I think, to let you crack on and code up other simple games, using the graphics primitives provided. And you can drive the display through the JavaScript blocks interface, so if you’re coding with kids, they don’t need to flip into the raw JavaScript interface.
The code provided here is in JavaScript (or TypeScript and, indeed, the pared down version of TypeScript used by the micro:bit). If you prefer Python, then the code should be fairly easy to port across. I partly chose the JavaScript approach so that if you’re coding with kids they can use the blocks interface.
Hardware Steps
Review the parts list below before working through the hardware steps.
- Prepare the connector for the TFT display. The TFT display comes with a connector that lets you plug it into the breadboard. The connector has more pins than are needed so you need to clip off some of the pins. You can do this with some sharp scissors or with a pair of pincers. Be careful not to take off too many pins. I recommend leaving one extra pin on and then pulling that pin out of the plastic.
- Solder the connector to the display board. Long pin facing down (the opposite side to the display) and short poking through to the top side (the display side).
- Wire up. To understand what’s going on refer to the micro:bit pin out diagram and also the documentation provided by AdaFruit. These are the connections that you need to make:
- Power: so the micro:bit can “power’ the display
- micro:bit 0v goes to the Breadboard blue/- rail
- micro:bit 3v goes to the Breadboard red/+ rail
- SPI Interface – so the micro:bit can “talk” to the display
- micro:bit P13 (SCK) goes to TFT display SCK. This is the clock signal for the serial interface.
- micro:bit P15 (MOSI) goes to TFT display SO. This is the “master out” signal. It is sends the data to the display from the micro:bit.
- micro:bit P16 to TFT display TCS. This is the TFT display “chip select” signal. When the micro:bit sets P16 to zero volts, it tells the display to listen. In software, we program P16 to be high (3v) by default and then pull it down to low (zero volts) when we are “speaking” to the display. (P16 is simply a free pin that I’ve chosen to do this job. The software below assumes you’re using P16.)
- micro:bit P1 to TFT display D/C. This is the TFT display “data” or “command” signal. When the micro:bit sets P1 low (zero volts), it tells the TFT display we’re sending a command. When it’s set high (3v) it tells the display we’re sending data. (P1 is simply a free pin that I’ve chosen to do this job. The software below assumes you’re using P1.)
- Breadboard blue/- rail to TFT display GND. This is the ground connection for the display, i.e. power.
- Breadboard red/+ rail to the TFT display Vin. This is the +3 volts connection for the display, i.e. power.
- Note: the display does have a hardware reset option, but I didn’t wire this up. The display can be reset through the SPI interface in software.
- Piezo Buzzer
- micro:bit P0 to one pin of the buzzer
- Breadboard blue/- rail to the other pin of the buzzer
- Extra Push Button Switch
- micro:bit P12 to one pin of the push button. (P12 is simply a free pin that I’ve chosen to do this job. The software below assumes you’re using P12.)
- Breadboard blue/- rail to the other pin of the push button
Software Steps
Overview of Driving the SPI Interface
This is to explain how it all works. You might not be interested in this level of detail.
- I couldn’t find any code for the micro:bit to drive the AdaFruit 1.44″ display. But AdaFruit does provide some code that I was able to adapt.
- To talk to the display you need to send commands (which are documented in the ST7735R data sheet on the AdaFruit website). To send a command you need to set pin 1 to zero / zero volts (pin 1 is connected to the display’s command/data pin) and you need to set pin16 to one / +3 volts (pin 16 is connected to the display’s chip select pin). This done you can use the micro:bit’s spiWrite command to send the command.
- Most commands have some parameters. These are data. So you need to set pin 1 to one / +3 volts and then do one or more spiWrite commands to send the data.
- With some commands you are recommended to pause after sending them before sending the next one. I took the pause guidance directly from the AdaFruit code.
- Before you can send commands to set pixels you display you need to send a series of setup commands. I copied the setup sequence directly from the AdaFruit code. Their code has options for various different displays and the code I’ve provided is just for the 1.44″ display with the “green tab”. That’s the one Pimoroni supply.
Overview of the Graphics Code
- To get pixels on to the screen you first send the display a Set Address Window command. This specifies a starting x,y position and an ending x,y position. You follow this Set Address Window command by a series of byte pairs that represent the colour you want the pixel to be. In this setup, the pixels are delivered left to right.
- The drawPixel function just draws a single pixel. I’ve not provided a lot of help for defining the colours. You can go back to the AdaFruit documentation for more help with that or look at the data sheet.
- The drawRectangle function just a range for a block using Set Address Window. The clear screen function just draws a rectangle the size of the whole screen and sets it to black. You can vary the speed of the SPI interface. You’ll notice clearing the screen takes a moment or two at the default speed.
- I’ve included some functions to draw sprites and to define sprites in a friendly way using strings of spaces and X’s. This could be souped up for multi-coloured sprites etc.
- I’ve also included some functions to help draw the lunar landscape. The landscape is made out of segments that are defined by strings indication up / down / right-and-up / right-and-down / right.
- There’s some line drawing code there, but it’s not used in the current version of the game. It hasn’t been thoroughly tested and may need to be tweaked.
Overview of the Game Code
- This is pretty standard stuff. There’s a loop that goes on forever.
- Each time around the loop the game will either make a sound – which takes a brief moment – or will pause. This means things don’t go too fast.
- Each time around the loop the vertical velocity of the lander is increased by a ‘gravity” factor.
- Each time around the loop we check to see if the up / left / right booster button is being pressed. If it is, then we adjust the y or x velocity accordingly.
- When the landscape is built, we record its height. That means we can check to see if the lander has hit the moon’s surface each time around the loop. We also check to see if it’s in the landing zone and if it’s going slowly enough.
Installing the Code
From within the blocks interface, you need to select the JavaScript tab.
Then click on Explorer disclosure triangle (it’s on the left below the micro:bit simulator). And then click on the ‘+’ symbol to the right of the word ‘Explorer’.
You’ll be asked ‘Add custom blocks?’ Click on the ‘Go Ahead’ button. You’ll now find when you open the Explorer disclosure triangle that there is a custom.ts file in the list of files.
Copy the custom.ts file provided here and then paste it into your newly created custom.ts file. You will want to overwrite the default custom.ts file that is provided. Then do the same copying and paste for the main.ts file.
The main.ts file (mostly) represents what you see in the blocks editor. But the micro:bit editor can get confused sometimes when you make changes in main.ts and the flip back to the blocks editor. Sometimes refreshing the browser window will fix things up.
- main.ts code
- custom.ts code – this includes a partial ‘naive’ font (designed by an 8 year old, so please don’t knock it). You can readily edit and expand the font in the code.
The code is not super-tidy, but it is commented. If you’re using it and really stuck, send me a message and I’ll try to help. It’s possible, though how likely it’s hard to say, that I might tidy up the code to make something more like a standalone library. Or, of course, someone else might do that.
Tips and Gotchas With JavaScript (TypeScript) on micro:bit
- You can only use integers on the micro:bit. I’d done some test / proof of concept code in real JavaScript and then realised that none of this was going to work. To implement the Lunar Lander game you need to do sums on numbers that are fractions of a pixel. I adopted the approach of having some working coordinates that are pixel coordinates but multiplied up by 32. This allows for, say, velocity values, that are much smaller than one pixel.
- The SPI writes seem not to work when called from OnStart. I initially had my display setup code called from OnStart. This didn’t work. My best guess is that the SPI interface doesn’t get set up right away. In any case, calling the display setup code later fixed the issues. So the code now sets a “startup” flag on startup and the Forever loop checks the status of this. It calls the startup code if the flag is set and then clears the flag.
- Type inference is flaky. When you’re working in the blocks editor the system tries to figure out the type of variable based on first use. But it doesn’t seem to be very good at this and it can create issues flipping back and forth between the blocks editor and the JavaScript / TypeScript editor. For this reason, it helps to set up variables in the OnStart block with a default value. This ensure they are properly typed and prevents havoc. (This comment will seem just weird if you’ve not experienced the weirdness of the editor trying to fix things up and breaking your code.)
- No built in command to combine arrays. It appears – unless I’ve got very confused – that you can’t add / combine two arrays with the micro:bit version of TypeScript. I had to write a custom function to do this.
- You can specify crazy invalid types, through miscapitalisation, but only get bitten at runtime. TypeScript, unlike JavaScript, has static typing. You need to be explicit about what types you are using. This ought to be a good thing as it means that errors got flagged early and before something goes wrong at run time. Weirdly, though, you can make – and I did, more than once -new kind of mistakes that, in fact, only show up at runtime. The kind of mistake I made involved using the wrong capitalisation. So, for example, at one point, I’d wrttien “Boolean” instead of “boolean”. And, indeed, the editor had offered this up as an auto-completion. The behaviour that followed was just weird. So lesson for me is if it’s getting very weird, do a quick check for mis-typed types.
Parts List
- BBC micro:bit. I got mine from Maplin. They are widely available via mail order. At the time of writing, Maplin were charging £12.99
- AdaFruit 1.44″ Color TFT LCD Display with MicroSD Card breakout – ST7735R. I got mine from Pimoroni. At the time of writing, they were charging £18.50 (which includes £2.50 for P&P).
- Kitronik Inventor’s Kit. You can get this direct from Kitronik – and they send stuff out fast. I ordered mine from Maplin. At the time of writing they were charging £26.99. The key parts from the Inventors’s Kit used in this project, which can be sourced separately from Kitronik, are:
- Edge-connector for the BBC micro:bit. This makes it easy (some might say possible) to connect the micro:bit to the display, piezo electric sounder, and extra button.
- Breadboard and connecting cables. This lets you set up all the relevant wiring without doing any soldering. And, because there is no soldering, you can change you mind or reuse the breadboard and cables to make new projects later. Of course, if you’re going solder up a permanent project, using Veroboard or a handmade PCB, this wouldn’t be required. And using the breadboard makes everything very quick and more fun.
- Extra button switch. This isn’t needed for the display. But the example project, the Lunar Lander game, needs an extra switch and you get four in the kit.
- Piezo Buzzer. This is like a tiny speaker and enables the micro:bit to make sounds. This isn’t needed for the display. But the example project, the Lunar Lander game, needs a buzzer.
- USB Type-A to Micro-B USB Cable. This is used to connect the micro:bit to a computer so programs can be transferred. These are available all over. I got mind from Kitronik for £3.60. You might even have one already supplied with some other bit of equipment.
Questions and Comments
Comments are not enabled on this site, but if there are interesting comments or useful tips submitted then I’ll append them to this post.