Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb68ff7248 | ||
|
|
55f44f21be | ||
|
|
f38979def1 | ||
|
|
ba27df0b57 | ||
|
|
f39fa8ebef | ||
|
|
5832d097c6 | ||
|
|
2a2879a3b0 | ||
|
|
daea420f17 | ||
|
|
b7884948b2 | ||
|
|
01e9a597c1 | ||
|
|
ae503ee8fb | ||
|
|
4a398df058 | ||
|
|
efb84ccf53 | ||
|
|
a462ab027d | ||
|
|
6da25bced8 | ||
|
|
7cb137968b | ||
|
|
7ae7245956 | ||
|
|
91a894e369 | ||
|
|
f7cf8de167 | ||
|
|
66c0c588b0 | ||
|
|
0f139c386b | ||
|
|
3a4a5be709 | ||
|
|
a35486b2f4 | ||
|
|
8e79d05cc4 | ||
|
|
0e2ec97ce6 | ||
|
|
f6988f1ced |
@@ -1,39 +1,27 @@
|
||||
[target.thumbv6m-none-eabi]
|
||||
runner = 'arm-none-eabi-gdb'
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "linker=lld",
|
||||
"-Z", "linker-flavor=ld.lld",
|
||||
# "-C", "linker=arm-none-eabi-ld",
|
||||
# "-Z", "linker-flavor=ld",
|
||||
"-C", "link-arg=-Wl,-Tlink.x",
|
||||
"-C", "link-arg=-nostartfiles",
|
||||
]
|
||||
|
||||
[target.thumbv7m-none-eabi]
|
||||
runner = 'arm-none-eabi-gdb'
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "linker=lld",
|
||||
"-Z", "linker-flavor=ld.lld",
|
||||
# "-C", "linker=arm-none-eabi-ld",
|
||||
# "-Z", "linker-flavor=ld",
|
||||
"-C", "link-arg=-Wl,-Tlink.x",
|
||||
"-C", "link-arg=-nostartfiles",
|
||||
]
|
||||
|
||||
[target.thumbv7em-none-eabi]
|
||||
runner = 'arm-none-eabi-gdb'
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "linker=lld",
|
||||
"-Z", "linker-flavor=ld.lld",
|
||||
# "-C", "linker=arm-none-eabi-ld",
|
||||
# "-Z", "linker-flavor=ld",
|
||||
"-C", "link-arg=-Wl,-Tlink.x",
|
||||
"-C", "link-arg=-nostartfiles",
|
||||
]
|
||||
|
||||
[target.thumbv7em-none-eabihf]
|
||||
runner = 'arm-none-eabi-gdb'
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "linker=lld",
|
||||
"-Z", "linker-flavor=ld.lld",
|
||||
# "-C", "linker=arm-none-eabi-ld",
|
||||
# "-Z", "linker-flavor=ld",
|
||||
"-C", "link-arg=-Wl,-Tlink.x",
|
||||
"-C", "link-arg=-nostartfiles",
|
||||
]
|
||||
|
||||
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* @rust-embedded/cortex-m
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
**/*.rs.bk
|
||||
.#*
|
||||
.gdb_history
|
||||
Cargo.lock
|
||||
target/
|
||||
|
||||
21
.travis.yml
21
.travis.yml
@@ -6,37 +6,33 @@ matrix:
|
||||
rust: nightly
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- debian-sid
|
||||
packages:
|
||||
- binutils-arm-none-eabi
|
||||
- gcc-arm-none-eabi
|
||||
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||
|
||||
- env: TARGET=thumbv7m-none-eabi
|
||||
rust: nightly
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- debian-sid
|
||||
packages:
|
||||
- binutils-arm-none-eabi
|
||||
- gcc-arm-none-eabi
|
||||
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||
|
||||
- env: TARGET=thumbv7em-none-eabi
|
||||
rust: nightly
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- debian-sid
|
||||
packages:
|
||||
- binutils-arm-none-eabi
|
||||
- gcc-arm-none-eabi
|
||||
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||
|
||||
- env: TARGET=thumbv7em-none-eabihf
|
||||
rust: nightly
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- debian-sid
|
||||
packages:
|
||||
- binutils-arm-none-eabi
|
||||
- gcc-arm-none-eabi
|
||||
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||
|
||||
before_install: set -e
|
||||
|
||||
@@ -56,6 +52,7 @@ before_cache:
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- staging
|
||||
- trying
|
||||
|
||||
|
||||
46
CHANGELOG.md
46
CHANGELOG.md
@@ -5,6 +5,46 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.3.3] - 2018-08-07
|
||||
|
||||
### Changed
|
||||
|
||||
- Stopped recommending LLD as it requires an unstable feature.
|
||||
|
||||
### Fixed
|
||||
|
||||
- The allocator example. It now uses the `#[alloc_error_handler]` attribute
|
||||
instead of the unstable `oom` lang item.
|
||||
|
||||
## [v0.3.2] - 2018-06-19
|
||||
|
||||
### Fixed
|
||||
|
||||
- Bumped the panic-semihosting dependency to fix some examples when compiling with latest nightly.
|
||||
|
||||
## [v0.3.1] - 2018-05-13
|
||||
|
||||
- Document the standard `main` interface issue in the troubleshooting guide.
|
||||
|
||||
## [v0.3.0] - 2018-05-12
|
||||
|
||||
### Changed
|
||||
|
||||
- [breaking-change] `arm-none-eabi-gcc` is now a mandatory dependency as it's required by the
|
||||
`cortex-m-rt` dependency and also the default linker.
|
||||
|
||||
- Bumped the `cortex-m` and `cortex-m-rt` dependencies to v0.5.0. Updated all the examples to match
|
||||
the new `cortex-m-rt` API.
|
||||
|
||||
- Updated the `allocator` example to compile on a recent nightly.
|
||||
|
||||
- Set the number of codegen-units to 1 when compiling in release mode. This produces smaller and
|
||||
faster binaries.
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed `opt-level = "s"` from `profile.release`. This flag is still unstable.
|
||||
|
||||
## [v0.2.7] - 2018-04-24
|
||||
|
||||
### Changed
|
||||
@@ -149,7 +189,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.7...HEAD
|
||||
[Unreleased]: https://github.com/japaric/cortex-m-quickstart/compare/v0.3.3...HEAD
|
||||
[v0.3.3]: https://github.com/japaric/cortex-m-quickstart/compare/v0.3.2...v0.3.3
|
||||
[v0.3.2]: https://github.com/japaric/cortex-m-quickstart/compare/v0.3.1...v0.3.2
|
||||
[v0.3.1]: https://github.com/japaric/cortex-m-quickstart/compare/v0.3.0...v0.3.1
|
||||
[v0.3.0]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.7...v0.3.0
|
||||
[v0.2.7]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.6...v0.2.7
|
||||
[v0.2.6]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.5...v0.2.6
|
||||
[v0.2.5]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.4...v0.2.5
|
||||
|
||||
37
CODE_OF_CONDUCT.md
Normal file
37
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# The Rust Code of Conduct
|
||||
|
||||
## Conduct
|
||||
|
||||
**Contact**: [Cortex-M team](https://github.com/rust-embedded/wg#the-cortex-m-team)
|
||||
|
||||
* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
|
||||
* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
|
||||
* Please be kind and courteous. There's no need to be mean or rude.
|
||||
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
|
||||
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
|
||||
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
|
||||
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Cortex-M team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
|
||||
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
|
||||
|
||||
## Moderation
|
||||
|
||||
These are the policies for upholding our community's standards of conduct.
|
||||
|
||||
1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
|
||||
2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
|
||||
3. Moderators will first respond to such remarks with a warning.
|
||||
4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
|
||||
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
|
||||
6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
|
||||
7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
|
||||
8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
|
||||
|
||||
In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
|
||||
|
||||
And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
|
||||
|
||||
The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org).
|
||||
|
||||
*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
|
||||
|
||||
[team]: https://github.com/rust-embedded/wg#the-cortex-m-team
|
||||
23
Cargo.toml
23
Cargo.toml
@@ -6,23 +6,26 @@ 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.2.7"
|
||||
version = "0.3.3"
|
||||
|
||||
[dependencies]
|
||||
cortex-m = "0.4.0"
|
||||
cortex-m-rt = "0.4.0"
|
||||
cortex-m-semihosting = "0.2.0"
|
||||
panic-abort = "0.1.1"
|
||||
panic-semihosting = "0.1.0"
|
||||
cortex-m = "0.5.0"
|
||||
cortex-m-rt = "0.5.0"
|
||||
cortex-m-semihosting = "0.3.0"
|
||||
panic-semihosting = "0.3.0"
|
||||
|
||||
# Uncomment for the panic example.
|
||||
# panic-itm = "0.1.1"
|
||||
|
||||
# Uncomment for the allocator example.
|
||||
#alloc-cortex-m = "0.3.3"
|
||||
# alloc-cortex-m = "0.3.4"
|
||||
|
||||
# Uncomment for the device example.
|
||||
# [dependencies.stm32f103xx]
|
||||
# features = ["rt"]
|
||||
# version = "0.9.0"
|
||||
# version = "0.10.0"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1 # better optimizations
|
||||
debug = true
|
||||
lto = true
|
||||
opt-level = "s"
|
||||
lto = true # better optimizations
|
||||
|
||||
11
README.md
11
README.md
@@ -2,6 +2,8 @@
|
||||
|
||||
> A template for building applications for ARM Cortex-M microcontrollers
|
||||
|
||||
This project is developed and maintained by the [Cortex-M team][team].
|
||||
|
||||
# [Documentation](https://docs.rs/cortex-m-quickstart)
|
||||
|
||||
# License
|
||||
@@ -20,3 +22,12 @@ at your option.
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Contribution to this crate is organized under the terms of the [Rust Code of
|
||||
Conduct][CoC], the maintainer of this crate, the [Cortex-M team][team], promises
|
||||
to intervene to uphold that code of conduct.
|
||||
|
||||
[CoC]: CODE_OF_CONDUCT.md
|
||||
[team]: https://github.com/rust-embedded/wg#the-cortex-m-team
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
status = [
|
||||
"continuous-integration/travis-ci/push",
|
||||
]
|
||||
delete_merged_branches = true
|
||||
required_approvals = 1
|
||||
status = ["continuous-integration/travis-ci/push"]
|
||||
|
||||
3
build.rs
3
build.rs
@@ -12,6 +12,7 @@ fn main() {
|
||||
.unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
// Only re-run the build script when memory.x is changed,
|
||||
// instead of when any part of the source code changes.
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
}
|
||||
|
||||
10
ci/script.sh
10
ci/script.sh
@@ -9,7 +9,6 @@ main() {
|
||||
cat >memory.x <<'EOF'
|
||||
MEMORY
|
||||
{
|
||||
/* NOTE K = KiBi = 1024 bytes */
|
||||
FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
||||
}
|
||||
@@ -17,8 +16,9 @@ EOF
|
||||
|
||||
local examples=(
|
||||
crash
|
||||
exception
|
||||
hello
|
||||
override-exception-handler
|
||||
minimal
|
||||
panic
|
||||
)
|
||||
for ex in "${examples[@]}"; do
|
||||
@@ -33,17 +33,15 @@ EOF
|
||||
cargo build --target $TARGET --example $ex --release
|
||||
|
||||
examples+=( $ex )
|
||||
|
||||
fi
|
||||
|
||||
# Allocator example needs an extra dependency
|
||||
cat >>Cargo.toml <<'EOF'
|
||||
[dependencies.alloc-cortex-m]
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
EOF
|
||||
|
||||
local ex=allocator
|
||||
cargo build --target $TARGET --example $ex
|
||||
cargo build --target $TARGET --example $ex --release
|
||||
|
||||
examples+=( $ex )
|
||||
@@ -53,7 +51,7 @@ EOF
|
||||
cat >>Cargo.toml <<'EOF'
|
||||
[dependencies.stm32f103xx]
|
||||
features = ["rt"]
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
EOF
|
||||
|
||||
local ex=device
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! ---
|
||||
|
||||
#![feature(alloc)]
|
||||
#![feature(alloc_error_handler)]
|
||||
#![feature(global_allocator)]
|
||||
#![feature(used)]
|
||||
#![feature(lang_items)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
// This is the allocator crate; you can use a different one
|
||||
@@ -19,42 +21,57 @@ extern crate alloc_cortex_m;
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
extern crate cortex_m_semihosting;
|
||||
extern crate panic_abort; // panicking behavior
|
||||
#[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::fmt::Write;
|
||||
|
||||
use alloc_cortex_m::CortexMHeap;
|
||||
use cortex_m::asm;
|
||||
use cortex_m_semihosting::hio;
|
||||
use rt::ExceptionFrame;
|
||||
use sh::hio;
|
||||
|
||||
// this is the allocator the application will use
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
|
||||
|
||||
extern "C" {
|
||||
static mut _sheap: u32;
|
||||
}
|
||||
|
||||
const HEAP_SIZE: usize = 1024; // in bytes
|
||||
|
||||
fn main() {
|
||||
// Initialize the allocator
|
||||
let start = unsafe { &mut _sheap as *mut u32 as usize };
|
||||
unsafe { ALLOCATOR.init(start, HEAP_SIZE) }
|
||||
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 {}
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
#[used]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
// define what happens in an Out Of Memory (OOM) condition
|
||||
#[alloc_error_handler]
|
||||
#[no_mangle]
|
||||
pub fn alloc_error(layout: Layout) -> ! {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,85 +1,114 @@
|
||||
//! Debugging a crash (exception)
|
||||
//!
|
||||
//! The `cortex-m-rt` crate provides functionality for this through a default exception handler.
|
||||
//! When an exception is hit, the default handler will trigger a breakpoint and in this debugging
|
||||
//! context the stacked registers are accessible.
|
||||
//! 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.
|
||||
//!
|
||||
//! In you run the example below, you'll be able to inspect the state of your program under the
|
||||
//! debugger using these commands:
|
||||
//! 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) # Exception frame = program state during the crash
|
||||
//! (gdb) print/x *ef
|
||||
//! $1 = cortex_m::exception::ExceptionFrame {
|
||||
//! r0 = 0x2fffffff,
|
||||
//! r1 = 0x2fffffff,
|
||||
//! r2 = 0x0,
|
||||
//! r3 = 0x0,
|
||||
//! r12 = 0x0,
|
||||
//! lr = 0x8000481,
|
||||
//! pc = 0x8000460,
|
||||
//! xpsr = 0x61000000,
|
||||
//! }
|
||||
//! (gdb) continue
|
||||
//! Program received signal SIGTRAP, Trace/breakpoint trap.
|
||||
//! __bkpt () at asm/bkpt.s:3
|
||||
//! 3 bkpt
|
||||
//!
|
||||
//! (gdb) # Where did we come from?
|
||||
//! (gdb) backtrace
|
||||
//! #0 cortex_m_rt::default_handler (ef=0x20004f54) at (..)
|
||||
//! #1 <signal handler called>
|
||||
//! #2 0x08000460 in core::ptr::read_volatile<u32> (src=0x2fffffff) at (..)
|
||||
//! #3 0x08000480 in crash::main () at examples/crash.rs:68
|
||||
//! #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?)
|
||||
//! ```
|
||||
//!
|
||||
//! (gdb) # Nail down the location of the crash
|
||||
//! (gdb) disassemble/m ef.pc
|
||||
//! Dump of assembler code for function core::ptr::read_volatile<u32>:
|
||||
//! 408 pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||
//! 0x08000454 <+0>: sub sp, #20
|
||||
//! 0x08000456 <+2>: mov r1, r0
|
||||
//! 0x08000458 <+4>: str r0, [sp, #8]
|
||||
//! 0x0800045a <+6>: ldr r0, [sp, #8]
|
||||
//! 0x0800045c <+8>: str r0, [sp, #12]
|
||||
//! In the console output one will find the state of the Program Counter (PC) register at the time
|
||||
//! of the exception.
|
||||
//!
|
||||
//! 409 intrinsics::volatile_load(src)
|
||||
//! 0x0800045e <+10>: ldr r0, [sp, #12]
|
||||
//! 0x08000460 <+12>: ldr r0, [r0, #0]
|
||||
//! 0x08000462 <+14>: str r0, [sp, #16]
|
||||
//! 0x08000464 <+16>: ldr r0, [sp, #16]
|
||||
//! 0x08000466 <+18>: str r1, [sp, #4]
|
||||
//! 0x08000468 <+20>: str r0, [sp, #0]
|
||||
//! 0x0800046a <+22>: b.n 0x800046c <core::ptr::read_volatile<u32>+24>
|
||||
//! ``` 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
|
||||
//! ```
|
||||
//!
|
||||
//! 410 }
|
||||
//! 0x0800046c <+24>: ldr r0, [sp, #0]
|
||||
//! 0x0800046e <+26>: add sp, #20
|
||||
//! 0x08000470 <+28>: bx lr
|
||||
//! 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.
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#![feature(used)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
extern crate panic_abort; // panicking behavior
|
||||
#[macro_use]
|
||||
extern crate cortex_m_rt as rt;
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use core::ptr;
|
||||
|
||||
use cortex_m::asm;
|
||||
use rt::ExceptionFrame;
|
||||
|
||||
fn main() {
|
||||
// Read an invalid memory address
|
||||
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 {}
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
#[used]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
// define the hard fault handler
|
||||
exception!(HardFault, hard_fault);
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
asm::bkpt();
|
||||
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,12 +1,12 @@
|
||||
//! Using a device crate
|
||||
//!
|
||||
//! Crates generated using [`svd2rust`] are referred to as device crates. These crates provides an
|
||||
//! API to access the peripherals of a device. When you depend on one of these crates and the "rt"
|
||||
//! feature is enabled you don't need link to the cortex-m-rt 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 to register interrupt handlers.
|
||||
//! 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.
|
||||
//!
|
||||
@@ -16,80 +16,74 @@
|
||||
//! $ edit Cargo.toml && tail $_
|
||||
//! [dependencies.stm32f103xx]
|
||||
//! features = ["rt"]
|
||||
//! version = "0.9.0"
|
||||
//! version = "0.10.0"
|
||||
//! ```
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#![deny(warnings)]
|
||||
#![feature(const_fn)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
// extern crate cortex_m_rt; // included in the device crate
|
||||
extern crate cortex_m_semihosting;
|
||||
#[macro_use(exception, interrupt)]
|
||||
#[macro_use]
|
||||
extern crate cortex_m_rt as rt;
|
||||
extern crate cortex_m_semihosting as sh;
|
||||
#[macro_use]
|
||||
extern crate stm32f103xx;
|
||||
extern crate panic_abort; // panicking behavior
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use core::cell::RefCell;
|
||||
use core::fmt::Write;
|
||||
|
||||
use cortex_m::interrupt::{self, Mutex};
|
||||
use cortex_m::peripheral::syst::SystClkSource;
|
||||
use cortex_m_semihosting::hio::{self, HStdout};
|
||||
use rt::ExceptionFrame;
|
||||
use sh::hio::{self, HStdout};
|
||||
use stm32f103xx::Interrupt;
|
||||
|
||||
static HSTDOUT: Mutex<RefCell<Option<HStdout>>> = Mutex::new(RefCell::new(None));
|
||||
entry!(main);
|
||||
|
||||
static NVIC: Mutex<RefCell<Option<cortex_m::peripheral::NVIC>>> = Mutex::new(RefCell::new(None));
|
||||
fn main() -> ! {
|
||||
let p = cortex_m::Peripherals::take().unwrap();
|
||||
|
||||
fn main() {
|
||||
let global_p = cortex_m::Peripherals::take().unwrap();
|
||||
interrupt::free(|cs| {
|
||||
let hstdout = HSTDOUT.borrow(cs);
|
||||
if let Ok(fd) = hio::hstdout() {
|
||||
*hstdout.borrow_mut() = Some(fd);
|
||||
}
|
||||
let mut syst = p.SYST;
|
||||
let mut nvic = p.NVIC;
|
||||
|
||||
let mut nvic = global_p.NVIC;
|
||||
nvic.enable(Interrupt::TIM2);
|
||||
*NVIC.borrow(cs).borrow_mut() = Some(nvic);
|
||||
nvic.enable(Interrupt::EXTI0);
|
||||
|
||||
let mut syst = global_p.SYST;
|
||||
// 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();
|
||||
syst.enable_interrupt();
|
||||
});
|
||||
|
||||
loop {
|
||||
// busy wait until the timer wraps around
|
||||
while !syst.has_wrapped() {}
|
||||
|
||||
// trigger the `EXTI0` interrupt
|
||||
nvic.set_pending(Interrupt::EXTI0);
|
||||
}
|
||||
}
|
||||
|
||||
exception!(SYS_TICK, tick);
|
||||
// try commenting out this line: you'll end in `default_handler` instead of in `exti0`
|
||||
interrupt!(EXTI0, exti0, state: Option<HStdout> = None);
|
||||
|
||||
fn tick() {
|
||||
interrupt::free(|cs| {
|
||||
let hstdout = HSTDOUT.borrow(cs);
|
||||
if let Some(hstdout) = hstdout.borrow_mut().as_mut() {
|
||||
writeln!(*hstdout, "Tick").ok();
|
||||
fn exti0(state: &mut Option<HStdout>) {
|
||||
if state.is_none() {
|
||||
*state = Some(hio::hstdout().unwrap());
|
||||
}
|
||||
|
||||
if let Some(nvic) = NVIC.borrow(cs).borrow_mut().as_mut() {
|
||||
nvic.set_pending(Interrupt::TIM2);
|
||||
if let Some(hstdout) = state.as_mut() {
|
||||
hstdout.write_str(".").unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
interrupt!(TIM2, tock, locals: {
|
||||
tocks: u32 = 0;
|
||||
});
|
||||
exception!(HardFault, hard_fault);
|
||||
|
||||
fn tock(l: &mut TIM2::Locals) {
|
||||
l.tocks += 1;
|
||||
|
||||
interrupt::free(|cs| {
|
||||
let hstdout = HSTDOUT.borrow(cs);
|
||||
if let Some(hstdout) = hstdout.borrow_mut().as_mut() {
|
||||
writeln!(*hstdout, "Tock ({})", l.tocks).ok();
|
||||
}
|
||||
});
|
||||
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||
panic!("HardFault at {:#?}", ef);
|
||||
}
|
||||
|
||||
exception!(*, default_handler);
|
||||
|
||||
fn default_handler(irqn: i16) {
|
||||
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||
}
|
||||
|
||||
64
examples/exception.rs
Normal file
64
examples/exception.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
//! 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);
|
||||
}
|
||||
@@ -2,29 +2,36 @@
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#![feature(used)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
extern crate cortex_m_semihosting;
|
||||
extern crate panic_abort; // panicking behavior
|
||||
#[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::asm;
|
||||
use cortex_m_semihosting::hio;
|
||||
use rt::ExceptionFrame;
|
||||
use sh::hio;
|
||||
|
||||
fn main() {
|
||||
entry!(main);
|
||||
|
||||
fn main() -> ! {
|
||||
let mut stdout = hio::hstdout().unwrap();
|
||||
writeln!(stdout, "Hello, world!").unwrap();
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
#[used]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
exception!(HardFault, hard_fault);
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
asm::bkpt();
|
||||
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||
panic!("HardFault at {:#?}", ef);
|
||||
}
|
||||
|
||||
exception!(*, default_handler);
|
||||
|
||||
fn default_handler(irqn: i16) {
|
||||
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||
}
|
||||
|
||||
@@ -1,39 +1,54 @@
|
||||
//! Sends "Hello, world!" through the ITM port 0
|
||||
//!
|
||||
//! **IMPORTANT** Not all Cortex-M chips 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.
|
||||
//!
|
||||
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
|
||||
//!
|
||||
//! You'll need [`itmdump`] to receive the message on the host plus you'll need to uncomment the
|
||||
//! **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/
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#![feature(used)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
extern crate panic_abort; // panicking behavior
|
||||
#[macro_use]
|
||||
extern crate cortex_m_rt as rt;
|
||||
extern crate panic_semihosting;
|
||||
|
||||
use cortex_m::{asm, Peripherals};
|
||||
use rt::ExceptionFrame;
|
||||
|
||||
fn main() {
|
||||
let p = Peripherals::take().unwrap();
|
||||
let mut itm = p.ITM;
|
||||
entry!(main);
|
||||
|
||||
iprintln!(&mut itm.stim[0], "Hello, world!");
|
||||
}
|
||||
fn main() -> ! {
|
||||
let mut p = Peripherals::take().unwrap();
|
||||
let stim = &mut p.ITM.stim[0];
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
#[used]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
iprintln!(stim, "Hello, world!");
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
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);
|
||||
}
|
||||
|
||||
63
examples/minimal.rs
Normal file
63
examples/minimal.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
//! 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);
|
||||
}
|
||||
@@ -1,47 +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.3.2/cortex_m_rt/macro.exception.html
|
||||
//!
|
||||
//! The default exception handler can be overridden using the [`default_handler!`][2] macro
|
||||
//!
|
||||
//! [2]: https://docs.rs/cortex-m-rt/0.3.2/cortex_m_rt/macro.default_handler.html
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#![feature(used)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
#[macro_use(exception)]
|
||||
extern crate cortex_m_rt;
|
||||
extern crate panic_abort; // panicking behavior
|
||||
|
||||
use core::ptr;
|
||||
|
||||
use cortex_m::asm;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
// Invalid memory access
|
||||
ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
||||
}
|
||||
}
|
||||
|
||||
exception!(HARD_FAULT, handler);
|
||||
|
||||
fn handler() {
|
||||
// You'll hit this breakpoint rather than the one in cortex-m-rt
|
||||
asm::bkpt()
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[allow(dead_code)]
|
||||
#[used]
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
asm::bkpt();
|
||||
}
|
||||
@@ -1,31 +1,44 @@
|
||||
//! Changing the panic handler
|
||||
//!
|
||||
//! The easiest way to change the panic handler is to use a different [panic implementation
|
||||
//! crate][0].
|
||||
//! The easiest way to change the panic handler is to use a different [panic handler crate][0].
|
||||
//!
|
||||
//! [0]: https://crates.io/keywords/panic-impl
|
||||
//!
|
||||
//! ---
|
||||
|
||||
#![feature(used)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
extern crate cortex_m_rt;
|
||||
// extern crate panic_abort;
|
||||
extern crate panic_semihosting; // reports panic messages to the host stderr using semihosting
|
||||
#[macro_use]
|
||||
extern crate cortex_m_rt as rt;
|
||||
|
||||
use cortex_m::asm;
|
||||
// Pick one of these two panic handlers:
|
||||
|
||||
fn main() {
|
||||
panic!("Oops");
|
||||
// Reports panic messages to the host stderr using semihosting
|
||||
extern crate panic_semihosting;
|
||||
|
||||
// Logs panic messages using the ITM (Instrumentation Trace Macrocell)
|
||||
// NOTE to use this you need to uncomment the `panic-itm` dependency in Cargo.toml
|
||||
// extern crate panic_itm;
|
||||
|
||||
use rt::ExceptionFrame;
|
||||
|
||||
entry!(main);
|
||||
|
||||
fn main() -> ! {
|
||||
panic!("Oops")
|
||||
}
|
||||
|
||||
// As we are not using interrupts, we just register a dummy catch all handler
|
||||
#[link_section = ".vector_table.interrupts"]
|
||||
#[used]
|
||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
// define the hard fault handler
|
||||
exception!(HardFault, hard_fault);
|
||||
|
||||
extern "C" fn default_handler() {
|
||||
asm::bkpt();
|
||||
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,13 +5,14 @@ set -ex
|
||||
|
||||
main() {
|
||||
local examples=(
|
||||
minimal
|
||||
hello
|
||||
itm
|
||||
panic
|
||||
crash
|
||||
override-exception-handler
|
||||
device
|
||||
exception
|
||||
allocator
|
||||
device
|
||||
)
|
||||
|
||||
rm -rf src/examples
|
||||
@@ -19,7 +20,7 @@ main() {
|
||||
mkdir src/examples
|
||||
|
||||
cat >src/examples/mod.rs <<'EOF'
|
||||
//! Examples
|
||||
//! Examples sorted in increasing degree of complexity
|
||||
// Auto-generated. Do not modify.
|
||||
EOF
|
||||
|
||||
|
||||
4
memory.x
4
memory.x
@@ -2,8 +2,8 @@ MEMORY
|
||||
{
|
||||
/* NOTE K = KiBi = 1024 bytes */
|
||||
/* TODO Adjust these memory regions to match your device memory layout */
|
||||
FLASH : ORIGIN = 0xBAAAAAAD, LENGTH = 0K
|
||||
RAM : ORIGIN = 0xBAAAAAAD, LENGTH = 0K
|
||||
FLASH : ORIGIN = 0x000BAAD0, LENGTH = 0K
|
||||
RAM : ORIGIN = 0xBAAD0000, LENGTH = 0K
|
||||
}
|
||||
|
||||
/* This is where the call stack will be allocated. */
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
||||
//!
|
||||
//! ---
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! #![feature(used)]
|
||||
//! #![no_std]
|
||||
//!
|
||||
//! extern crate cortex_m;
|
||||
//! extern crate cortex_m_rt;
|
||||
//! extern crate cortex_m_semihosting;
|
||||
//! extern crate panic_abort; // panicking behavior
|
||||
//!
|
||||
//! use core::fmt::Write;
|
||||
//!
|
||||
//! use cortex_m::asm;
|
||||
//! use cortex_m_semihosting::hio;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut stdout = hio::hstdout().unwrap();
|
||||
//! writeln!(stdout, "Hello, world!").unwrap();
|
||||
//! }
|
||||
//!
|
||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||
//! #[link_section = ".vector_table.interrupts"]
|
||||
//! #[used]
|
||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
//!
|
||||
//! extern "C" fn default_handler() {
|
||||
//! asm::bkpt();
|
||||
//! }
|
||||
//! ```
|
||||
// Auto-generated. Do not modify.
|
||||
67
src/examples/_0_minimal.rs
Normal file
67
src/examples/_0_minimal.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
//! 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.
|
||||
41
src/examples/_1_hello.rs
Normal file
41
src/examples/_1_hello.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
//! 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,43 +0,0 @@
|
||||
//! Sends "Hello, world!" through the ITM port 0
|
||||
//!
|
||||
//! **IMPORTANT** Not all Cortex-M chips 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.
|
||||
//!
|
||||
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
|
||||
//!
|
||||
//! You'll need [`itmdump`] to receive the message on the host plus you'll need to uncomment the
|
||||
//! `monitor` commands in the `.gdbinit` file.
|
||||
//!
|
||||
//! [`itmdump`]: https://docs.rs/itm/0.2.1/itm/
|
||||
//!
|
||||
//! ---
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! #![feature(used)]
|
||||
//! #![no_std]
|
||||
//!
|
||||
//! #[macro_use]
|
||||
//! extern crate cortex_m;
|
||||
//! extern crate cortex_m_rt;
|
||||
//! extern crate panic_abort; // panicking behavior
|
||||
//!
|
||||
//! use cortex_m::{asm, Peripherals};
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let p = Peripherals::take().unwrap();
|
||||
//! let mut itm = p.ITM;
|
||||
//!
|
||||
//! iprintln!(&mut itm.stim[0], "Hello, world!");
|
||||
//! }
|
||||
//!
|
||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||
//! #[link_section = ".vector_table.interrupts"]
|
||||
//! #[used]
|
||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
//!
|
||||
//! extern "C" fn default_handler() {
|
||||
//! asm::bkpt();
|
||||
//! }
|
||||
//! ```
|
||||
// Auto-generated. Do not modify.
|
||||
58
src/examples/_2_itm.rs
Normal file
58
src/examples/_2_itm.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
//! 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,35 +0,0 @@
|
||||
//! Changing the panic handler
|
||||
//!
|
||||
//! The easiest way to change the panic handler is to use a different [panic implementation
|
||||
//! crate][0].
|
||||
//!
|
||||
//! [0]: https://crates.io/keywords/panic-impl
|
||||
//!
|
||||
//! ---
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! #![feature(used)]
|
||||
//! #![no_std]
|
||||
//!
|
||||
//! extern crate cortex_m;
|
||||
//! extern crate cortex_m_rt;
|
||||
//! // extern crate panic_abort;
|
||||
//! extern crate panic_semihosting; // reports panic messages to the host stderr using semihosting
|
||||
//!
|
||||
//! use cortex_m::asm;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! panic!("Oops");
|
||||
//! }
|
||||
//!
|
||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||
//! #[link_section = ".vector_table.interrupts"]
|
||||
//! #[used]
|
||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
//!
|
||||
//! extern "C" fn default_handler() {
|
||||
//! asm::bkpt();
|
||||
//! }
|
||||
//! ```
|
||||
// Auto-generated. Do not modify.
|
||||
@@ -1,89 +0,0 @@
|
||||
//! Debugging a crash (exception)
|
||||
//!
|
||||
//! The `cortex-m-rt` crate provides functionality for this through a default exception handler.
|
||||
//! When an exception is hit, the default handler will trigger a breakpoint and in this debugging
|
||||
//! context the stacked registers are accessible.
|
||||
//!
|
||||
//! In you run the example below, you'll be able to inspect the state of your program under the
|
||||
//! debugger using these commands:
|
||||
//!
|
||||
//! ``` text
|
||||
//! (gdb) # Exception frame = program state during the crash
|
||||
//! (gdb) print/x *ef
|
||||
//! $1 = cortex_m::exception::ExceptionFrame {
|
||||
//! r0 = 0x2fffffff,
|
||||
//! r1 = 0x2fffffff,
|
||||
//! r2 = 0x0,
|
||||
//! r3 = 0x0,
|
||||
//! r12 = 0x0,
|
||||
//! lr = 0x8000481,
|
||||
//! pc = 0x8000460,
|
||||
//! xpsr = 0x61000000,
|
||||
//! }
|
||||
//!
|
||||
//! (gdb) # Where did we come from?
|
||||
//! (gdb) backtrace
|
||||
//! #0 cortex_m_rt::default_handler (ef=0x20004f54) at (..)
|
||||
//! #1 <signal handler called>
|
||||
//! #2 0x08000460 in core::ptr::read_volatile<u32> (src=0x2fffffff) at (..)
|
||||
//! #3 0x08000480 in crash::main () at examples/crash.rs:68
|
||||
//!
|
||||
//! (gdb) # Nail down the location of the crash
|
||||
//! (gdb) disassemble/m ef.pc
|
||||
//! Dump of assembler code for function core::ptr::read_volatile<u32>:
|
||||
//! 408 pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||
//! 0x08000454 <+0>: sub sp, #20
|
||||
//! 0x08000456 <+2>: mov r1, r0
|
||||
//! 0x08000458 <+4>: str r0, [sp, #8]
|
||||
//! 0x0800045a <+6>: ldr r0, [sp, #8]
|
||||
//! 0x0800045c <+8>: str r0, [sp, #12]
|
||||
//!
|
||||
//! 409 intrinsics::volatile_load(src)
|
||||
//! 0x0800045e <+10>: ldr r0, [sp, #12]
|
||||
//! 0x08000460 <+12>: ldr r0, [r0, #0]
|
||||
//! 0x08000462 <+14>: str r0, [sp, #16]
|
||||
//! 0x08000464 <+16>: ldr r0, [sp, #16]
|
||||
//! 0x08000466 <+18>: str r1, [sp, #4]
|
||||
//! 0x08000468 <+20>: str r0, [sp, #0]
|
||||
//! 0x0800046a <+22>: b.n 0x800046c <core::ptr::read_volatile<u32>+24>
|
||||
//!
|
||||
//! 410 }
|
||||
//! 0x0800046c <+24>: ldr r0, [sp, #0]
|
||||
//! 0x0800046e <+26>: add sp, #20
|
||||
//! 0x08000470 <+28>: bx lr
|
||||
//!
|
||||
//! End of assembler dump.
|
||||
//! ```
|
||||
//!
|
||||
//! ---
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! #![feature(used)]
|
||||
//! #![no_std]
|
||||
//!
|
||||
//! extern crate cortex_m;
|
||||
//! extern crate cortex_m_rt;
|
||||
//! extern crate panic_abort; // panicking behavior
|
||||
//!
|
||||
//! use core::ptr;
|
||||
//!
|
||||
//! use cortex_m::asm;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! // Read an invalid memory address
|
||||
//! unsafe {
|
||||
//! ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||
//! #[link_section = ".vector_table.interrupts"]
|
||||
//! #[used]
|
||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
//!
|
||||
//! extern "C" fn default_handler() {
|
||||
//! asm::bkpt();
|
||||
//! }
|
||||
//! ```
|
||||
// Auto-generated. Do not modify.
|
||||
47
src/examples/_3_panic.rs
Normal file
47
src/examples/_3_panic.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
//! 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.
|
||||
118
src/examples/_4_crash.rs
Normal file
118
src/examples/_4_crash.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
//! 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,51 +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.3.2/cortex_m_rt/macro.exception.html
|
||||
//!
|
||||
//! The default exception handler can be overridden using the [`default_handler!`][2] macro
|
||||
//!
|
||||
//! [2]: https://docs.rs/cortex-m-rt/0.3.2/cortex_m_rt/macro.default_handler.html
|
||||
//!
|
||||
//! ---
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! #![feature(used)]
|
||||
//! #![no_std]
|
||||
//!
|
||||
//! extern crate cortex_m;
|
||||
//! #[macro_use(exception)]
|
||||
//! extern crate cortex_m_rt;
|
||||
//! extern crate panic_abort; // panicking behavior
|
||||
//!
|
||||
//! use core::ptr;
|
||||
//!
|
||||
//! use cortex_m::asm;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! unsafe {
|
||||
//! // Invalid memory access
|
||||
//! ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! exception!(HARD_FAULT, handler);
|
||||
//!
|
||||
//! fn handler() {
|
||||
//! // You'll hit this breakpoint rather than the one in cortex-m-rt
|
||||
//! asm::bkpt()
|
||||
//! }
|
||||
//!
|
||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||
//! #[allow(dead_code)]
|
||||
//! #[used]
|
||||
//! #[link_section = ".vector_table.interrupts"]
|
||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
//!
|
||||
//! extern "C" fn default_handler() {
|
||||
//! asm::bkpt();
|
||||
//! }
|
||||
//! ```
|
||||
// Auto-generated. Do not modify.
|
||||
@@ -1,99 +0,0 @@
|
||||
//! Using a device crate
|
||||
//!
|
||||
//! Crates generated using [`svd2rust`] are referred to as device crates. These crates provides an
|
||||
//! API to access the peripherals of a device. When you depend on one of these crates and the "rt"
|
||||
//! feature is enabled you don't need link to the cortex-m-rt crate.
|
||||
//!
|
||||
//! [`svd2rust`]: https://crates.io/crates/svd2rust
|
||||
//!
|
||||
//! Device crates also provide an `interrupt!` macro 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.9.0"
|
||||
//! ```
|
||||
//!
|
||||
//! ---
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! #![deny(warnings)]
|
||||
//! #![feature(const_fn)]
|
||||
//! #![no_std]
|
||||
//!
|
||||
//! extern crate cortex_m;
|
||||
//! // extern crate cortex_m_rt; // included in the device crate
|
||||
//! extern crate cortex_m_semihosting;
|
||||
//! #[macro_use(exception, interrupt)]
|
||||
//! extern crate stm32f103xx;
|
||||
//! extern crate panic_abort; // panicking behavior
|
||||
//!
|
||||
//! use core::cell::RefCell;
|
||||
//! use core::fmt::Write;
|
||||
//!
|
||||
//! use cortex_m::interrupt::{self, Mutex};
|
||||
//! use cortex_m::peripheral::syst::SystClkSource;
|
||||
//! use cortex_m_semihosting::hio::{self, HStdout};
|
||||
//! use stm32f103xx::Interrupt;
|
||||
//!
|
||||
//! static HSTDOUT: Mutex<RefCell<Option<HStdout>>> = Mutex::new(RefCell::new(None));
|
||||
//!
|
||||
//! static NVIC: Mutex<RefCell<Option<cortex_m::peripheral::NVIC>>> = Mutex::new(RefCell::new(None));
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let global_p = cortex_m::Peripherals::take().unwrap();
|
||||
//! interrupt::free(|cs| {
|
||||
//! let hstdout = HSTDOUT.borrow(cs);
|
||||
//! if let Ok(fd) = hio::hstdout() {
|
||||
//! *hstdout.borrow_mut() = Some(fd);
|
||||
//! }
|
||||
//!
|
||||
//! let mut nvic = global_p.NVIC;
|
||||
//! nvic.enable(Interrupt::TIM2);
|
||||
//! *NVIC.borrow(cs).borrow_mut() = Some(nvic);
|
||||
//!
|
||||
//! let mut syst = global_p.SYST;
|
||||
//! syst.set_clock_source(SystClkSource::Core);
|
||||
//! syst.set_reload(8_000_000); // 1s
|
||||
//! syst.enable_counter();
|
||||
//! syst.enable_interrupt();
|
||||
//! });
|
||||
//! }
|
||||
//!
|
||||
//! exception!(SYS_TICK, tick);
|
||||
//!
|
||||
//! fn tick() {
|
||||
//! interrupt::free(|cs| {
|
||||
//! let hstdout = HSTDOUT.borrow(cs);
|
||||
//! if let Some(hstdout) = hstdout.borrow_mut().as_mut() {
|
||||
//! writeln!(*hstdout, "Tick").ok();
|
||||
//! }
|
||||
//!
|
||||
//! if let Some(nvic) = NVIC.borrow(cs).borrow_mut().as_mut() {
|
||||
//! nvic.set_pending(Interrupt::TIM2);
|
||||
//! }
|
||||
//! });
|
||||
//! }
|
||||
//!
|
||||
//! interrupt!(TIM2, tock, locals: {
|
||||
//! tocks: u32 = 0;
|
||||
//! });
|
||||
//!
|
||||
//! fn tock(l: &mut TIM2::Locals) {
|
||||
//! l.tocks += 1;
|
||||
//!
|
||||
//! interrupt::free(|cs| {
|
||||
//! let hstdout = HSTDOUT.borrow(cs);
|
||||
//! if let Some(hstdout) = hstdout.borrow_mut().as_mut() {
|
||||
//! writeln!(*hstdout, "Tock ({})", l.tocks).ok();
|
||||
//! }
|
||||
//! });
|
||||
//! }
|
||||
//! ```
|
||||
// Auto-generated. Do not modify.
|
||||
68
src/examples/_5_exception.rs
Normal file
68
src/examples/_5_exception.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
//! 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.
|
||||
@@ -13,7 +13,8 @@
|
||||
//!
|
||||
//! #![feature(alloc)]
|
||||
//! #![feature(global_allocator)]
|
||||
//! #![feature(used)]
|
||||
//! #![feature(lang_items)]
|
||||
//! #![no_main]
|
||||
//! #![no_std]
|
||||
//!
|
||||
//! // This is the allocator crate; you can use a different one
|
||||
@@ -21,44 +22,58 @@
|
||||
//! #[macro_use]
|
||||
//! extern crate alloc;
|
||||
//! extern crate cortex_m;
|
||||
//! extern crate cortex_m_rt;
|
||||
//! extern crate cortex_m_semihosting;
|
||||
//! extern crate panic_abort; // panicking behavior
|
||||
//! #[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 cortex_m_semihosting::hio;
|
||||
//! use rt::ExceptionFrame;
|
||||
//! use sh::hio;
|
||||
//!
|
||||
//! // this is the allocator the application will use
|
||||
//! #[global_allocator]
|
||||
//! static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
|
||||
//!
|
||||
//! extern "C" {
|
||||
//! static mut _sheap: u32;
|
||||
//! }
|
||||
//!
|
||||
//! const HEAP_SIZE: usize = 1024; // in bytes
|
||||
//!
|
||||
//! fn main() {
|
||||
//! // Initialize the allocator
|
||||
//! let start = unsafe { &mut _sheap as *mut u32 as usize };
|
||||
//! unsafe { ALLOCATOR.init(start, HEAP_SIZE) }
|
||||
//! 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 {}
|
||||
//! }
|
||||
//!
|
||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||
//! #[link_section = ".vector_table.interrupts"]
|
||||
//! #[used]
|
||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||
//!
|
||||
//! extern "C" fn default_handler() {
|
||||
//! // 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.
|
||||
|
||||
93
src/examples/_7_device.rs
Normal file
93
src/examples/_7_device.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
//! 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,9 +1,10 @@
|
||||
//! Examples
|
||||
//! Examples sorted in increasing degree of complexity
|
||||
// Auto-generated. Do not modify.
|
||||
pub mod _0_hello;
|
||||
pub mod _1_itm;
|
||||
pub mod _2_panic;
|
||||
pub mod _3_crash;
|
||||
pub mod _4_override_exception_handler;
|
||||
pub mod _5_device;
|
||||
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;
|
||||
|
||||
109
src/lib.rs
109
src/lib.rs
@@ -4,9 +4,9 @@
|
||||
//!
|
||||
//! - Nightly Rust toolchain newer than `nightly-2018-04-08`: `rustup default nightly`
|
||||
//! - Cargo `clone` subcommand: `cargo install cargo-clone`
|
||||
//! - ARM toolchain: `sudo apt-get install gcc-arm-none-eabi` (on Ubuntu)
|
||||
//! - GDB: `sudo apt-get install gdb-arm-none-eabi` (on Ubuntu)
|
||||
//! - OpenOCD: `sudo apt-get install OpenOCD` (on Ubuntu)
|
||||
//! - [Optional] ARM linker: `sudo apt-get install binutils-arm-none-eabi` (on Ubuntu)
|
||||
//! - [Optional] Cargo `add` subcommand: `cargo install cargo-edit`
|
||||
//!
|
||||
//! # Usage
|
||||
@@ -27,7 +27,7 @@
|
||||
//! 2) Clone this crate
|
||||
//!
|
||||
//! ``` text
|
||||
//! $ cargo clone cortex-m-quickstart && cd $_
|
||||
//! $ cargo clone cortex-m-quickstart --vers 0.3.0
|
||||
//! ```
|
||||
//!
|
||||
//! 3) Change the crate name, author and version
|
||||
@@ -43,8 +43,8 @@
|
||||
//! 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* the `memory.x` and `build.rs`
|
||||
//! files.
|
||||
//! 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'
|
||||
@@ -57,7 +57,8 @@
|
||||
//! EOF
|
||||
//! ```
|
||||
//!
|
||||
//! 5) Optionally, set a default build target
|
||||
//! 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'
|
||||
@@ -113,27 +114,7 @@
|
||||
//! Tag_ABI_FP_16bit_format: IEEE 754
|
||||
//! ```
|
||||
//!
|
||||
//! **NOTE** By default Cargo will use the LLD linker shipped with the Rust toolchain. If you
|
||||
//! encounter any linking error try to switch to the GNU linker by modifying the `.cargo/config`
|
||||
//! file as shown below:
|
||||
//!
|
||||
//! ``` text
|
||||
//! runner = 'arm-none-eabi-gdb'
|
||||
//! rustflags = [
|
||||
//! "-C", "link-arg=-Tlink.x",
|
||||
//! - "-C", "linker=lld",
|
||||
//! - "-Z", "linker-flavor=ld.lld",
|
||||
//! - # "-C", "linker=arm-none-eabi-ld",
|
||||
//! - # "-Z", "linker-flavor=ld",
|
||||
//! + # "-C", "linker=lld",
|
||||
//! + # "-Z", "linker-flavor=ld.lld",
|
||||
//! + "-C", "linker=arm-none-eabi-ld",
|
||||
//! + "-Z", "linker-flavor=ld",
|
||||
//! "-Z", "thinlto=no",
|
||||
//! ]
|
||||
//! ```
|
||||
//!
|
||||
//! 9) Flash the program
|
||||
//! 9) Flash and debug the program
|
||||
//!
|
||||
//! ``` text
|
||||
//! $ # Launch OpenOCD on a terminal
|
||||
@@ -154,13 +135,28 @@
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Check the [examples module](./examples/index.html)
|
||||
//! 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:
|
||||
@@ -185,34 +181,28 @@
|
||||
//! Compiling demo v0.1.0 (file:///home/japaric/tmp/demo)
|
||||
//! error: linking with `arm-none-eabi-ld` failed: exit code: 1
|
||||
//! |
|
||||
//! = note: "lld" "-L" (..)
|
||||
//! = note: arm-none-eabi-ld: address 0xbaaab838 of hello section `.text' is ..
|
||||
//! arm-none-eabi-ld: address 0xbaaab838 of hello section `.text' is ..
|
||||
//! arm-none-eabi-ld:
|
||||
//! Invalid '.rodata.exceptions' section.
|
||||
//! Make sure to place a static with type `cortex_m::exception::Handlers`
|
||||
//! in that section (cf. #[link_section]) ONLY ONCE.
|
||||
//! = note: "arm-none-eabi-gcc" "-L" (..)
|
||||
//! (..)
|
||||
//! (..)/ld: region `FLASH' overflowed by XXX bytes
|
||||
//! ```
|
||||
//!
|
||||
//! Solution: Specify your device memory layout in the `memory.x` linker script.
|
||||
//! See [Usage] section.
|
||||
//! Solution: Specify your device memory layout in the `memory.x` linker script. See [Usage]
|
||||
//! section.
|
||||
//!
|
||||
//! ## Forgot to set a default build target
|
||||
//! ## Didn't set a default build target and forgot to pass `--target` to Cargo
|
||||
//!
|
||||
//! Error message:
|
||||
//!
|
||||
//! ``` text
|
||||
//! $ cargo build
|
||||
//! (..)
|
||||
//! Compiling cortex-m-semihosting v0.2.0
|
||||
//! error[E0463]: can't find crate for `std`
|
||||
//! 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`.
|
||||
//! 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
|
||||
//!
|
||||
@@ -236,11 +226,10 @@
|
||||
//! collect2: error: ld returned 1 exit status
|
||||
//! ```
|
||||
//!
|
||||
//! 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
|
||||
//! 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
|
||||
@@ -255,9 +244,21 @@
|
||||
//! 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.
|
||||
//! 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
|
||||
//!
|
||||
@@ -281,12 +282,12 @@
|
||||
//!
|
||||
//! ``` text
|
||||
//! $ cargo build
|
||||
//! error: failed to run `rustc` to learn about target-specific information
|
||||
//!
|
||||
//! To learn more, run the command again with --verbose.
|
||||
//! error[E0463]: can't find crate for `core`
|
||||
//! |
|
||||
//! = note: the `thumbv7em-none-eabihf` target may not be installed
|
||||
//! ```
|
||||
//!
|
||||
//! Solution: Switch to the nightly toolchain with `rustup default nightly`.
|
||||
//! Solution: We are not there yet! Switch to the nightly toolchain with `rustup default nightly`.
|
||||
//!
|
||||
//! ## Used `gdb` instead of `arm-none-eabi-gdb`
|
||||
//!
|
||||
|
||||
Reference in New Issue
Block a user