From f6988f1ced06ff6b67c766f8883558c468495593 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 24 Apr 2018 20:56:52 +0200 Subject: [PATCH 1/7] use less unstable dependencies --- Cargo.toml | 10 ++++++---- examples/minimal.rs | 35 +++++++++++++++++++++++++++++++++++ interrupts.x | 1 + 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 examples/minimal.rs create mode 100644 interrupts.x diff --git a/Cargo.toml b/Cargo.toml index 3249b67..3b64ba8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,11 +9,13 @@ repository = "https://github.com/japaric/cortex-m-quickstart" version = "0.2.7" [dependencies] -cortex-m = "0.4.0" -cortex-m-rt = "0.4.0" -cortex-m-semihosting = "0.2.0" +# cortex-m = "0.4.0" +# cortex-m-rt = "0.4.0" +cortex-m-rt = { git = "https://github.com/japaric/cortex-m-rt", branch = "stable" } +# cortex-m-semihosting = "0.2.0" +# panic-loop = { path = "../panic-loop" } panic-abort = "0.1.1" -panic-semihosting = "0.1.0" +# panic-semihosting = "0.1.0" # Uncomment for the allocator example. #alloc-cortex-m = "0.3.3" diff --git a/examples/minimal.rs b/examples/minimal.rs new file mode 100644 index 0000000..1e0932f --- /dev/null +++ b/examples/minimal.rs @@ -0,0 +1,35 @@ +#![no_main] // <- IMPORTANT! +#![no_std] + +#[macro_use] +extern crate cortex_m_rt; +extern crate panic_abort; + +use core::ptr; + +// user entry point +main!(main); + +fn main() -> ! { + loop { + unsafe { + // NOTE side affect to avoid UB + ptr::read_volatile(0x2000_0000 as *const u32); + } + } +} + +// define the default exception handler +exception!(DefaultHandler, deh); + +fn deh(_nr: u8) -> ! { + loop { + unsafe { + // NOTE side affect to avoid UB + ptr::read_volatile(0x2000_0004 as *const u32); + } + } +} + +// bind all interrupts to the default exception handler +interrupts!(DefaultHandler); diff --git a/interrupts.x b/interrupts.x new file mode 100644 index 0000000..65ab4a4 --- /dev/null +++ b/interrupts.x @@ -0,0 +1 @@ +/* Remove this file if you are linking to a device crate that provides this file */ From 0e2ec97ce6d921455d0e59e9170e419988987948 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 25 Apr 2018 07:54:05 +0200 Subject: [PATCH 2/7] make the hello example work --- Cargo.toml | 5 ++++- examples/hello.rs | 28 ++++++++++++++++------------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3b64ba8..e40dde2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,13 +12,16 @@ version = "0.2.7" # cortex-m = "0.4.0" # cortex-m-rt = "0.4.0" cortex-m-rt = { git = "https://github.com/japaric/cortex-m-rt", branch = "stable" } -# cortex-m-semihosting = "0.2.0" # panic-loop = { path = "../panic-loop" } panic-abort = "0.1.1" # panic-semihosting = "0.1.0" # Uncomment for the allocator example. #alloc-cortex-m = "0.3.3" +[dependencies.cortex-m-semihosting] +default-features = false +version = "0.2.1" + # Uncomment for the device example. # [dependencies.stm32f103xx] # features = ["rt"] diff --git a/examples/hello.rs b/examples/hello.rs index 3d9d8c0..a4f1e5d 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -2,29 +2,33 @@ //! //! --- -#![feature(used)] +#![feature(asm)] +#![no_main] #![no_std] -extern crate cortex_m; +#[macro_use] extern crate cortex_m_rt; -extern crate cortex_m_semihosting; +extern crate cortex_m_semihosting as sh; extern crate panic_abort; // panicking behavior use core::fmt::Write; -use cortex_m::asm; -use cortex_m_semihosting::hio; +use sh::hio; -fn main() { +main!(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!(DefaultHandler, dh); -extern "C" fn default_handler() { - asm::bkpt(); +fn dh(_nr: u8) -> ! { + loop {} } + +// As we are not using interrupts, we just bind them all to the `DefaultHandler` exception handler +interrupts!(DefaultHandler); From 8e79d05cc4b1014ab9f1e9e966e76525749eb048 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 26 Apr 2018 05:25:27 +0200 Subject: [PATCH 3/7] drop linker-flavor, port more examples --- .cargo/config | 28 ++----- .gitignore | 1 + Cargo.toml | 13 ++- ci/script.sh | 3 +- examples/crash.rs | 112 +++++++++++++++---------- examples/exception.rs | 69 +++++++++++++++ examples/hello.rs | 18 +++- examples/itm.rs | 38 ++++++--- examples/minimal.rs | 36 ++++---- examples/override-exception-handler.rs | 47 ----------- examples/panic.rs | 32 +++++-- gen-examples.sh | 3 +- 12 files changed, 246 insertions(+), 154 deletions(-) create mode 100644 examples/exception.rs delete mode 100644 examples/override-exception-handler.rs diff --git a/.cargo/config b/.cargo/config index 2f4d0ad..5999ced 100644 --- a/.cargo/config +++ b/.cargo/config @@ -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", ] diff --git a/.gitignore b/.gitignore index 6cda3bd..59a4524 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ **/*.rs.bk +.#* .gdb_history Cargo.lock target/ diff --git a/Cargo.toml b/Cargo.toml index e40dde2..badd70a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,15 +9,20 @@ repository = "https://github.com/japaric/cortex-m-quickstart" version = "0.2.7" [dependencies] -# cortex-m = "0.4.0" -# cortex-m-rt = "0.4.0" +# cortex-m-rt = "0.5.0" cortex-m-rt = { git = "https://github.com/japaric/cortex-m-rt", branch = "stable" } -# panic-loop = { path = "../panic-loop" } panic-abort = "0.1.1" -# panic-semihosting = "0.1.0" +# panic-semihosting = "0.1.1" +panic-semihosting = { git = "https://github.com/japaric/panic-semihosting", branch = "stable" } # Uncomment for the allocator example. #alloc-cortex-m = "0.3.3" +[dependencies.cortex-m] +branch = "stable" +default-features = false +git = "https://github.com/japaric/cortex-m" +# version = "0.4.4" + [dependencies.cortex-m-semihosting] default-features = false version = "0.2.1" diff --git a/ci/script.sh b/ci/script.sh index 82d2e0f..ac47fd8 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -17,8 +17,9 @@ EOF local examples=( crash + exception hello - override-exception-handler + minimal panic ) for ex in "${examples[@]}"; do diff --git a/examples/crash.rs b/examples/crash.rs index e5cd545..1f6ecfb 100644 --- a/examples/crash.rs +++ b/examples/crash.rs @@ -8,78 +8,104 @@ //! debugger using these commands: //! //! ``` text +//! (gdb) continue +//! Program received signal SIGTRAP, Trace/breakpoint trap. +//! __bkpt () at asm/bkpt.s:3 +//! 3 bkpt +//! +//! (gdb) finish +//! Run till exit from #0 __bkpt () at asm/bkpt.s:3 +//! Note: automatically using hardware breakpoints for read-only addresses. +//! crash::hf (_ef=0x20004fa0) at examples/crash.rs:102 +//! 99 asm::bkpt(); +//! //! (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) print/x *_ef +//! $1 = cortex_m_rt::ExceptionFrame { +//! r0: 0x2fffffff, +//! r1: 0x2fffffff, +//! r2: 0x80006b0, +//! r3: 0x80006b0, +//! r12: 0x20000000, +//! lr: 0x800040f, +//! pc: 0x800066a, +//! xpsr: 0x61000000 //! } //! //! (gdb) # Where did we come from? //! (gdb) backtrace -//! #0 cortex_m_rt::default_handler (ef=0x20004f54) at (..) -//! #1 -//! #2 0x08000460 in core::ptr::read_volatile (src=0x2fffffff) at (..) -//! #3 0x08000480 in crash::main () at examples/crash.rs:68 +//! #0 crash::hf (_ef=0x20004fa0) at examples/crash.rs:102 +//! #1 0x080004ac in UserHardFault (ef=0x20004fa0) at :9 +//! #2 +//! #3 0x0800066a in core::ptr::read_volatile (src=0x2fffffff) at /checkout/src/libcore/ptr.rs:452 +//! #4 0x0800040e in crash::main () at examples/crash.rs:85 +//! #5 0x08000456 in main () at
:3 //! //! (gdb) # Nail down the location of the crash -//! (gdb) disassemble/m ef.pc -//! Dump of assembler code for function core::ptr::read_volatile: -//! 408 pub unsafe fn read_volatile(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] +//! (gdb) disassemble/m _ef.pc +//! Dump of assembler code for function core::ptr::read_volatile: +//! 451 pub unsafe fn read_volatile(src: *const T) -> T {} +//! 0x08000662 <+0>: sub sp, #16 +//! 0x08000664 <+2>: mov r1, r0 +//! 0x08000666 <+4>: str r0, [sp, #8] //! -//! 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 +24> +//! 452 intrinsics::volatile_load(src) +//! 0x08000668 <+6>: ldr r0, [sp, #8] +//! 0x0800066a <+8>: ldr r0, [r0, #0] +//! 0x0800066c <+10>: str r0, [sp, #12] +//! 0x0800066e <+12>: ldr r0, [sp, #12] +//! 0x08000670 <+14>: str r1, [sp, #4] +//! 0x08000672 <+16>: str r0, [sp, #0] +//! 0x08000674 <+18>: b.n 0x8000676 //! -//! 410 } -//! 0x0800046c <+24>: ldr r0, [sp, #0] -//! 0x0800046e <+26>: add sp, #20 -//! 0x08000470 <+28>: bx lr +//! 453 } +//! 0x08000676 <+20>: ldr r0, [sp, #0] +//! 0x08000678 <+22>: add sp, #16 +//! 0x0800067a <+24>: bx lr //! //! End of assembler dump. //! ``` //! //! --- -#![feature(used)] +#![no_main] #![no_std] extern crate cortex_m; -extern crate cortex_m_rt; +#[macro_use] +extern crate cortex_m_rt as rt; extern crate panic_abort; // panicking behavior use core::ptr; use cortex_m::asm; +use rt::ExceptionFrame; + +main!(main); -fn main() { - // Read an invalid memory address +#[inline(always)] +fn main() -> ! { unsafe { ptr::read_volatile(0x2FFF_FFFF as *const u32); } + + loop {} +} + +exception!(DefaultHandler, dh); + +#[inline(always)] +fn dh(_nr: u8) { + asm::bkpt(); } -// 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, hf); -extern "C" fn default_handler() { +#[inline(always)] +fn hf(_ef: &ExceptionFrame) -> ! { asm::bkpt(); + + loop {} } + +interrupts!(DefaultHandler); diff --git a/examples/exception.rs b/examples/exception.rs new file mode 100644 index 0000000..11ad73f --- /dev/null +++ b/examples/exception.rs @@ -0,0 +1,69 @@ +//! 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_abort; + +use core::fmt::Write; + +use cortex_m::peripheral::syst::SystClkSource; +use cortex_m::{asm, Peripherals}; +use rt::ExceptionFrame; +use sh::hio::{self, HStdout}; + +main!(main); + +fn main() -> ! { + let p = Peripherals::take().unwrap(); + let mut syst = p.SYST; + + syst.set_clock_source(SystClkSource::Core); + syst.set_reload(8_000_000); // 1s + syst.enable_counter(); + syst.enable_interrupt(); + + loop {} +} + +// try commenting out this line: you'll end in `deh` instead of in `sys_tick` +exception!(SysTick, sys_tick, state: Option = None); + +fn sys_tick(state: &mut Option) { + if state.is_none() { + *state = Some(hio::hstdout().unwrap()); + } + + if let Some(hstdout) = state.as_mut() { + hstdout.write_str(".").unwrap(); + } +} + +exception!(DefaultHandler, deh); + +#[inline(always)] +fn deh(_nr: u8) { + asm::bkpt(); +} + +exception!(HardFault, hf); + +#[inline(always)] +fn hf(_ef: &ExceptionFrame) -> ! { + asm::bkpt(); + + loop {} +} + +interrupts!(DefaultHandler); diff --git a/examples/hello.rs b/examples/hello.rs index a4f1e5d..b9411de 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -2,17 +2,19 @@ //! //! --- -#![feature(asm)] #![no_main] #![no_std] +extern crate cortex_m; #[macro_use] -extern crate cortex_m_rt; +extern crate cortex_m_rt as rt; extern crate cortex_m_semihosting as sh; extern crate panic_abort; // panicking behavior use core::fmt::Write; +use cortex_m::asm; +use rt::ExceptionFrame; use sh::hio; main!(main); @@ -26,7 +28,17 @@ fn main() -> ! { exception!(DefaultHandler, dh); -fn dh(_nr: u8) -> ! { +#[inline(always)] +fn dh(_nr: u8) { + asm::bkpt(); +} + +exception!(HardFault, hf); + +#[inline(always)] +fn hf(_ef: &ExceptionFrame) -> ! { + asm::bkpt(); + loop {} } diff --git a/examples/itm.rs b/examples/itm.rs index f5b9f17..7b21cae 100644 --- a/examples/itm.rs +++ b/examples/itm.rs @@ -12,28 +12,44 @@ //! //! --- -#![feature(used)] +#![no_main] #![no_std] #[macro_use] extern crate cortex_m; -extern crate cortex_m_rt; +#[macro_use] +extern crate cortex_m_rt as rt; extern crate panic_abort; // panicking behavior use cortex_m::{asm, Peripherals}; +use rt::ExceptionFrame; + +main!(main); + +#[inline(always)] +fn main() -> ! { + let mut p = Peripherals::take().unwrap(); + let stim = &mut p.ITM.stim[0]; -fn main() { - let p = Peripherals::take().unwrap(); - let mut itm = p.ITM; + iprintln!(stim, "Hello, world!"); - iprintln!(&mut itm.stim[0], "Hello, world!"); + 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!(DefaultHandler, dh); -extern "C" fn default_handler() { +#[inline(always)] +fn dh(_nr: u8) { asm::bkpt(); } + +exception!(HardFault, hf); + +#[inline(always)] +fn hf(_ef: &ExceptionFrame) -> ! { + asm::bkpt(); + + loop {} +} + +interrupts!(DefaultHandler); diff --git a/examples/minimal.rs b/examples/minimal.rs index 1e0932f..5385e2c 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -1,34 +1,40 @@ #![no_main] // <- IMPORTANT! #![no_std] +extern crate cortex_m; #[macro_use] -extern crate cortex_m_rt; +extern crate cortex_m_rt as rt; extern crate panic_abort; -use core::ptr; +use cortex_m::asm; +use rt::ExceptionFrame; // user entry point main!(main); +#[inline(always)] fn main() -> ! { - loop { - unsafe { - // NOTE side affect to avoid UB - ptr::read_volatile(0x2000_0000 as *const u32); - } - } + asm::bkpt(); + + loop {} } // define the default exception handler exception!(DefaultHandler, deh); -fn deh(_nr: u8) -> ! { - loop { - unsafe { - // NOTE side affect to avoid UB - ptr::read_volatile(0x2000_0004 as *const u32); - } - } +#[inline(always)] +fn deh(_nr: u8) { + asm::bkpt(); +} + +// define the hard fault handler +exception!(HardFault, hf); + +#[inline(always)] +fn hf(_ef: &ExceptionFrame) -> ! { + asm::bkpt(); + + loop {} } // bind all interrupts to the default exception handler diff --git a/examples/override-exception-handler.rs b/examples/override-exception-handler.rs deleted file mode 100644 index 43f3080..0000000 --- a/examples/override-exception-handler.rs +++ /dev/null @@ -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(); -} diff --git a/examples/panic.rs b/examples/panic.rs index c3e8002..951cc05 100644 --- a/examples/panic.rs +++ b/examples/panic.rs @@ -7,25 +7,39 @@ //! //! --- -#![feature(used)] +#![no_main] #![no_std] extern crate cortex_m; -extern crate cortex_m_rt; +#[macro_use] +extern crate cortex_m_rt as rt; // extern crate panic_abort; extern crate panic_semihosting; // reports panic messages to the host stderr using semihosting use cortex_m::asm; +use rt::ExceptionFrame; -fn main() { - panic!("Oops"); +main!(main); + +#[inline(always)] +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]; +exception!(DefaultHandler, deh); -extern "C" fn default_handler() { +#[inline(always)] +fn deh(_nr: u8) { asm::bkpt(); } + +exception!(HardFault, hf); + +#[inline(always)] +fn hf(_ef: &ExceptionFrame) -> ! { + asm::bkpt(); + + loop {} +} + +interrupts!(DefaultHandler); diff --git a/gen-examples.sh b/gen-examples.sh index 660607b..a1f55d2 100644 --- a/gen-examples.sh +++ b/gen-examples.sh @@ -5,11 +5,12 @@ set -ex main() { local examples=( + minimal hello itm panic crash - override-exception-handler + exception device allocator ) From a35486b2f48f9f5052a779f93d3a5dec1a6ede55 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 26 Apr 2018 07:37:15 +0200 Subject: [PATCH 4/7] update examples and docs --- examples/allocator.rs | 44 ++++--- examples/crash.rs | 2 +- examples/device.rs | 108 ++++++++-------- examples/hello.rs | 2 +- examples/minimal.rs | 31 ++++- src/examples/_0_hello.rs | 34 ------ src/examples/_0_minimal.rs | 70 +++++++++++ src/examples/_1_hello.rs | 50 ++++++++ src/examples/{_1_itm.rs => _2_itm.rs} | 38 ++++-- src/examples/_3_crash.rs | 89 -------------- src/examples/{_2_panic.rs => _3_panic.rs} | 32 +++-- src/examples/_4_crash.rs | 115 ++++++++++++++++++ src/examples/_4_override_exception_handler.rs | 51 -------- src/examples/_5_device.rs | 99 --------------- src/examples/_5_exception.rs | 73 +++++++++++ src/examples/_6_device.rs | 101 +++++++++++++++ .../{_6_allocator.rs => _7_allocator.rs} | 44 ++++--- src/examples/mod.rs | 15 +-- src/lib.rs | 54 +++----- 19 files changed, 625 insertions(+), 427 deletions(-) delete mode 100644 src/examples/_0_hello.rs create mode 100644 src/examples/_0_minimal.rs create mode 100644 src/examples/_1_hello.rs rename src/examples/{_1_itm.rs => _2_itm.rs} (58%) delete mode 100644 src/examples/_3_crash.rs rename src/examples/{_2_panic.rs => _3_panic.rs} (53%) create mode 100644 src/examples/_4_crash.rs delete mode 100644 src/examples/_4_override_exception_handler.rs delete mode 100644 src/examples/_5_device.rs create mode 100644 src/examples/_5_exception.rs create mode 100644 src/examples/_6_device.rs rename src/examples/{_6_allocator.rs => _7_allocator.rs} (63%) diff --git a/examples/allocator.rs b/examples/allocator.rs index 01d2a62..f342e72 100644 --- a/examples/allocator.rs +++ b/examples/allocator.rs @@ -11,7 +11,7 @@ #![feature(alloc)] #![feature(global_allocator)] -#![feature(used)] +#![no_main] #![no_std] // This is the allocator crate; you can use a different one @@ -19,42 +19,52 @@ 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_abort; use core::fmt::Write; use alloc_cortex_m::CortexMHeap; use cortex_m::asm; -use cortex_m_semihosting::hio; +use rt::ExceptionFrame; +use sh::hio; #[global_allocator] static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); -extern "C" { - static mut _sheap: u32; -} - const HEAP_SIZE: usize = 1024; // in bytes -fn main() { +main!(main); + +fn main() -> ! { // Initialize the allocator - let start = unsafe { &mut _sheap as *mut u32 as usize }; - unsafe { ALLOCATOR.init(start, HEAP_SIZE) } + 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]; +exception!(DefaultHandler, dh); -extern "C" fn default_handler() { +#[inline(always)] +fn dh(_nr: u8) { asm::bkpt(); } + +exception!(HardFault, hf); + +#[inline(always)] +fn hf(_ef: &ExceptionFrame) -> ! { + asm::bkpt(); + + loop {} +} + +interrupts!(DefaultHandler); diff --git a/examples/crash.rs b/examples/crash.rs index 1f6ecfb..5c25e26 100644 --- a/examples/crash.rs +++ b/examples/crash.rs @@ -74,7 +74,7 @@ extern crate cortex_m; #[macro_use] extern crate cortex_m_rt as rt; -extern crate panic_abort; // panicking behavior +extern crate panic_abort; use core::ptr; diff --git a/examples/device.rs b/examples/device.rs index 91e6332..beb0883 100644 --- a/examples/device.rs +++ b/examples/device.rs @@ -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. +//! 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,82 @@ //! $ edit Cargo.toml && tail $_ //! [dependencies.stm32f103xx] //! features = ["rt"] -//! version = "0.9.0" +//! version = "0.10.0" //! ``` //! +//! The `stm32f103xx` crate provides an `interrupts.x` file so you must remove the one in the root +//! of this crate. +//! //! --- -#![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_abort; -use core::cell::RefCell; use core::fmt::Write; -use cortex_m::interrupt::{self, Mutex}; +use cortex_m::asm; 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>> = Mutex::new(RefCell::new(None)); +main!(main); + +fn main() -> ! { + let p = cortex_m::Peripherals::take().unwrap(); -static NVIC: Mutex>> = Mutex::new(RefCell::new(None)); + let mut syst = p.SYST; + let mut nvic = p.NVIC; -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); - } + nvic.enable(Interrupt::EXTI0); - let mut nvic = global_p.NVIC; - nvic.enable(Interrupt::TIM2); - *NVIC.borrow(cs).borrow_mut() = Some(nvic); + syst.set_clock_source(SystClkSource::Core); + syst.set_reload(8_000_000); // 1s + syst.enable_counter(); - 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(); - }); + 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); +interrupt!(EXTI0, exti0, state: Option = 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) { + 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!(DefaultHandler, deh); -fn tock(l: &mut TIM2::Locals) { - l.tocks += 1; +#[inline(always)] +fn deh(_nr: u8) { + asm::bkpt(); +} - interrupt::free(|cs| { - let hstdout = HSTDOUT.borrow(cs); - if let Some(hstdout) = hstdout.borrow_mut().as_mut() { - writeln!(*hstdout, "Tock ({})", l.tocks).ok(); - } - }); +exception!(HardFault, hf); + +#[inline(always)] +fn hf(_ef: &ExceptionFrame) -> ! { + asm::bkpt(); + + loop {} } + +interrupts!(DefaultHandler); diff --git a/examples/hello.rs b/examples/hello.rs index b9411de..aa4f12c 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -9,7 +9,7 @@ extern crate cortex_m; #[macro_use] extern crate cortex_m_rt as rt; extern crate cortex_m_semihosting as sh; -extern crate panic_abort; // panicking behavior +extern crate panic_abort; use core::fmt::Write; diff --git a/examples/minimal.rs b/examples/minimal.rs index 5385e2c..d27b761 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -1,15 +1,40 @@ +//! Minimal Cortex-M program +//! +//! 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 `main!`. The entry point doesn't need to be called `main` and +//! it doesn't need to be in the root of the crate. +//! +//! - 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 implementation crate][0] +//! +//! [0]: https://crates.io/keywords/panic-impl +//! +//! - Define the `HardFault` handler. This function is called when a hard fault exception is raised +//! by the hardware. +//! +//! - Define a default handler. This function will be used to handle all interrupts and exceptions +//! which have not been assigned a specific handler. +//! +//! - Define the device specific interrupt handlers. `interrupts!` can be used to create a generic +//! program that works for all Cortex-M devices by binding all the possible interrupt handlers to +//! the `DefaultHandler`. + #![no_main] // <- IMPORTANT! #![no_std] extern crate cortex_m; -#[macro_use] +#[macro_use(main, exception, interrupts)] extern crate cortex_m_rt as rt; -extern crate panic_abort; +extern crate panic_abort; // panicking behavior use cortex_m::asm; use rt::ExceptionFrame; -// user entry point +// the program entry point main!(main); #[inline(always)] diff --git a/src/examples/_0_hello.rs b/src/examples/_0_hello.rs deleted file mode 100644 index d6c70bf..0000000 --- a/src/examples/_0_hello.rs +++ /dev/null @@ -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. diff --git a/src/examples/_0_minimal.rs b/src/examples/_0_minimal.rs new file mode 100644 index 0000000..d73257d --- /dev/null +++ b/src/examples/_0_minimal.rs @@ -0,0 +1,70 @@ +//! Minimal Cortex-M program +//! +//! 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 `main!`. The entry point doesn't need to be called `main` and +//! it doesn't need to be in the root of the crate. +//! +//! - 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 implementation crate][0] +//! +//! [0]: https://crates.io/keywords/panic-impl +//! +//! - Define the `HardFault` handler. This function is called when a hard fault exception is raised +//! by the hardware. +//! +//! - Define a default handler. This function will be used to handle all interrupts and exceptions +//! which have not been assigned a specific handler. +//! +//! - Define the device specific interrupt handlers. `interrupts!` can be used to create a generic +//! program that works for all Cortex-M devices by binding all the possible interrupt handlers to +//! the `DefaultHandler`. +//! +//! ``` +//! +//! #![no_main] // <- IMPORTANT! +//! #![no_std] +//! +//! extern crate cortex_m; +//! #[macro_use(main, exception, interrupts)] +//! extern crate cortex_m_rt as rt; +//! extern crate panic_abort; // panicking behavior +//! +//! use cortex_m::asm; +//! use rt::ExceptionFrame; +//! +//! // the program entry point +//! main!(main); +//! +//! #[inline(always)] +//! fn main() -> ! { +//! asm::bkpt(); +//! +//! loop {} +//! } +//! +//! // define the default exception handler +//! exception!(DefaultHandler, deh); +//! +//! #[inline(always)] +//! fn deh(_nr: u8) { +//! asm::bkpt(); +//! } +//! +//! // define the hard fault handler +//! exception!(HardFault, hf); +//! +//! #[inline(always)] +//! fn hf(_ef: &ExceptionFrame) -> ! { +//! asm::bkpt(); +//! +//! loop {} +//! } +//! +//! // bind all interrupts to the default exception handler +//! interrupts!(DefaultHandler); +//! ``` +// Auto-generated. Do not modify. diff --git a/src/examples/_1_hello.rs b/src/examples/_1_hello.rs new file mode 100644 index 0000000..badaa62 --- /dev/null +++ b/src/examples/_1_hello.rs @@ -0,0 +1,50 @@ +//! Prints "Hello, world!" on the OpenOCD console using semihosting +//! +//! --- +//! +//! ``` +//! +//! #![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_abort; +//! +//! use core::fmt::Write; +//! +//! use cortex_m::asm; +//! use rt::ExceptionFrame; +//! use sh::hio; +//! +//! main!(main); +//! +//! fn main() -> ! { +//! let mut stdout = hio::hstdout().unwrap(); +//! writeln!(stdout, "Hello, world!").unwrap(); +//! +//! loop {} +//! } +//! +//! exception!(DefaultHandler, dh); +//! +//! #[inline(always)] +//! fn dh(_nr: u8) { +//! asm::bkpt(); +//! } +//! +//! exception!(HardFault, hf); +//! +//! #[inline(always)] +//! fn hf(_ef: &ExceptionFrame) -> ! { +//! asm::bkpt(); +//! +//! loop {} +//! } +//! +//! // As we are not using interrupts, we just bind them all to the `DefaultHandler` exception handler +//! interrupts!(DefaultHandler); +//! ``` +// Auto-generated. Do not modify. diff --git a/src/examples/_1_itm.rs b/src/examples/_2_itm.rs similarity index 58% rename from src/examples/_1_itm.rs rename to src/examples/_2_itm.rs index 6793f70..42abeff 100644 --- a/src/examples/_1_itm.rs +++ b/src/examples/_2_itm.rs @@ -14,30 +14,46 @@ //! //! ``` //! -//! #![feature(used)] +//! #![no_main] //! #![no_std] //! //! #[macro_use] //! extern crate cortex_m; -//! extern crate cortex_m_rt; +//! #[macro_use] +//! extern crate cortex_m_rt as rt; //! extern crate panic_abort; // panicking behavior //! //! use cortex_m::{asm, Peripherals}; +//! use rt::ExceptionFrame; +//! +//! main!(main); +//! +//! #[inline(always)] +//! fn main() -> ! { +//! let mut p = Peripherals::take().unwrap(); +//! let stim = &mut p.ITM.stim[0]; //! -//! fn main() { -//! let p = Peripherals::take().unwrap(); -//! let mut itm = p.ITM; +//! iprintln!(stim, "Hello, world!"); //! -//! iprintln!(&mut itm.stim[0], "Hello, world!"); +//! 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!(DefaultHandler, dh); //! -//! extern "C" fn default_handler() { +//! #[inline(always)] +//! fn dh(_nr: u8) { //! asm::bkpt(); //! } +//! +//! exception!(HardFault, hf); +//! +//! #[inline(always)] +//! fn hf(_ef: &ExceptionFrame) -> ! { +//! asm::bkpt(); +//! +//! loop {} +//! } +//! +//! interrupts!(DefaultHandler); //! ``` // Auto-generated. Do not modify. diff --git a/src/examples/_3_crash.rs b/src/examples/_3_crash.rs deleted file mode 100644 index 96b1516..0000000 --- a/src/examples/_3_crash.rs +++ /dev/null @@ -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 -//! #2 0x08000460 in core::ptr::read_volatile (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: -//! 408 pub unsafe fn read_volatile(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 +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. diff --git a/src/examples/_2_panic.rs b/src/examples/_3_panic.rs similarity index 53% rename from src/examples/_2_panic.rs rename to src/examples/_3_panic.rs index 0ea182b..7ad410f 100644 --- a/src/examples/_2_panic.rs +++ b/src/examples/_3_panic.rs @@ -9,27 +9,41 @@ //! //! ``` //! -//! #![feature(used)] +//! #![no_main] //! #![no_std] //! //! extern crate cortex_m; -//! extern crate cortex_m_rt; +//! #[macro_use] +//! extern crate cortex_m_rt as rt; //! // extern crate panic_abort; //! extern crate panic_semihosting; // reports panic messages to the host stderr using semihosting //! //! use cortex_m::asm; +//! use rt::ExceptionFrame; //! -//! fn main() { -//! panic!("Oops"); +//! main!(main); +//! +//! #[inline(always)] +//! 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]; +//! exception!(DefaultHandler, deh); //! -//! extern "C" fn default_handler() { +//! #[inline(always)] +//! fn deh(_nr: u8) { //! asm::bkpt(); //! } +//! +//! exception!(HardFault, hf); +//! +//! #[inline(always)] +//! fn hf(_ef: &ExceptionFrame) -> ! { +//! asm::bkpt(); +//! +//! loop {} +//! } +//! +//! interrupts!(DefaultHandler); //! ``` // Auto-generated. Do not modify. diff --git a/src/examples/_4_crash.rs b/src/examples/_4_crash.rs new file mode 100644 index 0000000..861d161 --- /dev/null +++ b/src/examples/_4_crash.rs @@ -0,0 +1,115 @@ +//! 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) continue +//! Program received signal SIGTRAP, Trace/breakpoint trap. +//! __bkpt () at asm/bkpt.s:3 +//! 3 bkpt +//! +//! (gdb) finish +//! Run till exit from #0 __bkpt () at asm/bkpt.s:3 +//! Note: automatically using hardware breakpoints for read-only addresses. +//! crash::hf (_ef=0x20004fa0) at examples/crash.rs:102 +//! 99 asm::bkpt(); +//! +//! (gdb) # Exception frame = program state during the crash +//! (gdb) print/x *_ef +//! $1 = cortex_m_rt::ExceptionFrame { +//! r0: 0x2fffffff, +//! r1: 0x2fffffff, +//! r2: 0x80006b0, +//! r3: 0x80006b0, +//! r12: 0x20000000, +//! lr: 0x800040f, +//! pc: 0x800066a, +//! xpsr: 0x61000000 +//! } +//! +//! (gdb) # Where did we come from? +//! (gdb) backtrace +//! #0 crash::hf (_ef=0x20004fa0) at examples/crash.rs:102 +//! #1 0x080004ac in UserHardFault (ef=0x20004fa0) at :9 +//! #2 +//! #3 0x0800066a in core::ptr::read_volatile (src=0x2fffffff) at /checkout/src/libcore/ptr.rs:452 +//! #4 0x0800040e in crash::main () at examples/crash.rs:85 +//! #5 0x08000456 in main () at
:3 +//! +//! (gdb) # Nail down the location of the crash +//! (gdb) disassemble/m _ef.pc +//! Dump of assembler code for function core::ptr::read_volatile: +//! 451 pub unsafe fn read_volatile(src: *const T) -> T {} +//! 0x08000662 <+0>: sub sp, #16 +//! 0x08000664 <+2>: mov r1, r0 +//! 0x08000666 <+4>: str r0, [sp, #8] +//! +//! 452 intrinsics::volatile_load(src) +//! 0x08000668 <+6>: ldr r0, [sp, #8] +//! 0x0800066a <+8>: ldr r0, [r0, #0] +//! 0x0800066c <+10>: str r0, [sp, #12] +//! 0x0800066e <+12>: ldr r0, [sp, #12] +//! 0x08000670 <+14>: str r1, [sp, #4] +//! 0x08000672 <+16>: str r0, [sp, #0] +//! 0x08000674 <+18>: b.n 0x8000676 +//! +//! 453 } +//! 0x08000676 <+20>: ldr r0, [sp, #0] +//! 0x08000678 <+22>: add sp, #16 +//! 0x0800067a <+24>: bx lr +//! +//! End of assembler dump. +//! ``` +//! +//! --- +//! +//! ``` +//! +//! #![no_main] +//! #![no_std] +//! +//! extern crate cortex_m; +//! #[macro_use] +//! extern crate cortex_m_rt as rt; +//! extern crate panic_abort; +//! +//! use core::ptr; +//! +//! use cortex_m::asm; +//! use rt::ExceptionFrame; +//! +//! main!(main); +//! +//! #[inline(always)] +//! fn main() -> ! { +//! unsafe { +//! ptr::read_volatile(0x2FFF_FFFF as *const u32); +//! } +//! +//! loop {} +//! } +//! +//! exception!(DefaultHandler, dh); +//! +//! #[inline(always)] +//! fn dh(_nr: u8) { +//! asm::bkpt(); +//! } +//! +//! exception!(HardFault, hf); +//! +//! #[inline(always)] +//! fn hf(_ef: &ExceptionFrame) -> ! { +//! asm::bkpt(); +//! +//! loop {} +//! } +//! +//! interrupts!(DefaultHandler); +//! ``` +// Auto-generated. Do not modify. diff --git a/src/examples/_4_override_exception_handler.rs b/src/examples/_4_override_exception_handler.rs deleted file mode 100644 index a7df0c1..0000000 --- a/src/examples/_4_override_exception_handler.rs +++ /dev/null @@ -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. diff --git a/src/examples/_5_device.rs b/src/examples/_5_device.rs deleted file mode 100644 index 06b1723..0000000 --- a/src/examples/_5_device.rs +++ /dev/null @@ -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>> = Mutex::new(RefCell::new(None)); -//! -//! static NVIC: Mutex>> = 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. diff --git a/src/examples/_5_exception.rs b/src/examples/_5_exception.rs new file mode 100644 index 0000000..49c98aa --- /dev/null +++ b/src/examples/_5_exception.rs @@ -0,0 +1,73 @@ +//! 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_abort; +//! +//! use core::fmt::Write; +//! +//! use cortex_m::peripheral::syst::SystClkSource; +//! use cortex_m::{asm, Peripherals}; +//! use rt::ExceptionFrame; +//! use sh::hio::{self, HStdout}; +//! +//! main!(main); +//! +//! fn main() -> ! { +//! let p = Peripherals::take().unwrap(); +//! let mut syst = p.SYST; +//! +//! syst.set_clock_source(SystClkSource::Core); +//! syst.set_reload(8_000_000); // 1s +//! syst.enable_counter(); +//! syst.enable_interrupt(); +//! +//! loop {} +//! } +//! +//! // try commenting out this line: you'll end in `deh` instead of in `sys_tick` +//! exception!(SysTick, sys_tick, state: Option = None); +//! +//! fn sys_tick(state: &mut Option) { +//! if state.is_none() { +//! *state = Some(hio::hstdout().unwrap()); +//! } +//! +//! if let Some(hstdout) = state.as_mut() { +//! hstdout.write_str(".").unwrap(); +//! } +//! } +//! +//! exception!(DefaultHandler, deh); +//! +//! #[inline(always)] +//! fn deh(_nr: u8) { +//! asm::bkpt(); +//! } +//! +//! exception!(HardFault, hf); +//! +//! #[inline(always)] +//! fn hf(_ef: &ExceptionFrame) -> ! { +//! asm::bkpt(); +//! +//! loop {} +//! } +//! +//! interrupts!(DefaultHandler); +//! ``` +// Auto-generated. Do not modify. diff --git a/src/examples/_6_device.rs b/src/examples/_6_device.rs new file mode 100644 index 0000000..83656b1 --- /dev/null +++ b/src/examples/_6_device.rs @@ -0,0 +1,101 @@ +//! 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. +//! +//! [`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" +//! ``` +//! +//! The `stm32f103xx` crate provides an `interrupts.x` file so you must remove the one in the root +//! of this crate. +//! +//! --- +//! +//! ``` +//! +//! #![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_abort; +//! +//! use core::fmt::Write; +//! +//! use cortex_m::asm; +//! use cortex_m::peripheral::syst::SystClkSource; +//! use rt::ExceptionFrame; +//! use sh::hio::{self, HStdout}; +//! use stm32f103xx::Interrupt; +//! +//! main!(main); +//! +//! fn main() -> ! { +//! let p = cortex_m::Peripherals::take().unwrap(); +//! +//! let mut syst = p.SYST; +//! let mut nvic = p.NVIC; +//! +//! nvic.enable(Interrupt::EXTI0); +//! +//! 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); +//! } +//! } +//! +//! interrupt!(EXTI0, exti0, state: Option = None); +//! +//! fn exti0(state: &mut Option) { +//! if state.is_none() { +//! *state = Some(hio::hstdout().unwrap()); +//! } +//! +//! if let Some(hstdout) = state.as_mut() { +//! hstdout.write_str(".").unwrap(); +//! } +//! } +//! +//! exception!(DefaultHandler, deh); +//! +//! #[inline(always)] +//! fn deh(_nr: u8) { +//! asm::bkpt(); +//! } +//! +//! exception!(HardFault, hf); +//! +//! #[inline(always)] +//! fn hf(_ef: &ExceptionFrame) -> ! { +//! asm::bkpt(); +//! +//! loop {} +//! } +//! +//! interrupts!(DefaultHandler); +//! ``` +// Auto-generated. Do not modify. diff --git a/src/examples/_6_allocator.rs b/src/examples/_7_allocator.rs similarity index 63% rename from src/examples/_6_allocator.rs rename to src/examples/_7_allocator.rs index f85a7b5..071261d 100644 --- a/src/examples/_6_allocator.rs +++ b/src/examples/_7_allocator.rs @@ -13,7 +13,7 @@ //! //! #![feature(alloc)] //! #![feature(global_allocator)] -//! #![feature(used)] +//! #![no_main] //! #![no_std] //! //! // This is the allocator crate; you can use a different one @@ -21,44 +21,54 @@ //! #[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_abort; //! //! use core::fmt::Write; //! //! use alloc_cortex_m::CortexMHeap; //! use cortex_m::asm; -//! use cortex_m_semihosting::hio; +//! use rt::ExceptionFrame; +//! use sh::hio; //! //! #[global_allocator] //! static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); //! -//! extern "C" { -//! static mut _sheap: u32; -//! } -//! //! const HEAP_SIZE: usize = 1024; // in bytes //! -//! fn main() { +//! main!(main); +//! +//! fn main() -> ! { //! // Initialize the allocator -//! let start = unsafe { &mut _sheap as *mut u32 as usize }; -//! unsafe { ALLOCATOR.init(start, HEAP_SIZE) } +//! 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]; +//! exception!(DefaultHandler, dh); //! -//! extern "C" fn default_handler() { +//! #[inline(always)] +//! fn dh(_nr: u8) { //! asm::bkpt(); //! } +//! +//! exception!(HardFault, hf); +//! +//! #[inline(always)] +//! fn hf(_ef: &ExceptionFrame) -> ! { +//! asm::bkpt(); +//! +//! loop {} +//! } +//! +//! interrupts!(DefaultHandler); //! ``` // Auto-generated. Do not modify. diff --git a/src/examples/mod.rs b/src/examples/mod.rs index fd0e6e4..dc816c2 100644 --- a/src/examples/mod.rs +++ b/src/examples/mod.rs @@ -1,9 +1,10 @@ //! Examples // 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 _6_allocator; +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_device; +pub mod _7_allocator; diff --git a/src/lib.rs b/src/lib.rs index dca15de..d2489e8 100644 --- a/src/lib.rs +++ b/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 $_ +//! $ git clone https://github.com/japaric/cortex-m-quickstart --branch less-unstable //! ``` //! //! 3) Change the crate name, author and version @@ -113,26 +113,6 @@ //! 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 //! //! ``` text @@ -185,13 +165,7 @@ //! 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" (..) //! ``` //! //! Solution: Specify your device memory layout in the `memory.x` linker script. @@ -204,8 +178,7 @@ //! ``` 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 //! ``` @@ -259,6 +232,19 @@ //! `/usr/share/openocd/scripts` directory (exact location varies per //! distribution / OS) for a list of scripts that can be used. //! +//! ## Forgot to install the `rust-std` component +//! +//! Error message: +//! +//! ``` text +//! $ cargo build +//! error[E0463]: can't find crate for `core` +//! | +//! = note: the `thumbv7m-none-eabi` target may not be installed +//! ``` +//! +//! Solution: call `rustup target add thumbv7m-none-eabi` but with the name of your target +//! //! ## Used an old nightly //! //! Error message: @@ -281,12 +267,10 @@ //! //! ``` 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` //! ``` //! -//! 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` //! From 3a4a5be7097e066009993ce730b04fb69353cf83 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 26 Apr 2018 07:57:34 +0200 Subject: [PATCH 5/7] TODO: drop opt-level=s --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index badd70a..afc3268 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,4 +35,4 @@ version = "0.2.1" [profile.release] debug = true lto = true -opt-level = "s" +opt-level = "s" # TODO remove; this flag requires nightly From 0f139c386b17ed1bc925e1b482455a9c64b7a33b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 12 May 2018 20:41:42 +0200 Subject: [PATCH 6/7] use published versions, doc up, update CHANGELOG --- .cargo/config | 23 +++ CHANGELOG.md | 20 ++- Cargo.toml | 31 ++-- examples/allocator.rs | 33 ++-- examples/crash.rs | 127 ++++++++------- examples/device.rs | 30 ++-- examples/exception.rs | 29 ++-- examples/hello.rs | 25 +-- examples/itm.rs | 39 +++-- examples/minimal.rs | 63 ++++---- examples/panic.rs | 38 +++-- gen-examples.sh | 4 +- interrupts.x | 1 - memory.x | 4 +- src/examples/_0_minimal.rs | 81 +++++----- src/examples/_1_hello.rs | 47 +++--- src/examples/_2_itm.rs | 61 ++++--- src/examples/_3_panic.rs | 56 ++++--- src/examples/_4_crash.rs | 153 +++++++++--------- src/examples/_5_exception.rs | 59 ++++--- .../{_7_allocator.rs => _6_allocator.rs} | 63 ++++---- src/examples/{_6_device.rs => _7_device.rs} | 66 ++++---- src/examples/mod.rs | 6 +- src/lib.rs | 40 ++--- 24 files changed, 546 insertions(+), 553 deletions(-) delete mode 100644 interrupts.x rename src/examples/{_7_allocator.rs => _6_allocator.rs} (66%) rename src/examples/{_6_device.rs => _7_device.rs} (76%) diff --git a/.cargo/config b/.cargo/config index 5999ced..337c283 100644 --- a/.cargo/config +++ b/.cargo/config @@ -3,6 +3,11 @@ runner = 'arm-none-eabi-gdb' rustflags = [ "-C", "link-arg=-Wl,-Tlink.x", "-C", "link-arg=-nostartfiles", + + # uncomment to use rustc LLD to link programs (a) + # "-C", "link-arg=-Tlink.x", + # "-C", "linker=lld", + # "-Z", "linker-flavor=ld.lld", ] [target.thumbv7m-none-eabi] @@ -10,6 +15,11 @@ runner = 'arm-none-eabi-gdb' rustflags = [ "-C", "link-arg=-Wl,-Tlink.x", "-C", "link-arg=-nostartfiles", + + # uncomment to use rustc LLD to link programs (a) + # "-C", "link-arg=-Tlink.x", + # "-C", "linker=lld", + # "-Z", "linker-flavor=ld.lld", ] [target.thumbv7em-none-eabi] @@ -17,6 +27,11 @@ runner = 'arm-none-eabi-gdb' rustflags = [ "-C", "link-arg=-Wl,-Tlink.x", "-C", "link-arg=-nostartfiles", + + # uncomment to use rustc LLD to link programs (a) + # "-C", "link-arg=-Tlink.x", + # "-C", "linker=lld", + # "-Z", "linker-flavor=ld.lld", ] [target.thumbv7em-none-eabihf] @@ -24,4 +39,12 @@ runner = 'arm-none-eabi-gdb' rustflags = [ "-C", "link-arg=-Wl,-Tlink.x", "-C", "link-arg=-nostartfiles", + + # uncomment to use rustc LLD to link programs (a) + # "-C", "link-arg=-Tlink.x", + # "-C", "linker=lld", + # "-Z", "linker-flavor=ld.lld", ] + +# (a) you also need to comment out the other two `link-arg` lines. But note that as of v0.6.0 LLD +# has a bug where it mislinks FFI calls and they up crashing the program at runtime \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a1cfc1..be91fe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [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. + +- Removed `opt-level = "s"` from `profile.release`. This flag is still unstable. + +- Set the number of codegen-units to 1 when compiling in release mode. This produces smaller and + faster binaries. + ## [v0.2.7] - 2018-04-24 ### Changed @@ -149,7 +166,8 @@ 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.0...HEAD +[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 diff --git a/Cargo.toml b/Cargo.toml index afc3268..bc60c97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,33 +6,24 @@ 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.0" [dependencies] -# cortex-m-rt = "0.5.0" -cortex-m-rt = { git = "https://github.com/japaric/cortex-m-rt", branch = "stable" } -panic-abort = "0.1.1" -# panic-semihosting = "0.1.1" -panic-semihosting = { git = "https://github.com/japaric/panic-semihosting", branch = "stable" } -# Uncomment for the allocator example. -#alloc-cortex-m = "0.3.3" - -[dependencies.cortex-m] -branch = "stable" -default-features = false -git = "https://github.com/japaric/cortex-m" -# version = "0.4.4" +cortex-m = "0.5.0" +cortex-m-rt = "0.5.0" +cortex-m-semihosting = "0.3.0" +panic-itm = "0.1.1" +panic-semihosting = "0.2.0" -[dependencies.cortex-m-semihosting] -default-features = false -version = "0.2.1" +# Uncomment for the allocator example. +# alloc-cortex-m = "0.3.6" # 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" # TODO remove; this flag requires nightly +lto = true \ No newline at end of file diff --git a/examples/allocator.rs b/examples/allocator.rs index f342e72..0d06669 100644 --- a/examples/allocator.rs +++ b/examples/allocator.rs @@ -11,6 +11,7 @@ #![feature(alloc)] #![feature(global_allocator)] +#![feature(lang_items)] #![no_main] #![no_std] @@ -22,7 +23,7 @@ extern crate cortex_m; #[macro_use] extern crate cortex_m_rt as rt; extern crate cortex_m_semihosting as sh; -extern crate panic_abort; +extern crate panic_semihosting; use core::fmt::Write; @@ -31,15 +32,16 @@ use cortex_m::asm; use rt::ExceptionFrame; use sh::hio; +// this is the allocator the application will use #[global_allocator] static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); const HEAP_SIZE: usize = 1024; // in bytes -main!(main); +entry!(main); fn main() -> ! { - // Initialize the allocator + // Initialize the allocator BEFORE you use it unsafe { ALLOCATOR.init(rt::heap_start() as usize, HEAP_SIZE) } // Growable array allocated on the heap @@ -51,20 +53,23 @@ fn main() -> ! { loop {} } -exception!(DefaultHandler, dh); - -#[inline(always)] -fn dh(_nr: u8) { +// define what happens in an Out Of Memory (OOM) condition +#[lang = "oom"] +#[no_mangle] +pub fn rust_oom() -> ! { asm::bkpt(); -} -exception!(HardFault, hf); + loop {} +} -#[inline(always)] -fn hf(_ef: &ExceptionFrame) -> ! { - asm::bkpt(); +exception!(HardFault, hard_fault); - loop {} +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); } -interrupts!(DefaultHandler); +exception!(*, default_handler); + +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); +} diff --git a/examples/crash.rs b/examples/crash.rs index 5c25e26..fafe436 100644 --- a/examples/crash.rs +++ b/examples/crash.rs @@ -1,11 +1,12 @@ //! 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) continue @@ -13,59 +14,66 @@ //! __bkpt () at asm/bkpt.s:3 //! 3 bkpt //! -//! (gdb) finish -//! Run till exit from #0 __bkpt () at asm/bkpt.s:3 -//! Note: automatically using hardware breakpoints for read-only addresses. -//! crash::hf (_ef=0x20004fa0) at examples/crash.rs:102 -//! 99 asm::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 :10 +//! #6 0x0800093a in HardFault () at asm.s:5 +//! Backtrace stopped: previous frame identical to this frame (corrupt stack?) +//! ``` //! -//! (gdb) # Exception frame = program state during the crash -//! (gdb) print/x *_ef -//! $1 = cortex_m_rt::ExceptionFrame { -//! r0: 0x2fffffff, -//! r1: 0x2fffffff, -//! r2: 0x80006b0, -//! r3: 0x80006b0, -//! r12: 0x20000000, -//! lr: 0x800040f, -//! pc: 0x800066a, -//! xpsr: 0x61000000 -//! } +//! In the console output one will find the state of the Program Counter (PC) register at the time +//! of the exception. //! -//! (gdb) # Where did we come from? -//! (gdb) backtrace -//! #0 crash::hf (_ef=0x20004fa0) at examples/crash.rs:102 -//! #1 0x080004ac in UserHardFault (ef=0x20004fa0) at :9 -//! #2 -//! #3 0x0800066a in core::ptr::read_volatile (src=0x2fffffff) at /checkout/src/libcore/ptr.rs:452 -//! #4 0x0800040e in crash::main () at examples/crash.rs:85 -//! #5 0x08000456 in main () at
:3 +//! ``` 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. //! -//! (gdb) # Nail down the location of the crash -//! (gdb) disassemble/m _ef.pc +//! ``` text +//! (gdb) disassemble/m 0x08000ab6 //! Dump of assembler code for function core::ptr::read_volatile: -//! 451 pub unsafe fn read_volatile(src: *const T) -> T {} -//! 0x08000662 <+0>: sub sp, #16 -//! 0x08000664 <+2>: mov r1, r0 -//! 0x08000666 <+4>: str r0, [sp, #8] +//! 451 pub unsafe fn read_volatile(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) -//! 0x08000668 <+6>: ldr r0, [sp, #8] -//! 0x0800066a <+8>: ldr r0, [r0, #0] -//! 0x0800066c <+10>: str r0, [sp, #12] -//! 0x0800066e <+12>: ldr r0, [sp, #12] -//! 0x08000670 <+14>: str r1, [sp, #4] -//! 0x08000672 <+16>: str r0, [sp, #0] -//! 0x08000674 <+18>: b.n 0x8000676 +//! 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 //! //! 453 } -//! 0x08000676 <+20>: ldr r0, [sp, #0] -//! 0x08000678 <+22>: add sp, #16 -//! 0x0800067a <+24>: bx lr +//! 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] @@ -74,38 +82,33 @@ extern crate cortex_m; #[macro_use] extern crate cortex_m_rt as rt; -extern crate panic_abort; +extern crate panic_semihosting; use core::ptr; -use cortex_m::asm; use rt::ExceptionFrame; -main!(main); +entry!(main); -#[inline(always)] fn main() -> ! { unsafe { + // read an address outside of the RAM region; causes a HardFault exception ptr::read_volatile(0x2FFF_FFFF as *const u32); } loop {} } -exception!(DefaultHandler, dh); +// define the hard fault handler +exception!(HardFault, hard_fault); -#[inline(always)] -fn dh(_nr: u8) { - asm::bkpt(); +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); } -exception!(HardFault, hf); - -#[inline(always)] -fn hf(_ef: &ExceptionFrame) -> ! { - asm::bkpt(); +// define the default exception handler +exception!(*, default_handler); - loop {} +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); } - -interrupts!(DefaultHandler); diff --git a/examples/device.rs b/examples/device.rs index beb0883..e2c1a04 100644 --- a/examples/device.rs +++ b/examples/device.rs @@ -1,6 +1,6 @@ //! Using a device crate //! -//! Crates generated using [`svd2rust`] are referred to as device crates. These crates provides an +//! 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 @@ -19,9 +19,6 @@ //! version = "0.10.0" //! ``` //! -//! The `stm32f103xx` crate provides an `interrupts.x` file so you must remove the one in the root -//! of this crate. -//! //! --- #![no_main] @@ -33,17 +30,16 @@ extern crate cortex_m_rt as rt; extern crate cortex_m_semihosting as sh; #[macro_use] extern crate stm32f103xx; -extern crate panic_abort; +extern crate panic_semihosting; use core::fmt::Write; -use cortex_m::asm; use cortex_m::peripheral::syst::SystClkSource; use rt::ExceptionFrame; use sh::hio::{self, HStdout}; use stm32f103xx::Interrupt; -main!(main); +entry!(main); fn main() -> ! { let p = cortex_m::Peripherals::take().unwrap(); @@ -53,6 +49,7 @@ fn main() -> ! { 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(); @@ -66,6 +63,7 @@ fn main() -> ! { } } +// try commenting out this line: you'll end in `default_handler` instead of in `exti0` interrupt!(EXTI0, exti0, state: Option = None); fn exti0(state: &mut Option) { @@ -78,20 +76,14 @@ fn exti0(state: &mut Option) { } } -exception!(DefaultHandler, deh); +exception!(HardFault, hard_fault); -#[inline(always)] -fn deh(_nr: u8) { - asm::bkpt(); +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); } -exception!(HardFault, hf); - -#[inline(always)] -fn hf(_ef: &ExceptionFrame) -> ! { - asm::bkpt(); +exception!(*, default_handler); - loop {} +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); } - -interrupts!(DefaultHandler); diff --git a/examples/exception.rs b/examples/exception.rs index 11ad73f..d62e6d4 100644 --- a/examples/exception.rs +++ b/examples/exception.rs @@ -14,30 +14,31 @@ extern crate cortex_m; #[macro_use] extern crate cortex_m_rt as rt; extern crate cortex_m_semihosting as sh; -extern crate panic_abort; +extern crate panic_semihosting; use core::fmt::Write; use cortex_m::peripheral::syst::SystClkSource; -use cortex_m::{asm, Peripherals}; +use cortex_m::Peripherals; use rt::ExceptionFrame; use sh::hio::{self, HStdout}; -main!(main); +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); // 1s + syst.set_reload(8_000_000); // period = 1s syst.enable_counter(); syst.enable_interrupt(); loop {} } -// try commenting out this line: you'll end in `deh` instead of in `sys_tick` +// try commenting out this line: you'll end in `default_handler` instead of in `sys_tick` exception!(SysTick, sys_tick, state: Option = None); fn sys_tick(state: &mut Option) { @@ -50,20 +51,14 @@ fn sys_tick(state: &mut Option) { } } -exception!(DefaultHandler, deh); +exception!(HardFault, hard_fault); -#[inline(always)] -fn deh(_nr: u8) { - asm::bkpt(); +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); } -exception!(HardFault, hf); +exception!(*, default_handler); -#[inline(always)] -fn hf(_ef: &ExceptionFrame) -> ! { - asm::bkpt(); - - loop {} +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); } - -interrupts!(DefaultHandler); diff --git a/examples/hello.rs b/examples/hello.rs index aa4f12c..3c4b5ec 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -5,19 +5,17 @@ #![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_abort; +extern crate panic_semihosting; use core::fmt::Write; -use cortex_m::asm; use rt::ExceptionFrame; use sh::hio; -main!(main); +entry!(main); fn main() -> ! { let mut stdout = hio::hstdout().unwrap(); @@ -26,21 +24,14 @@ fn main() -> ! { loop {} } -exception!(DefaultHandler, dh); +exception!(HardFault, hard_fault); -#[inline(always)] -fn dh(_nr: u8) { - asm::bkpt(); +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); } -exception!(HardFault, hf); +exception!(*, default_handler); -#[inline(always)] -fn hf(_ef: &ExceptionFrame) -> ! { - asm::bkpt(); - - loop {} +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); } - -// As we are not using interrupts, we just bind them all to the `DefaultHandler` exception handler -interrupts!(DefaultHandler); diff --git a/examples/itm.rs b/examples/itm.rs index 7b21cae..6fddea1 100644 --- a/examples/itm.rs +++ b/examples/itm.rs @@ -1,11 +1,13 @@ //! 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/ @@ -19,37 +21,34 @@ extern crate cortex_m; #[macro_use] extern crate cortex_m_rt as rt; -extern crate panic_abort; // panicking behavior +extern crate panic_semihosting; use cortex_m::{asm, Peripherals}; use rt::ExceptionFrame; -main!(main); +entry!(main); -#[inline(always)] fn main() -> ! { let mut p = Peripherals::take().unwrap(); let stim = &mut p.ITM.stim[0]; iprintln!(stim, "Hello, world!"); - loop {} + loop { + asm::bkpt(); + } } -exception!(DefaultHandler, dh); +// define the hard fault handler +exception!(HardFault, hard_fault); -#[inline(always)] -fn dh(_nr: u8) { - asm::bkpt(); +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); } -exception!(HardFault, hf); +// define the default exception handler +exception!(*, default_handler); -#[inline(always)] -fn hf(_ef: &ExceptionFrame) -> ! { - asm::bkpt(); - - loop {} +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); } - -interrupts!(DefaultHandler); diff --git a/examples/minimal.rs b/examples/minimal.rs index d27b761..db91840 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -1,66 +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 `main!`. The entry point doesn't need to be called `main` and -//! it doesn't need to be in the root of the crate. +//! - 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 implementation crate][0] +//! define a panicking behavior is to link to a [panic handler crate][0] //! //! [0]: https://crates.io/keywords/panic-impl //! -//! - Define the `HardFault` handler. This function is called when a hard fault exception is raised -//! by the hardware. +//! - Define the `HardFault` handler using the [`exception!`] macro. This handler (function) is +//! called when a hard fault exception is raised by the hardware. //! -//! - Define a default handler. This function will be used to handle all interrupts and exceptions -//! which have not been assigned a specific handler. +//! [`exception!`]: https://docs.rs/cortex-m-rt/~0.5/cortex_m_rt/macro..html //! -//! - Define the device specific interrupt handlers. `interrupts!` can be used to create a generic -//! program that works for all Cortex-M devices by binding all the possible interrupt handlers to -//! the `DefaultHandler`. +//! - 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(main, exception, interrupts)] + +#[macro_use(entry, exception)] extern crate cortex_m_rt as rt; -extern crate panic_abort; // panicking behavior + +// 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 -main!(main); +// the program entry point is ... +entry!(main); -#[inline(always)] +// ... this never ending function fn main() -> ! { - asm::bkpt(); - - loop {} + loop { + asm::bkpt(); + } } -// define the default exception handler -exception!(DefaultHandler, deh); +// define the hard fault handler +exception!(HardFault, hard_fault); -#[inline(always)] -fn deh(_nr: u8) { - asm::bkpt(); +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); } -// define the hard fault handler -exception!(HardFault, hf); - -#[inline(always)] -fn hf(_ef: &ExceptionFrame) -> ! { - asm::bkpt(); +// define the default exception handler +exception!(*, default_handler); - loop {} +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); } - -// bind all interrupts to the default exception handler -interrupts!(DefaultHandler); diff --git a/examples/panic.rs b/examples/panic.rs index 951cc05..0ce22af 100644 --- a/examples/panic.rs +++ b/examples/panic.rs @@ -1,7 +1,6 @@ //! 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 //! @@ -10,36 +9,35 @@ #![no_main] #![no_std] -extern crate cortex_m; #[macro_use] extern crate cortex_m_rt as rt; -// extern crate panic_abort; -extern crate panic_semihosting; // reports panic messages to the host stderr using semihosting -use cortex_m::asm; +// 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; -main!(main); +entry!(main); -#[inline(always)] fn main() -> ! { panic!("Oops") } -exception!(DefaultHandler, deh); +// define the hard fault handler +exception!(HardFault, hard_fault); -#[inline(always)] -fn deh(_nr: u8) { - asm::bkpt(); +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); } -exception!(HardFault, hf); +// define the default exception handler +exception!(*, default_handler); -#[inline(always)] -fn hf(_ef: &ExceptionFrame) -> ! { - asm::bkpt(); - - loop {} +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); } - -interrupts!(DefaultHandler); diff --git a/gen-examples.sh b/gen-examples.sh index a1f55d2..5676c01 100644 --- a/gen-examples.sh +++ b/gen-examples.sh @@ -11,8 +11,8 @@ main() { panic crash exception - device allocator + device ) rm -rf src/examples @@ -20,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 diff --git a/interrupts.x b/interrupts.x deleted file mode 100644 index 65ab4a4..0000000 --- a/interrupts.x +++ /dev/null @@ -1 +0,0 @@ -/* Remove this file if you are linking to a device crate that provides this file */ diff --git a/memory.x b/memory.x index f407292..32879e1 100644 --- a/memory.x +++ b/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. */ diff --git a/src/examples/_0_minimal.rs b/src/examples/_0_minimal.rs index d73257d..8926e23 100644 --- a/src/examples/_0_minimal.rs +++ b/src/examples/_0_minimal.rs @@ -1,70 +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 `main!`. The entry point doesn't need to be called `main` and -//! it doesn't need to be in the root of the crate. +//! - 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 implementation crate][0] +//! define a panicking behavior is to link to a [panic handler crate][0] //! //! [0]: https://crates.io/keywords/panic-impl //! -//! - Define the `HardFault` handler. This function is called when a hard fault exception is raised -//! by the hardware. +//! - Define the `HardFault` handler using the [`exception!`] macro. This handler (function) is +//! called when a hard fault exception is raised by the hardware. //! -//! - Define a default handler. This function will be used to handle all interrupts and exceptions -//! which have not been assigned a specific handler. +//! [`exception!`]: https://docs.rs/cortex-m-rt/~0.5/cortex_m_rt/macro..html //! -//! - Define the device specific interrupt handlers. `interrupts!` can be used to create a generic -//! program that works for all Cortex-M devices by binding all the possible interrupt handlers to -//! the `DefaultHandler`. +//! - 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(main, exception, interrupts)] +//! +//! #[macro_use(entry, exception)] //! extern crate cortex_m_rt as rt; -//! extern crate panic_abort; // panicking behavior -//! +//! +//! // 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 -//! main!(main); -//! -//! #[inline(always)] +//! +//! // the program entry point is ... +//! entry!(main); +//! +//! // ... this never ending function //! fn main() -> ! { -//! asm::bkpt(); -//! -//! loop {} +//! loop { +//! asm::bkpt(); +//! } //! } -//! -//! // define the default exception handler -//! exception!(DefaultHandler, deh); -//! -//! #[inline(always)] -//! fn deh(_nr: u8) { -//! asm::bkpt(); -//! } -//! +//! //! // define the hard fault handler -//! exception!(HardFault, hf); -//! -//! #[inline(always)] -//! fn hf(_ef: &ExceptionFrame) -> ! { -//! asm::bkpt(); -//! -//! loop {} +//! 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); //! } -//! -//! // bind all interrupts to the default exception handler -//! interrupts!(DefaultHandler); //! ``` // Auto-generated. Do not modify. diff --git a/src/examples/_1_hello.rs b/src/examples/_1_hello.rs index badaa62..413c4fb 100644 --- a/src/examples/_1_hello.rs +++ b/src/examples/_1_hello.rs @@ -3,48 +3,39 @@ //! --- //! //! ``` -//! +//! //! #![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_abort; -//! +//! extern crate panic_semihosting; +//! //! use core::fmt::Write; -//! -//! use cortex_m::asm; +//! //! use rt::ExceptionFrame; //! use sh::hio; -//! -//! main!(main); -//! +//! +//! entry!(main); +//! //! fn main() -> ! { //! let mut stdout = hio::hstdout().unwrap(); //! writeln!(stdout, "Hello, world!").unwrap(); -//! +//! //! loop {} //! } -//! -//! exception!(DefaultHandler, dh); -//! -//! #[inline(always)] -//! fn dh(_nr: u8) { -//! asm::bkpt(); +//! +//! exception!(HardFault, hard_fault); +//! +//! fn hard_fault(ef: &ExceptionFrame) -> ! { +//! panic!("HardFault at {:#?}", ef); //! } -//! -//! exception!(HardFault, hf); -//! -//! #[inline(always)] -//! fn hf(_ef: &ExceptionFrame) -> ! { -//! asm::bkpt(); -//! -//! loop {} +//! +//! exception!(*, default_handler); +//! +//! fn default_handler(irqn: i16) { +//! panic!("Unhandled exception (IRQn = {})", irqn); //! } -//! -//! // As we are not using interrupts, we just bind them all to the `DefaultHandler` exception handler -//! interrupts!(DefaultHandler); //! ``` // Auto-generated. Do not modify. diff --git a/src/examples/_2_itm.rs b/src/examples/_2_itm.rs index 42abeff..568a467 100644 --- a/src/examples/_2_itm.rs +++ b/src/examples/_2_itm.rs @@ -1,11 +1,13 @@ //! 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/ @@ -13,47 +15,44 @@ //! --- //! //! ``` -//! +//! //! #![no_main] //! #![no_std] -//! +//! //! #[macro_use] //! extern crate cortex_m; //! #[macro_use] //! extern crate cortex_m_rt as rt; -//! extern crate panic_abort; // panicking behavior -//! +//! extern crate panic_semihosting; +//! //! use cortex_m::{asm, Peripherals}; //! use rt::ExceptionFrame; -//! -//! main!(main); -//! -//! #[inline(always)] +//! +//! entry!(main); +//! //! fn main() -> ! { //! let mut p = Peripherals::take().unwrap(); //! let stim = &mut p.ITM.stim[0]; -//! +//! //! iprintln!(stim, "Hello, world!"); -//! -//! loop {} +//! +//! loop { +//! asm::bkpt(); +//! } //! } -//! -//! exception!(DefaultHandler, dh); -//! -//! #[inline(always)] -//! fn dh(_nr: u8) { -//! asm::bkpt(); +//! +//! // define the hard fault handler +//! exception!(HardFault, hard_fault); +//! +//! fn hard_fault(ef: &ExceptionFrame) -> ! { +//! panic!("HardFault at {:#?}", ef); //! } -//! -//! exception!(HardFault, hf); -//! -//! #[inline(always)] -//! fn hf(_ef: &ExceptionFrame) -> ! { -//! asm::bkpt(); -//! -//! loop {} +//! +//! // define the default exception handler +//! exception!(*, default_handler); +//! +//! fn default_handler(irqn: i16) { +//! panic!("Unhandled exception (IRQn = {})", irqn); //! } -//! -//! interrupts!(DefaultHandler); //! ``` // Auto-generated. Do not modify. diff --git a/src/examples/_3_panic.rs b/src/examples/_3_panic.rs index 7ad410f..4d6a7dd 100644 --- a/src/examples/_3_panic.rs +++ b/src/examples/_3_panic.rs @@ -1,49 +1,47 @@ //! 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 //! //! --- //! //! ``` -//! +//! //! #![no_main] //! #![no_std] -//! -//! extern crate cortex_m; +//! //! #[macro_use] //! extern crate cortex_m_rt as rt; -//! // extern crate panic_abort; -//! extern crate panic_semihosting; // reports panic messages to the host stderr using semihosting -//! -//! use cortex_m::asm; +//! +//! // 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; -//! -//! main!(main); -//! -//! #[inline(always)] +//! +//! entry!(main); +//! //! fn main() -> ! { //! panic!("Oops") //! } -//! -//! exception!(DefaultHandler, deh); -//! -//! #[inline(always)] -//! fn deh(_nr: u8) { -//! asm::bkpt(); +//! +//! // define the hard fault handler +//! exception!(HardFault, hard_fault); +//! +//! fn hard_fault(ef: &ExceptionFrame) -> ! { +//! panic!("HardFault at {:#?}", ef); //! } -//! -//! exception!(HardFault, hf); -//! -//! #[inline(always)] -//! fn hf(_ef: &ExceptionFrame) -> ! { -//! asm::bkpt(); -//! -//! loop {} +//! +//! // define the default exception handler +//! exception!(*, default_handler); +//! +//! fn default_handler(irqn: i16) { +//! panic!("Unhandled exception (IRQn = {})", irqn); //! } -//! -//! interrupts!(DefaultHandler); //! ``` // Auto-generated. Do not modify. diff --git a/src/examples/_4_crash.rs b/src/examples/_4_crash.rs index 861d161..f3957d1 100644 --- a/src/examples/_4_crash.rs +++ b/src/examples/_4_crash.rs @@ -1,11 +1,12 @@ //! 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) continue @@ -13,103 +14,105 @@ //! __bkpt () at asm/bkpt.s:3 //! 3 bkpt //! -//! (gdb) finish -//! Run till exit from #0 __bkpt () at asm/bkpt.s:3 -//! Note: automatically using hardware breakpoints for read-only addresses. -//! crash::hf (_ef=0x20004fa0) at examples/crash.rs:102 -//! 99 asm::bkpt(); -//! -//! (gdb) # Exception frame = program state during the crash -//! (gdb) print/x *_ef -//! $1 = cortex_m_rt::ExceptionFrame { -//! r0: 0x2fffffff, -//! r1: 0x2fffffff, -//! r2: 0x80006b0, -//! r3: 0x80006b0, -//! r12: 0x20000000, -//! lr: 0x800040f, -//! pc: 0x800066a, -//! xpsr: 0x61000000 -//! } -//! -//! (gdb) # Where did we come from? //! (gdb) backtrace -//! #0 crash::hf (_ef=0x20004fa0) at examples/crash.rs:102 -//! #1 0x080004ac in UserHardFault (ef=0x20004fa0) at :9 -//! #2 -//! #3 0x0800066a in core::ptr::read_volatile (src=0x2fffffff) at /checkout/src/libcore/ptr.rs:452 -//! #4 0x0800040e in crash::main () at examples/crash.rs:85 -//! #5 0x08000456 in main () at
:3 -//! -//! (gdb) # Nail down the location of the crash -//! (gdb) disassemble/m _ef.pc +//! #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 :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(src: *const T) -> T {} -//! 0x08000662 <+0>: sub sp, #16 -//! 0x08000664 <+2>: mov r1, r0 -//! 0x08000666 <+4>: str r0, [sp, #8] +//! 451 pub unsafe fn read_volatile(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) -//! 0x08000668 <+6>: ldr r0, [sp, #8] -//! 0x0800066a <+8>: ldr r0, [r0, #0] -//! 0x0800066c <+10>: str r0, [sp, #12] -//! 0x0800066e <+12>: ldr r0, [sp, #12] -//! 0x08000670 <+14>: str r1, [sp, #4] -//! 0x08000672 <+16>: str r0, [sp, #0] -//! 0x08000674 <+18>: b.n 0x8000676 +//! 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 //! //! 453 } -//! 0x08000676 <+20>: ldr r0, [sp, #0] -//! 0x08000678 <+22>: add sp, #16 -//! 0x0800067a <+24>: bx lr +//! 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_abort; -//! +//! extern crate panic_semihosting; +//! //! use core::ptr; -//! -//! use cortex_m::asm; +//! //! use rt::ExceptionFrame; -//! -//! main!(main); -//! -//! #[inline(always)] +//! +//! 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 {} //! } -//! -//! exception!(DefaultHandler, dh); -//! -//! #[inline(always)] -//! fn dh(_nr: u8) { -//! asm::bkpt(); +//! +//! // define the hard fault handler +//! exception!(HardFault, hard_fault); +//! +//! fn hard_fault(ef: &ExceptionFrame) -> ! { +//! panic!("HardFault at {:#?}", ef); //! } -//! -//! exception!(HardFault, hf); -//! -//! #[inline(always)] -//! fn hf(_ef: &ExceptionFrame) -> ! { -//! asm::bkpt(); -//! -//! loop {} +//! +//! // define the default exception handler +//! exception!(*, default_handler); +//! +//! fn default_handler(irqn: i16) { +//! panic!("Unhandled exception (IRQn = {})", irqn); //! } -//! -//! interrupts!(DefaultHandler); //! ``` // Auto-generated. Do not modify. diff --git a/src/examples/_5_exception.rs b/src/examples/_5_exception.rs index 49c98aa..f2a65f3 100644 --- a/src/examples/_5_exception.rs +++ b/src/examples/_5_exception.rs @@ -7,67 +7,62 @@ //! --- //! //! ``` -//! +//! //! #![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_abort; -//! +//! extern crate panic_semihosting; +//! //! use core::fmt::Write; -//! +//! //! use cortex_m::peripheral::syst::SystClkSource; -//! use cortex_m::{asm, Peripherals}; +//! use cortex_m::Peripherals; //! use rt::ExceptionFrame; //! use sh::hio::{self, HStdout}; -//! -//! main!(main); -//! +//! +//! 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); // 1s +//! syst.set_reload(8_000_000); // period = 1s //! syst.enable_counter(); //! syst.enable_interrupt(); -//! +//! //! loop {} //! } -//! -//! // try commenting out this line: you'll end in `deh` instead of in `sys_tick` +//! +//! // try commenting out this line: you'll end in `default_handler` instead of in `sys_tick` //! exception!(SysTick, sys_tick, state: Option = None); -//! +//! //! fn sys_tick(state: &mut Option) { //! if state.is_none() { //! *state = Some(hio::hstdout().unwrap()); //! } -//! +//! //! if let Some(hstdout) = state.as_mut() { //! hstdout.write_str(".").unwrap(); //! } //! } -//! -//! exception!(DefaultHandler, deh); -//! -//! #[inline(always)] -//! fn deh(_nr: u8) { -//! asm::bkpt(); +//! +//! exception!(HardFault, hard_fault); +//! +//! fn hard_fault(ef: &ExceptionFrame) -> ! { +//! panic!("HardFault at {:#?}", ef); //! } -//! -//! exception!(HardFault, hf); -//! -//! #[inline(always)] -//! fn hf(_ef: &ExceptionFrame) -> ! { -//! asm::bkpt(); -//! -//! loop {} +//! +//! exception!(*, default_handler); +//! +//! fn default_handler(irqn: i16) { +//! panic!("Unhandled exception (IRQn = {})", irqn); //! } -//! -//! interrupts!(DefaultHandler); //! ``` // Auto-generated. Do not modify. diff --git a/src/examples/_7_allocator.rs b/src/examples/_6_allocator.rs similarity index 66% rename from src/examples/_7_allocator.rs rename to src/examples/_6_allocator.rs index 071261d..c7bddcc 100644 --- a/src/examples/_7_allocator.rs +++ b/src/examples/_6_allocator.rs @@ -10,12 +10,13 @@ //! --- //! //! ``` -//! +//! //! #![feature(alloc)] //! #![feature(global_allocator)] +//! #![feature(lang_items)] //! #![no_main] //! #![no_std] -//! +//! //! // This is the allocator crate; you can use a different one //! extern crate alloc_cortex_m; //! #[macro_use] @@ -24,51 +25,55 @@ //! #[macro_use] //! extern crate cortex_m_rt as rt; //! extern crate cortex_m_semihosting as sh; -//! extern crate panic_abort; -//! +//! extern crate panic_semihosting; +//! //! use core::fmt::Write; -//! +//! //! use alloc_cortex_m::CortexMHeap; //! use cortex_m::asm; //! use rt::ExceptionFrame; //! use sh::hio; -//! +//! +//! // this is the allocator the application will use //! #[global_allocator] //! static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); -//! +//! //! const HEAP_SIZE: usize = 1024; // in bytes -//! -//! main!(main); -//! +//! +//! entry!(main); +//! //! fn main() -> ! { -//! // Initialize the allocator +//! // 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 {} //! } -//! -//! exception!(DefaultHandler, dh); -//! -//! #[inline(always)] -//! fn dh(_nr: u8) { -//! asm::bkpt(); -//! } -//! -//! exception!(HardFault, hf); -//! -//! #[inline(always)] -//! fn hf(_ef: &ExceptionFrame) -> ! { +//! +//! // define what happens in an Out Of Memory (OOM) condition +//! #[lang = "oom"] +//! #[no_mangle] +//! pub fn rust_oom() -> ! { //! asm::bkpt(); -//! +//! //! loop {} //! } -//! -//! interrupts!(DefaultHandler); +//! +//! 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. diff --git a/src/examples/_6_device.rs b/src/examples/_7_device.rs similarity index 76% rename from src/examples/_6_device.rs rename to src/examples/_7_device.rs index 83656b1..7564284 100644 --- a/src/examples/_6_device.rs +++ b/src/examples/_7_device.rs @@ -1,6 +1,6 @@ //! Using a device crate //! -//! Crates generated using [`svd2rust`] are referred to as device crates. These crates provides an +//! 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 @@ -19,83 +19,75 @@ //! version = "0.10.0" //! ``` //! -//! The `stm32f103xx` crate provides an `interrupts.x` file so you must remove the one in the root -//! of this crate. -//! //! --- //! //! ``` -//! +//! //! #![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_abort; -//! +//! extern crate panic_semihosting; +//! //! use core::fmt::Write; -//! -//! use cortex_m::asm; +//! //! use cortex_m::peripheral::syst::SystClkSource; //! use rt::ExceptionFrame; //! use sh::hio::{self, HStdout}; //! use stm32f103xx::Interrupt; -//! -//! main!(main); -//! +//! +//! 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 = None); -//! +//! //! fn exti0(state: &mut Option) { //! if state.is_none() { //! *state = Some(hio::hstdout().unwrap()); //! } -//! +//! //! if let Some(hstdout) = state.as_mut() { //! hstdout.write_str(".").unwrap(); //! } //! } -//! -//! exception!(DefaultHandler, deh); -//! -//! #[inline(always)] -//! fn deh(_nr: u8) { -//! asm::bkpt(); +//! +//! exception!(HardFault, hard_fault); +//! +//! fn hard_fault(ef: &ExceptionFrame) -> ! { +//! panic!("HardFault at {:#?}", ef); //! } -//! -//! exception!(HardFault, hf); -//! -//! #[inline(always)] -//! fn hf(_ef: &ExceptionFrame) -> ! { -//! asm::bkpt(); -//! -//! loop {} +//! +//! exception!(*, default_handler); +//! +//! fn default_handler(irqn: i16) { +//! panic!("Unhandled exception (IRQn = {})", irqn); //! } -//! -//! interrupts!(DefaultHandler); //! ``` // Auto-generated. Do not modify. diff --git a/src/examples/mod.rs b/src/examples/mod.rs index dc816c2..0358d78 100644 --- a/src/examples/mod.rs +++ b/src/examples/mod.rs @@ -1,4 +1,4 @@ -//! Examples +//! Examples sorted in increasing degree of complexity // Auto-generated. Do not modify. pub mod _0_minimal; pub mod _1_hello; @@ -6,5 +6,5 @@ pub mod _2_itm; pub mod _3_panic; pub mod _4_crash; pub mod _5_exception; -pub mod _6_device; -pub mod _7_allocator; +pub mod _6_allocator; +pub mod _7_device; diff --git a/src/lib.rs b/src/lib.rs index d2489e8..89dcc23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ //! 2) Clone this crate //! //! ``` text -//! $ git clone https://github.com/japaric/cortex-m-quickstart --branch less-unstable +//! $ git 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,7 +114,7 @@ //! Tag_ABI_FP_16bit_format: IEEE 754 //! ``` //! -//! 9) Flash the program +//! 9) Flash and debug the program //! //! ``` text //! $ # Launch OpenOCD on a terminal @@ -166,12 +167,14 @@ //! error: linking with `arm-none-eabi-ld` failed: exit code: 1 //! | //! = 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: //! @@ -183,9 +186,8 @@ //! 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 //! @@ -209,11 +211,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 @@ -228,9 +229,8 @@ //! 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 //! @@ -268,6 +268,8 @@ //! ``` text //! $ cargo build //! error[E0463]: can't find crate for `core` +//! | +//! = note: the `thumbv7em-none-eabihf` target may not be installed //! ``` //! //! Solution: We are not there yet! Switch to the nightly toolchain with `rustup default nightly`. From 66c0c588b0136c73c41f8071f11f2552835febc6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 12 May 2018 20:49:12 +0200 Subject: [PATCH 7/7] fix tests --- .travis.yml | 16 ++++------------ Cargo.toml | 8 +++++--- ci/script.sh | 7 ++----- examples/panic.rs | 1 + 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index b939699..ec6158e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,37 +6,29 @@ matrix: rust: nightly addons: apt: - sources: - - debian-sid packages: - - binutils-arm-none-eabi + - gcc-arm-none-eabi - env: TARGET=thumbv7m-none-eabi rust: nightly addons: apt: - sources: - - debian-sid packages: - - binutils-arm-none-eabi + - gcc-arm-none-eabi - env: TARGET=thumbv7em-none-eabi rust: nightly addons: apt: - sources: - - debian-sid packages: - - binutils-arm-none-eabi + - gcc-arm-none-eabi - env: TARGET=thumbv7em-none-eabihf rust: nightly addons: apt: - sources: - - debian-sid packages: - - binutils-arm-none-eabi + - gcc-arm-none-eabi before_install: set -e diff --git a/Cargo.toml b/Cargo.toml index bc60c97..a1f9148 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,11 +12,13 @@ version = "0.3.0" cortex-m = "0.5.0" cortex-m-rt = "0.5.0" cortex-m-semihosting = "0.3.0" -panic-itm = "0.1.1" panic-semihosting = "0.2.0" +# Uncomment for the panic example. +# panic-itm = "0.1.1" + # Uncomment for the allocator example. -# alloc-cortex-m = "0.3.6" +# alloc-cortex-m = "0.3.4" # Uncomment for the device example. # [dependencies.stm32f103xx] @@ -26,4 +28,4 @@ panic-semihosting = "0.2.0" [profile.release] codegen-units = 1 # better optimizations debug = true -lto = true \ No newline at end of file +lto = true diff --git a/ci/script.sh b/ci/script.sh index ac47fd8..d2195a2 100644 --- a/ci/script.sh +++ b/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 } @@ -34,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 ) @@ -54,7 +51,7 @@ EOF cat >>Cargo.toml <<'EOF' [dependencies.stm32f103xx] features = ["rt"] -version = "0.9.0" +version = "0.10.0" EOF local ex=device diff --git a/examples/panic.rs b/examples/panic.rs index 0ce22af..0822156 100644 --- a/examples/panic.rs +++ b/examples/panic.rs @@ -18,6 +18,7 @@ extern crate cortex_m_rt as rt; 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;