Update setup and getting-started, add display
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
# MicroRust
|
||||
# MicroRust
|
||||
|
||||
[](https://travis-ci.org/droogmic/microrust)
|
||||
|
||||
> Learn embedded software in Rust on the micro:bit
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
- [Meet your hardware](hardware/README.md)
|
||||
|
||||
- [Development environment setup](setup/README.md)
|
||||
- [Linux](setup/LINUX.md)
|
||||
- [Linux](setup/LINUX.md)
|
||||
- [Windows](setup/WINDOWS.md)
|
||||
- [macOS](setup/MACOS.md)
|
||||
- [Verify the installation](setup/VERIFY.md)
|
||||
@@ -16,15 +16,24 @@
|
||||
- [Building](getting-started/01.00.PROJECT.md)
|
||||
- [Flashing](getting-started/02.00.FLASH.md)
|
||||
- [LED](getting-started/03.00.LED.md)
|
||||
- [Debugging](getting-started/04.00.DEBUGGING.md)
|
||||
- [Debugging](getting-started/04.00.DEBUG.md)
|
||||
|
||||
- [WIP - Hello world](hello-world/00.00.README.md)
|
||||
- [Semi-hosting](hello-world/01.00.SEMIHOSTING.md)
|
||||
- [UART](hello-world/02.00.UART.md)
|
||||
|
||||
- [WIP - Choose your own adventure](choice/00.00.README.md)
|
||||
- [Choose your own adventure](choice/00.00.README.md)
|
||||
|
||||
- [WIP - LED display](display/00.00.README.md)
|
||||
- [LED display](display/00.00.README.md)
|
||||
- [Theory](display/01.00.THEORY.md)
|
||||
- [Problem](display/02.00.PROBLEM.md)
|
||||
- [Layout](display/02.01.LAYOUT.md)
|
||||
- [Delays](display/02.02.DELAY.md)
|
||||
- [Multiplexing](display/02.03.MULT.md)
|
||||
- [WIP - Solution](display/03.00.SOLUTION.md)
|
||||
- [Layout](display/03.01.LAYOUT.md)
|
||||
- [Multiplexing](display/03.02.MULT.md)
|
||||
- [Full](display/03.03.FULL.md)
|
||||
|
||||
- [WIP - Sensors and I²C](sensors/00.00.README.md)
|
||||
|
||||
|
||||
10
src/choice/00.00.README.md
Normal file
10
src/choice/00.00.README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Choose your own adventure
|
||||
|
||||
At this point of the book,
|
||||
you know the basics to get you started with embedded development with Rust.
|
||||
|
||||
The following chapters are all independent of each other.
|
||||
This means they can be done in any order,
|
||||
and the only required knowledge is found in the chapters before this.
|
||||
You can either follow the rest of the boo in order, or choose a chapter based on:
|
||||
what sounds the most interesting, or contains the information to solve a problem.
|
||||
11
src/display/00.00.README.md
Normal file
11
src/display/00.00.README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# WIP - LED display
|
||||
|
||||
This chapters follows on from the basic LED example from getting started.
|
||||
The LEDs are wired up in a matrix, as described in [these schematics][schematics].
|
||||
Only a small proportion of images can be displayed at once with this layout;
|
||||
it is impossible for example to turn on both LED1 and LED11 without also having LED2 and LED10 turning on.
|
||||
|
||||
In this chapter we will be talking through how to achieve the impossible,
|
||||
displaying any chosen image, and even adjusting the brightness!
|
||||
|
||||
[schematics]: https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf
|
||||
26
src/display/01.00.THEORY.md
Normal file
26
src/display/01.00.THEORY.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Theory
|
||||
|
||||
## LED dot matrix display
|
||||
|
||||
A dot matrix display is a display containing a two dimensional array of points,
|
||||
used to represent characters, symbols, or images.
|
||||
All displays today are dot matrix displays, but vector displays also used to exist,
|
||||
examples include radar displays and 1980s arcade games.
|
||||
|
||||
## Persistence of vision
|
||||
|
||||
In order to achieve full control of all LEDs we need to use an optical illusion called the [persistence of vision][pov].
|
||||
This effect causes light which has ceased entering the eye to still be seen for a little while after it has disappeared.
|
||||
|
||||
## Multiplexing
|
||||
|
||||
Multiplexing is the combination of multiple signals over shared medium.
|
||||
In this case, we will be using human vision to multiplex time and space divided signals
|
||||
|
||||
## Method
|
||||
|
||||
We are able to fully control one (circuit) row of LEDs at a time,
|
||||
so by quickly looping through the rows lof LEDs,
|
||||
we can let the brain blur them together into a complete image.
|
||||
|
||||
[pov]: https://en.wikipedia.org/wiki/Persistence_of_vision
|
||||
21
src/display/02.00.PROBLEM.md
Normal file
21
src/display/02.00.PROBLEM.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Problem statement
|
||||
|
||||
> Display any given image on the micro:bit display.
|
||||
> The image will be a 5x5 array, where 0 will represent off and 1 will represent on.
|
||||
|
||||
The following, for example, should display a heart:
|
||||
|
||||
``` rust
|
||||
let heart = [
|
||||
[0, 1, 0, 1, 0],
|
||||
[1, 0, 1, 0, 1],
|
||||
[1, 0, 0, 0, 1],
|
||||
[0, 1, 0, 1, 0],
|
||||
[0, 0, 1, 0, 0],
|
||||
];
|
||||
```
|
||||
|
||||
At this point, you may know enough to solve the problem yourself.
|
||||
If you want to jump straight to the solution, you can go to the end of the next section in this chapter.
|
||||
|
||||
This section will continue formally breaking this problem down into smaller and more tractable pieces.
|
||||
38
src/display/02.01.LAYOUT.md
Normal file
38
src/display/02.01.LAYOUT.md
Normal file
@@ -0,0 +1,38 @@
|
||||
## LED layout
|
||||
|
||||
> Convert a 5x5 array into a 3x9 array to match the display's circuitry.
|
||||
|
||||
### Schematics
|
||||
|
||||
The [schem1] discussed earlier describe the electrical layout of the LEDs,
|
||||
but they do not describe how it relates to the visual layout.
|
||||
It would be a mistake to assume that the numbers 1 to 25 have any correlation
|
||||
to the visual layout of the LEDs on the micro:bit as they do *NOT*.
|
||||
It just happened to be that ROW0 and COL0 intersect at an LED in the top left corner.
|
||||
|
||||
### Reference design
|
||||
|
||||
To find the relationship between the electrical array and visual array,
|
||||
we need to look at the reference design for the micro:bit.
|
||||
This can be found through a link at the bottom of the [micro:bit hardware page][hw]
|
||||
|
||||
|
||||
|
||||
By navigating to the github page > PDF > Schematic Print,
|
||||
you can find a [detailed electrical schematic for the micro:bit][schem2].
|
||||
|
||||
In the top right, you will see an array which can be defined in Rust as follows:
|
||||
|
||||
``` rust
|
||||
const LED_LAYOUT: [[(usize, usize); 5]; 5] = [
|
||||
[(0, 0), (1, 3), (0, 1), (1, 4), (0, 2)],
|
||||
[(2, 3), (2, 4), (2, 5), (2, 6), (2, 7)],
|
||||
[(1, 1), (0, 8), (1, 2), (2, 8), (1, 0)],
|
||||
[(0, 7), (0, 6), (0, 5), (0, 4), (0, 3)],
|
||||
[(2, 2), (1, 6), (2, 0), (1, 5), (2, 1)],
|
||||
];
|
||||
```
|
||||
|
||||
[schem1]: https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf
|
||||
[hw]: http://tech.microbit.org/hardware/#links
|
||||
[schem2]: https://github.com/microbit-foundation/microbit-reference-design/blob/master/PDF/Schematic%20Print/Schematic%20Prints.PDF
|
||||
50
src/display/02.02.DELAY.md
Normal file
50
src/display/02.02.DELAY.md
Normal file
@@ -0,0 +1,50 @@
|
||||
## Delays
|
||||
|
||||
> Create a time delay.
|
||||
|
||||
Another piece of information you will need is how to create a time delay before moving to the next row.
|
||||
we want the time spent switching LED lines on and off to be much shorter than the time spent waiting with LEDs on.
|
||||
|
||||
### For loop
|
||||
|
||||
A first attempt to implement the `delay` function
|
||||
without using any peripherals is to implement it as a `for` loop delay:
|
||||
|
||||
``` rust
|
||||
fn delay(ms: u16) {
|
||||
const K: u16 = 16_000; // 16MHz microprocessor, needs to be tweaked
|
||||
for _ in 0..(K*ms) {}
|
||||
}
|
||||
```
|
||||
|
||||
When compiled in release mode however, this is optimized away.
|
||||
To solve this we could explicitly add an operation inside the loop.
|
||||
The perfect candidate is the [NOP](https://en.wikipedia.org/wiki/NOP).
|
||||
|
||||
``` rust
|
||||
fn delay(ms: u16) {
|
||||
const K: u16 = 16_000; // 16MHz microprocessor, needs to be tweaked
|
||||
for _ in 0..(K*ms) {
|
||||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Timers
|
||||
|
||||
A better way of implementing delays is by using timers.
|
||||
A one-shot timer (also called one pulse mode) works like an alarm clock.
|
||||
You set it once with the amount of time you want, and then wait until it goes off.
|
||||
Fortuinately for us, HAL crates usually have already solved this for us.
|
||||
|
||||
### Microbit
|
||||
|
||||
The microbit has 3 timers, we will use the first: TIMER0.
|
||||
To use it, do the following:
|
||||
|
||||
``` rust
|
||||
if let Some(p) = microbit::Peripherals::take() {
|
||||
let mut delay = Delay::new(p.TIMER0);
|
||||
delay.delay_ms(1000_u32);
|
||||
}
|
||||
```
|
||||
22
src/display/02.03.MULT.md
Normal file
22
src/display/02.03.MULT.md
Normal file
@@ -0,0 +1,22 @@
|
||||
## Multiplexing
|
||||
|
||||
> Multiplex the rows of the matrix
|
||||
|
||||
The final task is to multiplex the rows of electrical matrix into a full image.
|
||||
We will be doing this by scanning through the rows in the display.
|
||||
|
||||
### Pseudocode
|
||||
|
||||
In order to light up an LED,
|
||||
the row needs to be set high and the column needs to be set low.
|
||||
We will assume that at the start of a refresh cycle,
|
||||
that all the rows are set low and all the columns are set high.
|
||||
The order of operations during a refresh cycle is then, for each row:
|
||||
|
||||
1. set the row high
|
||||
2. for each column
|
||||
- set low if the LED associated with that row-column pair should be on
|
||||
3. sleep for a known duration, you should find 2ms is sufficient
|
||||
4. for each column
|
||||
- set high
|
||||
5. set the row low
|
||||
@@ -2,19 +2,23 @@
|
||||
|
||||
Flashing is the process of moving our program into the microcontroller's (persistent) memory. Once flashed, the microcontroller will execute the flashed program every time it is powered on.
|
||||
|
||||
In this case, our `rustled` program will be the only program in the microcontroller memory. By this I mean that there's nothing else running on the microcontroller: no OS, no "daemon", nothing. `rustled` has full control over the device. This is what is meant by *bare-metal* programming.
|
||||
In this case, our `rustled` program will be the only program in the microcontroller memory. By this I mean that there's nothing else running on the microcontroller: no OS, no daemon, nothing. `rustled` has full control over the device. This is what is meant by *bare-metal* programming.
|
||||
|
||||
Onto the actual flashing. First thing we need is to do is launch OpenOCD. We did that in the previous section but this time we'll run the command inside a temporary directory (/tmp on *nix; %TEMP% on Windows).
|
||||
> OS: operating system
|
||||
|
||||
> Daemon: program running in the background
|
||||
|
||||
<!-- Onto the actual flashing. First thing we need is to do is launch OpenOCD. We did that in the previous section but this time we'll run the command inside a temporary directory (/tmp on *nix; %TEMP% on Windows). -->
|
||||
|
||||
Connect the mirco:bit to your computer and run the following commands on a new terminal.
|
||||
|
||||
``` console
|
||||
<!-- ``` console
|
||||
$ # *nix
|
||||
$ cd /tmp
|
||||
|
||||
$ # Windows
|
||||
$ cd %TEMP%
|
||||
```
|
||||
``` -->
|
||||
|
||||
We need to give OCD the name of the interfaces we are using:
|
||||
|
||||
@@ -36,8 +40,13 @@ This SWD interface can be used to flash and debug a microcontroller.
|
||||
It uses the CMSIS-DAP protocol for host debugging of application programs.
|
||||
It will appear as a USB device when you connect the micro:bit to your laptop.
|
||||
|
||||
As for OpenOCD, it's software that provides some services like a *GDB server* on top of USB
|
||||
devices that expose a debugging protocol like SWD or JTAG.
|
||||
As for OpenOCD,
|
||||
it's software that provides some services like a *GDB server*
|
||||
on top of USB devices that expose a debugging protocol like SWD or JTAG.
|
||||
|
||||
> GDB: The **G**NU **d**e**b**ugger will allow us to debug our software
|
||||
> by controlling the execution of our program.
|
||||
> We will learn more about this a little bit later.
|
||||
|
||||
Onto the actual command: those `.cfg` files we are using instruct OpenOCD to look for
|
||||
- a CMSIS-DAP USB interface device (`interface/cmsis-dap.cfg`)
|
||||
@@ -46,32 +55,31 @@ Onto the actual command: those `.cfg` files we are using instruct OpenOCD to loo
|
||||
The OpenOCD output looks like this:
|
||||
|
||||
``` console
|
||||
Open On-Chip Debugger 0.9.0 (2016-04-27-23:18)
|
||||
Open On-Chip Debugger 0.10.0
|
||||
Licensed under GNU GPL v2
|
||||
For bug reports, read
|
||||
http://openocd.org/doc/doxygen/bugs.html
|
||||
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
|
||||
http://openocd.org/doc/doxygen/bugs.html
|
||||
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
|
||||
cortex_m reset_config sysresetreq
|
||||
adapter speed: 1000 kHz
|
||||
adapter_nsrst_delay: 100
|
||||
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
|
||||
none separate
|
||||
Info : Unable to match requested speed 1000 kHz, using 950 kHz
|
||||
Info : Unable to match requested speed 1000 kHz, using 950 kHz
|
||||
Info : clock speed 950 kHz
|
||||
Info : STLINK v2 JTAG v27 API v2 SWIM v15 VID 0x0483 PID 0x374B
|
||||
Info : using stlink api v2
|
||||
Info : Target voltage: 2.919073
|
||||
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
|
||||
Info : CMSIS-DAP: SWD Supported
|
||||
Info : CMSIS-DAP: Interface Initialised (SWD)
|
||||
Info : CMSIS-DAP: FW Version = 1.0
|
||||
Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1
|
||||
Info : CMSIS-DAP: Interface ready
|
||||
Info : clock speed 1000 kHz
|
||||
Info : SWD DPIDR 0x0bb11477
|
||||
Info : nrf51.cpu: hardware has 4 breakpoints, 2 watchpoints
|
||||
```
|
||||
|
||||
The "6 breakpoints, 4 watchpoints" part indicates the debugging features the processor has
|
||||
The "4 breakpoints, 2 watchpoints" part indicates the debugging features the processor has
|
||||
available.
|
||||
|
||||
I mentioned that OpenOCD provides a GDB server so let's connect to that right now:
|
||||
|
||||
``` console
|
||||
$ arm-none-eabi-gdb -q target/thumbv7em-none-eabihf/debug/led-roulette
|
||||
Reading symbols from target/thumbv7em-none-eabihf/debug/led-roulette...done.
|
||||
$ arm-none-eabi-gdb -q target/thumbv6m-none-eabi/debug/rustled
|
||||
Reading symbols from target/thumbv6m-none-eabi/debug/rustled...done.
|
||||
(gdb)
|
||||
```
|
||||
|
||||
@@ -90,10 +98,9 @@ that port.
|
||||
After entering this command, you'll see new output in the OpenOCD terminal:
|
||||
|
||||
``` diff
|
||||
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
|
||||
Info : stm32f3x.cpu: hardware has 4 breakpoints, 2 watchpoints
|
||||
+Info : accepting 'gdb' connection on tcp/3333
|
||||
+Info : device id = 0x10036422
|
||||
+Info : flash size = 256kbytes
|
||||
+Info : nRF51822-QFAA(build code: H0) 256kB Flash
|
||||
```
|
||||
|
||||
Almost there. To flash the device, we'll use the `load` command inside the GDB shell:
|
||||
@@ -151,6 +158,7 @@ This will automate the last few steps so we don't need to repeatedly do the same
|
||||
```
|
||||
target remote :3333
|
||||
load
|
||||
continue
|
||||
```
|
||||
|
||||
## LED
|
||||
@@ -181,10 +189,10 @@ On the first sheet you should find a diagram with a grid of numbered LEDs.
|
||||
> the LED at the point that they cross will have a potential difference across it,
|
||||
> so current will flow and it will light up.
|
||||
|
||||
It is worth noting that the 5x5 array of LEDs is wired up as a 9x3 array, with 2 missing.
|
||||
The 5x5 array of LEDs are actually wired up as a 3x9 array (3 rows by 9 columns), with 2 missing.
|
||||
This is usually done to make the circuit design easier.
|
||||
|
||||
The fifth sheet shows how each row and column correspond to each GPIO pin.
|
||||
The fifth sheet shows how each row and column correspond to each GPIO pin.
|
||||
|
||||
[hw]: http://tech.microbit.org/hardware/
|
||||
[schematics]: https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf
|
||||
|
||||
@@ -38,4 +38,8 @@ fn default_handler(irqn: i16) {
|
||||
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||
}
|
||||
```
|
||||
|
||||
It is worth noting that pin4 starts low, so does not need to be explicitly set low.
|
||||
|
||||
You now know enough to start playing around with the LED display,
|
||||
but before you do, you should know to debug your Rust code on the micro:bit.
|
||||
|
||||
211
src/getting-started/04.00.DEBUG.md
Normal file
211
src/getting-started/04.00.DEBUG.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# Debugging
|
||||
|
||||
We are already inside a debugging session so let's debug our program.
|
||||
|
||||
After the `load` command, our program is stopped at its *entry point*. This is indicated by the
|
||||
"Start address 0x8000XXX" part of GDB's output. The entry point is the part of a program that a
|
||||
processor / CPU will execute first.
|
||||
|
||||
The starter project I've provided to you has some extra code that runs *before* the `main` function.
|
||||
At this time, we are not interested in that "pre-main" part so let's skip right to the beginning of
|
||||
the `main` function. We'll do that using a breakpoint:
|
||||
|
||||
```
|
||||
(gdb) break rustled::main
|
||||
Breakpoint 1 at 0x8000218: file src/main.rs, line 8.
|
||||
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
Note: automatically using hardware breakpoints for read-only addresses.
|
||||
|
||||
Breakpoint 1, rustled::main () at src/rustled/src/main.rs:13
|
||||
13 let x = 42;
|
||||
```
|
||||
|
||||
Breakpoints can be used to stop the normal flow of a program.
|
||||
The `continue` command will let the program run freely *until* it reaches a breakpoint.
|
||||
In this case, until it reaches the `main` function because there's a breakpoint there.
|
||||
|
||||
Note that GDB output says "Breakpoint 1".
|
||||
Remember that our processor can only use four of these
|
||||
breakpoints so it's a good idea to pay attention to these messages.
|
||||
|
||||
For a nicer debugging experience, we'll be using GDB's Text User Interface (TUI).
|
||||
To enter into that mode, on the GDB shell enter the following command:
|
||||
|
||||
```
|
||||
(gdb) layout src
|
||||
```
|
||||
|
||||
> **NOTE** Apologies Windows users.
|
||||
> The GDB shipped with the GNU ARM Embedded Toolchain doesn't support this TUI mode `:(`.
|
||||
|
||||
At any point you can leave the TUI mode using the following command:
|
||||
|
||||
```
|
||||
(gdb) tui disable
|
||||
```
|
||||
|
||||
OK. We are now at the beginning of `main`.
|
||||
We can advance the program statement by statement using the `step` command.
|
||||
So let's use that twice to reach the `y = x` statement.
|
||||
Once you've typed `step` once you can just hit enter to run it again.
|
||||
|
||||
```
|
||||
(gdb) step
|
||||
14 _y = x;
|
||||
```
|
||||
|
||||
If you are not using the TUI mode,
|
||||
on each `step` call GDB will print back the current statement along with its line number.
|
||||
|
||||
We are now "on" the `y = x` statement; that statement hasn't been executed yet. This means that `x`
|
||||
is initialized but `y` is not. Let's inspect those stack/local variables using the `print` command:
|
||||
|
||||
```
|
||||
(gdb) print x
|
||||
$1 = 42
|
||||
|
||||
(gdb) print &x
|
||||
$2 = (i32 *) 0x10001fdc
|
||||
|
||||
(gdb) print _y
|
||||
$3 = 134219052
|
||||
|
||||
(gdb) print &_y
|
||||
$4 = (i32 *) 0x10001fd8
|
||||
```
|
||||
|
||||
As expected, `x` contains the value `42`. `y`, however, contains the value `134219052` (?). Because
|
||||
`_y` has not been initialized yet, it contains some garbage value.
|
||||
|
||||
The command `print &x` prints the address of the variable `x`. The interesting bit here is that GDB
|
||||
output shows the type of the reference: `i32*`, a pointer to an `i32` value. Another interesting
|
||||
thing is that the addresses of `x` and `_y` are very close to each other: their addresses are just
|
||||
`4` bytes apart.
|
||||
|
||||
Instead of printing the local variables one by one, you can also use the `info locals` command:
|
||||
|
||||
```
|
||||
(gdb) info locals
|
||||
x = 42
|
||||
_y = 134219052
|
||||
```
|
||||
|
||||
OK. With another `step`, we'll be on top of the `loop {}` statement:
|
||||
|
||||
```
|
||||
(gdb) step
|
||||
17 loop {}
|
||||
```
|
||||
|
||||
And `_y` should now be initialized.
|
||||
|
||||
```
|
||||
(gdb) print _y
|
||||
$5 = 42
|
||||
```
|
||||
|
||||
If we use `step` again on top of the `loop {}` statement, we'll get stuck because the program will
|
||||
never pass that statement. Instead, we'll switch to the disassemble view with the `layout asm`
|
||||
command and advance one instruction at a time using `stepi`.
|
||||
|
||||
> **NOTE** If you used the `step` command by mistake and GDB got stuck, you can get unstuck by hitting `Ctrl+C`.
|
||||
|
||||
```
|
||||
(gdb) layout asm
|
||||
```
|
||||
|
||||
If you are not using the TUI mode, you can use the `disassemble /m` command to disassemble the
|
||||
program around the line you are currently at.
|
||||
|
||||
```
|
||||
(gdb) disassemble /m
|
||||
Dump of assembler code for function led_roulette::main:
|
||||
11 fn main() -> ! {
|
||||
0x08000188 <+0>: sub sp, #8
|
||||
|
||||
12 let _y;
|
||||
13 let x = 42;
|
||||
0x0800018a <+2>: movs r0, #42 ; 0x2a
|
||||
0x0800018c <+4>: str r0, [sp, #4]
|
||||
|
||||
14 _y = x;
|
||||
0x0800018e <+6>: ldr r0, [sp, #4]
|
||||
0x08000190 <+8>: str r0, [sp, #0]
|
||||
|
||||
15
|
||||
16 // infinite loop; just so we don't leave this stack frame
|
||||
17 loop {}
|
||||
=> 0x08000192 <+10>: b.n 0x8000194 <led_roulette::main+12>
|
||||
0x08000194 <+12>: b.n 0x8000194 <led_roulette::main+12>
|
||||
|
||||
End of assembler dump.
|
||||
```
|
||||
|
||||
See the fat arrow `=>` on the left side? It shows the instruction the processor will execute next.
|
||||
|
||||
If not inside the TUI mode on each `stepi` command GDB will print the statement, the line number
|
||||
*and* the address of the instruction the processor will execute next.
|
||||
|
||||
```
|
||||
(gdb) stepi
|
||||
0x08000194 17 loop {}
|
||||
|
||||
(gdb) stepi
|
||||
0x08000194 17 loop {}
|
||||
```
|
||||
|
||||
One last trick before we move to something more interesting. Enter the following commands into GDB:
|
||||
|
||||
```
|
||||
(gdb) monitor reset halt
|
||||
Unable to match requested speed 1000 kHz, using 950 kHz
|
||||
Unable to match requested speed 1000 kHz, using 950 kHz
|
||||
adapter speed: 950 kHz
|
||||
target halted due to debug-request, current mode: Thread
|
||||
xPSR: 0x01000000 pc: 0x08000188 msp: 0x10002000
|
||||
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
|
||||
Breakpoint 1, led_roulette::main () at src/main.rs:8
|
||||
8 let x = 42;
|
||||
```
|
||||
|
||||
We are now back at the beginning of `main`!
|
||||
|
||||
`monitor reset halt` will reset the microcontroller and stop it right at the program entry point.
|
||||
The following `continue` command will let the program run freely until it reaches the `main`
|
||||
function that has a breakpoint on it.
|
||||
|
||||
This combo is handy when you, by mistake, skipped over a part of the program that you were
|
||||
interested in inspecting. You can easily roll back the state of your program back to its very
|
||||
beginning.
|
||||
|
||||
> **The fine print**: This `reset` command doesn't clear or touch RAM. That memory will retain its
|
||||
> values from the previous run. That shouldn't be a problem though, unless your program behavior
|
||||
> depends of the value of *uninitialized* variables but that's the definition of Undefined Behavior
|
||||
> (UB).
|
||||
|
||||
We are done with this debug session. You can end it with the `quit` command.
|
||||
|
||||
```
|
||||
(gdb) quit
|
||||
A debugging session is active.
|
||||
|
||||
Inferior 1 [Remote target] will be detached.
|
||||
|
||||
Quit anyway? (y or n) y
|
||||
Detaching from program: $PWD/target/thumbv7em-none-eabihf/debug/led-roulette, Remote target
|
||||
Ending remote debugging.
|
||||
```
|
||||
|
||||
> **NOTE** If the default GDB CLI is not to your liking check out [gdb-dashboard].
|
||||
> It uses Python to turn the default GDB CLI into a dashboard that shows registers,
|
||||
> the source view, the assembly view and other things.
|
||||
|
||||
[gdb-dashboard]: https://github.com/cyrus-and/gdb-dashboard#gdb-dashboard
|
||||
|
||||
Don't close OpenOCD though! We'll use it again and again later on. It's better
|
||||
just to leave it running.
|
||||
@@ -1 +0,0 @@
|
||||
# Debugging
|
||||
@@ -46,13 +46,21 @@ What does this board contain? For full details see the [microbit hardware page][
|
||||
|
||||
- A second microcontroller: NXP/Freescale KL26Z. This microcontroller handles the USB interface,
|
||||
communication between your computer and the main microcontroller,
|
||||
and changing the USB's input voltage from 5V to 3.3V.
|
||||
and converting the USB's input voltage from 5V to 3.3V.
|
||||
|
||||
## Micro-USB Cable
|
||||
|
||||
This can be any generic cable, and is used to connect the microbit to your computer.
|
||||
This comes with your microbit but can be any generic cable,
|
||||
and is used to connect the microbit to your computer.
|
||||
|
||||
## External battery pack
|
||||
|
||||
The external battery pack that comes with the microbit will not be used explicitly as part of this guide,
|
||||
but feel free to use it to test your software without being tethered to a computer.
|
||||
|
||||
## Plugging it in
|
||||
|
||||
You can use the micro-USB cable to power the micro:bit, and to transfer data.
|
||||
When you power up a new micro:bit you will see the display light up as the factory-installed program is executed.
|
||||
Otherwise, the last program will automatically be executed.
|
||||
The black reset button next to the USB input will restart the program being run.
|
||||
|
||||
@@ -40,11 +40,12 @@ With other development boards, this text would lose most if not all its beginner
|
||||
and "easy to follow"-ness, IMO.
|
||||
|
||||
There are other similar guides for different hardware. For a full list see [this list][books].
|
||||
[books]: https://github.com/rust-embedded/awesome-embedded-rust/#books-blogs-and-training-materials
|
||||
|
||||
The following are worth a special mention:
|
||||
|
||||
- [Discovery](https://japaric.github.io/discovery/) by @japaric: The genesis guide which this is based on. Uses the STM32F3DISCOVERY.
|
||||
|
||||
|
||||
[books]: https://github.com/rust-embedded/awesome-embedded-rust/#books-blogs-and-training-materials
|
||||
|
||||
If you have a different cortex-m development board and you don't consider yourself a total beginner, you are
|
||||
better off starting with the [cortex-m-quickstart] project template.
|
||||
|
||||
@@ -49,59 +49,20 @@ Then, use your editor of choice to append to your `PATH` in the appropriate shel
|
||||
PATH=$PATH:$HOME/local/gcc-arm-none-eabi-7-2017-q4-major/bin
|
||||
```
|
||||
|
||||
## Optional packages
|
||||
|
||||
- Ubuntu / Debian
|
||||
|
||||
``` console
|
||||
$ sudo apt-get install \
|
||||
bluez \
|
||||
rfkill
|
||||
```
|
||||
|
||||
- Fedora
|
||||
|
||||
``` console
|
||||
$ sudo dnf install \
|
||||
bluez \
|
||||
rfkill
|
||||
```
|
||||
|
||||
- Arch Linux
|
||||
|
||||
``` console
|
||||
$ sudo pacman -S \
|
||||
bluez \
|
||||
bluez-utils \
|
||||
rfkill
|
||||
```
|
||||
|
||||
## udev rules
|
||||
|
||||
These rules let you use USB devices like the F3 and the Serial module without root privilege, i.e.
|
||||
`sudo`.
|
||||
|
||||
Create these two files in `/etc/udev/rules.d` with the contents shown below.
|
||||
|
||||
``` console
|
||||
$ cat /etc/udev/rules.d/99-ftdi.rules
|
||||
```
|
||||
|
||||
``` text
|
||||
# FT232 - USB <-> Serial Converter
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", GROUP="uucp"
|
||||
```
|
||||
Create this file in `/etc/udev/rules.d` with the contents shown below.
|
||||
|
||||
``` console
|
||||
$ cat /etc/udev/rules.d/99-openocd.rules
|
||||
```
|
||||
|
||||
``` text
|
||||
# STM32F3DISCOVERY rev A/B - ST-LINK/V2
|
||||
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", GROUP="uucp"
|
||||
|
||||
# STM32F3DISCOVERY rev C+ - ST-LINK/V2-1
|
||||
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", GROUP="uucp"
|
||||
# microbit - CMSIS-DAP
|
||||
ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", GROUP="uucp"
|
||||
```
|
||||
|
||||
Then reload the udev rules with:
|
||||
@@ -120,7 +81,7 @@ $ groups $(id -nu)
|
||||
$ # ^^^^
|
||||
```
|
||||
|
||||
(`$(id -nu)` returns your user name. In my case it's `japaric`.)
|
||||
(`$(id -nu)` returns your user name.)
|
||||
|
||||
If `uucp` appears in the output. You are all set! Go to the [next section]. Otherwise, keep reading:
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# macOS
|
||||
|
||||
> UNTESTED: please submit an issue if you can confirm this works.
|
||||
|
||||
All the tools can be install using [Homebrew]:
|
||||
|
||||
[Homebrew]: http://brew.sh/
|
||||
@@ -14,4 +16,4 @@ Caskroom/tap` first and try again.
|
||||
|
||||
That's all! Go to the [next section].
|
||||
|
||||
[next section]: 03-setup/verify.html
|
||||
[next section]: 03-setup/VERIFY.html
|
||||
|
||||
@@ -61,6 +61,6 @@ $ cargo install itm
|
||||
|
||||
Now follow the instructions specific to the OS you are using:
|
||||
|
||||
- [Linux](setup/linux.html)
|
||||
- [Windows](setup/windows.html)
|
||||
- [macOS](setup/macos.html)
|
||||
- [Linux](setup/LINUX.html)
|
||||
- [Windows](setup/WINDOWS.html)
|
||||
- [macOS](setup/MACOS.html)
|
||||
|
||||
@@ -6,28 +6,29 @@ Let's verify that all the tools were installed correctly.
|
||||
|
||||
### Verify permissions
|
||||
|
||||
Connect the F3 to your laptop using an USB cable. Be sure to connect the cable to the "USB ST-LINK"
|
||||
port, the USB port in the center of the edge of the board.
|
||||
Connect the micro:bit to your laptop using an USB cable.
|
||||
|
||||
The F3 should now appear as a USB device (file) in `/dev/bus/usb`. Let's find out how it got
|
||||
enumerated:
|
||||
The micro:bit should now appear as a USB device (file) in `/dev/bus/usb`.
|
||||
Let's find out how it got enumerated:
|
||||
|
||||
``` console
|
||||
$ lsusb | grep -i stm
|
||||
Bus 003 Device 004: ID 0483:374b STMicroelectronics ST-LINK/V2.1
|
||||
$ # ^^^ ^^^
|
||||
$ lsusb | grep -i NXP
|
||||
Bus 002 Device 033: ID 0d28:0204 NXP ARM mbed
|
||||
^^^ ^^^
|
||||
```
|
||||
|
||||
In my case, the F3 got connected to the bus #3 and got enumerated as the device #4. This means the
|
||||
file `/dev/bus/usb/003/004` *is* the F3. Let's check its permissions:
|
||||
In my case, the micro:bit got connected to the bus #2 and got enumerated as the device #33.
|
||||
This means the file `/dev/bus/usb/002/033` *is* the Fmicro:bit3.
|
||||
Let's check its permissions:
|
||||
|
||||
``` console
|
||||
$ ls -l /dev/bus/usb/003/004
|
||||
crw-rw-r-- 1 root uucp 189, 262 Oct 27 00:00 /dev/bus/usb/003/004
|
||||
$ ls -l /dev/bus/usb/002/033
|
||||
crw-rw---- 1 root uucp 189, 160 Jul 8 14:06 /dev/bus/usb/002/033
|
||||
^^^^
|
||||
```
|
||||
|
||||
The group should be `uucp`. If it's not ... then check your [udev rules] and try re-loading them
|
||||
with:
|
||||
The group should be `uucp`.
|
||||
If it's not ... then check your [udev rules] and try re-loading them with:
|
||||
|
||||
[udev rules]: 03-setup/linux.html#udev%20rules
|
||||
|
||||
@@ -35,71 +36,45 @@ with:
|
||||
$ sudo udevadm control --reload-rules
|
||||
```
|
||||
|
||||
Now let's repeat the procedure for the Serial module.
|
||||
|
||||
Unplug the F3 and plug the Serial module. Now, figure out what's its associated file:
|
||||
|
||||
``` console
|
||||
$ lsusb | grep -i ft232
|
||||
Bus 003 Device 005: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC
|
||||
```
|
||||
|
||||
In my case, it's the `/dev/bus/usb/003/005`. Now, check its permissions:
|
||||
|
||||
``` console
|
||||
$ ls -l /dev/bus/usb/003/005
|
||||
crw-rw-r--+ 1 root uucp 189, 261 Oct 27 00:00 /dev/bus/usb/003/005
|
||||
```
|
||||
|
||||
As before, the group should be `uucp`.
|
||||
|
||||
## All
|
||||
|
||||
### First OpenOCD connection
|
||||
|
||||
First, connect the F3 to your laptop using an USB cable. Connect the cable to the USB port in the
|
||||
center of edge of the board, the one that's labeled "USB ST-LINK".
|
||||
|
||||
Two *red* LEDs should turn on right after connecting the USB cable to the board.
|
||||
First, connect the micro:bit to your computer using the micro-USB cable.
|
||||
The *yellow* LED next to the USB input should turn on right after connecting the USB cable to the board.
|
||||
|
||||
Next, run this command:
|
||||
|
||||
``` console
|
||||
$ # *nix
|
||||
$ openocd -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg
|
||||
$ openocd-f interface/cmsis-dap.cfg -f target/nrf51.cfg
|
||||
|
||||
$ # Windows
|
||||
$ # NOTE cygwin users have reported problems with the -s flag. If you run into
|
||||
$ # that you can call openocd from the `C:\OpenOCD\share\scripts` directory
|
||||
$ openocd -s C:\OpenOCD\share\scripts -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg
|
||||
$ openocd -s C:\OpenOCD\share\scripts -f interface/cmsis-dap.cfg -f target/nrf51.cfg
|
||||
```
|
||||
|
||||
> **NOTE** Windows users: `C:\OpenOCD` is the directory where you installed OpenOCD to.
|
||||
|
||||
> **IMPORTANT** There is more than one hardware revision of the STM32F3DISCOVERY board. For older
|
||||
> revisions, you'll need to change the "interface" argument to `-f interface/stlink-v2.cfg` (note:
|
||||
> no `-1` at the end). Alternatively, older revisions can use `-f board/stm32f3discovery.cfg`
|
||||
> instead of `-f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg`.
|
||||
|
||||
You should see output like this:
|
||||
|
||||
``` console
|
||||
Open On-Chip Debugger 0.10.0
|
||||
Licensed under GNU GPL v2
|
||||
For bug reports, read
|
||||
http://openocd.org/doc/doxygen/bugs.html
|
||||
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
|
||||
http://openocd.org/doc/doxygen/bugs.html
|
||||
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
|
||||
cortex_m reset_config sysresetreq
|
||||
adapter speed: 1000 kHz
|
||||
adapter_nsrst_delay: 100
|
||||
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
|
||||
none separate
|
||||
Info : Unable to match requested speed 1000 kHz, using 950 kHz
|
||||
Info : Unable to match requested speed 1000 kHz, using 950 kHz
|
||||
Info : clock speed 950 kHz
|
||||
Info : STLINK v2 JTAG v27 API v2 SWIM v15 VID 0x0483 PID 0x374B
|
||||
Info : using stlink api v2
|
||||
Info : Target voltage: 2.915608
|
||||
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
|
||||
Info : CMSIS-DAP: SWD Supported
|
||||
Info : CMSIS-DAP: Interface Initialised (SWD)
|
||||
Info : CMSIS-DAP: FW Version = 1.0
|
||||
Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1
|
||||
Info : CMSIS-DAP: Interface ready
|
||||
Info : clock speed 1000 kHz
|
||||
Info : SWD DPIDR 0x0bb11477
|
||||
Info : nrf51.cpu: hardware has 4 breakpoints, 2 watchpoints
|
||||
```
|
||||
|
||||
(If you don't ... then check the [general troubleshooting] instructions.)
|
||||
@@ -108,7 +83,7 @@ Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
|
||||
|
||||
`openocd` will block the terminal. That's fine.
|
||||
|
||||
Also, one of the red LEDs, the one closest to the USB port, should start oscillating between red
|
||||
light and green light.
|
||||
Also, the `yellow` LED should start blinking very fast.
|
||||
It may seem concerning, but it is a good sign.
|
||||
|
||||
That's it! It works. You can now close/kill `openocd`.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Windows
|
||||
|
||||
> UNTESTED: please submit an issue if you can confirm this works.
|
||||
|
||||
## `arm-none-eabi-*`
|
||||
|
||||
ARM provides `.exe` installers for Windows. Grab one from [here][gcc], and follow the instructions.
|
||||
@@ -38,13 +40,6 @@ Download the latest `putty.exe` from [this site] and place it somewhere in your
|
||||
|
||||
[this site]: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
|
||||
|
||||
## ST-LINK USB driver
|
||||
|
||||
You'll also need to install [this USB driver] or OpenOCD won't work. Follow the installer
|
||||
instructions and make sure you install the right (32-bit or 64-bit) version of the driver.
|
||||
|
||||
[this USB driver]: http://www.st.com/en/embedded-software/stsw-link009.html
|
||||
|
||||
That's all! Go to the [next section].
|
||||
|
||||
[next section]: 03-setup/verify.html
|
||||
[next section]: 03-setup/VERIFY.html
|
||||
|
||||
Reference in New Issue
Block a user