Instrumenting the micro:bit (Digital Systems)
These instructions explain how to capture and display signals from the micro:bit using either the lab oscilloscopes or one of the cheap-and-nasty logic analyser pods ("Saleae clones") that are floating around the lab. I will describe two set-ups: one to measure the time needed to call a subroutine that performs a multiplication, and another that also displays the signal that is sent by the UART when it is outputting characters. The second set-up is the one I used for Lectures 9 and 10 to analyse the behaviour of a program that computes primes and outputs them on the serial port. [Though the screenshots on those pages were made with an older scope and with a genuine Saleae logic analyser with better performance.]
In what follows, I have used a modified version of the mul1
program from Lab one, with the main program changed so that it performs the multiplication over and over again. In main.c
, I've replaced
while (1) { int a, b, c; a = getnum(); b = getnum(); TIMER0_CLEAR = 1; ... }
by
int a, b, c; a = getnum(); b = getnum(); while (1) { TIMER0_CLEAR = 1; ... }
This makes the program prompt for inputs just once, then loop forever performing its calculation with these inputs, so that all the signals on the board are repetitive, and we can use the scope or logic analyser to capture them without continually having to restart the program. If you want to change to different inputs, you can just press Reset.
For the first experiment, we need to connect the scope or logic analyser to just one signal, an I/O pin that powers some of the on-board LEDs. The ground wire from the oscilloscope or logic analyser also needs to be connected so as to provide a reference for measuring the signal.
Using the oscilloscope
1. Plug the micro:bit into an edge connector breakout, then connect the ground wire of the scope probe (a crocodile clip) to ground on the breakout, and the probe hook to pin P3 at the opposite end of the row. At the right-hand end, there are four pins together, all grounded, so if you use the bottom right pin, there is no risk in shorting to adjacent pins. It's easy enough to connect the probe hook at the other end without shorting; just hold the probe and pull back on the ring to expose the spring-loaded hook at the tip.
2. Now start the program and enter two numbers, say 1000 * 1000. We must now set up the oscilloscope to display the resulting signal.
- Hit 'Default Setup' to return all scope parameters to their initial settings. At this stage, you will probably see fleeting signals on the screen, and the challenge now is to turn them into a stable display.
- Oscilloscopes generally have an 'Auto Scale' button that sometimes produces a stable display automatically. Sadly, the widely spaced narrow pulses from the micro:bit are just the kind of signal that Auto Scale cannot deal with. So we will have to find it manually.
- Of the three large knobs, use the one at the lower left to increase the gain on channel 1 by two clicks, from 5V/div to 1V/div. The fleeting signals get taller.
- Use the small knob two to the right of the one you just turned to increase the trigger level to about 1.5V, as shown in the top right corner of the screen. The fleeting signals start to jitter less, but the display is still not stable.
- Change the trigger mode from Auto to Normal. In detail: push the Trigger button to display a menu, then push the bezel button labelled Mode/Auto twice, so that it changes to Mode/Normal. A stable, square pulse is shown in the screen.
- Now you can measure the width of the pulse by adding a measurement. In detail: push the Meas button, then the bezel button marked Type/Freq several times until it says Type/+Width. Now press the 'Add Measurement' button. A legend at the bottom of the display shows a pulse width of about 430ns.
- To see how quickly the pulses repeat, you can try slowing the time base by turning the big Horizontal knob to the left. The individual pulses become narrower on the screen, but if you turn the knob far enough, several successive pulses are shown. The interval between them is about 90ms.
A word about 'Auto' vs 'Normal' trigger modes. In Auto mode (which is the default), the oscilloscope captures waveforms even if no trigger event is detected for a certain time. This means that, even without a proper trigger level set, the display is not completely blank. That means we see the initial fleeting signals, rather than nothing; but after the trigger level is set, the interval between trigger events for our signal is long enough that the scope loses patience and gives up waiting, so the display is not stable. Normal mode overcomes this, by acquiring a signal only when a trigger event happens.
Using a logic analyser
The logic analyser contains a microcontroller, programmed with firmware to record the values on eight digital inputs at a rate of 24MHz. Similar gadgets can be ordered for £10 or less on eBay: just search for "24MHz 8 channel logic" and take your pick. It is a clone of a now outmoded device designed by the company Saleae[1], and can be accessed using either the open-source software called Pulseview (part of the Sigrok project), or the proprietary but free-to-download software supplied by Saleae themselves. Since we are not using genuine Saleae hardware, I think it's more honest to stick to the open source solution.
In using the clone, we face an off-by-one problem, because the logic analyser has channels labelled CH1 to CH8, while the software labels them D0 to D7, and uses the standard resistor colour code (Black = 0, Brown = 1, Red = 2, etc.). It's possible but tedious to relabel the channels and reassign the colours in the software, and fruitless to repeat this task whenever you make a new set-up, so it seems best all round to ignore the label on the LA and wire it up with colours that match those used by the software. That's what has been done in the pictures shown below. If you are lucky, the LA you use will come with the connectors super-glued into a block in the right arrangement: black, red, yellow, blue, grey reading right-to-left along the top row, and brown, orange, green, violet, white along the bottom row. The 8 inputs are now coloured black, red, ..., violet; Ground is white, and the grey Clock wire should be left unconnected.
To simplify connecting to the micro:bit, you can either plug the board into an edge-connector breakout as shown below, or you can use one of the boards that I've soldered with a row of header sockets.
1. Load the modified version of mul1
and check that it works. I chose inputs 1000 and 1000 to give a reasonable signal to search for.
2. Connect the logic analyser as shown in this picture. Note that both the micro:bit (for power and serial data) and the analyser (for power and samples) must be connected over USB. An A to Mini-B cable comes with the LA for this purpose. The white wire from the LA is connected to one of the two rightmost pins on the header – marked 0V – and the black wire is connected to one of the two leftmost pins – marked 3.
3. Start the program called Pulseview. Starting from scratch, you will need to configure it as follows.
3.1. If the LA is already plugged in before you start the program, then it should scan and detect it, and "Saleae Logic" will appear on the toolbar. If not, then you will need to click where it says "No device" or "Demo device", choose fx2lafw (not either of the Saleae devices listed) and USB, and click Scan and OK.
3.2. Choose 10M samples at 24MHz, then click Run. In a second or so, you should see traces that show a repetitive pulse on channel D0 with a period of something like 100ms.
4. To capture and measure the width of the pulses, proceed as follows.
4.1. Click on the tools button just to the right of where it says Saleae Logic and choose a Pre-trigger capture ratio of 1%. (This displays a bit of data captured before the trigger event so we can see the pulse width clearly.)
4.2. Click on the red probe button next to the right and turn off all but channel D0.
4.3. Click on the label saying D0 at the left and set the trigger type to rising edge (fourth from the left).
4.4. Click on Run again and you should see that the acquisition starts with one of the pulses. Zoom in (or reset the record size to 20k samples and re-acquire), and you should see that the pulse was a width of about 440μs.
5. To get a measurement of the pulse width, add a Timing analyser as follows.
5.1. Click on the yellow and green icon to the right of "24MHz" and choose Timing. A new trace will appear.
5.2. Click on the trace label Timing and choose Data = D0.
5.3. You should see a measurement appear that tells is the pulse has width 435μs or so, given inputs of 1000 and 1000 and an unmodified multiplication routine.
You might like to run the program with smaller inputs in order to detect the difference that results from adding one more iteration of the loop in the multiplication algorithm. Beware, though, that the LA's sample rate of 24MHz is not really high enough to resolve reliably single ticks of the 16MHz clock on the micro:bit.
Connecting the serial line
The micro:bit provides no convenient way of monitoring the signals on the serial line connecting the Nordic chip to the host via a USB adapter on the board; the microcontroller pins that are used for them are not brought out to the edge connector. What we can do instead to visualise the serial signals is to divert them to other microcontroller pins that are present on the edge connector, and connect these both to a scope of logic analyser and to the host processor via an external USB-to-serial adapter. Details coming soon. What follows are general instructions that assume you have succeeded in connecting up the UART pins.
If you are using the oscilloscope, you can connect the probe for Channel 1 to the I/O pin as before, and connect the probe for Channel 2 to the TX pin of the UART. With the LED side of the board facing down, there is room next to the Ground hole at the bottom left to connect the crocodile clips that ground the two probes. Adjacent small tracks on each side of the hole and wide track are also grounded, to there is little risk of a short.
After getting a stable picture of the pulses on Channel 1, you can turn on Channel 2 and see the UART signal. It's synchronised pretty well with the LED flashes, because the machine starts to print the results just after finishing the calculation. You can use the large and small Vertical knobs to scale the two signals and move them apart for ease of reading. Slowing down the timebase to 200 or 500μs/div and shifting the trigger position to the left will let you see more of the bits. Also, it's better to make the calculation slower, so that the tail end of the characters transmitted before the calculation starts is separated from the characters transmitted afterwards: try 5000 * 1000.
We haven't bought the scope option that allows automated decoding of UART signals, but just after the end of the LED pulse you can decipher the bits (0)01100110(1) for 01100110 = 0x66 = 'f' then (0)11110110(1) for 01101111 = 0x6f = 'o' and (0)11110110(1) again and (0)00010100(1) for 00101000 = 0x28 = '('. Slow and painful, but possible! (For this screenshot, I set the timebase to 520μs/div so exactly five bit-clocks fit in each horizontal division.)
If you are using a logic analyser, then the white (Ground) and black (D0) lines can be connected to the GND and P3 pins as before, and the Brown (D1) line can be connected to the TX pin of the UART.
In Pulseview, you can enable both Channel D0 and Channel D1, with triggering from a rising edge on D0. Then add a UART analyser, set its TX input to come from D1, and set it to 9600 baud, with all other settings left at their default values. You will then get a trace like the one below, with the characters sent on the UART decoded.
Notes
- ↑ Saleae is a meaningless word that the company's founder thought sounded good.