Continued improvements, leddisplay solution, linkchecker cache, etc.

This commit is contained in:
Michael Droogleever
2018-07-22 17:04:40 +02:00
parent b81ea7156d
commit 9931a3b241
25 changed files with 217 additions and 123 deletions

View File

@@ -19,7 +19,9 @@ script:
after_success:
- bash ci/after-success.sh
cache: cargo
cache:
- cargo
- pip
before_cache:
# Travis can't cache files that are not readable by "others"

View File

@@ -16,6 +16,7 @@
- [Building](getting-started/01.00.BUILD.md)
- [Flashing](getting-started/02.00.FLASH.md)
- [Debugging](getting-started/03.00.DEBUG.md)
- [Solution](getting-started/04.00.SOLUTION.md)
- [Hello world](hello-world/00.00.README.md)
- [Semihosting](hello-world/01.00.SEMIHOSTING.md)
@@ -33,7 +34,7 @@
- [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)
- [Solution](display/03.00.SOLUTION.md)
- [Layout](display/03.01.LAYOUT.md)
- [Multiplexing](display/03.02.MULT.md)
- [Full](display/03.03.FULL.md)
@@ -43,9 +44,9 @@
- [WIP - Real time](rtfm/00.00.README.md)
- [WIP - HAL](hal/00.00.README.md)
- [Registers](hal/01.00.REGISTERS.md)
<!-- - [Registers](hal/01.00.REGISTERS.md)
- [Peripherals](hal/01.00.PERIPHERALS.md)
- [Clocks and timers](hal/02.00.DELAY.md)
- [Clocks and timers](hal/02.00.DELAY.md) -->
[Explore](appendix/explore.md)

View File

@@ -123,7 +123,7 @@ So where to next? There are several options:
- You could check out the examples in the [`microbit`] board support crate repository. All those examples work for
the micro:bit board you have.
[`f3`]: https://docs.rs/f3
[`microbit`]: https://github.com/therealprof/microbit
- You could try out [this motion sensors demo][madgwick]. Details about the implementation and
source code are available in [this blog post][wd-1-2].

View File

@@ -1,15 +1,15 @@
# GDB cheatsheet
| Short | Command | Action |
|:---------- |:---------------- |:------------------------------------------- |
| b? | break | Add breakpoint |
| | continue | |
| | step | |
| | stepi | |
| | print | |
| | info locals | |
| | layout src | |
| | tui disable | |
| | layout asm | |
| | dissasmble /m | |
| | monitor reset halt| |
| Short | Command | Action |
|:----- |:------------------- |:---------------------------------------------- |
| b | break [location] | Set breakpoint at specified location. |
| c | continue | Continue program being debugged. |
| s | step | Step program until it reaches a different source line. |
| si | stepi | Step one instruction exactly. |
| p | print | Print value of expression EXP. |
| i lo | info locals | Local variables of current stack frame. |
| la s | layout src | Displays source and command windows. |
| la a | layout asm | Displays disassembly and command windows. |
| tu d | tui disable | Disable TUI display mode. |
| | dissasmble /m | Disassemble a specified section of memory. |
| | monitor reset halt | Send a command to the remote monitor. |

View File

@@ -1,10 +1,13 @@
# Choose your own adventure
At this point of the book,
you know the basics to get you started with embedded development with Rust.
you know the basics to get 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.
Feel free to either follow the rest of the book in order, or choose a chapter which interests you.
> A large portion of this book is still unfinished and we would love your support.
> Please submit an issue to request a new section, and a pull request to add a section.

View File

@@ -16,8 +16,6 @@ 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].

View File

@@ -0,0 +1,3 @@
# Solution
This solution describes a blocking display driver.

View File

@@ -0,0 +1,28 @@
# Layout
> Convert a 5x5 array into a 3x9 array to match the display's circuitry.
``` 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)],
];
/// Convert 5x5 display image to 3x9 matrix image
pub fn display2matrix(led_display: [[u8; 5]; 5]) -> [[u8; 9]; 3] {
// Create 3x9 array
let mut led_matrix: [[u8; 9]; 3] = [[0; 9]; 3];
// Iterate through zip of input array and layout array
for (led_display_row, layout_row) in led_display.iter().zip(LED_LAYOUT.iter()) {
// Continue iterating through rows
for (led_display_val, layout_loc) in led_display_row.iter().zip(layout_row) {
// Assign dereferenced val to array
led_matrix[layout_loc.0][layout_loc.1] = *led_display_val;
}
}
return led_matrix;
}
```

40
src/display/03.02.MULT.md Normal file
View File

@@ -0,0 +1,40 @@
# Multiplexing
> Multiplex the rows of the matrix
``` rust
/// Display 3x9 matrix image for a given duration.
pub fn display_pre(&mut self, delay: &mut Delay, led_matrix: [[u8; 9]; 3], duration_ms: u32) {
// TODO
// These need to be populated with PINs, e.g.:
let rows = [PIN; 3];
let cols = [PIN; 9];
// Set refresh rate.
let delay_ms = 2;
// Calculate number of loops.
let loops = duration_ms / (rows.len() as u32 * delay_ms);
for _ in 0..loops {
for (row_line, led_matrix_row) in rows.iter_mut().zip(led_matrix.iter()) {
// Set the row high.
row_line.set_high();
// Set the correct pins low (on)
// This could lead to very small differences in execution time,
// but this is not worth correcting for, as it is << 2ms.
for (col_line, led_matrix_val) in cols.iter_mut().zip(led_matrix_row.iter()) {
// We ignore any brightness setting, just use 0 and 1.
if *led_matrix_val > 0 {
col_line.set_low();
}
}
delay.delay_ms(delay_ms);
// It is not worth the logic to check which pins need resetting,
// so set all the pins back high.
for col_line in cols.iter_mut() {
col_line.set_high();
}
// Set the row back low.
row_line.set_low();
}
}
}
```

View File

@@ -0,0 +1,4 @@
# Full
Full solution still to come.
Please look at the implementation in the [micro:bit crate](https://github.com/therealprof/microbit]).

View File

@@ -6,4 +6,4 @@ rustflags = [
]
[build]
target = "thumbv6m-none-eabi"
target = "thumbv6m-none-eabi"

View File

@@ -1,4 +1,10 @@
# Connects GDB to OpenOCD server port
target remote :3333
# (optional) Unmangle function names when debugging
set print asm-demangle on
# Load your program, breaks at entry
load
# (optional) Add breakpoint at function
break main
continue
# Continue with execution
continue

View File

@@ -1,6 +1,6 @@
# New Project
``` console
``` shell
$ cargo new rustled
Created binary (application) `rustled` project
$ cd rustled
@@ -35,11 +35,11 @@ $ rustup target add thumbv6m-none-eabi
Now how should we use this? Well, if you were to take a look at `$ cargo build -h`, you would try:
``` console
``` shell
$ cargo build --target thumbv6m-none-eabi
```
```
``` shell
error[E0463]: can't find crate for `std`
|
= note: the `thumbv6m-none-eabi` target may not be installed
@@ -73,11 +73,11 @@ fn main() {
## Build 2
``` console
``` shell
$ cargo build --target thumbv6m-none-eabi
```
```
``` shell
error: cannot find macro `println!` in this scope
--> src/main.rs:4:5
|
@@ -90,7 +90,7 @@ We don't need it at the moment, so we can remove it and try to build again.
## Build 3
```
``` shell
error: language item required, but not found: `panic_impl`
```
@@ -111,13 +111,13 @@ If you have forgotten how to do this, try looking at [the cargo book][cargo].
[cargo]: https://doc.rust-lang.org/stable/cargo/
`Cargo.toml`
```
``` toml
[dependencies]
panic-abort = "~0.2"
```
`src/main.rs`
```
``` rust
#![no_std]
extern crate panic_abort;
@@ -128,11 +128,11 @@ fn main() {
## Build 4
``` console
``` shell
$ cargo build --target thumbv6m-none-eabi
```
```
``` shell
error: requires `start` lang_item
```
@@ -151,7 +151,7 @@ We need to replace the operating system entry point.
You could for example name a function after the default entry point, which for linux is `_main`,
and start that way. Note, you would also need to disable [name mangling][nm]:
```
``` rust
#![no_std]
#![no_main]
@@ -170,7 +170,7 @@ At this point we need the help of a board specific crate and a few cargo tweaks
Let us add a dependency on the board crate for the micro:bit.
```
``` toml
[dependencies]
panic-abort = "~0.2"
microbit="~0.5"
@@ -213,6 +213,8 @@ For more information, you can read [the documentation here][cargoconfig].
[cargoconfig]: https://doc.rust-lang.org/cargo/reference/config.html
### `.cargo/config`
``` toml
# Configure builds for our target
[target.thumbv6m-none-eabi]
@@ -241,15 +243,16 @@ and cargo will automatically add `--target thumbv6m-none-eabi`.
## Build 5
`Cargo.toml`
```
### `Cargo.toml`
``` toml
[dependencies]
panic-abort = "~0.2"
microbit="~0.5"
```
`src/main.rs`
```
### `src/main.rs`
``` rust
#![no_std]
#![no_main]
@@ -260,11 +263,11 @@ fn main() {
}
```
``` console
cargo build
``` shell
$ cargo build
```
```
``` shell
error[E0308]: mismatched types
--> src/main.rs:9:1
|
@@ -282,8 +285,9 @@ A little known rust feature, so I will forgive you if you do not know what this
A return type of `!` means that the function cannot return
An easy way to implement this, is by using an infinite loop.
`src/main.rs`
```
### `src/main.rs`
``` rust
#![no_std]
#![no_main]
@@ -300,7 +304,7 @@ fn main() -> ! {
## Build 6
```
``` shell
error: linking with `arm-none-eabi-gcc` failed: exit code: 1
|
= note: "arm-none-eabi-gcc" "-L" "/home/xxx/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/thumbv6m-none-eabi/lib" "/home/xxx/rust/rustled/target/thumbv6m-none-eabi/debug/deps/rustled-e6053d34b0422141.2yhvr0tmp69gb94x.rcgu.o" "-o"
@@ -314,15 +318,15 @@ A scary error, but if you look closely you will see `cannot open linker script f
We mentioned something a little earlier about memory.x file.
To save you the hassle of scouring the internet for one or creating your own, you can copy it over into your project:
``` console
cp ../../memory.x ./
``` shell
$ cp ../../memory.x ./
```
> Often a board support crate will already include this, so this step will not be necessary.
## Build 7
```
``` shell
error: linking with `arm-none-eabi-gcc` failed: exit code: 1
|
= note: "arm-none-eabi-gcc" "-L" "/home/xxx/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/thumbv6m-none-eabi/lib" "/home/xxx/rust/rustled/target/thumbv6m-none-eabi/debug/deps/rustled-e6053d34b0422141.2yhvr0tmp69gb94x.rcgu.o" "-o"
@@ -337,16 +341,18 @@ Notice `undefined symbol 'DefaultHandler' referenced in expression`.
We said earlier, as with the memory,
that the hard fault handler and default exception handler both need defining.
`Cargo.toml`
```
### `Cargo.toml`
``` toml
[dependencies]
panic-abort = "~0.2"
cortex-m-rt="~0.5"
microbit="~0.5"
```
`src/main.rs`
```
### `src/main.rs`
``` rust
#![no_std]
#![no_main]

View File

@@ -0,0 +1,27 @@
# Solution
This is a recap of what we have done so far.
## Cargo.toml
``` toml
{{#include Cargo.toml}}
```
## Rust
``` rust
{{#include src/main.rs}}
```
## `.cargo/config`
``` toml
{{#include .cargo/config}}
```
## `.gdbinit`
``` gdb
{{#include .gdbinit}}
```

View File

@@ -5,4 +5,4 @@ version = "0.1.0"
[dependencies]
panic-abort = "~0.2"
cortex-m-rt="~0.5"
microbit="~0.5"
microbit="~0.5"

View File

@@ -27,4 +27,4 @@ fn main() -> ! {
let x = 42;
_y = x;
loop {}
}
}

View File

@@ -72,6 +72,8 @@ use sh::hio;
// -- snip --
let mut stdout = hio::hstdout().unwrap();
stdout.write_str("semitest\n\r").unwrap();
// or
writeln!(hio::hstdout().unwrap(), "Init").unwrap();
```
And that's it!

View File

@@ -20,11 +20,11 @@ On the first sheet you should find a diagram with a grid of numbered LEDs.
> If you do not know much about electronics:
> Each row and column (labelled ROW and COL) represent a GPIO output pin.
> The components labelled LED are light emitting diodes;
> The components labelled LED are light emitting diodes.
> LEDs only let current flow one way, and only emit light when current is flowing.
> If a row is set high, high voltage, and a column is set low, low voltage,
> the LED at the point that they cross will have a potential difference across it,
> so current will flow and it will light up.
> the LED at the point that they cross will have a potential difference across it;
> current will flow and it will light up.
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.

View File

@@ -3,45 +3,13 @@
This is my solution:
``` rust
#![no_std]
#![no_main]
extern crate panic_abort;
extern crate cortex_m_rt as rt;
#[macro_use(entry, exception)]
extern crate microbit;
use rt::ExceptionFrame;
use microbit::hal::prelude::*;
entry!(main);
fn main() -> ! {
if let Some(p) = microbit::Peripherals::take() {
let mut gpio = p.GPIO.split();
let mut led = gpio.pin13.into_push_pull_output();
let _ = gpio.pin4.into_push_pull_output();
led.set_high();
}
loop {}
}
exception!(HardFault, hard_fault);
fn hard_fault(ef: &ExceptionFrame) -> ! {
panic!("{:#?}", ef);
}
exception!(*, default_handler);
fn default_handler(irqn: i16) {
panic!("Unhandled exception (IRQn = {})", irqn);
}
{{#include src/main.rs}}
```
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 and the GPIO in general.
Before you do,
you should know that the microbit crate already includes an abstraction for the LED display,
and how this is implemented is demonstrated in the [LED display chapter](display/00.00.README.html)
You now know enough to start playing around with the micro:bit's LED display and GPIO,
as well as logging data back to the host.
You should know that the microbit crate already includes an abstraction for the LED display for you to use.
How to implemented a simple blocking display driver is demonstrated in the [LED display chapter](display/00.00.README.html).

View File

@@ -31,16 +31,22 @@ fn default_handler(irqn: i16) {
entry!(main);
fn main() -> ! {
let mut stdout = hio::hstdout().unwrap();
stdout.write_str("semihosting test\n\r").unwrap();
writeln!(stdout, "Start").unwrap();
if let Some(p) = microbit::Peripherals::take() {
// Split GPIO
let mut gpio = p.GPIO.split();
// Configure RX and TX pins accordingly
let tx = gpio.pin24.into_push_pull_output().downgrade();
let rx = gpio.pin25.into_floating_input().downgrade();
// Configure serial communication
let (mut tx, _) = serial::Serial::uart0(p.UART0, tx, rx, BAUD115200).split();
let _ = write!(tx, "serial test\n\r");
write!(tx, "serial - start\r\n");
// Get row and column for display
let mut led = gpio.pin13.into_push_pull_output();
let _ = gpio.pin4.into_push_pull_output();
// Set row high (column starts low)
led.set_high();
write!(tx, "serial - LED on\r\n");
}
panic!("test-panic");
panic!("End");
}

View File

@@ -6,7 +6,7 @@ Here are the installation commands for a few Linux distributions.
- Ubuntu 16.04 or newer / Debian Jessie or newer
``` console
``` shell
$ sudo apt-get install \
gcc-arm-none-eabi \
gdb-arm-none-eabi \
@@ -16,7 +16,7 @@ $ sudo apt-get install \
- Fedora 23 or newer
``` console
``` shell
$ sudo dnf install \
arm-none-eabi-gcc-cs \
arm-none-eabi-gdb \
@@ -26,7 +26,7 @@ $ sudo dnf install \
- Arch Linux
``` console
``` shell
$ sudo pacman -S \
arm-none-eabi-gcc \
arm-none-eabi-gdb \
@@ -38,7 +38,7 @@ $ sudo pacman -S \
For distros that don't have packages for [ARM's pre-built toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads), download the "Linux 64-bit" file and put its `bin` directory on your path. Here's one way to do it:
``` console
``` shell
$ mkdir -p ~/local && cd ~/local
$ tar xjf /path/to/downloaded/file/gcc-arm-none-eabi-7-2017-q4-major-linux.tar.bz2.tbz
```
@@ -56,7 +56,7 @@ These rules let you use USB devices like the F3 and the Serial module without ro
Create this file in `/etc/udev/rules.d` with the contents shown below.
``` console
``` shell
$ cat /etc/udev/rules.d/99-openocd.rules
```
@@ -67,7 +67,7 @@ ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", GROUP="uucp"
Then reload the udev rules with:
``` console
``` shell
$ sudo udevadm control --reload-rules
```
@@ -75,7 +75,7 @@ If you had any board plugged to your laptop, unplug them and then plug them in a
Finally, check if you are in the `uucp` group.
``` console
``` shell
$ groups $(id -nu)
(..) uucp (..)
$ # ^^^^
@@ -89,13 +89,13 @@ If `uucp` appears in the output. You are all set! Go to the [next section]. Othe
- Add yourself to the `uucp` group.
``` console
``` shell
$ sudo usermod -a -G uucp $(id -u -n)
```
- Check again the output of `groups`. `uucp` should be there this time!
``` console
``` shell
$ groups $(id -nu)
(..) uucp (..)
$ # ^^^^
@@ -108,7 +108,7 @@ programs you have open right now.
The other option is to use the command below:
``` console
``` shell
$ su - $(id -nu)
```

View File

@@ -6,7 +6,7 @@ All the tools can be install using [Homebrew]:
[Homebrew]: http://brew.sh/
``` console
``` shell
$ brew cask install gcc-arm-embedded
$ brew install minicom openocd
```

View File

@@ -39,21 +39,21 @@ Install rustup by following the instructions at [https://rustup.rs](https://rust
Then, install or switch to the nightly channel.
``` console
``` shell
$ rustup default nightly
```
**NOTE** Make sure you have a nightly newer than `nightly-2018-06-22`.
`rustc -V` should return a date newer than the one shown below:
``` console
``` shell
$ rustc -V
rustc 1.28.0-nightly (056f589fb 2018-06-22)
```
### `itmdump`
``` console
``` shell
$ cargo install itm
```

View File

@@ -11,7 +11,7 @@ Connect the micro:bit to your laptop using an USB cable.
The micro:bit should now appear as a USB device (file) in `/dev/bus/usb`.
Let's find out how it got enumerated:
``` console
``` shell
$ lsusb | grep -i NXP
Bus 002 Device 033: ID 0d28:0204 NXP ARM mbed
^^^ ^^^
@@ -21,7 +21,7 @@ In my case, the micro:bit got connected to the bus #2 and got enumerated as the
This means the file `/dev/bus/usb/002/033` *is* the Fmicro:bit3.
Let's check its permissions:
``` console
``` shell
$ ls -l /dev/bus/usb/002/033
crw-rw---- 1 root uucp 189, 160 Jul 8 14:06 /dev/bus/usb/002/033
^^^^
@@ -32,7 +32,7 @@ If it's not ... then check your [udev rules] and try re-loading them with:
[udev rules]: setup/LINUX.html#udev%20rules
``` console
``` shell
$ sudo udevadm control --reload-rules
```
@@ -45,7 +45,7 @@ The *yellow* LED next to the USB input should turn on right after connecting the
Next, run this command:
``` console
``` shell
$ # *nix
$ openocd-f interface/cmsis-dap.cfg -f target/nrf51.cfg
@@ -59,7 +59,7 @@ $ openocd -s C:\OpenOCD\share\scripts -f interface/cmsis-dap.cfg -f target/nrf51
You should see output like this:
``` console
``` shell
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read

View File

@@ -8,7 +8,7 @@ ARM provides `.exe` installers for Windows. Grab one from [here][gcc], and follo
Just before the installation process finishes tick/select the "Add path to environment variable"
option. Then verify that the tools are in your `%PATH%`:
``` console
``` shell
$ arm-none-eabi-gcc -v
(..)
gcc version 5.4.1 20160919 (release) (..)
@@ -28,7 +28,7 @@ before).
Verify that OpenOCD is in yout `%PATH%` with:
``` console
``` shell
$ openocd -v
Open On-Chip Debugger 0.10.0
(..)