Skip to content
Snippets Groups Projects
Commit 917a2ad5 authored by Per Lindgren's avatar Per Lindgren
Browse files

preLaunchTask

parent b3d00ba6
No related branches found
No related tags found
No related merge requests found
......@@ -9,6 +9,7 @@
"request": "launch",
"servertype": "openocd",
"name": "itm 64Mhz (debug)",
"preLaunchTask": "cargo build --example itm",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/itm",
"configFiles": [
"interface/stlink.cfg",
......@@ -37,6 +38,7 @@
"request": "launch",
"servertype": "openocd",
"name": "hello 16Mhz (debug)",
"preLaunchTask": "cargo build --example hello",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/hello",
"configFiles": [
"interface/stlink.cfg",
......@@ -47,6 +49,22 @@
],
"cwd": "${workspaceRoot}"
},
{
"type": "cortex-debug",
"request": "launch",
"servertype": "openocd",
"name": "crash (release)",
"preLaunchTask": "cargo build --example crash --release",
"executable": "./target/thumbv7em-none-eabihf/release/examples/crash",
"configFiles": [
"interface/stlink.cfg",
"target/stm32f4x.cfg"
],
"postLaunchCommands": [
"b HardFault"
],
"cwd": "${workspaceRoot}"
},
{
"type": "cortex-debug",
"request": "launch",
......
......@@ -26,6 +26,42 @@
"kind": "build",
"isDefault": true
}
},
{
"type": "shell",
"label": "cargo build --example hello",
"command": "cargo build --example hello",
"problemMatcher": [
"$rustc"
],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "shell",
"label": "cargo build --example crash --release",
"command": "cargo build --example crash --release",
"problemMatcher": [
"$rustc"
],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "shell",
"label": "cargo build --example itm",
"command": "cargo build --example itm",
"problemMatcher": [
"$rustc"
],
"group": {
"kind": "build",
"isDefault": true
}
},
]
}
\ No newline at end of file
......@@ -15,6 +15,7 @@ panic-halt = "0.2.0"
# Uncomment for the panic example.
panic-semihosting = "0.5.1"
panic-itm = "0.4.0"
bare-metal = "0.2.4"
# Uncomment for the allocator example.
# alloc-cortex-m = "0.3.5"
......
......@@ -24,13 +24,15 @@ $ rustup target add thumbv7em-none-eabihf
- `itmdump` (for ITM trace output)
- `vscode` and `cortex-debug` (optional for an integrated debugging experience)
* https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug
---
## Examples
---
### Hello
### Hello World! Building and Debugging an Application
1. Connect your devkit using USB. To check that it is found you can run:
......@@ -110,9 +112,9 @@ You have now compiled and debugged a minimal Rust `hello` example. `gdb` is a ve
---
### ITM
### ITM Tracing
The `hello` example uses the `semihosting` interface to emit the trace information (appearing in the `openocd` terminal). The drawback is that `semihosting` is incredibly slow as it involves a lot of machinery to process each character. (Essentially, it writes a character to a given position in memory, runs a dedicated break instruction, `openocd` detecects the break, reads the character at the given postition in memory and emits the character to the console.)
The `hello.rs` example uses the `semihosting` interface to emit the trace information (appearing in the `openocd` terminal). The drawback is that `semihosting` is incredibly slow as it involves a lot of machinery to process each character. (Essentially, it writes a character to a given position in memory, runs a dedicated break instruction, `openocd` detecects the break, reads the character at the given postition in memory and emits the character to the console.)
A better approach is to use de bultin in ITM (Instrumentation Trace Macrocell), designed to more efficently implement tracing. The onboard `stlink` programmer can put up to 4 characters into an ITM package, and transmit that to the host (`openocd`). `openocd` can process the incoming data and send it to a file or FIFO queue. The ITM package stream needs to be decoded (header + data). To this end we use the `itmdump` tool.
......@@ -123,7 +125,7 @@ $ mkfifo /tmp/itm.log
$ itmdump -f /tmp/itm.log -F
```
Now you can compile and run the `itm` application using the same steps as the `hello` programg. In the `itmdump` console you should now have the trace output.
Now you can compile and run the `itm.rs` application using the same steps as the `hello` program. In the `itmdump` console you should now have the trace output.
``` console
$ mkfifo /tmp/itm.log
......@@ -181,13 +183,22 @@ A third alternative would be to store the panic message in some non-volatile mem
---
### Exception Handling
### Exception Handling and Core Peripheral Access
The ARM Cortex-M processors features a set of *core* peripherpherals and *exception* handlers. These offer basic functionality independent of vendor (NXP, STM, ...). The `SysTick` perihperal is a 24-bit countdown timer, that raises a `SysTick` exception when hitting 0 and reloads the set value. Seen as a real-time system, we can dispatch the `SysTick` task in a periodic fashion (without accumulated drift under some additional constraints).
In the example a `.` is emitted by the `SysTick` handler using `semihosting`. Running the example should give you a periodic updated of the `openocd` console.
In the `exception.rs` example a `.` is emitted by the `SysTick` handler using `semihosting`. Running the example should give you a periodic updated of the `openocd` console.
The `exception_itm.rs` and `exception_itm_raw.rs` uses the ITM instead. The difference is the way
they gain access to the `ITM` periphereal. In the first case we *steal* the whole set of core peripherals (stealing works only in `--release` mode), while the in the second case we use *raw* pointer access to the `ITM`. In both cases, the code is *unsafe*, as there is no guarantee that other tasks may access the peripheral simultaneously (causing a conflict/race). Later we will see how the concurrency problem is solved in RTFM to offer safe access to peripherals.
---
### Crash - Analysing the Exception Frame
In case the execution of an intstruction fails, a `HardFault` exception is raised by the hardware, and the `HardFault` handler is executed. We can define our own handler as in example `crash.rs`. In `main` we attempt to read an illegal address, causing a `HardFault`, and we hit a breakpoint (`openocd.gdb` script sets a breakbpoint at the `HardFualt` handler). From there you can print the exception frame, reflecting the state of the MCU when the error occured. You can use `gdb` to give a `back trace` of the call-stack leading up to the error. See the example for detailed information.
As an exercise make it use the ITM instead.
---
......@@ -349,11 +360,18 @@ This ensures 1) the program will not yet again overflow the ITM buffer, 2) the f
# Visual Studio Code
It is possible to run `gdb` from within the `vscode`. `vscode` is highly configurable, (keyboard shortcuts, keymaps, plugins etc.). Using the default setup, and the `cortex-debug` plugin you can:
`vscode` is highly configurable, (keyboard shortcuts, keymaps, plugins etc.) There is Rust support through the `rls-vscode` plugin (https://github.com/rust-lang/rls-vscode).
It is possible to run `arm-none-eabi-gdb` from within the `vscode` using the `cortex-debug` plugin (https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug).
For general informaiton regarding debugging in `vscode`, see https://code.visualstudio.com/docs/editor/debugging.
Some useful (default) shortcuts:
- `CTRL+m` compilation tasks, (e.g., compile all examples `cargo build --examples`). Cargo is smart and just re-compiles what is changed.
- `CTRL+m` compile all examples (`cargo build --examples`). Cargo is smart and just re-compiles what is changed.
- `CTRL+d` debug launch configurations, enter debug mode to choose a binary (e.g., `itm 64MHz (debug)`)
- `CTRL+d` enter debug mode to choose a binary. (`itm 64MHz (debug)`)
- `F5` to start. It will open the `cortex_m_rt/src/lib.rs` file, which contains the startup code. From there you can continue `F5` again.
- `F6` to break. The program will now be in the infinite loop.
- You can view the ITM trace in the `OUTPUT` tab, choose the dropdown `SWO: ITM [port 0, type console]`. It should now display:
......
......@@ -13,18 +13,14 @@
extern crate panic_halt;
use cortex_m::peripheral::syst::SystClkSource;
use cortex_m::{iprint, Peripherals};
use cortex_m_rt::{entry, exception};
use cortex_m::{iprint, iprintln, Peripherals};
#[entry]
fn main() -> ! {
cortex_m::asm::bkpt();
let mut p = Peripherals::take().unwrap();
let p = Peripherals::take().unwrap();
let mut syst = p.SYST;
let stim = &mut p.ITM.stim[0];
iprintln!(stim, "start");
// configures the system timer to trigger a SysTick exception every second
syst.set_clock_source(SystClkSource::Core);
syst.set_reload(16_000_000); // period = 1s
......@@ -36,6 +32,14 @@ fn main() -> ! {
#[exception]
fn SysTick() {
// Here we steal all the peripherals.
//
// This is unsafe, as some other task/tasks may access the peripherals
// simultaneously, causing a conflict/race.
//
// The operation is checked in `debug` mode but not in release
// using a `debug_assert`. As the periherals is already taken
// by main, we need to compile in `--release` mode, to avoid a panic.
let mut p = unsafe { cortex_m::Peripherals::steal() };
let stim = &mut p.ITM.stim[0];
iprint!(stim, ".");
......
//! Overriding an exception handler
//!
//! You can override an exception handler using the [`#[exception]`][1] attribute.
//!
//! [1]: https://rust-embedded.github.io/cortex-m-rt/0.6.1/cortex_m_rt_macros/fn.exception.html
//!
//! Notice, steal will panic! in debug mode, due to a `debug_assert` (ignored in release).
//! ---
#![no_main]
#![no_std]
extern crate panic_halt;
use cortex_m::peripheral::{syst::SystClkSource, ITM};
use cortex_m::{iprint, Peripherals};
use cortex_m_rt::{entry, exception};
#[entry]
fn main() -> ! {
let p = Peripherals::take().unwrap();
let mut syst = p.SYST;
// configures the system timer to trigger a SysTick exception every second
syst.set_clock_source(SystClkSource::Core);
syst.set_reload(16_000_000); // period = 1s
syst.enable_counter();
syst.enable_interrupt();
loop {}
}
#[exception]
fn SysTick() {
// here we access `ITM` using a *raw* pointer
// this is unsafe, as there may be other tasks accessing the peripheral
// simultaneously (and that might cause a conflict/race)
let itm = unsafe { &mut *ITM::ptr() };
let stim = &mut itm.stim[0];
iprint!(stim, ".");
}
......@@ -5,8 +5,8 @@ set print asm-demangle on
# detect unhandled exceptions, hard faults and panics
#break DefaultHandler
#break UserHardFault
#break rust_begin_unwind
break HardFault
break rust_begin_unwind
# *try* to stop at the user entry point (it might be gone due to inlining)
break main
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment