Skip to content

Commit 902d8ff

Browse files
bors[bot]japaric
andcommitted
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 <[email protected]>
2 parents cf262c9 + f04e448 commit 902d8ff

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

asm/delay.s

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.global __delay
2+
.syntax unified
3+
.thumb_func
4+
__delay:
5+
nop
6+
subs r0, #1
7+
bne __delay
8+
bx lr

build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ fn main() {
1515
.file("asm/control.s")
1616
.file("asm/cpsid.s")
1717
.file("asm/cpsie.s")
18+
.file("asm/delay.s")
1819
.file("asm/dmb.s")
1920
.file("asm/dsb.s")
2021
.file("asm/faultmask.s")

src/asm.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,41 @@ pub fn bkpt() {
2424
}
2525
}
2626

27+
/// Blocks the program for *at least* `n` instruction cycles
28+
///
29+
/// This is implemented in assembly so its execution time is the same regardless of the optimization
30+
/// level.
31+
///
32+
/// NOTE that the delay can take much longer if interrupts are serviced during its execution.
33+
#[inline]
34+
pub fn delay(_n: u32) {
35+
match () {
36+
#[cfg(all(cortex_m, feature = "inline-asm"))]
37+
() => unsafe {
38+
asm!("1:
39+
nop
40+
subs $0, $$1
41+
bne.n 1b"
42+
: "+r"(_n / 4 + 1)
43+
:
44+
:
45+
: "volatile");
46+
},
47+
48+
#[cfg(all(cortex_m, not(feature = "inline-asm")))]
49+
() => unsafe {
50+
extern "C" {
51+
fn __delay(n: u32);
52+
}
53+
54+
__delay(_n / 4 + 1);
55+
},
56+
57+
#[cfg(not(cortex_m))]
58+
() => unimplemented!(),
59+
}
60+
}
61+
2762
/// A no-operation. Useful to prevent delay loops from being optimized away.
2863
#[inline]
2964
pub fn nop() {

0 commit comments

Comments
 (0)