aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/itm.rs6
-rw-r--r--src/lib.rs10
-rw-r--r--src/macros.rs6
-rw-r--r--src/peripheral/dcb.rs21
-rw-r--r--src/peripheral/mod.rs1
-rw-r--r--src/peripheral/nvic.rs35
-rw-r--r--src/peripheral/scb.rs211
-rw-r--r--src/register/basepri.rs21
-rw-r--r--src/register/basepri_max.rs21
9 files changed, 297 insertions, 35 deletions
diff --git a/src/itm.rs b/src/itm.rs
index 0e32e3c..4f8dcf8 100644
--- a/src/itm.rs
+++ b/src/itm.rs
@@ -4,7 +4,7 @@
use core::{fmt, mem, ptr, slice};
-use aligned::Aligned;
+use aligned::{Aligned, A4};
use peripheral::itm::Stim;
@@ -77,7 +77,7 @@ pub fn write_all(port: &mut Stim, buffer: &[u8]) {
/// # Examples
///
/// ``` ignore
-/// let mut buffer: Aligned<u32, _> = Aligned([0; 14]);
+/// let mut buffer: Aligned<A4, _> = Aligned([0; 14]);
///
/// buffer.copy_from_slice(b"Hello, world!\n");
///
@@ -86,7 +86,7 @@ pub fn write_all(port: &mut Stim, buffer: &[u8]) {
/// // Or equivalently
/// itm::write_aligned(&itm.stim[0], &Aligned(*b"Hello, world!\n"));
/// ```
-pub fn write_aligned(port: &mut Stim, buffer: &Aligned<u32, [u8]>) {
+pub fn write_aligned(port: &mut Stim, buffer: &Aligned<A4, [u8]>) {
unsafe {
let len = buffer.len();
diff --git a/src/lib.rs b/src/lib.rs
index 540bc4d..fda3e01 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -7,25 +7,18 @@
//! - Interrupt manipulation mechanisms
//! - Safe wrappers around Cortex-M specific instructions like `bkpt`
//!
-//! # Requirements
-//!
-//! To use this crate on the stable or beta channel `arm-none-eabi-gcc` needs to be installed and
-//! available in your `$PATH`.
-//!
//! # Optional features
//!
//! ## `inline-asm`
//!
//! When this feature is enabled the implementation of all the functions inside the `asm` and
//! `register` modules use inline assembly (`asm!`) instead of external assembly (FFI into separate
-//! assembly files compiled using `arm-none-eabi-gcc`). The advantages the enabling `inline-asm`
+//! assembly files pre-compiled using `arm-none-eabi-gcc`). The advantages of enabling `inline-asm`
//! are:
//!
//! - Reduced overhead. FFI eliminates the possibility of inlining so all operations include a
//! function call overhead when `inline-asm` is not enabled.
//!
-//! - `arm-none-eabi-gcc` is not required for building this crate.
-//!
//! - Some of the `register` API only becomes available only when `inline-asm` is enabled. Check the
//! API docs for details.
//!
@@ -39,7 +32,6 @@
#![cfg_attr(feature = "inline-asm", feature(asm))]
#![deny(missing_docs)]
-#![deny(warnings)]
#![no_std]
extern crate aligned;
diff --git a/src/macros.rs b/src/macros.rs
index e41cdc5..813552f 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -13,13 +13,13 @@ macro_rules! iprint {
#[macro_export]
macro_rules! iprintln {
($channel:expr) => {
- iprint!($channel, "\n");
+ $crate::itm::write_str($channel, "\n");
};
($channel:expr, $fmt:expr) => {
- iprint!($channel, concat!($fmt, "\n"));
+ $crate::itm::write_str($channel, concat!($fmt, "\n"));
};
($channel:expr, $fmt:expr, $($arg:tt)*) => {
- iprint!($channel, concat!($fmt, "\n"), $($arg)*);
+ $crate::itm::write_fmt($channel, format_args!(concat!($fmt, "\n"), $($arg)*));
};
}
diff --git a/src/peripheral/dcb.rs b/src/peripheral/dcb.rs
index 02ec901..14dc75b 100644
--- a/src/peripheral/dcb.rs
+++ b/src/peripheral/dcb.rs
@@ -2,6 +2,10 @@
use volatile_register::{RW, WO};
+use peripheral::DCB;
+
+const DCB_DEMCR_TRCENA: u32 = 1 << 24;
+
/// Register block
#[repr(C)]
pub struct RegisterBlock {
@@ -14,3 +18,20 @@ pub struct RegisterBlock {
/// Debug Exception and Monitor Control
pub demcr: RW<u32>,
}
+
+impl DCB {
+ /// Enables TRACE. This is for example required by the
+ /// `peripheral::DWT` cycle counter to work properly.
+ /// As by STM documentation, this flag is not reset on
+ /// soft-reset, only on power reset.
+ pub fn enable_trace(&mut self) {
+ // set bit 24 / TRCENA
+ unsafe { self.demcr.modify(|w| w | DCB_DEMCR_TRCENA); }
+ }
+
+ /// Disables TRACE. See `DCB::enable_trace()` for more details
+ pub fn disable_trace(&mut self) {
+ // unset bit 24 / TRCENA
+ unsafe { self.demcr.modify(|w| w & !DCB_DEMCR_TRCENA); }
+ }
+}
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
index fe52bd1..6aacb73 100644
--- a/src/peripheral/mod.rs
+++ b/src/peripheral/mod.rs
@@ -77,7 +77,6 @@
// TODO stand-alone registers: ICTR, ACTLR and STIR
-#![allow(private_no_mangle_statics)]
use core::marker::PhantomData;
use core::ops;
diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
index 1a6a027..c59c2c8 100644
--- a/src/peripheral/nvic.rs
+++ b/src/peripheral/nvic.rs
@@ -69,13 +69,12 @@ pub struct RegisterBlock {
impl NVIC {
/// Clears `interrupt`'s pending state
+ #[deprecated(since = "0.5.8", note = "Use `NVIC::unpend`")]
pub fn clear_pending<I>(&mut self, interrupt: I)
where
I: Nr,
{
- let nr = interrupt.nr();
-
- unsafe { self.icpr[usize::from(nr / 32)].write(1 << (nr % 32)) }
+ Self::unpend(interrupt)
}
/// Disables `interrupt`
@@ -161,13 +160,23 @@ impl NVIC {
}
/// Forces `interrupt` into pending state
- pub fn set_pending<I>(&mut self, interrupt: I)
+ pub fn pend<I>(interrupt: I)
where
I: Nr,
{
let nr = interrupt.nr();
- unsafe { self.ispr[usize::from(nr / 32)].write(1 << (nr % 32)) }
+ // NOTE(unsafe) atomic stateless write; ICPR doesn't store any state
+ unsafe { (*Self::ptr()).ispr[usize::from(nr / 32)].write(1 << (nr % 32)) }
+ }
+
+ /// Forces `interrupt` into pending state
+ #[deprecated(since = "0.5.8", note = "Use `NVIC::pend`")]
+ pub fn set_pending<I>(&mut self, interrupt: I)
+ where
+ I: Nr,
+ {
+ Self::pend(interrupt)
}
/// Sets the "priority" of `interrupt` to `prio`
@@ -177,6 +186,11 @@ impl NVIC {
///
/// On ARMv6-M, updating an interrupt priority requires a read-modify-write operation. On
/// ARMv7-M, the operation is performed in a single atomic write operation.
+ ///
+ /// # Unsafety
+ ///
+ /// Changing priority levels can break priority-based critical sections (see
+ /// [`register::basepri`](../register/basepri/index.html)) and compromise memory safety.
pub unsafe fn set_priority<I>(&mut self, interrupt: I, prio: u8)
where
I: Nr,
@@ -198,6 +212,17 @@ impl NVIC {
}
}
+ /// Clears `interrupt`'s pending state
+ pub fn unpend<I>(interrupt: I)
+ where
+ I: Nr,
+ {
+ let nr = interrupt.nr();
+
+ // NOTE(unsafe) atomic stateless write; ICPR doesn't store any state
+ unsafe { (*Self::ptr()).icpr[usize::from(nr / 32)].write(1 << (nr % 32)) }
+ }
+
#[cfg(armv6m)]
fn ipr_index<I>(interrupt: &I) -> usize
where
diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs
index ba36093..c82e098 100644
--- a/src/peripheral/scb.rs
+++ b/src/peripheral/scb.rs
@@ -7,9 +7,9 @@ use volatile_register::RW;
#[cfg(not(armv6m))]
use super::cpuid::CsselrCacheType;
#[cfg(not(armv6m))]
-use super::CPUID;
-#[cfg(not(armv6m))]
use super::CBP;
+#[cfg(not(armv6m))]
+use super::CPUID;
use super::SCB;
/// Register block
@@ -19,10 +19,7 @@ pub struct RegisterBlock {
pub icsr: RW<u32>,
/// Vector Table Offset (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
pub vtor: RW<u32>,
- #[cfg(armv6m)]
- _reserved0: u32,
/// Application Interrupt and Reset Control
pub aircr: RW<u32>,
@@ -598,3 +595,207 @@ impl SCB {
}
}
}
+
+const SCB_SCR_SLEEPONEXIT: u32 = 0x1 << 1;
+
+impl SCB {
+ /// Set the SLEEPONEXIT bit in the SCR register
+ pub fn set_sleeponexit(&mut self) {
+ unsafe {
+ self.scr.modify(|scr| scr | SCB_SCR_SLEEPONEXIT);
+ }
+ }
+
+ /// Clear the SLEEPONEXIT bit in the SCR register
+ pub fn clear_sleeponexit(&mut self) {
+ unsafe {
+ self.scr.modify(|scr| scr & !SCB_SCR_SLEEPONEXIT);
+ }
+ }
+}
+
+const SCB_AIRCR_VECTKEY: u32 = 0x05FA << 16;
+const SCB_AIRCR_PRIGROUP_MASK: u32 = 0x5 << 8;
+const SCB_AIRCR_SYSRESETREQ: u32 = 1 << 2;
+
+impl SCB {
+ /// Initiate a system reset request to reset the MCU
+ pub fn system_reset(&mut self) -> ! {
+ ::asm::dsb();
+ unsafe {
+ self.aircr.modify(
+ |r| {
+ SCB_AIRCR_VECTKEY | // otherwise the write is ignored
+ r & SCB_AIRCR_PRIGROUP_MASK | // keep priority group unchanged
+ SCB_AIRCR_SYSRESETREQ
+ }, // set the bit
+ )
+ };
+ ::asm::dsb();
+ loop {
+ // wait for the reset
+ ::asm::nop(); // avoid rust-lang/rust#28728
+ }
+ }
+}
+
+const SCB_ICSR_PENDSVSET: u32 = 1 << 28;
+const SCB_ICSR_PENDSVCLR: u32 = 1 << 27;
+
+const SCB_ICSR_PENDSTSET: u32 = 1 << 26;
+const SCB_ICSR_PENDSTCLR: u32 = 1 << 25;
+
+impl SCB {
+ /// Set the PENDSVSET bit in the ICSR register which will pend the PendSV interrupt
+ pub fn set_pendsv() {
+ unsafe {
+ (*Self::ptr()).icsr.write(SCB_ICSR_PENDSVSET);
+ }
+ }
+
+ /// Check if PENDSVSET bit in the ICSR register is set meaning PendSV interrupt is pending
+ pub fn is_pendsv_pending() -> bool {
+ unsafe { (*Self::ptr()).icsr.read() & SCB_ICSR_PENDSVSET == SCB_ICSR_PENDSVSET }
+ }
+
+ /// Set the PENDSVCLR bit in the ICSR register which will clear a pending PendSV interrupt
+ pub fn clear_pendsv() {
+ unsafe {
+ (*Self::ptr()).icsr.write(SCB_ICSR_PENDSVCLR);
+ }
+ }
+
+ /// Set the PENDSTCLR bit in the ICSR register which will clear a pending SysTick interrupt
+ #[inline]
+ pub fn set_pendst() {
+ unsafe {
+ (*Self::ptr()).icsr.write(SCB_ICSR_PENDSTSET);
+ }
+ }
+
+ /// Check if PENDSTSET bit in the ICSR register is set meaning SysTick interrupt is pending
+ #[inline]
+ pub fn is_pendst_pending() -> bool {
+ unsafe { (*Self::ptr()).icsr.read() & SCB_ICSR_PENDSTSET == SCB_ICSR_PENDSTSET }
+ }
+
+ /// Set the PENDSTCLR bit in the ICSR register which will clear a pending SysTick interrupt
+ #[inline]
+ pub fn clear_pendst() {
+ unsafe {
+ (*Self::ptr()).icsr.write(SCB_ICSR_PENDSTCLR);
+ }
+ }
+}
+
+/// System handlers, exceptions with configurable priority
+#[allow(non_camel_case_types)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum SystemHandler {
+ // NonMaskableInt, // priority is fixed
+ // HardFault, // priority is fixed
+ /// Memory management interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ MemoryManagement,
+
+ /// Bus fault interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ BusFault,
+
+ /// Usage fault interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ UsageFault,
+
+ /// Secure fault interrupt (only on ARMv8-M)
+ #[cfg(any(armv8m, target_arch = "x86_64"))]
+ SecureFault,
+
+ /// SV call interrupt
+ SVCall,
+
+ /// Debug monitor interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ DebugMonitor,
+
+ /// Pend SV interrupt
+ PendSV,
+
+ /// System Tick interrupt
+ SysTick,
+}
+
+impl SystemHandler {
+ fn index(&self) -> u8 {
+ match *self {
+ #[cfg(not(armv6m))]
+ SystemHandler::MemoryManagement => 4,
+ #[cfg(not(armv6m))]
+ SystemHandler::BusFault => 5,
+ #[cfg(not(armv6m))]
+ SystemHandler::UsageFault => 6,
+ #[cfg(any(armv8m, target_arch = "x86_64"))]
+ SystemHandler::SecureFault => 7,
+ SystemHandler::SVCall => 11,
+ #[cfg(not(armv6m))]
+ SystemHandler::DebugMonitor => 12,
+ SystemHandler::PendSV => 14,
+ SystemHandler::SysTick => 15,
+ }
+ }
+}
+
+impl SCB {
+ /// Returns the hardware priority of `system_handler`
+ ///
+ /// *NOTE*: Hardware priority does not exactly match logical priority levels. See
+ /// [`NVIC.get_priority`](struct.NVIC.html#method.get_priority) for more details.
+ pub fn get_priority(system_handler: SystemHandler) -> u8 {
+ let index = system_handler.index();
+
+ #[cfg(not(armv6m))]
+ {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).shpr[usize::from(index - 4)].read() }
+ }
+
+ #[cfg(armv6m)]
+ {
+ // NOTE(unsafe) atomic read with no side effects
+ let shpr = unsafe { (*Self::ptr()).shpr[usize::from((index - 8) / 4)].read() };
+ let prio = (shpr >> (8 * (index % 4))) & 0x000000ff;
+ prio as u8
+ }
+ }
+
+ /// Sets the hardware priority of `system_handler` to `prio`
+ ///
+ /// *NOTE*: Hardware priority does not exactly match logical priority levels. See
+ /// [`NVIC.get_priority`](struct.NVIC.html#method.get_priority) for more details.
+ ///
+ /// On ARMv6-M, updating a system handler priority requires a read-modify-write operation. On
+ /// ARMv7-M, the operation is performed in a single, atomic write operation.
+ ///
+ /// # Unsafety
+ ///
+ /// Changing priority levels can break priority-based critical sections (see
+ /// [`register::basepri`](../register/basepri/index.html)) and compromise memory safety.
+ pub unsafe fn set_priority(&mut self, system_handler: SystemHandler, prio: u8) {
+ let index = system_handler.index();
+
+ #[cfg(not(armv6m))]
+ {
+ self.shpr[usize::from(index - 4)].write(prio)
+ }
+
+ #[cfg(armv6m)]
+ {
+ self.shpr[usize::from((index - 8) / 4)].modify(|value| {
+ let shift = 8 * (index % 4);
+ let mask = 0x000000ff << shift;
+ let prio = u32::from(prio) << shift;
+
+ (value & !mask) | prio
+ });
+ }
+ }
+}
diff --git a/src/register/basepri.rs b/src/register/basepri.rs
index c9f09cc..a9cd6ef 100644
--- a/src/register/basepri.rs
+++ b/src/register/basepri.rs
@@ -45,13 +45,24 @@ pub unsafe fn write(_basepri: u8) {
},
#[cfg(all(cortex_m, not(feature = "inline-asm")))]
- () => {
- extern "C" {
- fn __basepri_w(_: u8);
+ () => match () {
+ #[cfg(not(feature = "cm7-r0p1"))]
+ () => {
+ extern "C" {
+ fn __basepri_w(_: u8);
+ }
+
+ __basepri_w(_basepri);
}
+ #[cfg(feature = "cm7-r0p1")]
+ () => {
+ extern "C" {
+ fn __basepri_w_cm7_r0p1(_: u8);
+ }
- __basepri_w(_basepri);
- }
+ __basepri_w_cm7_r0p1(_basepri);
+ }
+ },
#[cfg(not(cortex_m))]
() => unimplemented!(),
diff --git a/src/register/basepri_max.rs b/src/register/basepri_max.rs
index 91698b6..59ddb44 100644
--- a/src/register/basepri_max.rs
+++ b/src/register/basepri_max.rs
@@ -24,11 +24,24 @@ pub fn write(_basepri: u8) {
#[cfg(all(cortex_m, not(feature = "inline-asm")))]
() => unsafe {
- extern "C" {
- fn __basepri_max(_: u8);
- }
+ match () {
+ #[cfg(not(feature = "cm7-r0p1"))]
+ () => {
+ extern "C" {
+ fn __basepri_max(_: u8);
+ }
- __basepri_max(_basepri)
+ __basepri_max(_basepri)
+ }
+ #[cfg(feature = "cm7-r0p1")]
+ () => {
+ extern "C" {
+ fn __basepri_max_cm7_r0p1(_: u8);
+ }
+
+ __basepri_max_cm7_r0p1(_basepri)
+ }
+ }
},
#[cfg(not(cortex_m))]