aboutsummaryrefslogtreecommitdiff
path: root/src/asm.rs
diff options
context:
space:
mode:
authorGravatar bors[bot] <bors[bot]@users.noreply.github.com> 2018-05-18 17:49:16 +0000
committerGravatar bors[bot] <bors[bot]@users.noreply.github.com> 2018-05-18 17:49:16 +0000
commit902d8ff191cbfad2a6735b50cc9fcb833c3e6379 (patch)
tree5ebac95b81adc083091c98c7dbc63af06792b693 /src/asm.rs
parentcf262c922fce7c5b0cff3b5d4acfd4008d194fa6 (diff)
parentf04e448e35d92a446a089f2fb2b7dcbd00454306 (diff)
downloadcortex-m-902d8ff191cbfad2a6735b50cc9fcb833c3e6379.tar.gz
cortex-m-902d8ff191cbfad2a6735b50cc9fcb833c3e6379.tar.zst
cortex-m-902d8ff191cbfad2a6735b50cc9fcb833c3e6379.zip
Merge #84
84: add asm::delay r=japaric a=japaric This PR adds an `asm::delay` function that can be used to block the program for the specified number of instruction cycles (NB in absence of interrupts, see API docs). The implementation is done in assembly so the execution time of that function is the same regardless of the used optimization level. Rationale: external devices (sensors) sometimes require delays in their initialization, or to workaround silicon errata. Having to set up a hardware peripheral like the SysTick can be overkill when the delay is to be done once. Why not provide an implementation of `embedded_hal::{DelayUs, DelayMs}`? Going from instruction cycles to human time requires knowing the clock configuration and in some cases the Flash access latency. As all that information is device specific it's best left to device crates to implement. Thoughts? Perhaps this is too error prone due to Flash access latency and interrupts? The interrupt issue could be avoided by calling the asm! block within an interrupt::free call. cc @therealprof @kunerd Co-authored-by: Jorge Aparicio <jorge@japaric.io>
Diffstat (limited to 'src/asm.rs')
-rw-r--r--src/asm.rs35
1 files changed, 35 insertions, 0 deletions
diff --git a/src/asm.rs b/src/asm.rs
index 6e90f09..fd1ce7c 100644
--- a/src/asm.rs
+++ b/src/asm.rs
@@ -24,6 +24,41 @@ pub fn bkpt() {
}
}
+/// Blocks the program for *at least* `n` instruction cycles
+///
+/// This is implemented in assembly so its execution time is the same regardless of the optimization
+/// level.
+///
+/// NOTE that the delay can take much longer if interrupts are serviced during its execution.
+#[inline]
+pub fn delay(_n: u32) {
+ match () {
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
+ () => unsafe {
+ asm!("1:
+ nop
+ subs $0, $$1
+ bne.n 1b"
+ : "+r"(_n / 4 + 1)
+ :
+ :
+ : "volatile");
+ },
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __delay(n: u32);
+ }
+
+ __delay(_n / 4 + 1);
+ },
+
+ #[cfg(not(cortex_m))]
+ () => unimplemented!(),
+ }
+}
+
/// A no-operation. Useful to prevent delay loops from being optimized away.
#[inline]
pub fn nop() {