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); -static NVIC: Mutex>> = Mutex::new(RefCell::new(None)); +fn main() -> ! { + let p = cortex_m::Peripherals::take().unwrap(); -fn main() { - let global_p = cortex_m::Peripherals::take().unwrap(); - interrupt::free(|cs| { - let hstdout = HSTDOUT.borrow(cs); - if let Ok(fd) = hio::hstdout() { - *hstdout.borrow_mut() = Some(fd); - } + let mut syst = p.SYST; + let mut nvic = p.NVIC; - let mut nvic = global_p.NVIC; - nvic.enable(Interrupt::TIM2); - *NVIC.borrow(cs).borrow_mut() = Some(nvic); + nvic.enable(Interrupt::EXTI0); - let mut syst = global_p.SYST; - syst.set_clock_source(SystClkSource::Core); - syst.set_reload(8_000_000); // 1s - syst.enable_counter(); - syst.enable_interrupt(); - }); + 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); + } } -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; - - interrupt::free(|cs| { - let hstdout = HSTDOUT.borrow(cs); - if let Some(hstdout) = hstdout.borrow_mut().as_mut() { - writeln!(*hstdout, "Tock ({})", l.tocks).ok(); - } - }); +#[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 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; //! -//! fn main() { -//! let p = Peripherals::take().unwrap(); -//! let mut itm = p.ITM; +//! main!(main); //! -//! iprintln!(&mut itm.stim[0], "Hello, world!"); +//! #[inline(always)] +//! fn main() -> ! { +//! let mut p = Peripherals::take().unwrap(); +//! let stim = &mut p.ITM.stim[0]; +//! +//! iprintln!(stim, "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` //!