move to cargo-generate; start with QEMU
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
# runner = 'arm-none-eabi-gdb -x debug.gdb'
|
|
||||||
rustflags = [
|
rustflags = [
|
||||||
# LLD (shipped with the Rust toolchain) is used as the default linker
|
# LLD (shipped with the Rust toolchain) is used as the default linker
|
||||||
"-C", "link-arg=-Tlink.x",
|
"-C", "link-arg=-Tlink.x",
|
||||||
@@ -16,23 +15,9 @@ rustflags = [
|
|||||||
# "-C", "link-arg=-nostartfiles",
|
# "-C", "link-arg=-nostartfiles",
|
||||||
]
|
]
|
||||||
|
|
||||||
# work around rust-lang/cargo#5946
|
|
||||||
[target.thumbv6m-none-eabi]
|
|
||||||
runner = 'arm-none-eabi-gdb -x debug.gdb'
|
|
||||||
|
|
||||||
[target.thumbv7m-none-eabi]
|
|
||||||
runner = 'arm-none-eabi-gdb -x debug.gdb'
|
|
||||||
|
|
||||||
[target.thumbv7em-none-eabi]
|
|
||||||
runner = 'arm-none-eabi-gdb -x debug.gdb'
|
|
||||||
|
|
||||||
[target.thumbv7em-none-eabihf]
|
|
||||||
runner = 'arm-none-eabi-gdb -x debug.gdb'
|
|
||||||
# end of workaround
|
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
# Pick one of these compilation targets
|
# Pick ONE of these compilation targets
|
||||||
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
||||||
# target = "thumbv7m-none-eabi" # Cortex-M3
|
target = "thumbv7m-none-eabi" # Cortex-M3
|
||||||
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
||||||
# target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
# target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||||
12
Cargo.toml
12
Cargo.toml
@@ -1,13 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
authors = ["{{authors}}"]
|
||||||
categories = ["embedded", "no-std"]
|
name = "{{project-name}}"
|
||||||
description = "A template for building applications for ARM Cortex-M microcontrollers"
|
version = "0.1.0"
|
||||||
documentation = "https://rust-embedded.github.io/cortex-m-quickstart/cortex_m_quickstart"
|
|
||||||
keywords = ["arm", "cortex-m", "template"]
|
|
||||||
license = "MIT OR Apache-2.0"
|
|
||||||
name = "cortex-m-quickstart"
|
|
||||||
repository = "https://github.com/japaric/cortex-m-quickstart"
|
|
||||||
version = "0.3.4"
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = "0.5.6"
|
cortex-m = "0.5.6"
|
||||||
|
|||||||
487
README.md
487
README.md
@@ -6,6 +6,493 @@ This project is developed and maintained by the [Cortex-M team][team].
|
|||||||
|
|
||||||
# [Documentation](https://rust-embedded.github.io/cortex-m-quickstart/cortex_m_quickstart)
|
# [Documentation](https://rust-embedded.github.io/cortex-m-quickstart/cortex_m_quickstart)
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
To build embedded programs using this template you'll need:
|
||||||
|
|
||||||
|
- Nightly Rust toolchain from 2018-08-28 or newer: `rustup default nightly`
|
||||||
|
- The `cargo generate` subcommand: `cargo install cargo-generate`
|
||||||
|
- `rust-std` components (pre-compiled `core` crate) for the ARM Cortex-M
|
||||||
|
targets. Run:
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ rustup target add thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf
|
||||||
|
```
|
||||||
|
|
||||||
|
## Non-dependencies
|
||||||
|
|
||||||
|
This section list programs that are *not* required to build embedded programs
|
||||||
|
but are useful or necessary for embedded development.
|
||||||
|
|
||||||
|
To flash (put the firmware on the target device) and debug embedded programs
|
||||||
|
you'll need these additional programs:
|
||||||
|
|
||||||
|
<!-- TODO These bullets should link to the debugonomicon, which has instructions -->
|
||||||
|
<!-- on how to install these tools -->
|
||||||
|
|
||||||
|
- GDB with ARM support or LLDB, for debugging.
|
||||||
|
- QEMU with ARM support, for running embedded programs on the build machine.
|
||||||
|
- OpenOCD and similar, which make debugging possible at all.
|
||||||
|
|
||||||
|
To inspect the produced binaries you'll want [`cargo-binutils`].
|
||||||
|
|
||||||
|
[`cargo-binutils`]: https://crates.io/crates/cargo-binutils
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### First timers
|
||||||
|
|
||||||
|
#### Building
|
||||||
|
|
||||||
|
If you are already familiar with the process of building and debugging embedded
|
||||||
|
Rust programs feel free to skip this section!
|
||||||
|
|
||||||
|
To get you familiar with building and debugging embedded Rust programs we'll use
|
||||||
|
the template with its default values to build a program for the LM3S6965, a
|
||||||
|
microcontroller with a Cortex-M3 core that QEMU can emulate.
|
||||||
|
|
||||||
|
In this section we'll use a debugger (GDB or LLDB) and QEMU. Be sure to have
|
||||||
|
them installed!
|
||||||
|
|
||||||
|
1. Initialize the template
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Build the example "Hello, world!" program
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
// example/hello.rs
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate cortex_m_rt;
|
||||||
|
extern crate cortex_m_semihosting as sh;
|
||||||
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use sh::hio;
|
||||||
|
|
||||||
|
entry!(main);
|
||||||
|
|
||||||
|
fn main() -> ! {
|
||||||
|
let mut stdout = hio::hstdout().unwrap();
|
||||||
|
writeln!(stdout, "Hello, world!").unwrap();
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
We'll cross compile the program for the `thumbv7m-none-eabi` target. This target
|
||||||
|
covers Cortex-M3 devices like the one we are targeting.
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ cargo build --target thumbv7m-none-eabi --example hello
|
||||||
|
```
|
||||||
|
You'll find the output binary in the following path:
|
||||||
|
`target/thumbv7m-none-eabi/debug/examples/hello`. The output is an ELF file.
|
||||||
|
|
||||||
|
If you have `file` installed you can print the file type of the output to
|
||||||
|
confirm it's an ELF file:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ( cd target/thumbv7m-none-eabi/debug/examples && file hello )
|
||||||
|
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped
|
||||||
|
```
|
||||||
|
|
||||||
|
If you have `cargo-binutils` installed you can look at the ELF header of the
|
||||||
|
output:
|
||||||
|
|
||||||
|
> NOTE `cargo-readelf` will be available in a *future* release of binutils
|
||||||
|
> (v0.1.3)
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ cargo readelf --example hello -- --file-headers
|
||||||
|
```
|
||||||
|
|
||||||
|
``` text
|
||||||
|
ELF Header:
|
||||||
|
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
|
||||||
|
Class: ELF32
|
||||||
|
Data: 2's complement, little endian
|
||||||
|
Version: 1 (current)
|
||||||
|
OS/ABI: UNIX - System V
|
||||||
|
ABI Version: 0x0
|
||||||
|
Type: EXEC (Executable file)
|
||||||
|
Machine: ARM
|
||||||
|
Version: 0x1
|
||||||
|
Entry point address: 0x23A3
|
||||||
|
Start of program headers: 52 (bytes into file)
|
||||||
|
Start of section headers: 673340 (bytes into file)
|
||||||
|
Flags: 0x5000200
|
||||||
|
Size of this header: 52 (bytes)
|
||||||
|
Size of program headers: 32 (bytes)
|
||||||
|
Number of program headers: 2
|
||||||
|
Size of section headers: 40 (bytes)
|
||||||
|
Number of section headers: 21
|
||||||
|
Section header string table index: 19
|
||||||
|
```
|
||||||
|
|
||||||
|
If you look at the bottom of the Cargo configuration file (`.cargo/config`)
|
||||||
|
you'll see that the `thumbv7m-none-eabi` target has been set as the default
|
||||||
|
compilation target. This means that you do *not* need to pass the `--target`
|
||||||
|
flag to cross compile because it's already implied. So:
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ cargo build --example hello
|
||||||
|
```
|
||||||
|
|
||||||
|
Does the same as before.
|
||||||
|
|
||||||
|
3. There's no step 3! Your build is done, but for completeness let's look at how
|
||||||
|
to run this program on QEMU.
|
||||||
|
|
||||||
|
#### Running the program on QEMU
|
||||||
|
|
||||||
|
Execute this command and you are done.
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ qemu-system-arm \
|
||||||
|
-cpu cortex-m3 \
|
||||||
|
-machine lm3s6965evb \
|
||||||
|
-nographic \
|
||||||
|
-semihosting-config enable=on,target=native \
|
||||||
|
-kernel target/thumbv7m-none-eabi/debug/examples/hello
|
||||||
|
Hello, world!
|
||||||
|
```
|
||||||
|
|
||||||
|
The above command will block the terminal because the `hello` program never
|
||||||
|
ends! To terminate QEMU input this in your terminal: `Ctrl+A`, followed by `X`.
|
||||||
|
|
||||||
|
Let me break down that long command for you:
|
||||||
|
|
||||||
|
- `qemu-system-arm`. This is the QEMU emulator. There are a few variants of
|
||||||
|
these QEMU binaries; this one does full *system* emulation of *ARM* machines
|
||||||
|
-- hence the name.
|
||||||
|
|
||||||
|
- `-cpu cortex-m3`. This tells QEMU to emulate a Cortex-M3 CPU. Specifying the
|
||||||
|
CPU model lets us catch some miscompilation errors: for example, running a
|
||||||
|
program compiled for the Cortex-M4F, which has a hardware FPU, will make QEMU
|
||||||
|
error during its execution.
|
||||||
|
|
||||||
|
- `-machine lm3s6965evb`. This tells QEMU to emulate the LM3S6965EVB, a
|
||||||
|
evaluation board that contains a LM3S6965 microcontroller.
|
||||||
|
|
||||||
|
- `-nographic`. This tells QEMU to not launch its GUI.
|
||||||
|
|
||||||
|
- `-semihosting-config (..)`. This tells QEMU to enable semihosting. Semihosting
|
||||||
|
lets the emulated device, among other things, use the host stdout, stderr and
|
||||||
|
stdin and create files on the host.
|
||||||
|
|
||||||
|
- `-kernel $file`. This tells QEMU which binary to flash (kind of) and run on
|
||||||
|
the emulated machine.
|
||||||
|
|
||||||
|
#### Debugging
|
||||||
|
|
||||||
|
First, we launch a QEMU instance:
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ qemu-system-arm \
|
||||||
|
-cpu cortex-m3 \
|
||||||
|
-machine lm3s6965evb \
|
||||||
|
-nographic \
|
||||||
|
-semihosting-config enable=on,target=native \
|
||||||
|
-gdb tcp::3333 \
|
||||||
|
-S \
|
||||||
|
-kernel target/thumbv7m-none-eabi/debug/examples/hello
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that this command won't print anything to the console but will block the
|
||||||
|
terminal. We have passed two extra flags this time:
|
||||||
|
|
||||||
|
- `-gdb tcp::3333`. This tells QEMU to wait for a GDB connection on TCP
|
||||||
|
port 3333.
|
||||||
|
|
||||||
|
- `-S`. This tells QEMU to freeze the machine at startup. Without this the
|
||||||
|
program would have reached the end of `main` before we had a chance to launch
|
||||||
|
the debugger!
|
||||||
|
|
||||||
|
Next, we start up LLDB in another terminal:
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ lldb target/thumbv7m-none-eabi/debug/examples/hello
|
||||||
|
```
|
||||||
|
|
||||||
|
And tell it to connect to the GDB server that QEMU created:
|
||||||
|
|
||||||
|
``` console
|
||||||
|
(lldb) gdb-remote 3333
|
||||||
|
Process 1 stopped
|
||||||
|
* thread #1, stop reason = signal SIGTRAP
|
||||||
|
frame #0: 0x000023a2 hello`Reset at lib.rs:475
|
||||||
|
472
|
||||||
|
473 #[doc(hidden)]
|
||||||
|
474 #[no_mangle]
|
||||||
|
-> 475 pub unsafe extern "C" fn Reset() -> ! {
|
||||||
|
476 extern "C" {
|
||||||
|
477 // This symbol will be provided by the user via the `entry!` macro
|
||||||
|
478 fn main() -> !;
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll see that the process is halted and that the program counter is pointing
|
||||||
|
to a function named `Reset`. That is the reset handler: what Cortex-M cores
|
||||||
|
execute upon booting.
|
||||||
|
|
||||||
|
This reset handler will eventually call our `main` function. Let's skip all the
|
||||||
|
way there using a breakpoint and the `continue` command:
|
||||||
|
|
||||||
|
``` console
|
||||||
|
(lldb) breakpoint set -name hello::main
|
||||||
|
Breakpoint 1: where = hello`hello::main::h9cf19a1378cbd1b8 + 2 at hello.rs:20, address = 0x000006a8
|
||||||
|
|
||||||
|
(lldb) continue
|
||||||
|
Process 1 resuming
|
||||||
|
Process 1 stopped
|
||||||
|
* thread #1, stop reason = breakpoint 1.1
|
||||||
|
frame #0: 0x000006a8 hello`hello::main::h9cf19a1378cbd1b8 at hello.rs:20
|
||||||
|
17 entry!(main);
|
||||||
|
18
|
||||||
|
19 fn main() -> ! {
|
||||||
|
-> 20 let mut stdout = hio::hstdout().unwrap();
|
||||||
|
21 writeln!(stdout, "Hello, world!").unwrap();
|
||||||
|
22
|
||||||
|
23 loop {}
|
||||||
|
```
|
||||||
|
|
||||||
|
We are now close to the code that prints "Hello, world!". Let's move the program
|
||||||
|
forward using the `next` command.
|
||||||
|
|
||||||
|
``` console
|
||||||
|
(lldb) next
|
||||||
|
Process 1 stopped
|
||||||
|
* thread #1, stop reason = step over
|
||||||
|
frame #0: 0x000006be hello`hello::main::h9cf19a1378cbd1b8 at hello.rs:21
|
||||||
|
18
|
||||||
|
19 fn main() -> ! {
|
||||||
|
20 let mut stdout = hio::hstdout().unwrap();
|
||||||
|
-> 21 writeln!(stdout, "Hello, world!").unwrap();
|
||||||
|
22
|
||||||
|
23 loop {}
|
||||||
|
24 }
|
||||||
|
|
||||||
|
(lldb) next
|
||||||
|
Process 1 stopped
|
||||||
|
* thread #1, stop reason = step over
|
||||||
|
frame #0: 0x000006f6 hello`hello::main::h9cf19a1378cbd1b8 at hello.rs:23
|
||||||
|
20 let mut stdout = hio::hstdout().unwrap();
|
||||||
|
21 writeln!(stdout, "Hello, world!").unwrap();
|
||||||
|
22
|
||||||
|
-> 23 loop {}
|
||||||
|
24 }
|
||||||
|
```
|
||||||
|
|
||||||
|
At this point you should see "Hello, world!" printed on the terminal that's
|
||||||
|
running `qemu-system-arm`.
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ qemu-system-arm (..)
|
||||||
|
Hello, world!
|
||||||
|
```
|
||||||
|
|
||||||
|
That's it! You can now exit `lldb`, which will also cause QEMU to terminate.
|
||||||
|
|
||||||
|
```
|
||||||
|
(lldb) exit
|
||||||
|
Quitting LLDB will kill one or more processes. Do you really want to proceed: [Y/n] y
|
||||||
|
```
|
||||||
|
|
||||||
|
### Not first timers
|
||||||
|
|
||||||
|
#### Building
|
||||||
|
|
||||||
|
This section explains how to configure this template to build programs for some
|
||||||
|
specific Cortex-M device.
|
||||||
|
|
||||||
|
0. Before everything else, you need to know the characteristics of the target
|
||||||
|
device:
|
||||||
|
|
||||||
|
- What's the ARM core? e.g. Cortex-M3.
|
||||||
|
|
||||||
|
- Does the ARM core include an FPU? e.g. the Cortex-M4F does.
|
||||||
|
|
||||||
|
- How much Flash memory and RAM does the target device has? e.g. 40 KB of RAM
|
||||||
|
|
||||||
|
- Where is Flash memory and RAM mapped in the address space? e.g. `0x2000_0000`
|
||||||
|
is common for RAM.
|
||||||
|
|
||||||
|
You should be able to find this information in the data sheet and / or reference
|
||||||
|
manual of your device.
|
||||||
|
|
||||||
|
As an example, we'll use the [STM32F303VCT6] microcontroller. This device has:
|
||||||
|
|
||||||
|
[STM32F303VCT6]: https://www.st.com/en/microcontrollers/stm32f303vc.html
|
||||||
|
|
||||||
|
- a Cortex-M4F core that includes a single precision FPU
|
||||||
|
|
||||||
|
- 256 KB of Flash located at address `0x0800_0000`.
|
||||||
|
|
||||||
|
- 40 KB of RAM located at address `0x2000_0000`. (There's another RAM region but
|
||||||
|
for simplicity we'll ignore it).
|
||||||
|
|
||||||
|
1. Initialize the template
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Set the default compilation target in `.cargo/config`.
|
||||||
|
|
||||||
|
For the STM32F303VCT6, we pick the `thumbv7em-none-eabihf` target as that covers
|
||||||
|
the Cortex-M4F core.
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ tail .cargo/config
|
||||||
|
```
|
||||||
|
|
||||||
|
``` toml
|
||||||
|
[build]
|
||||||
|
# Pick ONE of these compilation targets
|
||||||
|
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
||||||
|
# target = "thumbv7m-none-eabi" # Cortex-M3
|
||||||
|
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
||||||
|
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Enter the memory region information into `memory.x`.
|
||||||
|
|
||||||
|
As we mentioned before the STM32F303VCT6 has 40 KB of RAM located at address
|
||||||
|
`0x2000_0000` and 256 KB of Flash memory located at address `0x0800_0000`.
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ cat memory.x
|
||||||
|
```
|
||||||
|
|
||||||
|
``` text
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
/* NOTE K = KiBi = 1024 bytes */
|
||||||
|
FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Build one of the examples:
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ cargo build --example hello
|
||||||
|
```
|
||||||
|
|
||||||
|
You are done! You should be able to flash and run this example on your
|
||||||
|
device.
|
||||||
|
|
||||||
|
#### Debugging
|
||||||
|
|
||||||
|
Teaching you how to flash and debug this program on *your* device is out of
|
||||||
|
scope for this document due to the sheer variety of possible hardware / software
|
||||||
|
combinations. But the steps required to flash and debug this program on the
|
||||||
|
[STM32F3DISCOVERY] using OpenOCD are provided below as a reference.
|
||||||
|
|
||||||
|
[STM32F3DISCOVERY]: https://www.st.com/en/evaluation-tools/stm32f3discovery.html
|
||||||
|
|
||||||
|
On a terminal run `openocd` to connect to the ST-LINK on the discovery board.
|
||||||
|
Run this command from the root of the template; `openocd` will pick up the
|
||||||
|
`openocd.cfg` file which indicates which interface file and target file to use.
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ cat openocd.cfg
|
||||||
|
```
|
||||||
|
|
||||||
|
``` text
|
||||||
|
source [find interface/stlink-v2-1.cfg]
|
||||||
|
source [find target/stm32f3x.cfg]
|
||||||
|
```
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ openocd
|
||||||
|
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>'.
|
||||||
|
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.913879
|
||||||
|
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
|
||||||
|
```
|
||||||
|
|
||||||
|
On another terminal run GDB, also from the root of the template.
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ cat openocd.gdb
|
||||||
|
```
|
||||||
|
|
||||||
|
``` text
|
||||||
|
target remote :3333
|
||||||
|
|
||||||
|
# print demangled symbols
|
||||||
|
set print asm-demangle on
|
||||||
|
|
||||||
|
# detect unhandled exceptions and hard faults
|
||||||
|
break DefaultHandler
|
||||||
|
break UserHardFault
|
||||||
|
|
||||||
|
monitor arm semihosting enable
|
||||||
|
|
||||||
|
load
|
||||||
|
```
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ arm-none-eabi-gdb -x openocd.gdb target/thumbv7em-none-eabihf/debug/examples/hello
|
||||||
|
(..)
|
||||||
|
Loading section .vector_table, size 0x400 lma 0x8000000
|
||||||
|
Loading section .text, size 0x21dc lma 0x8000400
|
||||||
|
Loading section .rodata, size 0x6a4 lma 0x80025e0
|
||||||
|
Start address 0x800238c, load size 11392
|
||||||
|
Transfer rate: 17 KB/sec, 3797 bytes/write.
|
||||||
|
|
||||||
|
(gdb) list
|
||||||
|
470 #[no_mangle]
|
||||||
|
471 pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset;
|
||||||
|
472
|
||||||
|
473 #[doc(hidden)]
|
||||||
|
474 #[no_mangle]
|
||||||
|
475 pub unsafe extern "C" fn Reset() -> ! {
|
||||||
|
476 extern "C" {
|
||||||
|
477 // This symbol will be provided by the user via the `entry!` macro
|
||||||
|
478 fn main() -> !;
|
||||||
|
479
|
||||||
|
```
|
||||||
|
|
||||||
|
The `openocd.gdb` script will connect GDB to OpenOCD and then flash the program
|
||||||
|
into the device. After that you can do a normal debugging session.
|
||||||
|
|
||||||
|
If you `continue` the program past the semihosting write operation you'll see
|
||||||
|
"Hello, world" printed on the OpenOCD console.
|
||||||
|
|
||||||
|
``` console
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ openocd
|
||||||
|
(..)
|
||||||
|
Hello, world!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next steps
|
||||||
|
|
||||||
|
> TODO point the reader to embedded-hal, awesome-embedded-rust, etc.
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
Licensed under either of
|
Licensed under either of
|
||||||
|
|||||||
21
debug.gdb
21
debug.gdb
@@ -1,21 +0,0 @@
|
|||||||
target remote :3333
|
|
||||||
|
|
||||||
# print demangled symbols by default
|
|
||||||
set print asm-demangle on
|
|
||||||
|
|
||||||
monitor arm semihosting enable
|
|
||||||
|
|
||||||
# # send captured ITM to the file itm.fifo
|
|
||||||
# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
|
|
||||||
# # 8000000 must match the core clock frequency
|
|
||||||
# monitor tpiu config internal itm.fifo uart off 8000000
|
|
||||||
|
|
||||||
# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
|
|
||||||
# # 2000000 is the frequency of the SWO pin
|
|
||||||
# monitor tpiu config external uart off 8000000 2000000
|
|
||||||
|
|
||||||
# # enable ITM port 0
|
|
||||||
# monitor itm port 0 on
|
|
||||||
|
|
||||||
load
|
|
||||||
step
|
|
||||||
@@ -6,13 +6,12 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate cortex_m_rt as rt;
|
extern crate cortex_m_rt;
|
||||||
extern crate cortex_m_semihosting as sh;
|
extern crate cortex_m_semihosting as sh;
|
||||||
extern crate panic_semihosting;
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
|
||||||
use rt::ExceptionFrame;
|
|
||||||
use sh::hio;
|
use sh::hio;
|
||||||
|
|
||||||
entry!(main);
|
entry!(main);
|
||||||
@@ -23,15 +22,3 @@ fn main() -> ! {
|
|||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
exception!(HardFault, hard_fault);
|
|
||||||
|
|
||||||
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
|
||||||
panic!("HardFault at {:#?}", ef);
|
|
||||||
}
|
|
||||||
|
|
||||||
exception!(*, default_handler);
|
|
||||||
|
|
||||||
fn default_handler(irqn: i16) {
|
|
||||||
panic!("Unhandled exception (IRQn = {})", irqn);
|
|
||||||
}
|
|
||||||
|
|||||||
5
memory.x
5
memory.x
@@ -2,8 +2,9 @@ MEMORY
|
|||||||
{
|
{
|
||||||
/* NOTE K = KiBi = 1024 bytes */
|
/* NOTE K = KiBi = 1024 bytes */
|
||||||
/* TODO Adjust these memory regions to match your device memory layout */
|
/* TODO Adjust these memory regions to match your device memory layout */
|
||||||
FLASH : ORIGIN = 0x000BAAD0, LENGTH = 0K
|
/* These values correspond to the LM3S6965, one of the few devices QEMU can emulate */
|
||||||
RAM : ORIGIN = 0xBAAD0000, LENGTH = 0K
|
FLASH : ORIGIN = 0x00000000, LENGTH = 256K
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 64K
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is where the call stack will be allocated. */
|
/* This is where the call stack will be allocated. */
|
||||||
|
|||||||
2
openocd.cfg
Normal file
2
openocd.cfg
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
source [find interface/stlink-v2-1.cfg]
|
||||||
|
source [find target/stm32f3x.cfg]
|
||||||
12
openocd.gdb
Normal file
12
openocd.gdb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
target remote :3333
|
||||||
|
|
||||||
|
# print demangled symbols
|
||||||
|
set print asm-demangle on
|
||||||
|
|
||||||
|
# detect unhandled exceptions and hard faults
|
||||||
|
break DefaultHandler
|
||||||
|
break UserHardFault
|
||||||
|
|
||||||
|
monitor arm semihosting enable
|
||||||
|
|
||||||
|
load
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
//! Minimal Cortex-M program
|
|
||||||
//!
|
|
||||||
//! When executed this program will hit the breakpoint set in `main`.
|
|
||||||
//!
|
|
||||||
//! All Cortex-M programs need to:
|
|
||||||
//!
|
|
||||||
//! - Contain the `#![no_main]` and `#![no_std]` attributes. Embedded programs don't use the
|
|
||||||
//! standard Rust `main` interface or the Rust standard (`std`) library.
|
|
||||||
//!
|
|
||||||
//! - Define their entry point using [`entry!`] macro.
|
|
||||||
//!
|
|
||||||
//! [`entry!`]: https://docs.rs/cortex-m-rt/~0.5/cortex_m_rt/macro.entry.html
|
|
||||||
//!
|
|
||||||
//! - Define their panicking behavior, i.e. what happens when `panic!` is called. The easiest way to
|
|
||||||
//! define a panicking behavior is to link to a [panic handler crate][0]
|
|
||||||
//!
|
|
||||||
//! [0]: https://crates.io/keywords/panic-impl
|
|
||||||
//!
|
|
||||||
//! - Define the `HardFault` handler using the [`exception!`] macro. This handler (function) is
|
|
||||||
//! called when a hard fault exception is raised by the hardware.
|
|
||||||
//!
|
|
||||||
//! [`exception!`]: https://docs.rs/cortex-m-rt/~0.5/cortex_m_rt/macro..html
|
|
||||||
//!
|
|
||||||
//! - Define a default handler using the [`exception!`] macro. This function will be used to handle
|
|
||||||
//! all interrupts and exceptions which have not been assigned a specific handler.
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![no_main] // <- IMPORTANT!
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//!
|
|
||||||
//! #[macro_use(entry, exception)]
|
|
||||||
//! extern crate cortex_m_rt as rt;
|
|
||||||
//!
|
|
||||||
//! // makes `panic!` print messages to the host stderr using semihosting
|
|
||||||
//! extern crate panic_semihosting;
|
|
||||||
//!
|
|
||||||
//! use cortex_m::asm;
|
|
||||||
//! use rt::ExceptionFrame;
|
|
||||||
//!
|
|
||||||
//! // the program entry point is ...
|
|
||||||
//! entry!(main);
|
|
||||||
//!
|
|
||||||
//! // ... this never ending function
|
|
||||||
//! fn main() -> ! {
|
|
||||||
//! loop {
|
|
||||||
//! asm::bkpt();
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // define the hard fault handler
|
|
||||||
//! exception!(HardFault, hard_fault);
|
|
||||||
//!
|
|
||||||
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
|
||||||
//! panic!("HardFault at {:#?}", ef);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // define the default exception handler
|
|
||||||
//! exception!(*, default_handler);
|
|
||||||
//!
|
|
||||||
//! fn default_handler(irqn: i16) {
|
|
||||||
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
|
||||||
//!
|
|
||||||
//! ---
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![no_main]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m_rt as rt;
|
|
||||||
//! extern crate cortex_m_semihosting as sh;
|
|
||||||
//! extern crate panic_semihosting;
|
|
||||||
//!
|
|
||||||
//! use core::fmt::Write;
|
|
||||||
//!
|
|
||||||
//! use rt::ExceptionFrame;
|
|
||||||
//! use sh::hio;
|
|
||||||
//!
|
|
||||||
//! entry!(main);
|
|
||||||
//!
|
|
||||||
//! fn main() -> ! {
|
|
||||||
//! let mut stdout = hio::hstdout().unwrap();
|
|
||||||
//! writeln!(stdout, "Hello, world!").unwrap();
|
|
||||||
//!
|
|
||||||
//! loop {}
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! exception!(HardFault, hard_fault);
|
|
||||||
//!
|
|
||||||
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
|
||||||
//! panic!("HardFault at {:#?}", ef);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! exception!(*, default_handler);
|
|
||||||
//!
|
|
||||||
//! fn default_handler(irqn: i16) {
|
|
||||||
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
//! Sends "Hello, world!" through the ITM port 0
|
|
||||||
//!
|
|
||||||
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
|
|
||||||
//!
|
|
||||||
//! **NOTE** Cortex-M0 chips don't support ITM.
|
|
||||||
//!
|
|
||||||
//! You'll have to connect the microcontroller's SWO pin to the SWD interface. Note that some
|
|
||||||
//! development boards don't provide this option.
|
|
||||||
//!
|
|
||||||
//! You'll need [`itmdump`] to receive the message on the host plus you'll need to uncomment two
|
|
||||||
//! `monitor` commands in the `.gdbinit` file.
|
|
||||||
//!
|
|
||||||
//! [`itmdump`]: https://docs.rs/itm/0.2.1/itm/
|
|
||||||
//!
|
|
||||||
//! ---
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![no_main]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m_rt as rt;
|
|
||||||
//! extern crate panic_semihosting;
|
|
||||||
//!
|
|
||||||
//! use cortex_m::{asm, Peripherals};
|
|
||||||
//! use rt::ExceptionFrame;
|
|
||||||
//!
|
|
||||||
//! entry!(main);
|
|
||||||
//!
|
|
||||||
//! fn main() -> ! {
|
|
||||||
//! let mut p = Peripherals::take().unwrap();
|
|
||||||
//! let stim = &mut p.ITM.stim[0];
|
|
||||||
//!
|
|
||||||
//! iprintln!(stim, "Hello, world!");
|
|
||||||
//!
|
|
||||||
//! loop {
|
|
||||||
//! asm::bkpt();
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // define the hard fault handler
|
|
||||||
//! exception!(HardFault, hard_fault);
|
|
||||||
//!
|
|
||||||
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
|
||||||
//! panic!("HardFault at {:#?}", ef);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // define the default exception handler
|
|
||||||
//! exception!(*, default_handler);
|
|
||||||
//!
|
|
||||||
//! fn default_handler(irqn: i16) {
|
|
||||||
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
//! Changing the panic handler
|
|
||||||
//!
|
|
||||||
//! The easiest way to change the panic handler is to use a different [panic handler crate][0].
|
|
||||||
//!
|
|
||||||
//! [0]: https://crates.io/keywords/panic-impl
|
|
||||||
//!
|
|
||||||
//! ---
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![no_main]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m_rt as rt;
|
|
||||||
//!
|
|
||||||
//! // Pick one of these two panic handlers:
|
|
||||||
//!
|
|
||||||
//! // Reports panic messages to the host stderr using semihosting
|
|
||||||
//! extern crate panic_semihosting;
|
|
||||||
//!
|
|
||||||
//! // Logs panic messages using the ITM (Instrumentation Trace Macrocell)
|
|
||||||
//! // extern crate panic_itm;
|
|
||||||
//!
|
|
||||||
//! use rt::ExceptionFrame;
|
|
||||||
//!
|
|
||||||
//! entry!(main);
|
|
||||||
//!
|
|
||||||
//! fn main() -> ! {
|
|
||||||
//! panic!("Oops")
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // define the hard fault handler
|
|
||||||
//! exception!(HardFault, hard_fault);
|
|
||||||
//!
|
|
||||||
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
|
||||||
//! panic!("HardFault at {:#?}", ef);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // define the default exception handler
|
|
||||||
//! exception!(*, default_handler);
|
|
||||||
//!
|
|
||||||
//! fn default_handler(irqn: i16) {
|
|
||||||
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
//! Debugging a crash (exception)
|
|
||||||
//!
|
|
||||||
//! Most crash conditions trigger a hard fault exception, whose handler is defined via
|
|
||||||
//! `exception!(HardFault, ..)`. The `HardFault` handler has access to the exception frame, a
|
|
||||||
//! snapshot of the CPU registers at the moment of the exception.
|
|
||||||
//!
|
|
||||||
//! This program crashes and the `HardFault` handler prints to the console the contents of the
|
|
||||||
//! `ExceptionFrame` and then triggers a breakpoint. From that breakpoint one can see the backtrace
|
|
||||||
//! that led to the exception.
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! (gdb) continue
|
|
||||||
//! Program received signal SIGTRAP, Trace/breakpoint trap.
|
|
||||||
//! __bkpt () at asm/bkpt.s:3
|
|
||||||
//! 3 bkpt
|
|
||||||
//!
|
|
||||||
//! (gdb) backtrace
|
|
||||||
//! #0 __bkpt () at asm/bkpt.s:3
|
|
||||||
//! #1 0x080030b4 in cortex_m::asm::bkpt () at $$/cortex-m-0.5.0/src/asm.rs:19
|
|
||||||
//! #2 rust_begin_unwind (args=..., file=..., line=99, col=5) at $$/panic-semihosting-0.2.0/src/lib.rs:87
|
|
||||||
//! #3 0x08001d06 in core::panicking::panic_fmt () at libcore/panicking.rs:71
|
|
||||||
//! #4 0x080004a6 in crash::hard_fault (ef=0x20004fa0) at examples/crash.rs:99
|
|
||||||
//! #5 0x08000548 in UserHardFault (ef=0x20004fa0) at <exception macros>:10
|
|
||||||
//! #6 0x0800093a in HardFault () at asm.s:5
|
|
||||||
//! Backtrace stopped: previous frame identical to this frame (corrupt stack?)
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! In the console output one will find the state of the Program Counter (PC) register at the time
|
|
||||||
//! of the exception.
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! panicked at 'HardFault at ExceptionFrame {
|
|
||||||
//! r0: 0x2fffffff,
|
|
||||||
//! r1: 0x2fffffff,
|
|
||||||
//! r2: 0x080051d4,
|
|
||||||
//! r3: 0x080051d4,
|
|
||||||
//! r12: 0x20000000,
|
|
||||||
//! lr: 0x08000435,
|
|
||||||
//! pc: 0x08000ab6,
|
|
||||||
//! xpsr: 0x61000000
|
|
||||||
//! }', examples/crash.rs:106:5
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! This register contains the address of the instruction that caused the exception. In GDB one can
|
|
||||||
//! disassemble the program around this address to observe the instruction that caused the
|
|
||||||
//! exception.
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! (gdb) disassemble/m 0x08000ab6
|
|
||||||
//! Dump of assembler code for function core::ptr::read_volatile:
|
|
||||||
//! 451 pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
|
||||||
//! 0x08000aae <+0>: sub sp, #16
|
|
||||||
//! 0x08000ab0 <+2>: mov r1, r0
|
|
||||||
//! 0x08000ab2 <+4>: str r0, [sp, #8]
|
|
||||||
//!
|
|
||||||
//! 452 intrinsics::volatile_load(src)
|
|
||||||
//! 0x08000ab4 <+6>: ldr r0, [sp, #8]
|
|
||||||
//! -> 0x08000ab6 <+8>: ldr r0, [r0, #0]
|
|
||||||
//! 0x08000ab8 <+10>: str r0, [sp, #12]
|
|
||||||
//! 0x08000aba <+12>: ldr r0, [sp, #12]
|
|
||||||
//! 0x08000abc <+14>: str r1, [sp, #4]
|
|
||||||
//! 0x08000abe <+16>: str r0, [sp, #0]
|
|
||||||
//! 0x08000ac0 <+18>: b.n 0x8000ac2 <core::ptr::read_volatile+20>
|
|
||||||
//!
|
|
||||||
//! 453 }
|
|
||||||
//! 0x08000ac2 <+20>: ldr r0, [sp, #0]
|
|
||||||
//! 0x08000ac4 <+22>: add sp, #16
|
|
||||||
//! 0x08000ac6 <+24>: bx lr
|
|
||||||
//!
|
|
||||||
//! End of assembler dump.
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! `ldr r0, [r0, #0]` caused the exception. This instruction tried to load (read) a 32-bit word
|
|
||||||
//! from the address stored in the register `r0`. Looking again at the contents of `ExceptionFrame`
|
|
||||||
//! we see that the `r0` contained the address `0x2FFF_FFFF` when this instruction was executed.
|
|
||||||
//!
|
|
||||||
//! ---
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![no_main]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m_rt as rt;
|
|
||||||
//! extern crate panic_semihosting;
|
|
||||||
//!
|
|
||||||
//! use core::ptr;
|
|
||||||
//!
|
|
||||||
//! use rt::ExceptionFrame;
|
|
||||||
//!
|
|
||||||
//! entry!(main);
|
|
||||||
//!
|
|
||||||
//! fn main() -> ! {
|
|
||||||
//! unsafe {
|
|
||||||
//! // read an address outside of the RAM region; causes a HardFault exception
|
|
||||||
//! ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! loop {}
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // define the hard fault handler
|
|
||||||
//! exception!(HardFault, hard_fault);
|
|
||||||
//!
|
|
||||||
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
|
||||||
//! panic!("HardFault at {:#?}", ef);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // define the default exception handler
|
|
||||||
//! exception!(*, default_handler);
|
|
||||||
//!
|
|
||||||
//! fn default_handler(irqn: i16) {
|
|
||||||
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
//! Overriding an exception handler
|
|
||||||
//!
|
|
||||||
//! You can override an exception handler using the [`exception!`][1] macro.
|
|
||||||
//!
|
|
||||||
//! [1]: https://docs.rs/cortex-m-rt/0.5.0/cortex_m_rt/macro.exception.html
|
|
||||||
//!
|
|
||||||
//! ---
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![deny(unsafe_code)]
|
|
||||||
//! #![no_main]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m_rt as rt;
|
|
||||||
//! extern crate cortex_m_semihosting as sh;
|
|
||||||
//! extern crate panic_semihosting;
|
|
||||||
//!
|
|
||||||
//! use core::fmt::Write;
|
|
||||||
//!
|
|
||||||
//! use cortex_m::peripheral::syst::SystClkSource;
|
|
||||||
//! use cortex_m::Peripherals;
|
|
||||||
//! use rt::ExceptionFrame;
|
|
||||||
//! use sh::hio::{self, HStdout};
|
|
||||||
//!
|
|
||||||
//! entry!(main);
|
|
||||||
//!
|
|
||||||
//! 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(8_000_000); // period = 1s
|
|
||||||
//! syst.enable_counter();
|
|
||||||
//! syst.enable_interrupt();
|
|
||||||
//!
|
|
||||||
//! loop {}
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // try commenting out this line: you'll end in `default_handler` instead of in `sys_tick`
|
|
||||||
//! exception!(SysTick, sys_tick, state: Option<HStdout> = None);
|
|
||||||
//!
|
|
||||||
//! fn sys_tick(state: &mut Option<HStdout>) {
|
|
||||||
//! if state.is_none() {
|
|
||||||
//! *state = Some(hio::hstdout().unwrap());
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! if let Some(hstdout) = state.as_mut() {
|
|
||||||
//! hstdout.write_str(".").unwrap();
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! exception!(HardFault, hard_fault);
|
|
||||||
//!
|
|
||||||
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
|
||||||
//! panic!("HardFault at {:#?}", ef);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! exception!(*, default_handler);
|
|
||||||
//!
|
|
||||||
//! fn default_handler(irqn: i16) {
|
|
||||||
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
//! How to use the heap and a dynamic memory allocator
|
|
||||||
//!
|
|
||||||
//! This example depends on the alloc-cortex-m crate so you'll have to add it to your Cargo.toml:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! # or edit the Cargo.toml file manually
|
|
||||||
//! $ cargo add alloc-cortex-m
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! ---
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![feature(alloc)]
|
|
||||||
//! #![feature(global_allocator)]
|
|
||||||
//! #![feature(lang_items)]
|
|
||||||
//! #![no_main]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! // This is the allocator crate; you can use a different one
|
|
||||||
//! extern crate alloc_cortex_m;
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate alloc;
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m_rt as rt;
|
|
||||||
//! extern crate cortex_m_semihosting as sh;
|
|
||||||
//! extern crate panic_semihosting;
|
|
||||||
//!
|
|
||||||
//! use core::fmt::Write;
|
|
||||||
//!
|
|
||||||
//! use alloc_cortex_m::CortexMHeap;
|
|
||||||
//! use cortex_m::asm;
|
|
||||||
//! use rt::ExceptionFrame;
|
|
||||||
//! use sh::hio;
|
|
||||||
//!
|
|
||||||
//! // this is the allocator the application will use
|
|
||||||
//! #[global_allocator]
|
|
||||||
//! static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
|
|
||||||
//!
|
|
||||||
//! const HEAP_SIZE: usize = 1024; // in bytes
|
|
||||||
//!
|
|
||||||
//! entry!(main);
|
|
||||||
//!
|
|
||||||
//! fn main() -> ! {
|
|
||||||
//! // Initialize the allocator BEFORE you use it
|
|
||||||
//! unsafe { ALLOCATOR.init(rt::heap_start() as usize, HEAP_SIZE) }
|
|
||||||
//!
|
|
||||||
//! // Growable array allocated on the heap
|
|
||||||
//! let xs = vec![0, 1, 2];
|
|
||||||
//!
|
|
||||||
//! let mut stdout = hio::hstdout().unwrap();
|
|
||||||
//! writeln!(stdout, "{:?}", xs).unwrap();
|
|
||||||
//!
|
|
||||||
//! loop {}
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // define what happens in an Out Of Memory (OOM) condition
|
|
||||||
//! #[lang = "oom"]
|
|
||||||
//! #[no_mangle]
|
|
||||||
//! pub fn rust_oom() -> ! {
|
|
||||||
//! asm::bkpt();
|
|
||||||
//!
|
|
||||||
//! loop {}
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! exception!(HardFault, hard_fault);
|
|
||||||
//!
|
|
||||||
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
|
||||||
//! panic!("HardFault at {:#?}", ef);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! exception!(*, default_handler);
|
|
||||||
//!
|
|
||||||
//! fn default_handler(irqn: i16) {
|
|
||||||
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
//! Using a device crate
|
|
||||||
//!
|
|
||||||
//! Crates generated using [`svd2rust`] are referred to as device crates. These crates provide an
|
|
||||||
//! API to access the peripherals of a device.
|
|
||||||
//!
|
|
||||||
//! [`svd2rust`]: https://crates.io/crates/svd2rust
|
|
||||||
//!
|
|
||||||
//! Device crates also provide an `interrupt!` macro (behind the "rt" feature) to register interrupt
|
|
||||||
//! handlers.
|
|
||||||
//!
|
|
||||||
//! This example depends on the [`stm32f103xx`] crate so you'll have to add it to your Cargo.toml.
|
|
||||||
//!
|
|
||||||
//! [`stm32f103xx`]: https://crates.io/crates/stm32f103xx
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! $ edit Cargo.toml && tail $_
|
|
||||||
//! [dependencies.stm32f103xx]
|
|
||||||
//! features = ["rt"]
|
|
||||||
//! version = "0.10.0"
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! ---
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![no_main]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m_rt as rt;
|
|
||||||
//! extern crate cortex_m_semihosting as sh;
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate stm32f103xx;
|
|
||||||
//! extern crate panic_semihosting;
|
|
||||||
//!
|
|
||||||
//! use core::fmt::Write;
|
|
||||||
//!
|
|
||||||
//! use cortex_m::peripheral::syst::SystClkSource;
|
|
||||||
//! use rt::ExceptionFrame;
|
|
||||||
//! use sh::hio::{self, HStdout};
|
|
||||||
//! use stm32f103xx::Interrupt;
|
|
||||||
//!
|
|
||||||
//! entry!(main);
|
|
||||||
//!
|
|
||||||
//! fn main() -> ! {
|
|
||||||
//! let p = cortex_m::Peripherals::take().unwrap();
|
|
||||||
//!
|
|
||||||
//! let mut syst = p.SYST;
|
|
||||||
//! let mut nvic = p.NVIC;
|
|
||||||
//!
|
|
||||||
//! nvic.enable(Interrupt::EXTI0);
|
|
||||||
//!
|
|
||||||
//! // configure the system timer to wrap around every second
|
|
||||||
//! syst.set_clock_source(SystClkSource::Core);
|
|
||||||
//! syst.set_reload(8_000_000); // 1s
|
|
||||||
//! syst.enable_counter();
|
|
||||||
//!
|
|
||||||
//! loop {
|
|
||||||
//! // busy wait until the timer wraps around
|
|
||||||
//! while !syst.has_wrapped() {}
|
|
||||||
//!
|
|
||||||
//! // trigger the `EXTI0` interrupt
|
|
||||||
//! nvic.set_pending(Interrupt::EXTI0);
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // try commenting out this line: you'll end in `default_handler` instead of in `exti0`
|
|
||||||
//! interrupt!(EXTI0, exti0, state: Option<HStdout> = None);
|
|
||||||
//!
|
|
||||||
//! fn exti0(state: &mut Option<HStdout>) {
|
|
||||||
//! if state.is_none() {
|
|
||||||
//! *state = Some(hio::hstdout().unwrap());
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! if let Some(hstdout) = state.as_mut() {
|
|
||||||
//! hstdout.write_str(".").unwrap();
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! exception!(HardFault, hard_fault);
|
|
||||||
//!
|
|
||||||
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
|
||||||
//! panic!("HardFault at {:#?}", ef);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! exception!(*, default_handler);
|
|
||||||
//!
|
|
||||||
//! fn default_handler(irqn: i16) {
|
|
||||||
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
//! Examples sorted in increasing degree of complexity
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
pub mod _0_minimal;
|
|
||||||
pub mod _1_hello;
|
|
||||||
pub mod _2_itm;
|
|
||||||
pub mod _3_panic;
|
|
||||||
pub mod _4_crash;
|
|
||||||
pub mod _5_exception;
|
|
||||||
pub mod _6_allocator;
|
|
||||||
pub mod _7_device;
|
|
||||||
342
src/lib.rs
342
src/lib.rs
@@ -1,342 +0,0 @@
|
|||||||
//! A template for building applications for ARM Cortex-M microcontrollers
|
|
||||||
//!
|
|
||||||
//! # Dependencies
|
|
||||||
//!
|
|
||||||
//! - Nightly Rust toolchain from 2018-08-28 or newer: `rustup default nightly`
|
|
||||||
//! - Cargo `clone` subcommand: `cargo install cargo-clone`
|
|
||||||
//! - GDB: `sudo apt-get install gdb-arm-none-eabi` (on Ubuntu)
|
|
||||||
//! - OpenOCD: `sudo apt-get install OpenOCD` (on Ubuntu)
|
|
||||||
//! - [Optional] Cargo `add` subcommand: `cargo install cargo-edit`
|
|
||||||
//!
|
|
||||||
//! # Usage
|
|
||||||
//!
|
|
||||||
//! 0) Figure out the cross compilation *target* to use.
|
|
||||||
//!
|
|
||||||
//! - Use `thumbv6m-none-eabi` for ARM Cortex-M0 and Cortex-M0+
|
|
||||||
//! - Use `thumbv7m-none-eabi` for ARM Cortex-M3
|
|
||||||
//! - Use `thumbv7em-none-eabi` for ARM Cortex-M4 and Cortex-M7 (*no* FPU support)
|
|
||||||
//! - Use `thumbv7em-none-eabihf` for ARM Cortex-M4**F** and Cortex-M7**F** (*with* FPU support)
|
|
||||||
//!
|
|
||||||
//! 1) Install the `rust-std` component for your target, if you haven't done so already
|
|
||||||
//!
|
|
||||||
//! ``` console
|
|
||||||
//! $ rustup target add thumbv7em-none-eabihf
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! 2) Clone this crate
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo clone cortex-m-quickstart --vers 0.3.4
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! 3) Change the crate name, author and version
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ edit Cargo.toml && head $_
|
|
||||||
//! [package]
|
|
||||||
//! authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
|
||||||
//! name = "demo"
|
|
||||||
//! version = "0.1.0"
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! 4) Specify the memory layout of the target device
|
|
||||||
//!
|
|
||||||
//! **NOTE** board support crates sometimes provide this file for you (check the crate
|
|
||||||
//! documentation). If you are using one that does then remove *both* `memory.x` and `build.rs` from
|
|
||||||
//! the root of this crate.
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cat >memory.x <<'EOF'
|
|
||||||
//! MEMORY
|
|
||||||
//! {
|
|
||||||
//! /* NOTE K = KiBi = 1024 bytes */
|
|
||||||
//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
|
||||||
//! RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
|
||||||
//! }
|
|
||||||
//! EOF
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! 5) Optionally, set a default build target. This way you don't have to pass `--target` to each
|
|
||||||
//! Cargo invocation.
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cat >>.cargo/config <<'EOF'
|
|
||||||
//! [build]
|
|
||||||
//! target = "thumbv7em-none-eabihf"
|
|
||||||
//! EOF
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! 6) Optionally, depend on a device, HAL implementation or a board support crate.
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ # add a device crate, OR
|
|
||||||
//! $ cargo add stm32f30x
|
|
||||||
//!
|
|
||||||
//! $ # add a HAL implementation crate, OR
|
|
||||||
//! $ cargo add stm32f30x-hal
|
|
||||||
//!
|
|
||||||
//! $ # add a board support crate
|
|
||||||
//! $ cargo add f3
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! 7) Write the application or start from one of the examples
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ rm -r src/* && cp examples/hello.rs src/main.rs
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! 8) Build the application
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo build --release
|
|
||||||
//!
|
|
||||||
//! $ # sanity check
|
|
||||||
//! $ arm-none-eabi-readelf -A target/thumbv7em-none-eabihf/release/demo
|
|
||||||
//! Attribute Section: aeabi
|
|
||||||
//! File Attributes
|
|
||||||
//! Tag_conformance: "2.09"
|
|
||||||
//! Tag_CPU_arch: v7E-M
|
|
||||||
//! Tag_CPU_arch_profile: Microcontroller
|
|
||||||
//! Tag_THUMB_ISA_use: Thumb-2
|
|
||||||
//! Tag_FP_arch: VFPv4-D16
|
|
||||||
//! Tag_ABI_PCS_GOT_use: direct
|
|
||||||
//! Tag_ABI_FP_denormal: Needed
|
|
||||||
//! Tag_ABI_FP_exceptions: Needed
|
|
||||||
//! Tag_ABI_FP_number_model: IEEE 754
|
|
||||||
//! Tag_ABI_align_needed: 8-byte
|
|
||||||
//! Tag_ABI_align_preserved: 8-byte, except leaf SP
|
|
||||||
//! Tag_ABI_HardFP_use: SP only
|
|
||||||
//! Tag_ABI_VFP_args: VFP registers
|
|
||||||
//! Tag_ABI_optimization_goals: Aggressive Speed
|
|
||||||
//! Tag_CPU_unaligned_access: v6
|
|
||||||
//! Tag_FP_HP_extension: Allowed
|
|
||||||
//! Tag_ABI_FP_16bit_format: IEEE 754
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! 9) Flash and debug the program
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ # Launch OpenOCD on a terminal
|
|
||||||
//! $ openocd -f (..)
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ # Start a debug session in another terminal
|
|
||||||
//! $ arm-none-eabi-gdb target/thumbv7em-none-eabihf/release/demo
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Alternatively, you can use `cargo run` to build, flash and debug the program in a single step.
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo run --example hello
|
|
||||||
//! > # drops you into a GDB session
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! # Examples
|
|
||||||
//!
|
|
||||||
//! Check the [examples module][examples]
|
|
||||||
//!
|
|
||||||
//! [examples]: ./examples/index.html
|
|
||||||
//!
|
|
||||||
//! # Troubleshooting
|
|
||||||
//!
|
|
||||||
//! This section contains fixes for common errors encountered when the
|
|
||||||
//! `cortex-m-quickstart` template is misused.
|
|
||||||
//!
|
|
||||||
//! ## Used the standard `main` interface
|
|
||||||
//!
|
|
||||||
//! Error message:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo build
|
|
||||||
//! Compiling demo v0.1.0 (file:///home/japaric/tmp/demo)
|
|
||||||
//!
|
|
||||||
//! error: requires `start` lang_item
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Solution: Use `#![no_main]` and `entry!` as shown in the [examples].
|
|
||||||
//!
|
|
||||||
//! ## Forgot to launch an OpenOCD instance
|
|
||||||
//!
|
|
||||||
//! Error message:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ arm-none-eabi-gdb target/..
|
|
||||||
//! Reading symbols from hello...done.
|
|
||||||
//! .gdbinit:1: Error in sourced command file:
|
|
||||||
//! :3333: Connection timed out.
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Solution: Launch OpenOCD on other terminal. See [Usage] section.
|
|
||||||
//!
|
|
||||||
//! [Usage]: ./index.html#usage
|
|
||||||
//!
|
|
||||||
//! ## Didn't modify the `memory.x` linker script
|
|
||||||
//!
|
|
||||||
//! Error message:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo build
|
|
||||||
//! Compiling demo v0.1.0 (file:///home/japaric/tmp/demo)
|
|
||||||
//! error: linking with `rust-lld` failed: exit code: 1
|
|
||||||
//! |
|
|
||||||
//! = note: "rust-lld" "-flavor" "gnu" "-L" (..)
|
|
||||||
//! (..)
|
|
||||||
//! = note: rust-lld: error: section '.vector_table' will not fit in region 'FLASH': overflowed by X bytes
|
|
||||||
//! rust-lld: error: section '.vector_table' will not fit in region 'FLASH': overflowed by Y bytes
|
|
||||||
//! (..)
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Solution: Specify your device memory layout in the `memory.x` linker script. See [Usage]
|
|
||||||
//! section.
|
|
||||||
//!
|
|
||||||
//! ## Didn't set a default build target and forgot to pass `--target` to Cargo
|
|
||||||
//!
|
|
||||||
//! Error message:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo build
|
|
||||||
//! (..)
|
|
||||||
//! error: language item required, but not found: `eh_personality`
|
|
||||||
//!
|
|
||||||
//! error: aborting due to previous error
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Solution: Set a default build target in the `.cargo/config` file (see [Usage] section), or call
|
|
||||||
//! Cargo with `--target` flag: `cargo build --target thumbv7em-none-eabi`.
|
|
||||||
//!
|
|
||||||
//! ## Overwrote the original `.cargo/config` file
|
|
||||||
//!
|
|
||||||
//! You won't get an error message but the output binary will be empty
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo build && echo OK
|
|
||||||
//! OK
|
|
||||||
//!
|
|
||||||
//! $ size target/thumbv7m-none-eabi/debug/app
|
|
||||||
//! text data bss dec hex filename
|
|
||||||
//! 0 0 0 0 0 target/thumbv7m-none-eabi/debug/app
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Solution: You probably overwrote the original `.cargo/config` instead of appending the default
|
|
||||||
//! build target (e.g. `cat >` instead of `cat >>`). The less error prone way to fix this is to
|
|
||||||
//! remove the `.cargo` directory, clone a new copy of the template and then copy the `.cargo`
|
|
||||||
//! directory from that fresh template into your current project. Don't forget to *append* the
|
|
||||||
//! default build target to `.cargo/config`.
|
|
||||||
//!
|
|
||||||
//! ## Called OpenOCD with wrong arguments
|
|
||||||
//!
|
|
||||||
//! Error message:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ openocd -f ..
|
|
||||||
//! (..)
|
|
||||||
//! Error: open failed
|
|
||||||
//! in procedure 'init'
|
|
||||||
//! in procedure 'ocd_bouncer'
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Solution: Correct the OpenOCD arguments. Check the `/usr/share/openocd/scripts` directory (exact
|
|
||||||
//! location varies per distribution / OS) for a list of scripts that can be used.
|
|
||||||
//!
|
|
||||||
//! ## Forgot to install the `rust-std` component
|
|
||||||
//!
|
|
||||||
//! Error message:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo build
|
|
||||||
//! error[E0463]: can't find crate for `core`
|
|
||||||
//! |
|
|
||||||
//! = note: the `thumbv7m-none-eabi` target may not be installed
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Solution: call `rustup target add thumbv7m-none-eabi` but with the name of your target
|
|
||||||
//!
|
|
||||||
//! ## Used an old nightly
|
|
||||||
//!
|
|
||||||
//! Error message:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo build
|
|
||||||
//! Compiling cortex-m-rt v0.2.0
|
|
||||||
//! error[E0463]: can't find crate for `core`
|
|
||||||
//! |
|
|
||||||
//! = note: the `thumbv7em-none-eabihf` target may not be installed
|
|
||||||
//!
|
|
||||||
//! error: aborting due to previous error
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Solution: Use a more recent nightly
|
|
||||||
//!
|
|
||||||
//! ## Used the stable toolchain
|
|
||||||
//!
|
|
||||||
//! Error message:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo build
|
|
||||||
//! error[E0463]: can't find crate for `core`
|
|
||||||
//! |
|
|
||||||
//! = note: the `thumbv7em-none-eabihf` target may not be installed
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Solution: We are not there yet! Switch to the nightly toolchain with `rustup default nightly`.
|
|
||||||
//!
|
|
||||||
//! ## Used `gdb` instead of `arm-none-eabi-gdb`
|
|
||||||
//!
|
|
||||||
//! Error message:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ gdb target/..
|
|
||||||
//! Reading symbols from hello...done.
|
|
||||||
//! warning: Architecture rejected target-supplied description
|
|
||||||
//! warning: Cannot convert floating-point register value to ..
|
|
||||||
//! value has been optimized out
|
|
||||||
//! Cannot write the dashboard
|
|
||||||
//! Traceback (most recent call last):
|
|
||||||
//! File "<string>", line 353, in render
|
|
||||||
//! File "<string>", line 846, in lines
|
|
||||||
//! gdb.error: Frame is invalid.
|
|
||||||
//! 0x00000000 in ?? ()
|
|
||||||
//! semihosting is enabled
|
|
||||||
//! Loading section .text, size 0xd88 lma 0x8000000
|
|
||||||
//! Start address 0x8000000, load size 3464
|
|
||||||
//! .gdbinit:6: Error in sourced command file:
|
|
||||||
//! Remote connection closed
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Solution: Use `arm-none-eabi-gdb target/..`
|
|
||||||
//!
|
|
||||||
//! # Used a named piped for `itm.fifo`
|
|
||||||
//!
|
|
||||||
//! Error message:
|
|
||||||
//!
|
|
||||||
//! ``` text
|
|
||||||
//! $ cargo run [--example ..]
|
|
||||||
//!
|
|
||||||
//! Reading symbols from target/thumbv7em-none-eabihf/debug/cortex-m-quickstart...done.
|
|
||||||
//! cortex_m_rt::reset_handler ()
|
|
||||||
//! at $REGISTRY/cortex-m-rt-0.3.12/src/lib.rs:330
|
|
||||||
//! 330 unsafe extern "C" fn reset_handler() -> ! {
|
|
||||||
//! semihosting is enabled
|
|
||||||
//! Ignoring packet error, continuing...
|
|
||||||
//! Ignoring packet error, continuing...
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Note that when you reach this point OpenOCD will become unresponsive and you'll have to kill it
|
|
||||||
//! and start a new OpenOCD process before you can invoke `cargo run` / start GDB.
|
|
||||||
//!
|
|
||||||
//! Cause: You uncommented the `monitor tpiu ..` line in `.gdbinit` and are using a named pipe to
|
|
||||||
//! receive the ITM data (i.e. you ran `mkfifo itm.fifo`). This error occurs when `itmdump -f
|
|
||||||
//! itm.fifo` (or equivalent, e.g. `cat itm.fifo`) is not running.
|
|
||||||
//!
|
|
||||||
//! Solution: Run `itmdump -f itm.fifo` (or equivalently `cat itm.fifo`) *before* invoking `cargo
|
|
||||||
//! run` / starting GDB. Note that sometimes `itmdump` will exit when the GDB session ends. In that
|
|
||||||
//! case you'll have to run `itmdump` before you start the next GDB session.
|
|
||||||
//!
|
|
||||||
//! Alternative solution: Use a plain text file instead of a named pipe. In this scenario you omit
|
|
||||||
//! the `mkfifo itm.dump` command. You can use `itmdump`'s *follow* mode (-F) to get named pipe like
|
|
||||||
//! output.
|
|
||||||
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
pub mod examples;
|
|
||||||
19
src/main.rs
Normal file
19
src/main.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate cortex_m;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate cortex_m_rt;
|
||||||
|
|
||||||
|
// TODO pick a panicking behavior
|
||||||
|
// extern crate panic_abort; // requires nightly
|
||||||
|
// extern crate panic_itm; // requires ITM support
|
||||||
|
// extern crate panic_semihosting; // requires a debugger
|
||||||
|
|
||||||
|
entry!(main);
|
||||||
|
|
||||||
|
fn main() -> ! {
|
||||||
|
loop {
|
||||||
|
// TODO your code goes here
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user