diff --git a/CHANGELOG.md b/CHANGELOG.md index cc5d740..7610a69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.2.0] - 2017-07-07 + +### Changed + +- [breaking-change] Bumped the cortex-m and cortex-m-rt versions to v0.3.0. + ## [v0.1.8] - 2017-05-30 ### Changed diff --git a/Cargo.toml b/Cargo.toml index e4e2fda..4eccd62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,16 @@ 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.1.8" +version = "0.2.0" [dependencies] -cortex-m = "0.2.7" -cortex-m-rt = "0.2.3" +cortex-m = "0.3.0" +cortex-m-semihosting = "0.2.0" + +[dependencies.cortex-m-rt] +features = ["abort-on-panic"] +version = "0.3.2" [profile.release] -lto = true debug = true +lto = true diff --git a/Xargo.toml b/Xargo.toml index 505d421..3c99a53 100644 --- a/Xargo.toml +++ b/Xargo.toml @@ -1,6 +1,6 @@ [dependencies.core] +stage = 0 [dependencies.compiler_builtins] -features = ["mem"] git = "https://github.com/rust-lang-nursery/compiler-builtins" stage = 1 \ No newline at end of file diff --git a/examples/allocator.rs b/examples/allocator.rs index 6b2ad85..c788d0f 100644 --- a/examples/allocator.rs +++ b/examples/allocator.rs @@ -6,10 +6,12 @@ //! //! ``` text //! [dependencies.core] -//! [dependencies.collections] # new +//! stage = 0 +//! +//! [dependencies.collections] # NEW +//! stage = 0 //! //! [dependencies.compiler_builtins] -//! features = ["mem"] //! git = "https://github.com/rust-lang-nursery/compiler-builtins" //! stage = 1 //! ``` @@ -21,7 +23,10 @@ //! # or edit the Cargo.toml file manually //! $ cargo add alloc-cortex-m //! ``` +//! +//! --- +#[allow(deprecated)] #![feature(collections)] #![feature(used)] #![no_std] @@ -30,11 +35,14 @@ extern crate alloc_cortex_m; #[macro_use] extern crate collections; -#[macro_use] extern crate cortex_m; extern crate cortex_m_rt; +extern crate cortex_m_semihosting; + +use core::fmt::Write; use cortex_m::asm; +use cortex_m_semihosting::hio; fn main() { // Initialize the allocator @@ -45,25 +53,26 @@ fn main() { } // Size of the heap in words (1 word = 4 bytes) - // WARNING: The bigger the heap the greater the chance to run into a - // stack overflow (collision between the stack and the heap) + // NOTE The bigger the heap the greater the chance to run into a stack + // overflow (collision between the stack and the heap) const SIZE: isize = 256; // End of the heap let _eheap = (&mut _sheap as *mut _).offset(SIZE); - alloc_cortex_m::init(&mut _sheap as *mut _, _eheap); + alloc_cortex_m::init(&mut _sheap, _eheap); } // Growable array allocated on the heap let xs = vec![0, 1, 2]; - hprintln!("{:?}", xs); + + let mut stdout = hio::hstdout().unwrap(); + writeln!(stdout, "{:?}", xs).unwrap(); } // As we are not using interrupts, we just register a dummy catch all handler -#[allow(dead_code)] +#[link_section = ".vector_table.interrupts"] #[used] -#[link_section = ".rodata.interrupts"] static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; extern "C" fn default_handler() { diff --git a/examples/crash.rs b/examples/crash.rs index c6d1234..f006323 100644 --- a/examples/crash.rs +++ b/examples/crash.rs @@ -8,27 +8,55 @@ //! In you run the example below, you'll be able to inspect the state of your //! program under the debugger using these commands: //! -//! ``` -//! (gdb) # Stacked registers = program state during the crash -//! (gdb) print/x *_sr -//! $1 = cortex_m::exception::StackedRegisters { +//! ``` 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 = 0x8000443, -//! pc = 0x8000190, -//! xpsr = 0x61000200, +//! lr = 0x8000481, +//! pc = 0x8000460, +//! xpsr = 0x61000000, //! } //! -//! (gdb) # What exception was triggered? -//! (gdb) print _e -//! $2 = cortex_m::exception::Exception::HardFault -//! //! (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] @@ -48,9 +76,8 @@ fn main() { } // As we are not using interrupts, we just register a dummy catch all handler -#[allow(dead_code)] +#[link_section = ".vector_table.interrupts"] #[used] -#[link_section = ".rodata.interrupts"] static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; extern "C" fn default_handler() { diff --git a/examples/device.rs b/examples/device.rs new file mode 100644 index 0000000..b835b52 --- /dev/null +++ b/examples/device.rs @@ -0,0 +1,58 @@ +//! 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 && cat $_ +//! [dependencies.stm32f103xx] +//! features = ["rt"] +//! version = "0.7.0" +//! ``` +//! +//! --- + +#![no_std] + +extern crate cortex_m; +#[macro_use(exception, interrupt)] +extern crate stm32f103xx; + +use cortex_m::interrupt; + +fn main() { + interrupt::free(|cs| { + let _gpioa = stm32f103xx::GPIOA.borrow(cs); + // do something with GPIOA + }); +} + +exception!(SYS_TICK, tick, locals: { + ticks: u32 = 0; +}); + +fn tick(l: &mut SYS_TICK::Locals) { + l.ticks += 1; + // .. +} + +interrupt!(TIM2, tock, locals: { + tocks: u32 = 0; +}); + +fn tock(l: &mut TIM2::Locals) { + l.tocks += 1; + // .. +} diff --git a/examples/hello.rs b/examples/hello.rs index b9c9deb..a3f0eb4 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,22 +1,27 @@ //! Prints "Hello, world!" on the OpenOCD console using semihosting +//! +//! --- #![feature(used)] #![no_std] -#[macro_use] extern crate cortex_m; extern crate cortex_m_rt; +extern crate cortex_m_semihosting; + +use core::fmt::Write; use cortex_m::asm; +use cortex_m_semihosting::hio; fn main() { - hprintln!("Hello, world!"); + 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 -#[allow(dead_code)] +#[link_section = ".vector_table.interrupts"] #[used] -#[link_section = ".rodata.interrupts"] static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; extern "C" fn default_handler() { diff --git a/examples/itm.rs b/examples/itm.rs index c1e5bfc..4159c43 100644 --- a/examples/itm.rs +++ b/examples/itm.rs @@ -7,9 +7,11 @@ //! 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 OpenOCD's ITM support in `.gdbinit`. +//! to uncomment the `monitor` commands in the `.gdbinit` file. //! //! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/ +//! +//! --- #![feature(used)] #![no_std] @@ -21,19 +23,16 @@ extern crate cortex_m_rt; use cortex_m::{asm, interrupt, peripheral}; fn main() { - interrupt::free( - |cs| { - let itm = peripheral::ITM.borrow(&cs); + interrupt::free(|cs| { + let itm = peripheral::ITM.borrow(&cs); - iprintln!(&itm.stim[0], "Hello, world!"); - }, - ); + iprintln!(&itm.stim[0], "Hello, world!"); + }); } // As we are not using interrupts, we just register a dummy catch all handler -#[allow(dead_code)] +#[link_section = ".vector_table.interrupts"] #[used] -#[link_section = ".rodata.interrupts"] static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; extern "C" fn default_handler() { diff --git a/examples/override-exception-handler.rs b/examples/override-exception-handler.rs index df8bf17..8785a2c 100644 --- a/examples/override-exception-handler.rs +++ b/examples/override-exception-handler.rs @@ -1,17 +1,26 @@ -//! Overriding an exception +//! Overriding an exception handler //! -//! **NOTE** You have to disable the `cortex-m-rt` crate's "exceptions" feature -//! to make this work. +//! 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; use core::ptr; -use cortex_m::{asm, exception}; +use cortex_m::asm; fn main() { unsafe { @@ -20,25 +29,17 @@ fn main() { } } -extern "C" fn hard_fault(_: exception::HardFault) { +exception!(HARD_FAULT, handler); + +fn handler() { // You'll hit this breakpoint rather than the one in cortex-m-rt asm::bkpt() } -// When the "exceptions" feature is disabled, you'll have to provide this symbol -#[allow(dead_code)] -#[used] -#[link_section = ".rodata.exceptions"] -static EXCEPTIONS: exception::Handlers = exception::Handlers { - // This is the exception handler override - hard_fault: hard_fault, - ..exception::DEFAULT_HANDLERS -}; - // As we are not using interrupts, we just register a dummy catch all handler #[allow(dead_code)] #[used] -#[link_section = ".rodata.interrupts"] +#[link_section = ".vector_table.interrupts"] static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; extern "C" fn default_handler() { diff --git a/examples/panic.rs b/examples/panic.rs index caa2c6e..a85f425 100644 --- a/examples/panic.rs +++ b/examples/panic.rs @@ -1,33 +1,56 @@ -//! Redirecting `panic!` messages +//! Defining the panic handler //! -//! The `cortex-m-rt` crate provides two options to redirect `panic!` messages -//! through these two Cargo features: +//! The panic handler can be defined through the `panic_fmt` [language item][1]. +//! Make sure that the "abort-on-panic" feature of the cortex-m-rt crate is +//! disabled to avoid redefining the language item. //! -//! - `panic-over-semihosting`. `panic!` messages will be printed to the OpenOCD -//! console using semihosting. This is slow. +//! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html //! -//! - `panic-over-itm`. `panic!` messages will be send through the ITM port 0. -//! This is much faster but requires ITM support on the device. -//! -//! If neither of these options is specified then the `panic!` message will be -//! lost. Note that all `panic!`s will trigger a debugger breakpoint. +//! --- +#![feature(core_intrinsics)] +#![feature(lang_items)] #![feature(used)] #![no_std] extern crate cortex_m; extern crate cortex_m_rt; +extern crate cortex_m_semihosting; + +use core::fmt::Write; +use core::intrinsics; use cortex_m::asm; +use cortex_m_semihosting::hio; fn main() { panic!("Oops"); } +#[lang = "panic_fmt"] +#[no_mangle] +unsafe extern "C" fn rust_begin_unwind( + args: core::fmt::Arguments, + file: &'static str, + line: u32, + col: u32, +) -> ! { + if let Ok(mut stdout) = hio::hstdout() { + write!(stdout, "panicked at '") + .and_then(|_| { + stdout + .write_fmt(args) + .and_then(|_| writeln!(stdout, "', {}:{}", file, line)) + }) + .ok(); + } + + intrinsics::abort() +} + // As we are not using interrupts, we just register a dummy catch all handler -#[allow(dead_code)] +#[link_section = ".vector_table.interrupts"] #[used] -#[link_section = ".rodata.interrupts"] static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; extern "C" fn default_handler() { diff --git a/examples/register-interrupt-handler.rs b/examples/register-interrupt-handler.rs deleted file mode 100644 index d324527..0000000 --- a/examples/register-interrupt-handler.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Register an interrupt handler -//! -//! NOTE Requires a device crate generated using `svd2rust` - -#![feature(used)] -#![no_std] - -extern crate cortex_m; -extern crate cortex_m_rt; -// NOTE this is the device crate -extern crate stm32f30x; - -use cortex_m::asm; -use stm32f30x::interrupt; - -fn main() {} - -// NOTE each interrupt handler has a different signature -extern "C" fn my_interrupt_handler(_ctxt: interrupt::Tim7) { - asm::bkpt(); -} - -extern "C" fn another_interrupt_handler(_ctxt: interrupt::Exti0) { - asm::bkpt(); -} - -// Here we override only two interrupt handlers, the rest of interrupt are -// handled by the same interrupt handler -#[allow(dead_code)] -#[used] -#[link_section = ".rodata.interrupts"] -static INTERRUPTS: interrupt::Handlers = interrupt::Handlers { - Tim7: my_interrupt_handler, - Exti0: another_interrupt_handler, - ..interrupt::DEFAULT_HANDLERS -}; diff --git a/gen-examples.sh b/gen-examples.sh index 1f3af68..660607b 100644 --- a/gen-examples.sh +++ b/gen-examples.sh @@ -9,8 +9,8 @@ main() { itm panic crash - register-interrupt-handler override-exception-handler + device allocator ) diff --git a/memory.x b/memory.x index 10b0844..0a4ba2b 100644 --- a/memory.x +++ b/memory.x @@ -8,12 +8,13 @@ MEMORY /* This is where the call stack will be allocated. */ /* The stack is of the full descending type. */ -/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */ -_stack_start = ORIGIN(RAM) + LENGTH(RAM); +/* You may want to use this variable to locate the call stack and static + variables in different memory regions. Below is shown the default value */ +/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */ /* You can use this symbol to customize the location of the .text section */ /* If omitted the .text section will be placed right after the .vector_table section */ -/* This is required only on some microcontrollers that store some configuration - right after the vector table */ +/* This is required only on microcontrollers that store some configuration right + after the vector table */ /* _stext = ORIGIN(FLASH) + 0x400; */ diff --git a/src/examples/_0_hello.rs b/src/examples/_0_hello.rs index f54ba72..8a6c470 100644 --- a/src/examples/_0_hello.rs +++ b/src/examples/_0_hello.rs @@ -1,24 +1,29 @@ //! Prints "Hello, world!" on the OpenOCD console using semihosting //! +//! --- +//! //! ``` //! //! #![feature(used)] //! #![no_std] //! -//! #[macro_use] //! extern crate cortex_m; //! extern crate cortex_m_rt; +//! extern crate cortex_m_semihosting; +//! +//! use core::fmt::Write; //! //! use cortex_m::asm; +//! use cortex_m_semihosting::hio; //! //! fn main() { -//! hprintln!("Hello, world!"); +//! 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 -//! #[allow(dead_code)] +//! #[link_section = ".vector_table.interrupts"] //! #[used] -//! #[link_section = ".rodata.interrupts"] //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! //! extern "C" fn default_handler() { diff --git a/src/examples/_1_itm.rs b/src/examples/_1_itm.rs index 0777f0d..2f85edc 100644 --- a/src/examples/_1_itm.rs +++ b/src/examples/_1_itm.rs @@ -7,10 +7,12 @@ //! 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 OpenOCD's ITM support in `.gdbinit`. +//! to uncomment the `monitor` commands in the `.gdbinit` file. //! //! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/ //! +//! --- +//! //! ``` //! //! #![feature(used)] @@ -23,19 +25,16 @@ //! use cortex_m::{asm, interrupt, peripheral}; //! //! fn main() { -//! interrupt::free( -//! |cs| { -//! let itm = peripheral::ITM.borrow(&cs); +//! interrupt::free(|cs| { +//! let itm = peripheral::ITM.borrow(&cs); //! -//! iprintln!(&itm.stim[0], "Hello, world!"); -//! }, -//! ); +//! iprintln!(&itm.stim[0], "Hello, world!"); +//! }); //! } //! //! // As we are not using interrupts, we just register a dummy catch all handler -//! #[allow(dead_code)] +//! #[link_section = ".vector_table.interrupts"] //! #[used] -//! #[link_section = ".rodata.interrupts"] //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! //! extern "C" fn default_handler() { diff --git a/src/examples/_2_panic.rs b/src/examples/_2_panic.rs index 33a07d6..5d6ebc5 100644 --- a/src/examples/_2_panic.rs +++ b/src/examples/_2_panic.rs @@ -1,35 +1,58 @@ -//! Redirecting `panic!` messages +//! Defining the panic handler //! -//! The `cortex-m-rt` crate provides two options to redirect `panic!` messages -//! through these two Cargo features: +//! The panic handler can be defined through the `panic_fmt` [language item][1]. +//! Make sure that the "abort-on-panic" feature of the cortex-m-rt crate is +//! disabled to avoid redefining the language item. //! -//! - `panic-over-semihosting`. `panic!` messages will be printed to the OpenOCD -//! console using semihosting. This is slow. +//! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html //! -//! - `panic-over-itm`. `panic!` messages will be send through the ITM port 0. -//! This is much faster but requires ITM support on the device. -//! -//! If neither of these options is specified then the `panic!` message will be -//! lost. Note that all `panic!`s will trigger a debugger breakpoint. +//! --- //! //! ``` //! +//! #![feature(core_intrinsics)] +//! #![feature(lang_items)] //! #![feature(used)] //! #![no_std] //! //! extern crate cortex_m; //! extern crate cortex_m_rt; +//! extern crate cortex_m_semihosting; +//! +//! use core::fmt::Write; +//! use core::intrinsics; //! //! use cortex_m::asm; +//! use cortex_m_semihosting::hio; //! //! fn main() { //! panic!("Oops"); //! } //! +//! #[lang = "panic_fmt"] +//! #[no_mangle] +//! unsafe extern "C" fn rust_begin_unwind( +//! args: core::fmt::Arguments, +//! file: &'static str, +//! line: u32, +//! col: u32, +//! ) -> ! { +//! if let Ok(mut stdout) = hio::hstdout() { +//! write!(stdout, "panicked at '") +//! .and_then(|_| { +//! stdout +//! .write_fmt(args) +//! .and_then(|_| writeln!(stdout, "', {}:{}", file, line)) +//! }) +//! .ok(); +//! } +//! +//! intrinsics::abort() +//! } +//! //! // As we are not using interrupts, we just register a dummy catch all handler -//! #[allow(dead_code)] +//! #[link_section = ".vector_table.interrupts"] //! #[used] -//! #[link_section = ".rodata.interrupts"] //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! //! extern "C" fn default_handler() { diff --git a/src/examples/_3_crash.rs b/src/examples/_3_crash.rs index dd8f871..1aa431e 100644 --- a/src/examples/_3_crash.rs +++ b/src/examples/_3_crash.rs @@ -8,28 +8,56 @@ //! In you run the example below, you'll be able to inspect the state of your //! program under the debugger using these commands: //! -//! ``` -//! (gdb) # Stacked registers = program state during the crash -//! (gdb) print/x *_sr -//! $1 = cortex_m::exception::StackedRegisters { +//! ``` 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 = 0x8000443, -//! pc = 0x8000190, -//! xpsr = 0x61000200, +//! lr = 0x8000481, +//! pc = 0x8000460, +//! xpsr = 0x61000000, //! } //! -//! (gdb) # What exception was triggered? -//! (gdb) print _e -//! $2 = cortex_m::exception::Exception::HardFault -//! //! (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)] @@ -50,9 +78,8 @@ //! } //! //! // As we are not using interrupts, we just register a dummy catch all handler -//! #[allow(dead_code)] +//! #[link_section = ".vector_table.interrupts"] //! #[used] -//! #[link_section = ".rodata.interrupts"] //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! //! extern "C" fn default_handler() { diff --git a/src/examples/_5_override_exception_handler.rs b/src/examples/_4_override_exception_handler.rs similarity index 53% rename from src/examples/_5_override_exception_handler.rs rename to src/examples/_4_override_exception_handler.rs index 8f8dbd7..bc07a2a 100644 --- a/src/examples/_5_override_exception_handler.rs +++ b/src/examples/_4_override_exception_handler.rs @@ -1,7 +1,15 @@ -//! Overriding an exception +//! Overriding an exception handler //! -//! **NOTE** You have to disable the `cortex-m-rt` crate's "exceptions" feature -//! to make this work. +//! 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 +//! +//! --- //! //! ``` //! @@ -9,11 +17,12 @@ //! #![no_std] //! //! extern crate cortex_m; +//! #[macro_use(exception)] //! extern crate cortex_m_rt; //! //! use core::ptr; //! -//! use cortex_m::{asm, exception}; +//! use cortex_m::asm; //! //! fn main() { //! unsafe { @@ -22,25 +31,17 @@ //! } //! } //! -//! extern "C" fn hard_fault(_: exception::HardFault) { +//! exception!(HARD_FAULT, handler); +//! +//! fn handler() { //! // You'll hit this breakpoint rather than the one in cortex-m-rt //! asm::bkpt() //! } //! -//! // When the "exceptions" feature is disabled, you'll have to provide this symbol -//! #[allow(dead_code)] -//! #[used] -//! #[link_section = ".rodata.exceptions"] -//! static EXCEPTIONS: exception::Handlers = exception::Handlers { -//! // This is the exception handler override -//! hard_fault: hard_fault, -//! ..exception::DEFAULT_HANDLERS -//! }; -//! //! // As we are not using interrupts, we just register a dummy catch all handler //! #[allow(dead_code)] //! #[used] -//! #[link_section = ".rodata.interrupts"] +//! #[link_section = ".vector_table.interrupts"] //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! //! extern "C" fn default_handler() { diff --git a/src/examples/_4_register_interrupt_handler.rs b/src/examples/_4_register_interrupt_handler.rs deleted file mode 100644 index 8c904da..0000000 --- a/src/examples/_4_register_interrupt_handler.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Register an interrupt handler -//! -//! NOTE Requires a device crate generated using `svd2rust` -//! -//! ``` -//! -//! #![feature(used)] -//! #![no_std] -//! -//! extern crate cortex_m; -//! extern crate cortex_m_rt; -//! // NOTE this is the device crate -//! extern crate stm32f30x; -//! -//! use cortex_m::asm; -//! use stm32f30x::interrupt; -//! -//! fn main() {} -//! -//! // NOTE each interrupt handler has a different signature -//! extern "C" fn my_interrupt_handler(_ctxt: interrupt::Tim7) { -//! asm::bkpt(); -//! } -//! -//! extern "C" fn another_interrupt_handler(_ctxt: interrupt::Exti0) { -//! asm::bkpt(); -//! } -//! -//! // Here we override only two interrupt handlers, the rest of interrupt are -//! // handled by the same interrupt handler -//! #[allow(dead_code)] -//! #[used] -//! #[link_section = ".rodata.interrupts"] -//! static INTERRUPTS: interrupt::Handlers = interrupt::Handlers { -//! Tim7: my_interrupt_handler, -//! Exti0: another_interrupt_handler, -//! ..interrupt::DEFAULT_HANDLERS -//! }; -//! ``` -// Auto-generated. Do not modify. diff --git a/src/examples/_5_device.rs b/src/examples/_5_device.rs new file mode 100644 index 0000000..7a047ff --- /dev/null +++ b/src/examples/_5_device.rs @@ -0,0 +1,62 @@ +//! 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 && cat $_ +//! [dependencies.stm32f103xx] +//! features = ["rt"] +//! version = "0.7.0" +//! ``` +//! +//! --- +//! +//! ``` +//! +//! #![no_std] +//! +//! extern crate cortex_m; +//! #[macro_use(exception, interrupt)] +//! extern crate stm32f103xx; +//! +//! use cortex_m::interrupt; +//! +//! fn main() { +//! interrupt::free(|cs| { +//! let _gpioa = stm32f103xx::GPIOA.borrow(cs); +//! // do something with GPIOA +//! }); +//! } +//! +//! exception!(SYS_TICK, tick, locals: { +//! ticks: u32 = 0; +//! }); +//! +//! fn tick(l: &mut SYS_TICK::Locals) { +//! l.ticks += 1; +//! // .. +//! } +//! +//! interrupt!(TIM2, tock, locals: { +//! tocks: u32 = 0; +//! }); +//! +//! fn tock(l: &mut TIM2::Locals) { +//! l.tocks += 1; +//! // .. +//! } +//! ``` +// Auto-generated. Do not modify. diff --git a/src/examples/_6_allocator.rs b/src/examples/_6_allocator.rs index 5170dda..71cc549 100644 --- a/src/examples/_6_allocator.rs +++ b/src/examples/_6_allocator.rs @@ -6,10 +6,12 @@ //! //! ``` text //! [dependencies.core] -//! [dependencies.collections] # new +//! stage = 0 +//! +//! [dependencies.collections] # NEW +//! stage = 0 //! //! [dependencies.compiler_builtins] -//! features = ["mem"] //! git = "https://github.com/rust-lang-nursery/compiler-builtins" //! stage = 1 //! ``` @@ -22,8 +24,11 @@ //! $ cargo add alloc-cortex-m //! ``` //! +//! --- +//! //! ``` //! +//! #[allow(deprecated)] //! #![feature(collections)] //! #![feature(used)] //! #![no_std] @@ -32,11 +37,14 @@ //! extern crate alloc_cortex_m; //! #[macro_use] //! extern crate collections; -//! #[macro_use] //! extern crate cortex_m; //! extern crate cortex_m_rt; +//! extern crate cortex_m_semihosting; +//! +//! use core::fmt::Write; //! //! use cortex_m::asm; +//! use cortex_m_semihosting::hio; //! //! fn main() { //! // Initialize the allocator @@ -47,25 +55,26 @@ //! } //! //! // Size of the heap in words (1 word = 4 bytes) -//! // WARNING: The bigger the heap the greater the chance to run into a -//! // stack overflow (collision between the stack and the heap) +//! // NOTE The bigger the heap the greater the chance to run into a stack +//! // overflow (collision between the stack and the heap) //! const SIZE: isize = 256; //! //! // End of the heap //! let _eheap = (&mut _sheap as *mut _).offset(SIZE); //! -//! alloc_cortex_m::init(&mut _sheap as *mut _, _eheap); +//! alloc_cortex_m::init(&mut _sheap, _eheap); //! } //! //! // Growable array allocated on the heap //! let xs = vec![0, 1, 2]; -//! hprintln!("{:?}", xs); +//! +//! let mut stdout = hio::hstdout().unwrap(); +//! writeln!(stdout, "{:?}", xs).unwrap(); //! } //! //! // As we are not using interrupts, we just register a dummy catch all handler -//! #[allow(dead_code)] +//! #[link_section = ".vector_table.interrupts"] //! #[used] -//! #[link_section = ".rodata.interrupts"] //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! //! extern "C" fn default_handler() { diff --git a/src/examples/mod.rs b/src/examples/mod.rs index 5e0dad7..fd0e6e4 100644 --- a/src/examples/mod.rs +++ b/src/examples/mod.rs @@ -4,6 +4,6 @@ pub mod _0_hello; pub mod _1_itm; pub mod _2_panic; pub mod _3_crash; -pub mod _4_register_interrupt_handler; -pub mod _5_override_exception_handler; +pub mod _4_override_exception_handler; +pub mod _5_device; pub mod _6_allocator; diff --git a/src/lib.rs b/src/lib.rs index ff33878..e449b63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,11 +42,6 @@ //! FLASH : ORIGIN = 0x08000000, LENGTH = 256K //! RAM : ORIGIN = 0x20000000, LENGTH = 40K //! } -//! -//! /* This is where the call stack will be allocated. */ -//! /* The stack is of the full descending type. */ -//! /* NOTE Do NOT modify `_stack_start` unless you know what you are doing */ -//! _stack_start = ORIGIN(RAM) + LENGTH(RAM); //! ``` //! //! - Optionally, set a default build target @@ -62,10 +57,10 @@ //! //! ``` text //! # add a device crate, or -//! $ cargo add stm32f30x +//! $ cargo add stm32f103xx //! //! # add a board support crate -//! $ cargo add f3 +//! $ cargo add blue-pill --git https://github.com/japaric/blue-pill //! ``` //! //! - Write the application or start from one of the examples @@ -117,7 +112,7 @@ //! ``` //! //! ``` text -//! # Start debug session +//! # Start a debug session in another terminal //! $ arm-none-eabi-gdb target/.. //! ``` //!