# 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 toolchain 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/debug 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 automatically. The RLS plugin is experimental but already quite useful. If it fails to install you may check the [RLS git](https://github.com/rust-lang-nursery/rls), for further instructions (actually you can run the plugin from `javascript` 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 configuration 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] = "..."` determinates 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 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 altogether, there is a setting in the ARM-core debug unit that allows incoming connections on `WFI` (this feature is disabled by default to save power).