micro:bit v1 with yotta – removing build warnings

problem

Running yotta build with the micro:bit v1 C tools produces screenfulls of depreceation warnings, such as:

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

This makes it hard to find the error messages with the reason why the build failed.

solution

Tell the C++ compiler not to include depreceation warnings.

instructions

Add the compiler flag -Wno-deprecated to the CMAKE_CXX_FLAGS_INIT options in the file toolchain.cmake.

File location:

<project>/yotta_targets/bbc-microbit-classic-gcc/CMake/toolchain.cmake>/yotta_targets/bbc-microbit-classic-gcc/CMake/toolchain.cmake

Line before:

set(CMAKE_CXX_FLAGS_INIT           "${CMAKE_CXX_FLAGS_INIT} ${_CPU_COMPILATION_OPTIONS} -std=c++11 -fwrapv")

Line after adding flag:

set(CMAKE_CXX_FLAGS_INIT           "${CMAKE_CXX_FLAGS_INIT} ${_CPU_COMPILATION_OPTIONS} -std=c++11 -fwrapv -Wno-deprecated")

extra flags to suppress other distracting warning

While we're on a roll, we can also suppress distracting warnings for array-bounds and misleading indentation by adding:

-Wno-array-bounds -Wno-misleading-indentation

to the same line.

endnote

There are layers of build tools used to transform your C code into a hex file that can be copied onto the micro:bit. I tried to understand and explain the toolchain in these blogs:

c-toolchain-make-ninja-cmake-explained

c-toolchain-explained-part-2-yotta-file-locations

Getting started with C++ on the micro:bit v2 in Linux

Aims

This post is about getting started with programming the micro:bit v2 using C++. I use the example code from the Lancaster University GitHub for this.

We will:

  • Download the GitHub repository with the sample code.
  • Build and load the default HelloWorld example to the micro:bit, which scrolls 'HELLO WORLD!' on the LEDs.
  • Modify and build one of the other examples to use one of the micro:bit pins as an analog input. The LEDs display the voltage on this pin.

I tried to load one of the MICROBIT.hex files onto a v1 of the micro:bit with no success. This post is aimed at v2 of the micro:bit only.

Download the samples

Download the GitHub repository with the sample files produced by Lancaster University from their GitHub site here.

There are a couple of ways to do this. You can click on the green 'Code' button to download a zip file and unzip it, or you can use the 'git clone' command if you have git installed:
git clone https://github.com/lancaster-university/microbit-v2-samples

Setting up for coding

The README.md file in the repository is pretty good. There are several packages that need to be installed on your Linux installation to be able to build the example code with. The maintainers of the repository use Ubuntu, so the package installation commands use the 'apt' package manager:

sudo apt install gcc
sudo apt install git
sudo apt install cmake
sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi

gcc is the Gnu C compiler. This is used to compile the example C++ code with.

cmake is used for creating files that tell the system how to build the project.

gcc-arm-none-eabi is a version of gcc designed to run with the target hardware we are using on the micro:bit.

binutils-arm-none-eabi contains tools that build the .hex file that goes onto the micro:bit - the assembler and linker amongst other things.

If you have a different Linux distro, you may have a different command to install these packages with. I use Debian with the 'aptitude' package manager.

On the GitHub site and in the README.md file, there is some guidance on how to use a Dockerfile for installing the dependencies. I didn't use this, so can't comment.

You also need Python 3 installed, but odds on you already have this set up.

Directory structure layout

Like all GitHub repositories, the file layout seems really obvious to whoever created it, but might not be as clear to the rest of us.

In the top level directory, we have a file called build.py. This is the file that builds (clue is in the name) the MICROBIT.hex file that we will copy to our micro:bit. We will come back to this file in a moment.

In the source directory you find the file main.cpp. This is the file that we will work with. The samples directory contains - you guessed it! - the sample files that we will work with.

Hello World

The main.cpp file that comes with the GitHub repository is all set up with the classic Hello World example. All we have to do to get this running on our micro:bit is:

  • Build the code to create a MICROBIT.hex file.
  • Copy the MICROBIT.hex file to an attached micro:bit v2.

Building the code

Go to the top directory in the repository and type the command:

python build.py

After some seconds and a wall of text, the MICROBIT.hex file is created in the same directory as our build.py file.

This is the file that needs to be copied to our micro:bit.

Copying the MICROBIT.hex file to the micro:bit

One simple way to deploy the newly created MICROBIT.hex file to the micro:bit is to use a file browser, such as Nautilus. Connect the micro:bit to your PC and it should appear as a drive called MICROBIT. Double click on this to connect the micro:bit to your PC. Then drag and drop the MICROBIT.hex file onto this folder. The LED on the back of the micro:bit should flash for a few seconds and then the code will run. You will see 'HELLO WORLD' scroll across the LEDs on the front of the micro:bit.

There are slicker ways to transfer the hex file across though. Each time that the micro:bit has new code flashed to it, the connection to the PC is lost. This means that you need to double click on the MICROBIT drive each time you want to load a new hex file to connect the board, then drag over the newly created hex file. Wouldn't it be nice to automate this, so that each time you create a new hex file, it is automagically loaded to the micro:bit?

Automating loading hex files to the micro:bit

I wrote a blog post about a script I created to find and mount a micro:bit after it is connected to my laptop's USB port. Please find this post here. I aliased the script needed to find and mount an attached micro:bit in my .bashrc file as 'mm'. In LInux, we can use the 'inotifywait' command to watch the MICROBIT.hex file we create when we build the C++ project for an update. When the hex file is updated, we can tell the system to mount the attached micro:bit and write the new hex file to the micro:bit. Here's the command that I use:

while inotifywait -e close_write MICROBIT.hex ; do mm && cp ./MICROBIT.hex /media/myusername/MICROBIT ; done

You need to change 'myusername' to your user-name. You could, of course, put this into your .bashrc file with a suitable alias.

Analog input test example

The next test I did was to edit one of the sample files supplied in the 'source/samples' directory to display the voltage applied to pin 1 of the micro:bit. I am looking to interface a sensor with the micro:bit, so this is the first step in the project.

If we look in the samples directory, there are a plethora of example files. The one that we will work with is called GPIOTest.cpp. If you look through the example files, you may notice something. None of them have a main function. The main function is needed for a c++ file to execute - this is the first function that runs. Why is this?

When we run python build.py from the root directory of the repository, it looks for a main function throughout the source directory. If there is more than one, the build crashes. I found this out the hard way. So we need to add a main function to our example file. Here's what I did:

Move the sample files to a new directory under the root directory of the repository.
mv ./source/samples samples_all

I moved the file ./source/main.cpp to the samples_all directory and renamed it HelloWorld.cpp
mv ./source/main.cpp ./samples_all/HelloWorld.cpp

Then I copied and renamed the GPIOTest.cpp file to the source directory:
cp ./samples_all/GPIOTest.cpp ./source/main.cpp

Now we need to add a main function to the main.cpp file that runs the relevant analog testing function in the file. Looking through the file listing, there is a function called 'analog_test()' starting at line 61 which looks a good bet. Line 69 is:

int px = analogPins[0]->getAnalogValue() / 40;

Looks like analogPins[0] is the pin that is set up to read an analog input. So which pin is analogPins[0]?

Line 16 is:

static Pin *analogPins[] = {&uBit.io.P1};

So analogPins[0] is uBit.io.P1, which looks a lot like pin 1 on the edge connector. Worth a shot. I dug through the firmware files on the relevant repository to confirm this.

Add the following few lines to the end of your new main.cpp file:

int main() {
    uBit.init();
    analog_test();
}

This runs the analog_test() function.

Now we have to build the project to generate a new MICROBIT.hex file. Go to the root directory and type python build.py.

We get an error!

This is because line 2 of the file is:

#include "Tests.h"

We need to copy this file back from our samples_all directory to the source directory, alongside our main.cpp file. The other #include ... files are found in the libraries folder in the repository.

After a wall of text, we should have a new MICROBIT.hex file, ready to load on to the micro:bit. After copying this file over, the LED on the back of the micro:bit will flash for a few seconds, then we should see about half of the LEDs on. This shows that the analog input is 'floating' at about half of the voltage of the power supply.

So, how do we test the analog input? We can test the 0 and maximum input by connecting the ground pin to pin 1. I used a pair of tweezers to do this. Probably more sensible to use some alligator clips connected by a wire. With the ground connected to pin1, no LEDs are on. With the 3V connected to pin 1, all of the LEDs are on. So far so good.

I then tested the input using a 1/2Hz 3V sinusoidal input signal.I have an Analog Discovery 2 board made by Digilent. I programmed this to create the sinusoid and also to power the board. I connected this to the micro:bit using a Kitronik edge connector. If you are powering the micro:bit through the edge connector pins, be sure to only apply 3V. The micro:bit is only designed to take 5V through the USB connector. The little board starts to get quite hot quite quickly if you inadvertantly put 5V into the 3V pin on the edge connector!

To see a short YouTube video showing testing the analog input with the sinusoidal input please click on the picture below: