aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Viktor Sonesten <v@tmplt.dev> 2021-10-27 00:23:07 +0200
committerGravatar Viktor Sonesten <v@tmplt.dev> 2021-10-27 00:23:07 +0200
commit880b947c44e78fd07d7c231a3c0c82ed3e54b9ef (patch)
treec8f67545f42ab2311b57150f20c57c4e9903551a
parentaa17958147ac57af6f10de170d869626397ba1d8 (diff)
parent6b013138b734b9bbeb24a345f75d2bcc1c69fa8d (diff)
downloadcortex-m-880b947c44e78fd07d7c231a3c0c82ed3e54b9ef.tar.gz
cortex-m-880b947c44e78fd07d7c231a3c0c82ed3e54b9ef.tar.zst
cortex-m-880b947c44e78fd07d7c231a3c0c82ed3e54b9ef.zip
Merge branch 'master' into feat/tracing
-rw-r--r--CHANGELOG.md31
-rw-r--r--Cargo.toml5
-rw-r--r--src/delay.rs32
-rw-r--r--src/peripheral/ac.rs93
-rw-r--r--src/peripheral/dwt.rs162
-rw-r--r--src/peripheral/mod.rs39
-rw-r--r--src/peripheral/nvic.rs2
-rw-r--r--src/peripheral/scb.rs4
8 files changed, 347 insertions, 21 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d29633..2e7d1e7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+### Added
+- Added support for additional DWT counters (#349)
+ - CPI counter
+ - Exception overhead counter
+ - LSU counter
+ - Folded-instruction counter
+- Added `DWT.set_cycle_count` (#347).
+- Added support for the Cortex-M7 TCM and cache access control registers.
+ There is a feature `cm7` to enable access to these.
+
+### Deprecated
+
+- `DWT::get_cycle_count` has been deprecated in favor of `DWT::cycle_count`.
+ This change was made for consistency with the [C-GETTER] convention. (#349)
+
+[C-GETTER]: https://rust-lang.github.io/api-guidelines/naming.html#c-getter
+
+## [v0.7.3] - 2021-07-03
+
+### Fixed
+
+- Fixed compilation for native targets on non-x86 host systems (#336, #337).
+
+### Added
+
+- The `Delay` struct now offers direct `delay_us()` and `delay_ms()` methods
+ without having to go through the embedded-hal traits (#344).
+
## [v0.7.2] - 2021-03-07
### Fixed
@@ -689,7 +717,8 @@ fn main() {
- Functions to get the vector table
- Wrappers over miscellaneous instructions like `bkpt`
-[Unreleased]: https://github.com/rust-embedded/cortex-m/compare/v0.7.2...HEAD
+[Unreleased]: https://github.com/rust-embedded/cortex-m/compare/v0.7.3...HEAD
+[v0.7.3]: https://github.com/rust-embedded/cortex-m/compare/v0.7.2...v0.7.3
[v0.7.2]: https://github.com/rust-embedded/cortex-m/compare/v0.7.1...v0.7.2
[v0.7.1]: https://github.com/rust-embedded/cortex-m/compare/v0.7.0...v0.7.1
[v0.7.0]: https://github.com/rust-embedded/cortex-m/compare/v0.6.4...v0.7.0
diff --git a/Cargo.toml b/Cargo.toml
index 7e605a8..19aa249 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0"
name = "cortex-m"
readme = "README.md"
repository = "https://github.com/rust-embedded/cortex-m"
-version = "0.7.2"
+version = "0.7.3"
edition = "2018"
links = "cortex-m" # prevent multiple versions of this crate to be linked together
@@ -22,7 +22,8 @@ bitfield = "0.13.2"
embedded-hal = "0.2.4"
[features]
-cm7-r0p1 = []
+cm7 = []
+cm7-r0p1 = ["cm7"]
inline-asm = []
linker-plugin-lto = []
diff --git a/src/delay.rs b/src/delay.rs
index 2f5b8e0..8ed1fea 100644
--- a/src/delay.rs
+++ b/src/delay.rs
@@ -29,8 +29,10 @@ impl Delay {
self.syst
}
- fn _delay_us(&mut self, us: u32) {
- let ticks = (us as u64) * (self.ahb_frequency as u64) / 1_000_000;
+ /// Delay using the Cortex-M systick for a certain duration, in µs.
+ #[allow(clippy::missing_inline_in_public_items)]
+ pub fn delay_us(&mut self, us: u32) {
+ let ticks = (u64::from(us)) * (u64::from(self.ahb_frequency)) / 1_000_000;
let full_cycles = ticks >> 24;
if full_cycles > 0 {
@@ -54,11 +56,10 @@ impl Delay {
self.syst.disable_counter();
}
-}
-impl DelayMs<u32> for Delay {
+ /// Delay using the Cortex-M systick for a certain duration, in ms.
#[inline]
- fn delay_ms(&mut self, mut ms: u32) {
+ pub fn delay_ms(&mut self, mut ms: u32) {
// 4294967 is the highest u32 value which you can multiply by 1000 without overflow
while ms > 4294967 {
self.delay_us(4294967000u32);
@@ -68,33 +69,40 @@ impl DelayMs<u32> for Delay {
}
}
+impl DelayMs<u32> for Delay {
+ #[inline]
+ fn delay_ms(&mut self, ms: u32) {
+ Delay::delay_ms(self, ms);
+ }
+}
+
// This is a workaround to allow `delay_ms(42)` construction without specifying a type.
impl DelayMs<i32> for Delay {
#[inline(always)]
fn delay_ms(&mut self, ms: i32) {
assert!(ms >= 0);
- self.delay_ms(ms as u32);
+ Delay::delay_ms(self, ms as u32);
}
}
impl DelayMs<u16> for Delay {
#[inline(always)]
fn delay_ms(&mut self, ms: u16) {
- self.delay_ms(u32::from(ms));
+ Delay::delay_ms(self, u32::from(ms));
}
}
impl DelayMs<u8> for Delay {
#[inline(always)]
fn delay_ms(&mut self, ms: u8) {
- self.delay_ms(u32::from(ms));
+ Delay::delay_ms(self, u32::from(ms));
}
}
impl DelayUs<u32> for Delay {
#[inline]
fn delay_us(&mut self, us: u32) {
- self._delay_us(us);
+ Delay::delay_us(self, us);
}
}
@@ -103,20 +111,20 @@ impl DelayUs<i32> for Delay {
#[inline(always)]
fn delay_us(&mut self, us: i32) {
assert!(us >= 0);
- self.delay_us(us as u32);
+ Delay::delay_us(self, us as u32);
}
}
impl DelayUs<u16> for Delay {
#[inline(always)]
fn delay_us(&mut self, us: u16) {
- self.delay_us(u32::from(us))
+ Delay::delay_us(self, u32::from(us))
}
}
impl DelayUs<u8> for Delay {
#[inline(always)]
fn delay_us(&mut self, us: u8) {
- self.delay_us(u32::from(us))
+ Delay::delay_us(self, u32::from(us))
}
}
diff --git a/src/peripheral/ac.rs b/src/peripheral/ac.rs
new file mode 100644
index 0000000..1ac5be1
--- /dev/null
+++ b/src/peripheral/ac.rs
@@ -0,0 +1,93 @@
+//! Cortex-M7 TCM and Cache access control.
+
+use volatile_register::RW;
+
+/// Register block
+#[repr(C)]
+pub struct RegisterBlock {
+ /// Instruction Tightly-Coupled Memory Control Register
+ pub itcmcr: RW<u32>,
+ /// Data Tightly-Coupled Memory Control Register
+ pub dtcmcr: RW<u32>,
+ /// AHBP Control Register
+ pub ahbpcr: RW<u32>,
+ /// L1 Cache Control Register
+ pub cacr: RW<u32>,
+ /// AHB Slave Control Register
+ pub ahbscr: RW<u32>,
+ reserved0: u32,
+ /// Auxilary Bus Fault Status Register
+ pub abfsr: RW<u32>,
+}
+
+/// ITCMCR and DTCMCR TCM enable bit.
+pub const TCM_EN: u32 = 1;
+
+/// ITCMCR and DTCMCR TCM read-modify-write bit.
+pub const TCM_RMW: u32 = 2;
+
+/// ITCMCR and DTCMCR TCM rety phase enable bit.
+pub const TCM_RETEN: u32 = 4;
+
+/// ITCMCR and DTCMCR TCM size mask.
+pub const TCM_SZ_MASK: u32 = 0x78;
+
+/// ITCMCR and DTCMCR TCM shift.
+pub const TCM_SZ_SHIFT: usize = 3;
+
+/// AHBPCR AHBP enable bit.
+pub const AHBPCR_EN: u32 = 1;
+
+/// AHBPCR AHBP size mask.
+pub const AHBPCR_SZ_MASK: u32 = 0x0e;
+
+/// AHBPCR AHBP size shit.
+pub const AHBPCR_SZ_SHIFT: usize = 1;
+
+/// CACR Shared cachedable-is-WT for data cache.
+pub const CACR_SIWT: u32 = 1;
+
+/// CACR ECC in the instruction and data cache (disable).
+pub const CACR_ECCDIS: u32 = 2;
+
+/// CACR Force Write-Through in the data cache.
+pub const CACR_FORCEWT: u32 = 4;
+
+/// AHBSCR AHBS prioritization control mask.
+pub const AHBSCR_CTL_MASK: u32 = 0x03;
+
+/// AHBSCR AHBS prioritization control shift.
+pub const AHBSCR_CTL_SHIFT: usize = 0;
+
+/// AHBSCR Threshold execution prioity for AHBS traffic demotion, mask.
+pub const AHBSCR_TPRI_MASK: u32 = 0x7fc;
+
+/// AHBSCR Threshold execution prioity for AHBS traffic demotion, shift.
+pub const AHBSCR_TPRI_SHIFT: usize = 2;
+
+/// AHBSCR Failness counter initialization value, mask.
+pub const AHBSCR_INITCOUNT_MASK: u32 = 0xf800;
+
+/// AHBSCR Failness counter initialization value, shift.
+pub const AHBSCR_INITCOUNT_SHIFT: usize = 11;
+
+/// ABFSR Async fault on ITCM interface.
+pub const ABFSR_ITCM: u32 = 1;
+
+/// ABFSR Async fault on DTCM interface.
+pub const ABFSR_DTCM: u32 = 2;
+
+/// ABFSR Async fault on AHBP interface.
+pub const ABFSR_AHBP: u32 = 4;
+
+/// ABFSR Async fault on AXIM interface.
+pub const ABFSR_AXIM: u32 = 8;
+
+/// ABFSR Async fault on EPPB interface.
+pub const ABFSR_EPPB: u32 = 16;
+
+/// ABFSR Indicates the type of fault on the AXIM interface, mask.
+pub const ABFSR_AXIMTYPE_MASK: u32 = 0x300;
+
+/// ABFSR Indicates the type of fault on the AXIM interface, shift.
+pub const ABFSR_AXIMTYPE_SHIFT: usize = 8;
diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs
index 57c9063..720511b 100644
--- a/src/peripheral/dwt.rs
+++ b/src/peripheral/dwt.rs
@@ -59,6 +59,11 @@ bitfield! {
get_cyccntena, set_cyccntena: 0;
get_pcsamplena, set_pcsamplena: 12;
get_exctrcena, set_exctrcena: 16;
+ get_noprfcnt, _: 24;
+ get_nocyccnt, _: 25;
+ get_noexttrig, _: 26;
+ get_notrcpkt, _: 27;
+ u8, get_numcomp, _: 31, 28;
}
/// Comparator
@@ -86,7 +91,50 @@ bitfield! {
}
impl DWT {
+ /// Number of comparators implemented
+ ///
+ /// A value of zero indicates no comparator support.
+ #[inline]
+ pub fn num_comp(&self) -> u8 {
+ self.ctrl.read().get_numcomp()
+ }
+
+ /// Returns `true` if the the implementation supports sampling and exception tracing
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn has_exception_trace(&self) -> bool {
+ self.ctrl.read().get_notrcpkt() == false
+ }
+
+ /// Returns `true` if the implementation includes external match signals
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn has_external_match(&self) -> bool {
+ self.ctrl.read().get_noexttrig() == false
+ }
+
+ /// Returns `true` if the implementation supports a cycle counter
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn has_cycle_counter(&self) -> bool {
+ self.ctrl.read().get_nocyccnt() == false
+ }
+
+ /// Returns `true` if the implementation the profiling counters
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn has_profiling_counter(&self) -> bool {
+ self.ctrl.read().get_noprfcnt() == false
+ }
+
/// Enables the cycle counter
+ ///
+ /// The global trace enable ([`DCB::enable_trace`]) should be set before
+ /// enabling the cycle counter, the processor may ignore writes to the
+ /// cycle counter enable if the global trace is disabled
+ /// (implementation defined behaviour).
+ ///
+ /// [`DCB::enable_trace`]: crate::peripheral::DCB::enable_trace
#[cfg(not(armv6m))]
#[inline]
pub fn enable_cycle_counter(&mut self) {
@@ -98,6 +146,13 @@ impl DWT {
}
}
+ /// Returns `true` if the cycle counter is enabled
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn cycle_counter_enabled(&self) -> bool {
+ self.ctrl.read().get_cyccntena()
+ }
+
/// Whether to enable exception tracing
#[cfg(not(armv6m))]
#[inline]
@@ -125,11 +180,29 @@ impl DWT {
/// Returns the current clock cycle count
#[cfg(not(armv6m))]
#[inline]
+ #[deprecated(
+ since = "0.7.4",
+ note = "Use `cycle_count` which follows the C-GETTER convention"
+ )]
pub fn get_cycle_count() -> u32 {
+ Self::cycle_count()
+ }
+
+ /// Returns the current clock cycle count
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn cycle_count() -> u32 {
// NOTE(unsafe) atomic read with no side effects
unsafe { (*Self::ptr()).cyccnt.read() }
}
+ /// Set the cycle count
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn set_cycle_count(&mut self, count: u32) {
+ unsafe { self.cyccnt.write(count) }
+ }
+
/// Removes the software lock on the DWT
///
/// Some devices, like the STM32F7, software lock the DWT after a power cycle.
@@ -139,6 +212,95 @@ impl DWT {
// NOTE(unsafe) atomic write to a stateless, write-only register
unsafe { (*Self::ptr()).lar.write(0xC5AC_CE55) }
}
+
+ /// Get the CPI count
+ ///
+ /// Counts additional cycles required to execute multi-cycle instructions,
+ /// except those recorded by [`lsu_count`], and counts any instruction fetch
+ /// stalls.
+ ///
+ /// [`lsu_count`]: DWT::lsu_count
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn cpi_count() -> u8 {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).cpicnt.read() as u8 }
+ }
+
+ /// Set the CPI count
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn set_cpi_count(&mut self, count: u8) {
+ unsafe { self.cpicnt.write(count as u32) }
+ }
+
+ /// Get the total cycles spent in exception processing
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn exception_count() -> u8 {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).exccnt.read() as u8 }
+ }
+
+ /// Set the exception count
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn set_exception_count(&mut self, count: u8) {
+ unsafe { self.exccnt.write(count as u32) }
+ }
+
+ /// Get the total number of cycles that the processor is sleeping
+ ///
+ /// ARM recommends that this counter counts all cycles when the processor is sleeping,
+ /// regardless of whether a WFI or WFE instruction, or the sleep-on-exit functionality,
+ /// caused the entry to sleep mode.
+ /// However, all sleep features are implementation defined and therefore when
+ /// this counter counts is implementation defined.
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn sleep_count() -> u8 {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).sleepcnt.read() as u8 }
+ }
+
+ /// Set the sleep count
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn set_sleep_count(&mut self, count: u8) {
+ unsafe { self.sleepcnt.write(count as u32) }
+ }
+
+ /// Get the additional cycles required to execute all load or store instructions
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn lsu_count() -> u8 {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).lsucnt.read() as u8 }
+ }
+
+ /// Set the lsu count
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn set_lsu_count(&mut self, count: u8) {
+ unsafe { self.lsucnt.write(count as u32) }
+ }
+
+ /// Get the folded instruction count
+ ///
+ /// Increments on each instruction that takes 0 cycles.
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn fold_count() -> u8 {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).foldcnt.read() as u8 }
+ }
+
+ /// Set the folded instruction count
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn set_fold_count(&mut self, count: u8) {
+ unsafe { self.foldcnt.write(count as u32) }
+ }
}
/// Whether the comparator should match on read, write or read/write operations.
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
index 7692f06..081aa0a 100644
--- a/src/peripheral/mod.rs
+++ b/src/peripheral/mod.rs
@@ -10,7 +10,7 @@
//! ``` no_run
//! # use cortex_m::peripheral::Peripherals;
//! let mut peripherals = Peripherals::take().unwrap();
-//! peripherals.DWT.enable_cycle_counter();
+//! peripherals.DCB.enable_trace();
//! ```
//!
//! This method can only be successfully called *once* -- this is why the method returns an
@@ -23,17 +23,18 @@
//! ```
//! A part of the peripheral API doesn't require access to a peripheral instance. This part of the
//! API is provided as static methods on the peripheral types. One example is the
-//! [`DWT::get_cycle_count`](struct.DWT.html#method.get_cycle_count) method.
+//! [`DWT::cycle_count`](struct.DWT.html#method.cycle_count) method.
//!
//! ``` no_run
//! # use cortex_m::peripheral::{DWT, Peripherals};
//! {
//! let mut peripherals = Peripherals::take().unwrap();
+//! peripherals.DCB.enable_trace();
//! peripherals.DWT.enable_cycle_counter();
//! } // all the peripheral singletons are destroyed here
//!
//! // but this method can be called without a DWT instance
-//! let cyccnt = DWT::get_cycle_count();
+//! let cyccnt = DWT::cycle_count();
//! ```
//!
//! The singleton property can be *unsafely* bypassed using the `ptr` static method which is
@@ -44,6 +45,7 @@
//! # use cortex_m::peripheral::{DWT, Peripherals};
//! {
//! let mut peripherals = Peripherals::take().unwrap();
+//! peripherals.DCB.enable_trace();
//! peripherals.DWT.enable_cycle_counter();
//! } // all the peripheral singletons are destroyed here
//!
@@ -60,6 +62,8 @@ use core::ops;
use crate::interrupt;
+#[cfg(cm7)]
+pub mod ac;
#[cfg(not(armv6m))]
pub mod cbp;
pub mod cpuid;
@@ -91,6 +95,10 @@ mod test;
#[allow(non_snake_case)]
#[allow(clippy::manual_non_exhaustive)]
pub struct Peripherals {
+ /// Cortex-M7 TCM and cache access control.
+ #[cfg(cm7)]
+ pub AC: AC,
+
/// Cache and branch predictor maintenance operations.
/// Not available on Armv6-M.
pub CBP: CBP,
@@ -172,6 +180,10 @@ impl Peripherals {
TAKEN = true;
Peripherals {
+ #[cfg(cm7)]
+ AC: AC {
+ _marker: PhantomData,
+ },
CBP: CBP {
_marker: PhantomData,
},
@@ -219,6 +231,27 @@ impl Peripherals {
}
}
+/// Access control
+#[cfg(cm7)]
+pub struct AC {
+ _marker: PhantomData<*const ()>,
+}
+
+#[cfg(cm7)]
+unsafe impl Send for AC {}
+
+#[cfg(cm7)]
+impl AC {
+ /// Pointer to the register block
+ pub const PTR: *const self::ac::RegisterBlock = 0xE000_EF90 as *const _;
+
+ /// Returns a pointer to the register block (to be deprecated in 0.7)
+ #[inline(always)]
+ pub const fn ptr() -> *const self::ac::RegisterBlock {
+ Self::PTR
+ }
+}
+
/// Cache and branch predictor maintenance operations
#[allow(clippy::upper_case_acronyms)]
pub struct CBP {
diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
index 4332707..f0c5457 100644
--- a/src/peripheral/nvic.rs
+++ b/src/peripheral/nvic.rs
@@ -210,7 +210,7 @@ impl NVIC {
/// # Unsafety
///
/// Changing priority levels can break priority-based critical sections (see
- /// [`register::basepri`](../register/basepri/index.html)) and compromise memory safety.
+ /// [`register::basepri`](crate::register::basepri)) and compromise memory safety.
#[inline]
pub unsafe fn set_priority<I>(&mut self, interrupt: I, prio: u8)
where
diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs
index b619328..688c431 100644
--- a/src/peripheral/scb.rs
+++ b/src/peripheral/scb.rs
@@ -832,7 +832,7 @@ impl SCB {
}
const SCB_AIRCR_VECTKEY: u32 = 0x05FA << 16;
-const SCB_AIRCR_PRIGROUP_MASK: u32 = 0x5 << 8;
+const SCB_AIRCR_PRIGROUP_MASK: u32 = 0x7 << 8;
const SCB_AIRCR_SYSRESETREQ: u32 = 1 << 2;
impl SCB {
@@ -994,7 +994,7 @@ impl SCB {
/// # Unsafety
///
/// Changing priority levels can break priority-based critical sections (see
- /// [`register::basepri`](../register/basepri/index.html)) and compromise memory safety.
+ /// [`register::basepri`](crate::register::basepri)) and compromise memory safety.
#[inline]
pub unsafe fn set_priority(&mut self, system_handler: SystemHandler, prio: u8) {
let index = system_handler as u8;