diff options
author | 2018-05-18 17:49:16 +0000 | |
---|---|---|
committer | 2018-05-18 17:49:16 +0000 | |
commit | 902d8ff191cbfad2a6735b50cc9fcb833c3e6379 (patch) | |
tree | 5ebac95b81adc083091c98c7dbc63af06792b693 /src/asm.rs | |
parent | cf262c922fce7c5b0cff3b5d4acfd4008d194fa6 (diff) | |
parent | f04e448e35d92a446a089f2fb2b7dcbd00454306 (diff) | |
download | cortex-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.rs | 35 |
1 files changed, 35 insertions, 0 deletions
@@ -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() { |