# Embedded Programming in Rust # ARM Toolchain Rust relying on LLVM is already a cross compiler, however currently linking to embedded targets are done using `binutils`. Under arch you can install the complete GNU toolchaion for ARM using the package `arm-none-eabi-gcc`, which also installs `arm-none-eabi-binutils`. (The package also installs `arm-none-eabi-gdb`, which you will use later for debugging.) # Openocd In order to debug code on the ARM target you need to establish a connection, e.g., using [openocd](http://openocd.org/), available under arch as `openocd`. Later you will start `openocd` in the background using e.g.: ``` > openocd openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg ``` (Assuming that this is a `bluepill` target, programmed using a `stlink-v2` interface.) ``` > openocd openocd -f interface/stlink-v2-1.cfg -f target/stm32f4x.cfg ``` (Assuming that this is a `nucleo stm32f401re` target, programmed using the onboard `stlink-v2-1` interface.) ## port configuration By default `openocd` listens at port `3333` for incoming gdb connections. If you want to program/dubug multiple targets using SWD (Serial Wire Debug) like offered by the `stlink` based interfaces you need one interface per target. In that case you may run several instances of `openocd` listening in on different ports. To that end the target configuration is defined in the `target/*.cfg` ``` ... gdb_port 3333 tcl_port 6666 telnet_port 4444 ... ``` ## interface detection The interface is defined by the `interface/*.cfg` file, e.g, `stlink-v2.cfg`. ``` interface hla hla_layout stlink hla_device_desc "ST-LINK/V2" hla_vid_pid 0x0483 0x3748 ``` You can check the device descriptor by ``` > lsusb ``` # Stutil Not mandatory but offers additional tooling. # Sysroot manager For compiling embedded targets install the `xargo` crate. ```> cargo install xargo``` (Your top level module should give the crate-wide attribute `#![no_std]` in order to use `core` instead of `std` as the default library.) # Using VS Code ## Installation Install the latest version of Visual Studio Code using your packet manager, under arch e.g., [arch wiki](https://wiki.archlinux.org/index.php/Visual_Studio_Code). ## Rust support Install the `Rust(rls)` plugin (just search for `Rust` in the extensions, chose the plugin and install). Assuming you already have `rustup` and the Rust tools installed the required crates will be installed autematically. The RLS plugin is experimental but already quite useuful. If it fails installing you may check the [RLS git](https://github.com/rust-lang-nursery/rls), for further instructions (actually you can run the plugin from `java script` source.) ## Debugging Install the `Native Debug` tool for GDB/LLDB debug support. Visual code is highly customisable using `.json` configuration files. In the `launch.json`, add the section below: ```javascript { "type": "gdb", "request": "attach", "name": "Debug", "gdbpath": "/usr/bin/arm-none-eabi-gdb", "executable": "./target/thumbv7m-none-eabi/debug/bluepill", "target": ":3333", "remote": true, "autorun": [ "monitor reset init", "monitor arm semihosting enable", "set mem inaccessible-by-default off", "d breakpoints", "set remotetimeout 300", "load ./target/thumbv7m-none-eabi/debug/bluepill", "step", "monitor reset halt" ], "cwd": "${workspaceRoot}" } ``` This defines a `Debug` launch configuration, assuming the executable is named `bluepill`, and compiled using ``` >xargo build ``` It launches `/usr/bin/arm-none-eabi-gdb` and attach the target on port `:3333`, the `:` indicates that the connection to be on the local host). It assumes `openocd` is running and has established a connection to the target. Similarly a launch confirguration for release (optimised) builds: ```javascript { "type": "gdb", "request": "attach", "name": "Debug", "gdbpath": "/usr/bin/arm-none-eabi-gdb", "executable": "./target/thumbv7m-none-eabi/release/bluepill", "target": ":3333", "remote": true, "autorun": [ "monitor reset init", "monitor arm semihosting enable", "set mem inaccessible-by-default off", "d breakpoints", "set remotetimeout 300", "load ./target/thumbv7m-none-eabi/release/bluepill", "step", "monitor reset halt" ], "cwd": "${workspaceRoot}" } ``` An optimized build is generated by ``` >xargo build --release ``` You may set specific settings in the `Cargo.toml` for each build type (`dev` for debug, `release` for release). Notice debugging of optimized code may be difficult as many symbols are *optimised out* and setting breakpoints may not give the desired results. To that end you may choose to use `asm::bkpt()` (defined in the [contex-m](https://github.com/japaric/cortex-m) crate) in the code instead of breakpoints in the debugger. ## Compilation and Linking The `xargo/cargo` build system will look into your `.cargo/config` for flags. The first example builds for the `m3` architecture while the second for the `m4` with *hard float* code. Notice, to use the *hard floats*, they need to be enabled in the ARM-core (not enabled at reset by default to save power...). You may have several configurations in the `.cargo/config`, and the `[build] = "..."` determintes the default configuration, it may be overridden e.g, by ``` > xargo build ... --target thumbv7m-none-eabi ``` ``` [target.thumbv7m-none-eabi] runner = 'arm-none-eabi-gdb' rustflags = [ "-C", "link-arg=-Tlink.x", "-C", "linker=arm-none-eabi-ld", "-Z", "linker-flavor=ld", ] [build] target = "thumbv7m-none-eabi" ``` ``` [target.thumbv7em-none-eabihf] runner = 'arm-none-eabi-gdb' rustflags = [ "-C", "link-arg=-Tlink.x", "-C", "linker=arm-none-eabi-ld", "-Z", "linker-flavor=ld", ] [build] target = "thumbv7em-none-eabihf" ``` ## A note on WFI If your code hits a `WFI` (Wait For Interrupt), the MCU is put into a low power mode, and by default not accepting new debug request. Thus if trying to connect a new `gdb` session, it will fail (or even worse partially work, while not behaving correctly). To remedy this you may try: * close `openocd` and restart it * unplug the the debugger (`stlink` probe), and re-plug it, you may need to hold the `reset` at startup to force the debugger and MCU into a correct state If we want to overcome this problem alltogether, there is a setting in the ARM-core debug unit that allows incoming connections on `WFI` (this feature is disabled by defauld to save power).