move out most of text
see https://github.com/rust-embedded/book/pull/20
This commit is contained in:
@@ -1,4 +1,12 @@
|
|||||||
|
[target.thumbv7m-none-eabi]
|
||||||
|
# uncomment this to make `cargo run` execute programs on QEMU
|
||||||
|
# runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
|
||||||
|
|
||||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
# uncomment this to make `cargo run` start a GDB session
|
||||||
|
# NOTE: you may need to change `arm-none-eabi-gdb`
|
||||||
|
# runner = "arm-none-eabi-gdb -x openocd.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",
|
||||||
@@ -20,4 +28,4 @@ rustflags = [
|
|||||||
# 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)
|
||||||
|
|||||||
22
Cargo.toml
22
Cargo.toml
@@ -1,13 +1,17 @@
|
|||||||
|
# TODO remove
|
||||||
|
cargo-features = ["edition"]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
|
edition = "2018"
|
||||||
authors = ["{{authors}}"]
|
authors = ["{{authors}}"]
|
||||||
name = "{{project-name}}"
|
name = "{{project-name}}"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = "0.5.6"
|
cortex-m = "0.5.7"
|
||||||
cortex-m-rt = "0.5.3"
|
cortex-m-rt = "0.6.1"
|
||||||
cortex-m-semihosting = "0.3.1"
|
cortex-m-semihosting = "0.3.1"
|
||||||
panic-semihosting = "0.4.0"
|
panic-halt = "0.1.3"
|
||||||
|
|
||||||
# Uncomment for the panic example.
|
# Uncomment for the panic example.
|
||||||
# panic-itm = "0.3.0"
|
# panic-itm = "0.3.0"
|
||||||
@@ -16,11 +20,17 @@ panic-semihosting = "0.4.0"
|
|||||||
# alloc-cortex-m = "0.3.5"
|
# alloc-cortex-m = "0.3.5"
|
||||||
|
|
||||||
# Uncomment for the device example.
|
# Uncomment for the device example.
|
||||||
# [dependencies.stm32f103xx]
|
# [dependencies.stm32f30x]
|
||||||
# features = ["rt"]
|
# features = ["rt"]
|
||||||
# version = "0.10.0"
|
# version = "0.7.1"
|
||||||
|
|
||||||
|
# this lets you use `cargo fix`!
|
||||||
|
[[bin]]
|
||||||
|
name = "{{project-name}}"
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1 # better optimizations
|
codegen-units = 1 # better optimizations
|
||||||
debug = true
|
debug = true # symbols are nice and they don't increase the size on Flash
|
||||||
lto = true # better optimizations
|
lto = true # better optimizations
|
||||||
|
|||||||
464
README.md
464
README.md
@@ -4,14 +4,14 @@
|
|||||||
|
|
||||||
This project is developed and maintained by the [Cortex-M team][team].
|
This project is developed and maintained by the [Cortex-M team][team].
|
||||||
|
|
||||||
# [Documentation](https://rust-embedded.github.io/cortex-m-quickstart/cortex_m_quickstart)
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
To build embedded programs using this template you'll need:
|
To build embedded programs using this template you'll need:
|
||||||
|
|
||||||
- Nightly Rust toolchain from 2018-08-28 or newer: `rustup default nightly`
|
- Rust 1.30-beta or nightly. `rustup default beta`
|
||||||
|
|
||||||
- The `cargo generate` subcommand: `cargo install cargo-generate`
|
- The `cargo generate` subcommand: `cargo install cargo-generate`
|
||||||
|
|
||||||
- `rust-std` components (pre-compiled `core` crate) for the ARM Cortex-M
|
- `rust-std` components (pre-compiled `core` crate) for the ARM Cortex-M
|
||||||
targets. Run:
|
targets. Run:
|
||||||
|
|
||||||
@@ -19,337 +19,56 @@ To build embedded programs using this template you'll need:
|
|||||||
$ rustup target add thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf
|
$ rustup target add thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf
|
||||||
```
|
```
|
||||||
|
|
||||||
## Non-dependencies
|
## Using this template
|
||||||
|
|
||||||
This section list programs that are *not* required to build embedded programs
|
**NOTE**: This is the very short version that only covers building programs. For
|
||||||
but are useful or necessary for embedded development.
|
the long version check [the embedded Rust book][book].
|
||||||
|
|
||||||
To flash (put the firmware on the target device) and debug embedded programs
|
[book]: https://rust-embedded.github.io/book/blinky/blinky.html
|
||||||
you'll need these additional programs:
|
|
||||||
|
|
||||||
<!-- TODO These bullets should link to the debugonomicon, which has instructions -->
|
0. Before we begin you need to identify some characteristics of the target
|
||||||
<!-- on how to install these tools -->
|
device as these will be used to configure the project:
|
||||||
|
|
||||||
- GDB with ARM support or LLDB, for debugging.
|
- The ARM core. e.g. Cortex-M3.
|
||||||
- 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`].
|
- Does the ARM core include an FPU? Cortex-M4**F** and Cortex-M7**F** cores do.
|
||||||
|
|
||||||
[`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
|
- 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`
|
- Where are Flash memory and RAM mapped in the address space? e.g. RAM is
|
||||||
is common for RAM.
|
commonly located at address `0x2000_0000`.
|
||||||
|
|
||||||
You should be able to find this information in the data sheet and / or reference
|
You can find this information in the data sheet or the reference manual of your
|
||||||
manual of your device.
|
device.
|
||||||
|
|
||||||
As an example, we'll use the [STM32F303VCT6] microcontroller. This device has:
|
In this example we'll be using the STM32F3DISCOVERY. This board contains an
|
||||||
|
STM32F303VCT6 microcontroller. This microcontroller has:
|
||||||
|
|
||||||
[STM32F303VCT6]: https://www.st.com/en/microcontrollers/stm32f303vc.html
|
- A Cortex-M4F core that includes a single precision FPU
|
||||||
|
|
||||||
- a Cortex-M4F core that includes a single precision FPU
|
- 256 KB of Flash located at address 0x0800_0000.
|
||||||
|
|
||||||
- 256 KB of Flash located at address `0x0800_0000`.
|
- 40 KB of RAM located at address 0x2000_0000. (There's another RAM region but
|
||||||
|
|
||||||
- 40 KB of RAM located at address `0x2000_0000`. (There's another RAM region but
|
|
||||||
for simplicity we'll ignore it).
|
for simplicity we'll ignore it).
|
||||||
|
|
||||||
1. Initialize the template
|
1. Instantiate the template.
|
||||||
|
|
||||||
``` console
|
``` console
|
||||||
$ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
|
$ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
|
||||||
|
Project Name: app
|
||||||
|
Creating project called `app`...
|
||||||
|
Done! New project created /tmp/app
|
||||||
|
|
||||||
|
$ cd app
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Set the default compilation target in `.cargo/config`.
|
2. Set a default compilation target. There are four options as mentioned at the
|
||||||
|
bottom of `.cargo/config`. For the STM32F303VCT6, which has a Cortex-M4F
|
||||||
|
core, we'll pick the `thumbv7em-none-eabihf` target.
|
||||||
|
|
||||||
For the STM32F303VCT6, we pick the `thumbv7em-none-eabihf` target as that covers
|
|
||||||
the Cortex-M4F core.
|
|
||||||
|
|
||||||
``` console
|
``` console
|
||||||
$ tail .cargo/config
|
$ tail -n6 .cargo/config
|
||||||
```
|
```
|
||||||
|
|
||||||
``` toml
|
``` toml
|
||||||
@@ -361,138 +80,25 @@ $ tail .cargo/config
|
|||||||
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Enter the memory region information into `memory.x`.
|
3. Enter the memory region information into the `memory.x` file.
|
||||||
|
|
||||||
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
|
``` console
|
||||||
$ cat memory.x
|
$ cat memory.x
|
||||||
```
|
/* Linker script for the STM32F303VCT6 */
|
||||||
|
|
||||||
``` text
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
/* NOTE K = KiBi = 1024 bytes */
|
/* NOTE 1 K = 1 KiBi = 1024 bytes */
|
||||||
FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
||||||
RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Build one of the examples:
|
4. Build the template application or one of the examples.
|
||||||
|
|
||||||
``` console
|
``` console
|
||||||
$ cargo build --example hello
|
$ cargo build
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -11,27 +11,19 @@
|
|||||||
|
|
||||||
#![feature(alloc)]
|
#![feature(alloc)]
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
#![feature(lang_items)]
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
// This is the allocator crate; you can use a different one
|
extern crate panic_halt;
|
||||||
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::alloc::Layout;
|
use core::alloc::Layout;
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use alloc::vec;
|
||||||
use alloc_cortex_m::CortexMHeap;
|
use alloc_cortex_m::CortexMHeap;
|
||||||
use cortex_m::asm;
|
use cortex_m::asm;
|
||||||
use rt::ExceptionFrame;
|
use cortex_m_rt::entry;
|
||||||
use sh::hio;
|
use cortex_m_semihosting::hio;
|
||||||
|
|
||||||
// this is the allocator the application will use
|
// this is the allocator the application will use
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
@@ -39,11 +31,10 @@ static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
|
|||||||
|
|
||||||
const HEAP_SIZE: usize = 1024; // in bytes
|
const HEAP_SIZE: usize = 1024; // in bytes
|
||||||
|
|
||||||
entry!(main);
|
#[entry]
|
||||||
|
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
// Initialize the allocator BEFORE you use it
|
// Initialize the allocator BEFORE you use it
|
||||||
unsafe { ALLOCATOR.init(rt::heap_start() as usize, HEAP_SIZE) }
|
unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) }
|
||||||
|
|
||||||
// Growable array allocated on the heap
|
// Growable array allocated on the heap
|
||||||
let xs = vec![0, 1, 2];
|
let xs = vec![0, 1, 2];
|
||||||
@@ -56,21 +47,8 @@ fn main() -> ! {
|
|||||||
|
|
||||||
// define what happens in an Out Of Memory (OOM) condition
|
// define what happens in an Out Of Memory (OOM) condition
|
||||||
#[alloc_error_handler]
|
#[alloc_error_handler]
|
||||||
#[no_mangle]
|
fn alloc_error(_layout: Layout) -> ! {
|
||||||
pub fn alloc_error(_layout: Layout) -> ! {
|
|
||||||
asm::bkpt();
|
asm::bkpt();
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -79,36 +79,18 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate cortex_m;
|
extern crate panic_halt;
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rt as rt;
|
|
||||||
extern crate panic_semihosting;
|
|
||||||
|
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
use rt::ExceptionFrame;
|
use cortex_m_rt::entry;
|
||||||
|
|
||||||
entry!(main);
|
|
||||||
|
|
||||||
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
unsafe {
|
unsafe {
|
||||||
// read an address outside of the RAM region; causes a HardFault exception
|
// read an address outside of the RAM region; this causes a HardFault exception
|
||||||
ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {}
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -24,23 +24,17 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate cortex_m;
|
#[allow(unused_extern_crates)]
|
||||||
#[macro_use]
|
extern crate panic_halt;
|
||||||
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 core::fmt::Write;
|
||||||
|
|
||||||
use cortex_m::peripheral::syst::SystClkSource;
|
use cortex_m::peripheral::syst::SystClkSource;
|
||||||
use rt::ExceptionFrame;
|
use cortex_m_rt::entry;
|
||||||
use sh::hio::{self, HStdout};
|
use cortex_m_semihosting::hio::{self, HStdout};
|
||||||
use stm32f103xx::Interrupt;
|
use stm32f30x::{interrupt, Interrupt};
|
||||||
|
|
||||||
entry!(main);
|
|
||||||
|
|
||||||
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = cortex_m::Peripherals::take().unwrap();
|
let p = cortex_m::Peripherals::take().unwrap();
|
||||||
|
|
||||||
@@ -75,15 +69,3 @@ fn exti0(state: &mut Option<HStdout>) {
|
|||||||
hstdout.write_str(".").unwrap();
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! Overriding an exception handler
|
//! Overriding an exception handler
|
||||||
//!
|
//!
|
||||||
//! You can override an exception handler using the [`exception!`][1] macro.
|
//! You can override an exception handler using the [`#[exception]`][1] attribute.
|
||||||
//!
|
//!
|
||||||
//! [1]: https://docs.rs/cortex-m-rt/0.5.0/cortex_m_rt/macro.exception.html
|
//! [1]: https://rust-embedded.github.io/cortex-m-rt/0.6.1/cortex_m_rt_macros/fn.exception.html
|
||||||
//!
|
//!
|
||||||
//! ---
|
//! ---
|
||||||
|
|
||||||
@@ -10,21 +10,16 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate cortex_m;
|
extern crate panic_halt;
|
||||||
#[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 core::fmt::Write;
|
||||||
|
|
||||||
use cortex_m::peripheral::syst::SystClkSource;
|
use cortex_m::peripheral::syst::SystClkSource;
|
||||||
use cortex_m::Peripherals;
|
use cortex_m::Peripherals;
|
||||||
use rt::ExceptionFrame;
|
use cortex_m_rt::{entry, exception};
|
||||||
use sh::hio::{self, HStdout};
|
use cortex_m_semihosting::hio::{self, HStdout};
|
||||||
|
|
||||||
entry!(main);
|
|
||||||
|
|
||||||
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
let mut syst = p.SYST;
|
let mut syst = p.SYST;
|
||||||
@@ -38,27 +33,15 @@ fn main() -> ! {
|
|||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// try commenting out this line: you'll end in `default_handler` instead of in `sys_tick`
|
#[exception]
|
||||||
exception!(SysTick, sys_tick, state: Option<HStdout> = None);
|
fn SysTick() {
|
||||||
|
static mut STDOUT: Option<HStdout> = None;
|
||||||
|
|
||||||
fn sys_tick(state: &mut Option<HStdout>) {
|
if STDOUT.is_none() {
|
||||||
if state.is_none() {
|
*STDOUT = Some(hio::hstdout().unwrap());
|
||||||
*state = Some(hio::hstdout().unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(hstdout) = state.as_mut() {
|
if let Some(hstdout) = STDOUT.as_mut() {
|
||||||
hstdout.write_str(".").unwrap();
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,24 +1,22 @@
|
|||||||
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
//! Prints "Hello, world!" on the host console using semihosting
|
||||||
//!
|
|
||||||
//! ---
|
|
||||||
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#[macro_use]
|
extern crate panic_halt;
|
||||||
extern crate cortex_m_rt;
|
|
||||||
extern crate cortex_m_semihosting as sh;
|
|
||||||
extern crate panic_semihosting;
|
|
||||||
|
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
|
||||||
use sh::hio;
|
use cortex_m_rt::entry;
|
||||||
|
use cortex_m_semihosting::{debug, hio};
|
||||||
entry!(main);
|
|
||||||
|
|
||||||
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let mut stdout = hio::hstdout().unwrap();
|
let mut stdout = hio::hstdout().unwrap();
|
||||||
writeln!(stdout, "Hello, world!").unwrap();
|
writeln!(stdout, "Hello, world!").unwrap();
|
||||||
|
|
||||||
|
// exit QEMU or the debugger section
|
||||||
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,38 +17,17 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#[macro_use]
|
extern crate panic_halt;
|
||||||
extern crate cortex_m;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rt as rt;
|
|
||||||
extern crate panic_semihosting;
|
|
||||||
|
|
||||||
use cortex_m::{asm, Peripherals};
|
use cortex_m::{iprintln, Peripherals};
|
||||||
use rt::ExceptionFrame;
|
use cortex_m_rt::entry;
|
||||||
|
|
||||||
entry!(main);
|
|
||||||
|
|
||||||
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let mut p = Peripherals::take().unwrap();
|
let mut p = Peripherals::take().unwrap();
|
||||||
let stim = &mut p.ITM.stim[0];
|
let stim = &mut p.ITM.stim[0];
|
||||||
|
|
||||||
iprintln!(stim, "Hello, world!");
|
iprintln!(stim, "Hello, world!");
|
||||||
|
|
||||||
loop {
|
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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +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
|
|
||||||
|
|
||||||
#![no_main] // <- IMPORTANT!
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
#[macro_use(entry)]
|
|
||||||
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;
|
|
||||||
|
|
||||||
// the program entry point is ...
|
|
||||||
entry!(main);
|
|
||||||
|
|
||||||
// ... this never ending function
|
|
||||||
fn main() -> ! {
|
|
||||||
loop {
|
|
||||||
asm::bkpt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +1,28 @@
|
|||||||
//! Changing the panic handler
|
//! Changing the panicking behavior
|
||||||
//!
|
//!
|
||||||
//! The easiest way to change the panic handler is to use a different [panic handler crate][0].
|
//! The easiest way to change the panicking behavior is to use a different [panic handler crate][0].
|
||||||
//!
|
//!
|
||||||
//! [0]: https://crates.io/keywords/panic-impl
|
//! [0]: https://crates.io/keywords/panic-impl
|
||||||
//!
|
|
||||||
//! ---
|
|
||||||
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#[macro_use]
|
// Pick one of these panic handlers:
|
||||||
extern crate cortex_m_rt as rt;
|
|
||||||
|
|
||||||
// Pick one of these two panic handlers:
|
// `panic!` halts execution; the panic message is ignored
|
||||||
|
extern crate panic_halt;
|
||||||
|
|
||||||
// Reports panic messages to the host stderr using semihosting
|
// Reports panic messages to the host stderr using semihosting
|
||||||
extern crate panic_semihosting;
|
// NOTE to use this you need to uncomment the `panic-semihosting` dependency in Cargo.toml
|
||||||
|
// extern crate panic_semihosting;
|
||||||
|
|
||||||
// Logs panic messages using the ITM (Instrumentation Trace Macrocell)
|
// Logs panic messages using the ITM (Instrumentation Trace Macrocell)
|
||||||
// NOTE to use this you need to uncomment the `panic-itm` dependency in Cargo.toml
|
// NOTE to use this you need to uncomment the `panic-itm` dependency in Cargo.toml
|
||||||
// extern crate panic_itm;
|
// extern crate panic_itm;
|
||||||
|
|
||||||
use rt::ExceptionFrame;
|
use cortex_m_rt::entry;
|
||||||
|
|
||||||
entry!(main);
|
|
||||||
|
|
||||||
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
panic!("Oops")
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
5
memory.x
5
memory.x
@@ -1,6 +1,6 @@
|
|||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
/* NOTE K = KiBi = 1024 bytes */
|
/* NOTE 1 K = 1 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 */
|
||||||
/* These values correspond to the LM3S6965, one of the few devices QEMU can emulate */
|
/* These values correspond to the LM3S6965, one of the few devices QEMU can emulate */
|
||||||
FLASH : ORIGIN = 0x00000000, LENGTH = 256K
|
FLASH : ORIGIN = 0x00000000, LENGTH = 256K
|
||||||
@@ -19,6 +19,3 @@ MEMORY
|
|||||||
/* This is required only on microcontrollers that store some configuration right
|
/* This is required only on microcontrollers that store some configuration right
|
||||||
after the vector table */
|
after the vector table */
|
||||||
/* _stext = ORIGIN(FLASH) + 0x400; */
|
/* _stext = ORIGIN(FLASH) + 0x400; */
|
||||||
|
|
||||||
/* Size of the heap (in bytes) */
|
|
||||||
/* _heap_size = 1024; */
|
|
||||||
|
|||||||
@@ -3,10 +3,14 @@ target remote :3333
|
|||||||
# print demangled symbols
|
# print demangled symbols
|
||||||
set print asm-demangle on
|
set print asm-demangle on
|
||||||
|
|
||||||
# detect unhandled exceptions and hard faults
|
# detect unhandled exceptions, hard faults and panics
|
||||||
break DefaultHandler
|
break DefaultHandler
|
||||||
break UserHardFault
|
break UserHardFault
|
||||||
|
break rust_begin_unwind
|
||||||
|
|
||||||
monitor arm semihosting enable
|
monitor arm semihosting enable
|
||||||
|
|
||||||
load
|
load
|
||||||
|
|
||||||
|
# start the process but immediately halt the processor
|
||||||
|
stepi
|
||||||
18
src/main.rs
18
src/main.rs
@@ -1,19 +1,17 @@
|
|||||||
#![no_main]
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
extern crate cortex_m;
|
// pick a panicking behavior
|
||||||
#[macro_use]
|
extern crate panic_halt; // you can put a breakpoint on `rust_begin_unwind` to catch panics
|
||||||
extern crate cortex_m_rt;
|
|
||||||
|
|
||||||
// TODO pick a panicking behavior
|
|
||||||
// extern crate panic_abort; // requires nightly
|
// extern crate panic_abort; // requires nightly
|
||||||
// extern crate panic_itm; // requires ITM support
|
// extern crate panic_itm; // logs messages over ITM; requires ITM support
|
||||||
// extern crate panic_semihosting; // requires a debugger
|
// extern crate panic_semihosting; // logs messages to the host stderr; requires a debugger
|
||||||
|
|
||||||
entry!(main);
|
use cortex_m_rt::entry;
|
||||||
|
|
||||||
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
loop {
|
loop {
|
||||||
// TODO your code goes here
|
// your code goes here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user