Skip to content

v0.2.0 #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Mar 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4979a7d
changes to better integrate with svd2rust
Feb 28, 2017
5959572
hide the registers of the NVIC register block
Feb 28, 2017
4a40edc
NVIC: fix set/get_priority methods
Feb 28, 2017
afa752b
add shortcut for 'MSR BASEPRI_MAX'
Feb 28, 2017
fede207
fix get/set_priority
Mar 1, 2017
b4f105c
add a critical section token to `interrupt::free`
Mar 2, 2017
251d1aa
review safety of the existing API, make the register API type safe
Mar 5, 2017
fe0461f
fix cfg: thumbv6m -> armv6m
Mar 5, 2017
a8ae7c2
remove an unnecessary cast
Mar 5, 2017
9d3f3f3
nvic: don't shift the priority
Mar 5, 2017
c3a35c1
revamp for memory safety
Mar 8, 2017
0e628b3
turn bkpt! into a function
Mar 8, 2017
559da5e
add macros for writing to an ITM port
Mar 8, 2017
1313393
remove the semihosting Cargo feature
Mar 8, 2017
50d1989
add a borrow method to Peripheral
Mar 8, 2017
eb24793
improve throughput of ITM functions
Mar 9, 2017
8363022
remove macro_reexport feature gate
Mar 10, 2017
f2d4e38
rename Token to Context
Mar 11, 2017
81c9d39
CsCtxt renamed to CriticalSection. Mutex.lock removed in favor of Mut…
Mar 11, 2017
f6615b0
reformat
Mar 11, 2017
a9d701e
add a Local.borrow_mut method, default_handler now takes the context …
Mar 11, 2017
6db72a5
add Mutex.borrow_mut method
Mar 12, 2017
e666c0b
make ITM functions operate on `Stim`
Mar 12, 2017
9f2374a
update the changelog
Mar 12, 2017
e1a67e7
update CI scripts
Mar 12, 2017
511d3c9
add documentation to the ctxt module
Mar 12, 2017
23c2ee2
ci: manually generate lockfile
Mar 12, 2017
6d4478d
remove unsafe from exception::default_handler
Mar 12, 2017
d6f9534
pin to an older nightly
Mar 12, 2017
0856d2c
fix doctests
Mar 12, 2017
173b5bc
add unsafe block
Mar 12, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
dist: trusty
language: rust
rust: nightly
rust: nightly-2017-03-04
services: docker
sudo: required

Expand Down
58 changes: 51 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,50 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added

- Semihosting functionality in the `semihosting` module.

- `exception::Handlers` struct that represent the section of the vector table
that contains the exception handlers.

- A default exception handler

- A high level API for the NVIC peripheral.

- Context local data.

- `borrow`/`borrow_mut` methods to `Mutex` that replace `lock`.

- API and macros to send bytes / (formatted) strings through ITM

### Changed

- [breaking-change] `StackFrame` has been renamed to `StackedRegisters` and
moved into the `exceptions` module.

- [breaking-change] Core peripherals can now be modified via a `&-` reference
and are no longer `Sync`.

- [breaking-change] `interrupt::free`'s closure now includes a critical section
token, `CriticalSection`.

- [breaking-change] the core register API has been revamped for type safety.

- The safety of assembly wrappers like `wfi` and `interrupt::free` has been
reviewed. In many cases, the functions are no longer unsafe.

- [breaking-change] `bkpt!` has been turned into a function. It no longer
accepts an immediate value.

### Removed

- `vector_table` and its associated `struct`, `VectorTable`. It's not a good
idea to give people a simple way to call the exception handlers.

- `Mutex`'s `lock` method as it's unsound. You could use it to get multiple
`&mut -` references to the wrapped data.

## [v0.1.6] - 2017-01-22

### Added
Expand Down Expand Up @@ -60,10 +104,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Functions to get the vector table
- Wrappers over miscellaneous instructions like `bkpt`

[Unreleased]: https://github.com/japaric/rustc-cfg/compare/v0.1.6...HEAD
[v0.1.6]: https://github.com/japaric/rustc-cfg/compare/v0.1.5...v0.1.6
[v0.1.5]: https://github.com/japaric/rustc-cfg/compare/v0.1.4...v0.1.5
[v0.1.4]: https://github.com/japaric/rustc-cfg/compare/v0.1.3...v0.1.4
[v0.1.3]: https://github.com/japaric/rustc-cfg/compare/v0.1.2...v0.1.3
[v0.1.2]: https://github.com/japaric/rustc-cfg/compare/v0.1.1...v0.1.2
[v0.1.1]: https://github.com/japaric/rustc-cfg/compare/v0.1.0...v0.1.1
[Unreleased]: https://github.com/japaric/cortex-m/compare/v0.1.6...HEAD
[v0.1.6]: https://github.com/japaric/cortex-m/compare/v0.1.5...v0.1.6
[v0.1.5]: https://github.com/japaric/cortex-m/compare/v0.1.4...v0.1.5
[v0.1.4]: https://github.com/japaric/cortex-m/compare/v0.1.3...v0.1.4
[v0.1.3]: https://github.com/japaric/cortex-m/compare/v0.1.2...v0.1.3
[v0.1.2]: https://github.com/japaric/cortex-m/compare/v0.1.1...v0.1.2
[v0.1.1]: https://github.com/japaric/cortex-m/compare/v0.1.0...v0.1.1
7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ keywords = ["arm", "cortex-m", "register", "peripheral"]
license = "MIT OR Apache-2.0"
name = "cortex-m"
repository = "https://github.com/japaric/cortex-m"
version = "0.1.6"
version = "0.2.0"

[dependencies]
volatile-register = "0.1.0"
volatile-register = "0.2.0"

[dependencies.cortex-m-semihosting]
version = "0.1.3"
9 changes: 9 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use std::env;

fn main() {
let target = env::var("TARGET").unwrap();

if target.starts_with("thumbv6m-") {
println!("cargo:rustc-cfg=armv6m")
}
}
7 changes: 6 additions & 1 deletion ci/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ main() {
curl https://sh.rustup.rs -sSf | \
sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION

local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
| cut -d/ -f3 \
| grep -E '^v[0-9.]+$' \
| sort --version-sort \
| tail -n1)
curl -LSfs http://japaric.github.io/trust/install.sh | \
sh -s -- \
--force \
--git japaric/cross \
--tag v0.1.2 \
--tag $tag \
--target x86_64-unknown-linux-musl \
--to ~/.cargo/bin
}
Expand Down
80 changes: 41 additions & 39 deletions src/asm.rs
Original file line number Diff line number Diff line change
@@ -1,58 +1,60 @@
//! Miscellaneous assembly instructions

/// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint".
/// Puts the processor in Debug state. Debuggers can pick this up as a
/// "breakpoint".
///
/// Optionally, an "immediate" value (in the 0-255 range) can be passed to `bkpt!`. The debugger can
/// then read this value using the Program Counter (PC).
#[cfg(target_arch = "arm")]
#[macro_export]
macro_rules! bkpt {
() => {
asm!("bkpt" :::: "volatile");
};
($imm:expr) => {
asm!(concat!("bkpt #", stringify!($imm)) :::: "volatile");
};
/// NOTE calling `bkpt` when the processor is not connected to a debugger will
/// cause an exception
#[inline(always)]
pub fn bkpt() {
#[cfg(target_arch = "arm")]
unsafe {
asm!("bkpt"
:
:
:
: "volatile");
}
}

/// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint".
///
/// Optionally, an "immediate" value (in the 0-255 range) can be passed to `bkpt!`. The debugger can
/// then read this value using the Program Counter (PC).
#[cfg(not(target_arch = "arm"))]
#[macro_export]
macro_rules! bkpt {
() => {
asm!("nop" :::: "volatile");
};
($e:expr) => {
asm!("nop" :::: "volatile");
};
/// A no-operation. Useful to prevent delay loops from being optimized away.
pub fn nop() {
unsafe {
asm!("nop"
:
:
:
: "volatile");
}
}

/// Wait for event
pub unsafe fn wfe() {
/// Wait For Event
pub fn wfe() {
match () {
#[cfg(target_arch = "arm")]
() => asm!("wfe" :::: "volatile"),
() => unsafe {
asm!("wfe"
:
:
:
: "volatile")
},
#[cfg(not(target_arch = "arm"))]
() => {}
}
}

/// Wait for interupt
pub unsafe fn wfi() {
/// Wait For Interrupt
pub fn wfi() {
match () {
#[cfg(target_arch = "arm")]
() => asm!("wfi" :::: "volatile"),
() => unsafe{
asm!("wfi"
:
:
:
: "volatile")
},
#[cfg(not(target_arch = "arm"))]
() => {}
}
}

/// A no-operation. Useful to stop delay loops being elided.
pub fn nop() {
unsafe {
asm!("nop" :::: "volatile");
}
}
160 changes: 160 additions & 0 deletions src/ctxt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
//! Interrupt / Exception context local data
//!
//! The main use case is safely adding state to exception / interrupt handlers.
//!
//! This is done in two stages, first you define a token that will appear in the
//! interrupt handler signature; each handler will have its unique token. This
//! token must be zero sized type because interrupt handlers' real signature is
//! `fn()` and it must also implement the `Context` trait. You must also make
//! sure that the token can't be constructed outside of the crate where it's
//! defined.
//!
//! ```
//! # use cortex_m::ctxt::Context;
//! // This must be in a library crate
//! /// Token unique to the TIM7 interrupt handler
//! pub struct Tim7 { _0: () }
//!
//! unsafe impl Context for Tim7 {}
//! ```
//!
//! Then in the application one can pin data to the interrupt handler using
//! `Local`.
//!
//! ```
//! # #![feature(const_fn)]
//! # use std::cell::Cell;
//! # use cortex_m::ctxt::{Context, Local};
//! # struct Tim7;
//! # unsafe impl Context for Tim7 {}
//! // omitted: how to put this handler in the vector table
//! extern "C" fn tim7(ctxt: Tim7) {
//! static STATE: Local<Cell<bool>, Tim7> = Local::new(Cell::new(false));
//!
//! let state = STATE.borrow(&ctxt);
//!
//! // toggle state
//! state.set(!state.get());
//!
//! if state.get() {
//! // something
//! } else {
//! // something else
//! }
//! }
//! ```
//!
//! Note that due to the uniqueness of tokens, other handlers won't be able to
//! access context local data. (Given that you got the signatures right)
//!
//! ```
//! # #![feature(const_fn)]
//! # use std::cell::Cell;
//! # use cortex_m::ctxt::{Context, Local};
//! # struct Tim3;
//! # struct Tim4;
//! static TIM3_DATA: Local<Cell<bool>, Tim3> = Local::new(Cell::new(false));
//!
//! extern "C" fn tim3(ctxt: Tim3) {
//! let data = TIM3_DATA.borrow(&ctxt);
//! }
//!
//! extern "C" fn tim4(ctxt: Tim4) {
//! //let data = TIM3_DATA.borrow(&ctxt);
//! // ^ wouldn't work
//! }
//! # unsafe impl Context for Tim3 {}
//! # fn main() {}
//! ```
//!
//! To have the application use these tokenized function signatures, you can
//! define, in a library, a `Handlers` struct that represents the vector table:
//!
//! ```
//! # struct Tim1;
//! # struct Tim2;
//! # struct Tim3;
//! # struct Tim4;
//! # extern "C" fn default_handler<T>(_: T) {}
//! #[repr(C)]
//! pub struct Handlers {
//! tim1: extern "C" fn(Tim1),
//! tim2: extern "C" fn(Tim2),
//! tim3: extern "C" fn(Tim3),
//! tim4: extern "C" fn(Tim4),
//! /* .. */
//! }
//!
//! pub const DEFAULT_HANDLERS: Handlers = Handlers {
//! tim1: default_handler,
//! tim2: default_handler,
//! tim3: default_handler,
//! tim4: default_handler,
//! /* .. */
//! };
//! ```
//!
//! Then have the user use that `struct` to register the interrupt handlers:
//!
//! ```
//! # struct Tim3;
//! # struct Handlers { tim3: extern "C" fn(Tim3), tim4: extern "C" fn(Tim3) }
//! # const DEFAULT_HANDLERS: Handlers = Handlers { tim3: tim3, tim4: tim3 };
//! extern "C" fn tim3(ctxt: Tim3) { /* .. */ }
//!
//! // override the TIM3 interrupt handler
//! #[no_mangle]
//! static _INTERRUPTS: Handlers = Handlers {
//! tim3: tim3, ..DEFAULT_HANDLERS
//! };
//! ```
//!
//! This pattern is implemented for exceptions in this crate. See
//! `exception::Handlers` and `exception::DEFAULT_HANDLERS`.

use core::marker::PhantomData;
use core::cell::UnsafeCell;

/// Data local to a context
pub struct Local<T, Ctxt>
where
Ctxt: Context,
{
_ctxt: PhantomData<Ctxt>,
data: UnsafeCell<T>,
}

impl<T, Ctxt> Local<T, Ctxt>
where
Ctxt: Context,
{
/// Initializes context local data
pub const fn new(value: T) -> Self {
Local {
_ctxt: PhantomData,
data: UnsafeCell::new(value),
}
}

/// Acquires a reference to the context local data
pub fn borrow<'ctxt>(&'static self, _ctxt: &'ctxt Ctxt) -> &'ctxt T {
unsafe { &*self.data.get() }
}

/// Acquires a mutable reference to the context local data
pub fn borrow_mut<'ctxt>(
&'static self,
_ctxt: &'ctxt mut Ctxt,
) -> &'ctxt mut T {
unsafe { &mut *self.data.get() }
}
}

unsafe impl<T, Ctxt> Sync for Local<T, Ctxt>
where
Ctxt: Context,
{
}

/// A token unique to a context
pub unsafe trait Context {}
Loading