v0.2.0
This commit is contained in:
@@ -5,6 +5,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [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
|
## [v0.1.8] - 2017-05-30
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
12
Cargo.toml
12
Cargo.toml
@@ -6,12 +6,16 @@ keywords = ["arm", "cortex-m", "template"]
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
name = "cortex-m-quickstart"
|
name = "cortex-m-quickstart"
|
||||||
repository = "https://github.com/japaric/cortex-m-quickstart"
|
repository = "https://github.com/japaric/cortex-m-quickstart"
|
||||||
version = "0.1.8"
|
version = "0.2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = "0.2.7"
|
cortex-m = "0.3.0"
|
||||||
cortex-m-rt = "0.2.3"
|
cortex-m-semihosting = "0.2.0"
|
||||||
|
|
||||||
|
[dependencies.cortex-m-rt]
|
||||||
|
features = ["abort-on-panic"]
|
||||||
|
version = "0.3.2"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
|
||||||
debug = true
|
debug = true
|
||||||
|
lto = true
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[dependencies.core]
|
[dependencies.core]
|
||||||
|
stage = 0
|
||||||
|
|
||||||
[dependencies.compiler_builtins]
|
[dependencies.compiler_builtins]
|
||||||
features = ["mem"]
|
|
||||||
git = "https://github.com/rust-lang-nursery/compiler-builtins"
|
git = "https://github.com/rust-lang-nursery/compiler-builtins"
|
||||||
stage = 1
|
stage = 1
|
||||||
@@ -6,10 +6,12 @@
|
|||||||
//!
|
//!
|
||||||
//! ``` text
|
//! ``` text
|
||||||
//! [dependencies.core]
|
//! [dependencies.core]
|
||||||
//! [dependencies.collections] # new
|
//! stage = 0
|
||||||
|
//!
|
||||||
|
//! [dependencies.collections] # NEW
|
||||||
|
//! stage = 0
|
||||||
//!
|
//!
|
||||||
//! [dependencies.compiler_builtins]
|
//! [dependencies.compiler_builtins]
|
||||||
//! features = ["mem"]
|
|
||||||
//! git = "https://github.com/rust-lang-nursery/compiler-builtins"
|
//! git = "https://github.com/rust-lang-nursery/compiler-builtins"
|
||||||
//! stage = 1
|
//! stage = 1
|
||||||
//! ```
|
//! ```
|
||||||
@@ -21,7 +23,10 @@
|
|||||||
//! # or edit the Cargo.toml file manually
|
//! # or edit the Cargo.toml file manually
|
||||||
//! $ cargo add alloc-cortex-m
|
//! $ cargo add alloc-cortex-m
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
#![feature(collections)]
|
#![feature(collections)]
|
||||||
#![feature(used)]
|
#![feature(used)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
@@ -30,11 +35,14 @@
|
|||||||
extern crate alloc_cortex_m;
|
extern crate alloc_cortex_m;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate collections;
|
extern crate collections;
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m;
|
extern crate cortex_m;
|
||||||
extern crate cortex_m_rt;
|
extern crate cortex_m_rt;
|
||||||
|
extern crate cortex_m_semihosting;
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
use cortex_m::asm;
|
use cortex_m::asm;
|
||||||
|
use cortex_m_semihosting::hio;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Initialize the allocator
|
// Initialize the allocator
|
||||||
@@ -45,25 +53,26 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Size of the heap in words (1 word = 4 bytes)
|
// Size of the heap in words (1 word = 4 bytes)
|
||||||
// WARNING: The bigger the heap the greater the chance to run into a
|
// NOTE The bigger the heap the greater the chance to run into a stack
|
||||||
// stack overflow (collision between the stack and the heap)
|
// overflow (collision between the stack and the heap)
|
||||||
const SIZE: isize = 256;
|
const SIZE: isize = 256;
|
||||||
|
|
||||||
// End of the heap
|
// End of the heap
|
||||||
let _eheap = (&mut _sheap as *mut _).offset(SIZE);
|
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
|
// Growable array allocated on the heap
|
||||||
let xs = vec![0, 1, 2];
|
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
|
// As we are not using interrupts, we just register a dummy catch all handler
|
||||||
#[allow(dead_code)]
|
#[link_section = ".vector_table.interrupts"]
|
||||||
#[used]
|
#[used]
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
extern "C" fn default_handler() {
|
||||||
|
|||||||
@@ -8,27 +8,55 @@
|
|||||||
//! In you run the example below, you'll be able to inspect the state of your
|
//! In you run the example below, you'll be able to inspect the state of your
|
||||||
//! program under the debugger using these commands:
|
//! program under the debugger using these commands:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ``` text
|
||||||
//! (gdb) # Stacked registers = program state during the crash
|
//! (gdb) # Exception frame = program state during the crash
|
||||||
//! (gdb) print/x *_sr
|
//! (gdb) print/x *ef
|
||||||
//! $1 = cortex_m::exception::StackedRegisters {
|
//! $1 = cortex_m::exception::ExceptionFrame {
|
||||||
//! r0 = 0x2fffffff,
|
//! r0 = 0x2fffffff,
|
||||||
//! r1 = 0x2fffffff,
|
//! r1 = 0x2fffffff,
|
||||||
//! r2 = 0x0,
|
//! r2 = 0x0,
|
||||||
//! r3 = 0x0,
|
//! r3 = 0x0,
|
||||||
//! r12 = 0x0,
|
//! r12 = 0x0,
|
||||||
//! lr = 0x8000443,
|
//! lr = 0x8000481,
|
||||||
//! pc = 0x8000190,
|
//! pc = 0x8000460,
|
||||||
//! xpsr = 0x61000200,
|
//! xpsr = 0x61000000,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! (gdb) # What exception was triggered?
|
|
||||||
//! (gdb) print _e
|
|
||||||
//! $2 = cortex_m::exception::Exception::HardFault
|
|
||||||
//!
|
|
||||||
//! (gdb) # Where did we come from?
|
//! (gdb) # Where did we come from?
|
||||||
//! (gdb) backtrace
|
//! (gdb) backtrace
|
||||||
|
//! #0 cortex_m_rt::default_handler (ef=0x20004f54) at (..)
|
||||||
|
//! #1 <signal handler called>
|
||||||
|
//! #2 0x08000460 in core::ptr::read_volatile<u32> (src=0x2fffffff) at (..)
|
||||||
|
//! #3 0x08000480 in crash::main () at examples/crash.rs:68
|
||||||
|
//!
|
||||||
|
//! (gdb) # Nail down the location of the crash
|
||||||
|
//! (gdb) disassemble/m ef.pc
|
||||||
|
//! Dump of assembler code for function core::ptr::read_volatile<u32>:
|
||||||
|
//! 408 pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||||
|
//! 0x08000454 <+0>: sub sp, #20
|
||||||
|
//! 0x08000456 <+2>: mov r1, r0
|
||||||
|
//! 0x08000458 <+4>: str r0, [sp, #8]
|
||||||
|
//! 0x0800045a <+6>: ldr r0, [sp, #8]
|
||||||
|
//! 0x0800045c <+8>: str r0, [sp, #12]
|
||||||
|
//!
|
||||||
|
//! 409 intrinsics::volatile_load(src)
|
||||||
|
//! 0x0800045e <+10>: ldr r0, [sp, #12]
|
||||||
|
//! 0x08000460 <+12>: ldr r0, [r0, #0]
|
||||||
|
//! 0x08000462 <+14>: str r0, [sp, #16]
|
||||||
|
//! 0x08000464 <+16>: ldr r0, [sp, #16]
|
||||||
|
//! 0x08000466 <+18>: str r1, [sp, #4]
|
||||||
|
//! 0x08000468 <+20>: str r0, [sp, #0]
|
||||||
|
//! 0x0800046a <+22>: b.n 0x800046c <core::ptr::read_volatile<u32>+24>
|
||||||
|
//!
|
||||||
|
//! 410 }
|
||||||
|
//! 0x0800046c <+24>: ldr r0, [sp, #0]
|
||||||
|
//! 0x0800046e <+26>: add sp, #20
|
||||||
|
//! 0x08000470 <+28>: bx lr
|
||||||
|
//!
|
||||||
|
//! End of assembler dump.
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
|
||||||
#![feature(used)]
|
#![feature(used)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
@@ -48,9 +76,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// As we are not using interrupts, we just register a dummy catch all handler
|
// As we are not using interrupts, we just register a dummy catch all handler
|
||||||
#[allow(dead_code)]
|
#[link_section = ".vector_table.interrupts"]
|
||||||
#[used]
|
#[used]
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
extern "C" fn default_handler() {
|
||||||
|
|||||||
58
examples/device.rs
Normal file
58
examples/device.rs
Normal file
@@ -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;
|
||||||
|
// ..
|
||||||
|
}
|
||||||
@@ -1,22 +1,27 @@
|
|||||||
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
|
||||||
#![feature(used)]
|
#![feature(used)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m;
|
extern crate cortex_m;
|
||||||
extern crate cortex_m_rt;
|
extern crate cortex_m_rt;
|
||||||
|
extern crate cortex_m_semihosting;
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
use cortex_m::asm;
|
use cortex_m::asm;
|
||||||
|
use cortex_m_semihosting::hio;
|
||||||
|
|
||||||
fn main() {
|
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
|
// As we are not using interrupts, we just register a dummy catch all handler
|
||||||
#[allow(dead_code)]
|
#[link_section = ".vector_table.interrupts"]
|
||||||
#[used]
|
#[used]
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
extern "C" fn default_handler() {
|
||||||
|
|||||||
@@ -7,9 +7,11 @@
|
|||||||
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
|
//! 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
|
//! 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/
|
//! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
|
||||||
#![feature(used)]
|
#![feature(used)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
@@ -21,19 +23,16 @@ extern crate cortex_m_rt;
|
|||||||
use cortex_m::{asm, interrupt, peripheral};
|
use cortex_m::{asm, interrupt, peripheral};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
interrupt::free(
|
interrupt::free(|cs| {
|
||||||
|cs| {
|
|
||||||
let itm = peripheral::ITM.borrow(&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
|
// As we are not using interrupts, we just register a dummy catch all handler
|
||||||
#[allow(dead_code)]
|
#[link_section = ".vector_table.interrupts"]
|
||||||
#[used]
|
#[used]
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
extern "C" fn default_handler() {
|
||||||
|
|||||||
@@ -1,17 +1,26 @@
|
|||||||
//! Overriding an exception
|
//! Overriding an exception handler
|
||||||
//!
|
//!
|
||||||
//! **NOTE** You have to disable the `cortex-m-rt` crate's "exceptions" feature
|
//! You can override an exception handler using the [`exception!`][1] macro.
|
||||||
//! to make this work.
|
//!
|
||||||
|
//! [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)]
|
#![feature(used)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate cortex_m;
|
extern crate cortex_m;
|
||||||
|
#[macro_use(exception)]
|
||||||
extern crate cortex_m_rt;
|
extern crate cortex_m_rt;
|
||||||
|
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
use cortex_m::{asm, exception};
|
use cortex_m::asm;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
unsafe {
|
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
|
// You'll hit this breakpoint rather than the one in cortex-m-rt
|
||||||
asm::bkpt()
|
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
|
// As we are not using interrupts, we just register a dummy catch all handler
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[used]
|
#[used]
|
||||||
#[link_section = ".rodata.interrupts"]
|
#[link_section = ".vector_table.interrupts"]
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
extern "C" fn default_handler() {
|
||||||
|
|||||||
@@ -1,33 +1,56 @@
|
|||||||
//! Redirecting `panic!` messages
|
//! Defining the panic handler
|
||||||
//!
|
//!
|
||||||
//! The `cortex-m-rt` crate provides two options to redirect `panic!` messages
|
//! The panic handler can be defined through the `panic_fmt` [language item][1].
|
||||||
//! through these two Cargo features:
|
//! 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
|
//! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html
|
||||||
//! console using semihosting. This is slow.
|
|
||||||
//!
|
//!
|
||||||
//! - `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)]
|
#![feature(used)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate cortex_m;
|
extern crate cortex_m;
|
||||||
extern crate cortex_m_rt;
|
extern crate cortex_m_rt;
|
||||||
|
extern crate cortex_m_semihosting;
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
use core::intrinsics;
|
||||||
|
|
||||||
use cortex_m::asm;
|
use cortex_m::asm;
|
||||||
|
use cortex_m_semihosting::hio;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
panic!("Oops");
|
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
|
// As we are not using interrupts, we just register a dummy catch all handler
|
||||||
#[allow(dead_code)]
|
#[link_section = ".vector_table.interrupts"]
|
||||||
#[used]
|
#[used]
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
extern "C" fn default_handler() {
|
||||||
|
|||||||
@@ -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
|
|
||||||
};
|
|
||||||
@@ -9,8 +9,8 @@ main() {
|
|||||||
itm
|
itm
|
||||||
panic
|
panic
|
||||||
crash
|
crash
|
||||||
register-interrupt-handler
|
|
||||||
override-exception-handler
|
override-exception-handler
|
||||||
|
device
|
||||||
allocator
|
allocator
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
9
memory.x
9
memory.x
@@ -8,12 +8,13 @@ MEMORY
|
|||||||
|
|
||||||
/* This is where the call stack will be allocated. */
|
/* This is where the call stack will be allocated. */
|
||||||
/* The stack is of the full descending type. */
|
/* The stack is of the full descending type. */
|
||||||
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
|
/* You may want to use this variable to locate the call stack and static
|
||||||
_stack_start = ORIGIN(RAM) + LENGTH(RAM);
|
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 */
|
/* 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
|
/* If omitted the .text section will be placed right after the .vector_table
|
||||||
section */
|
section */
|
||||||
/* This is required only on some microcontrollers that store some configuration
|
/* This is required only on microcontrollers that store some configuration right
|
||||||
right after the vector table */
|
after the vector table */
|
||||||
/* _stext = ORIGIN(FLASH) + 0x400; */
|
/* _stext = ORIGIN(FLASH) + 0x400; */
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
||||||
//!
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! #![feature(used)]
|
//! #![feature(used)]
|
||||||
//! #![no_std]
|
//! #![no_std]
|
||||||
//!
|
//!
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m;
|
//! extern crate cortex_m;
|
||||||
//! extern crate cortex_m_rt;
|
//! extern crate cortex_m_rt;
|
||||||
|
//! extern crate cortex_m_semihosting;
|
||||||
|
//!
|
||||||
|
//! use core::fmt::Write;
|
||||||
//!
|
//!
|
||||||
//! use cortex_m::asm;
|
//! use cortex_m::asm;
|
||||||
|
//! use cortex_m_semihosting::hio;
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! 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
|
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||||
//! #[allow(dead_code)]
|
//! #[link_section = ".vector_table.interrupts"]
|
||||||
//! #[used]
|
//! #[used]
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
//!
|
//!
|
||||||
//! extern "C" fn default_handler() {
|
//! extern "C" fn default_handler() {
|
||||||
|
|||||||
@@ -7,10 +7,12 @@
|
|||||||
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
|
//! 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
|
//! 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/
|
//! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/
|
||||||
//!
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! #![feature(used)]
|
//! #![feature(used)]
|
||||||
@@ -23,19 +25,16 @@
|
|||||||
//! use cortex_m::{asm, interrupt, peripheral};
|
//! use cortex_m::{asm, interrupt, peripheral};
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! interrupt::free(
|
//! interrupt::free(|cs| {
|
||||||
//! |cs| {
|
|
||||||
//! let itm = peripheral::ITM.borrow(&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
|
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||||
//! #[allow(dead_code)]
|
//! #[link_section = ".vector_table.interrupts"]
|
||||||
//! #[used]
|
//! #[used]
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
//!
|
//!
|
||||||
//! extern "C" fn default_handler() {
|
//! extern "C" fn default_handler() {
|
||||||
|
|||||||
@@ -1,35 +1,58 @@
|
|||||||
//! Redirecting `panic!` messages
|
//! Defining the panic handler
|
||||||
//!
|
//!
|
||||||
//! The `cortex-m-rt` crate provides two options to redirect `panic!` messages
|
//! The panic handler can be defined through the `panic_fmt` [language item][1].
|
||||||
//! through these two Cargo features:
|
//! 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
|
//! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html
|
||||||
//! console using semihosting. This is slow.
|
|
||||||
//!
|
//!
|
||||||
//! - `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)]
|
//! #![feature(used)]
|
||||||
//! #![no_std]
|
//! #![no_std]
|
||||||
//!
|
//!
|
||||||
//! extern crate cortex_m;
|
//! extern crate cortex_m;
|
||||||
//! extern crate cortex_m_rt;
|
//! extern crate cortex_m_rt;
|
||||||
|
//! extern crate cortex_m_semihosting;
|
||||||
|
//!
|
||||||
|
//! use core::fmt::Write;
|
||||||
|
//! use core::intrinsics;
|
||||||
//!
|
//!
|
||||||
//! use cortex_m::asm;
|
//! use cortex_m::asm;
|
||||||
|
//! use cortex_m_semihosting::hio;
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! panic!("Oops");
|
//! 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
|
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||||
//! #[allow(dead_code)]
|
//! #[link_section = ".vector_table.interrupts"]
|
||||||
//! #[used]
|
//! #[used]
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
//!
|
//!
|
||||||
//! extern "C" fn default_handler() {
|
//! extern "C" fn default_handler() {
|
||||||
|
|||||||
@@ -8,28 +8,56 @@
|
|||||||
//! In you run the example below, you'll be able to inspect the state of your
|
//! In you run the example below, you'll be able to inspect the state of your
|
||||||
//! program under the debugger using these commands:
|
//! program under the debugger using these commands:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ``` text
|
||||||
//! (gdb) # Stacked registers = program state during the crash
|
//! (gdb) # Exception frame = program state during the crash
|
||||||
//! (gdb) print/x *_sr
|
//! (gdb) print/x *ef
|
||||||
//! $1 = cortex_m::exception::StackedRegisters {
|
//! $1 = cortex_m::exception::ExceptionFrame {
|
||||||
//! r0 = 0x2fffffff,
|
//! r0 = 0x2fffffff,
|
||||||
//! r1 = 0x2fffffff,
|
//! r1 = 0x2fffffff,
|
||||||
//! r2 = 0x0,
|
//! r2 = 0x0,
|
||||||
//! r3 = 0x0,
|
//! r3 = 0x0,
|
||||||
//! r12 = 0x0,
|
//! r12 = 0x0,
|
||||||
//! lr = 0x8000443,
|
//! lr = 0x8000481,
|
||||||
//! pc = 0x8000190,
|
//! pc = 0x8000460,
|
||||||
//! xpsr = 0x61000200,
|
//! xpsr = 0x61000000,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! (gdb) # What exception was triggered?
|
|
||||||
//! (gdb) print _e
|
|
||||||
//! $2 = cortex_m::exception::Exception::HardFault
|
|
||||||
//!
|
|
||||||
//! (gdb) # Where did we come from?
|
//! (gdb) # Where did we come from?
|
||||||
//! (gdb) backtrace
|
//! (gdb) backtrace
|
||||||
|
//! #0 cortex_m_rt::default_handler (ef=0x20004f54) at (..)
|
||||||
|
//! #1 <signal handler called>
|
||||||
|
//! #2 0x08000460 in core::ptr::read_volatile<u32> (src=0x2fffffff) at (..)
|
||||||
|
//! #3 0x08000480 in crash::main () at examples/crash.rs:68
|
||||||
|
//!
|
||||||
|
//! (gdb) # Nail down the location of the crash
|
||||||
|
//! (gdb) disassemble/m ef.pc
|
||||||
|
//! Dump of assembler code for function core::ptr::read_volatile<u32>:
|
||||||
|
//! 408 pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||||
|
//! 0x08000454 <+0>: sub sp, #20
|
||||||
|
//! 0x08000456 <+2>: mov r1, r0
|
||||||
|
//! 0x08000458 <+4>: str r0, [sp, #8]
|
||||||
|
//! 0x0800045a <+6>: ldr r0, [sp, #8]
|
||||||
|
//! 0x0800045c <+8>: str r0, [sp, #12]
|
||||||
|
//!
|
||||||
|
//! 409 intrinsics::volatile_load(src)
|
||||||
|
//! 0x0800045e <+10>: ldr r0, [sp, #12]
|
||||||
|
//! 0x08000460 <+12>: ldr r0, [r0, #0]
|
||||||
|
//! 0x08000462 <+14>: str r0, [sp, #16]
|
||||||
|
//! 0x08000464 <+16>: ldr r0, [sp, #16]
|
||||||
|
//! 0x08000466 <+18>: str r1, [sp, #4]
|
||||||
|
//! 0x08000468 <+20>: str r0, [sp, #0]
|
||||||
|
//! 0x0800046a <+22>: b.n 0x800046c <core::ptr::read_volatile<u32>+24>
|
||||||
|
//!
|
||||||
|
//! 410 }
|
||||||
|
//! 0x0800046c <+24>: ldr r0, [sp, #0]
|
||||||
|
//! 0x0800046e <+26>: add sp, #20
|
||||||
|
//! 0x08000470 <+28>: bx lr
|
||||||
|
//!
|
||||||
|
//! End of assembler dump.
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! #![feature(used)]
|
//! #![feature(used)]
|
||||||
@@ -50,9 +78,8 @@
|
|||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||||
//! #[allow(dead_code)]
|
//! #[link_section = ".vector_table.interrupts"]
|
||||||
//! #[used]
|
//! #[used]
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
//!
|
//!
|
||||||
//! extern "C" fn default_handler() {
|
//! extern "C" fn default_handler() {
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
//! Overriding an exception
|
//! Overriding an exception handler
|
||||||
//!
|
//!
|
||||||
//! **NOTE** You have to disable the `cortex-m-rt` crate's "exceptions" feature
|
//! You can override an exception handler using the [`exception!`][1] macro.
|
||||||
//! to make this work.
|
//!
|
||||||
|
//! [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]
|
//! #![no_std]
|
||||||
//!
|
//!
|
||||||
//! extern crate cortex_m;
|
//! extern crate cortex_m;
|
||||||
|
//! #[macro_use(exception)]
|
||||||
//! extern crate cortex_m_rt;
|
//! extern crate cortex_m_rt;
|
||||||
//!
|
//!
|
||||||
//! use core::ptr;
|
//! use core::ptr;
|
||||||
//!
|
//!
|
||||||
//! use cortex_m::{asm, exception};
|
//! use cortex_m::asm;
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! unsafe {
|
//! 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
|
//! // You'll hit this breakpoint rather than the one in cortex-m-rt
|
||||||
//! asm::bkpt()
|
//! 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
|
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||||
//! #[allow(dead_code)]
|
//! #[allow(dead_code)]
|
||||||
//! #[used]
|
//! #[used]
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
//! #[link_section = ".vector_table.interrupts"]
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
//!
|
//!
|
||||||
//! extern "C" fn default_handler() {
|
//! extern "C" fn default_handler() {
|
||||||
@@ -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.
|
|
||||||
62
src/examples/_5_device.rs
Normal file
62
src/examples/_5_device.rs
Normal file
@@ -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.
|
||||||
@@ -6,10 +6,12 @@
|
|||||||
//!
|
//!
|
||||||
//! ``` text
|
//! ``` text
|
||||||
//! [dependencies.core]
|
//! [dependencies.core]
|
||||||
//! [dependencies.collections] # new
|
//! stage = 0
|
||||||
|
//!
|
||||||
|
//! [dependencies.collections] # NEW
|
||||||
|
//! stage = 0
|
||||||
//!
|
//!
|
||||||
//! [dependencies.compiler_builtins]
|
//! [dependencies.compiler_builtins]
|
||||||
//! features = ["mem"]
|
|
||||||
//! git = "https://github.com/rust-lang-nursery/compiler-builtins"
|
//! git = "https://github.com/rust-lang-nursery/compiler-builtins"
|
||||||
//! stage = 1
|
//! stage = 1
|
||||||
//! ```
|
//! ```
|
||||||
@@ -22,8 +24,11 @@
|
|||||||
//! $ cargo add alloc-cortex-m
|
//! $ cargo add alloc-cortex-m
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
//! #[allow(deprecated)]
|
||||||
//! #![feature(collections)]
|
//! #![feature(collections)]
|
||||||
//! #![feature(used)]
|
//! #![feature(used)]
|
||||||
//! #![no_std]
|
//! #![no_std]
|
||||||
@@ -32,11 +37,14 @@
|
|||||||
//! extern crate alloc_cortex_m;
|
//! extern crate alloc_cortex_m;
|
||||||
//! #[macro_use]
|
//! #[macro_use]
|
||||||
//! extern crate collections;
|
//! extern crate collections;
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m;
|
//! extern crate cortex_m;
|
||||||
//! extern crate cortex_m_rt;
|
//! extern crate cortex_m_rt;
|
||||||
|
//! extern crate cortex_m_semihosting;
|
||||||
|
//!
|
||||||
|
//! use core::fmt::Write;
|
||||||
//!
|
//!
|
||||||
//! use cortex_m::asm;
|
//! use cortex_m::asm;
|
||||||
|
//! use cortex_m_semihosting::hio;
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! // Initialize the allocator
|
//! // Initialize the allocator
|
||||||
@@ -47,25 +55,26 @@
|
|||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! // Size of the heap in words (1 word = 4 bytes)
|
//! // Size of the heap in words (1 word = 4 bytes)
|
||||||
//! // WARNING: The bigger the heap the greater the chance to run into a
|
//! // NOTE The bigger the heap the greater the chance to run into a stack
|
||||||
//! // stack overflow (collision between the stack and the heap)
|
//! // overflow (collision between the stack and the heap)
|
||||||
//! const SIZE: isize = 256;
|
//! const SIZE: isize = 256;
|
||||||
//!
|
//!
|
||||||
//! // End of the heap
|
//! // End of the heap
|
||||||
//! let _eheap = (&mut _sheap as *mut _).offset(SIZE);
|
//! 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
|
//! // Growable array allocated on the heap
|
||||||
//! let xs = vec![0, 1, 2];
|
//! 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
|
//! // As we are not using interrupts, we just register a dummy catch all handler
|
||||||
//! #[allow(dead_code)]
|
//! #[link_section = ".vector_table.interrupts"]
|
||||||
//! #[used]
|
//! #[used]
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
||||||
//!
|
//!
|
||||||
//! extern "C" fn default_handler() {
|
//! extern "C" fn default_handler() {
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ pub mod _0_hello;
|
|||||||
pub mod _1_itm;
|
pub mod _1_itm;
|
||||||
pub mod _2_panic;
|
pub mod _2_panic;
|
||||||
pub mod _3_crash;
|
pub mod _3_crash;
|
||||||
pub mod _4_register_interrupt_handler;
|
pub mod _4_override_exception_handler;
|
||||||
pub mod _5_override_exception_handler;
|
pub mod _5_device;
|
||||||
pub mod _6_allocator;
|
pub mod _6_allocator;
|
||||||
|
|||||||
11
src/lib.rs
11
src/lib.rs
@@ -42,11 +42,6 @@
|
|||||||
//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
||||||
//! RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
//! 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
|
//! - Optionally, set a default build target
|
||||||
@@ -62,10 +57,10 @@
|
|||||||
//!
|
//!
|
||||||
//! ``` text
|
//! ``` text
|
||||||
//! # add a device crate, or
|
//! # add a device crate, or
|
||||||
//! $ cargo add stm32f30x
|
//! $ cargo add stm32f103xx
|
||||||
//!
|
//!
|
||||||
//! # add a board support crate
|
//! # 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
|
//! - Write the application or start from one of the examples
|
||||||
@@ -117,7 +112,7 @@
|
|||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ``` text
|
//! ``` text
|
||||||
//! # Start debug session
|
//! # Start a debug session in another terminal
|
||||||
//! $ arm-none-eabi-gdb target/..
|
//! $ arm-none-eabi-gdb target/..
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|||||||
Reference in New Issue
Block a user