aboutsummaryrefslogtreecommitdiff
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
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>
-rw-r--r--asm/delay.s8
-rw-r--r--build.rs1
-rw-r--r--src/asm.rs35
3 files changed, 44 insertions, 0 deletions
diff --git a/asm/delay.s b/asm/delay.s
new file mode 100644
index 0000000..2bf92f1
--- /dev/null
+++ b/asm/delay.s
@@ -0,0 +1,8 @@
+ .global __delay
+ .syntax unified
+ .thumb_func
+__delay:
+ nop
+ subs r0, #1
+ bne __delay
+ bx lr
diff --git a/build.rs b/build.rs
index 4866ed2..87e082e 100644
--- a/build.rs
+++ b/build.rs
@@ -15,6 +15,7 @@ fn main() {
.file("asm/control.s")
.file("asm/cpsid.s")
.file("asm/cpsie.s")
+ .file("asm/delay.s")
.file("asm/dmb.s")
.file("asm/dsb.s")
.file("asm/faultmask.s")
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() {