Skip to content

Commit 6558a18

Browse files
committed
Implement delay, delay_ms, and delay_us
1 parent 3a6ff52 commit 6558a18

File tree

2 files changed

+63
-91
lines changed

2 files changed

+63
-91
lines changed

src/delay_impl.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/// Internal function to implement a variable busy-wait loop.
2+
/// # Arguments
3+
/// * 'count' - a u32, the number of times to cycle the loop (4 clock cycles per loop).
4+
#[inline(always)]
5+
pub fn delay_count_32(count: u32) {
6+
let mut outer_count: u16 = (count >> 16) as u16;
7+
let inner_count: u16 = count as u16;
8+
if inner_count != 0 {
9+
delay_loop_4_cycles(inner_count);
10+
}
11+
while outer_count != 0 {
12+
delay_loop_4_cycles(0);
13+
outer_count -= 1;
14+
}
15+
}
16+
17+
/// Internal function to implement a variable busy-wait loop.
18+
/// # Arguments
19+
/// * 'count' - a u64, the number of times to cycle the loop (4 clock cycles per loop). *The top 16 bits are ignored.*
20+
#[inline(always)]
21+
pub fn delay_count_48(count: u64) {
22+
let mut outer_count: u32 = (count >> 16) as u32;
23+
let inner_count: u16 = count as u16;
24+
if inner_count != 0 {
25+
delay_loop_4_cycles(inner_count);
26+
}
27+
while outer_count != 0 {
28+
delay_loop_4_cycles(0);
29+
outer_count -= 1;
30+
}
31+
}
32+
33+
/// Internal function to implement a 16-bit busy-wait loop in assembly.
34+
/// Delays for 4 cycles per iteration, not including setup overhead.
35+
/// Up to 2^16 iterations (the value 2^16 would have to be passed as 0).
36+
/// # Arguments
37+
/// * 'cycles' - a u16, the number of times to cycle the loop.
38+
#[inline(always)]
39+
#[allow(unused_variables, unused_mut, unused_assignments, dead_code)]
40+
pub fn delay_loop_4_cycles(mut cycles: u16) {
41+
#[cfg(target_arch = "avr")]
42+
unsafe {
43+
asm!("1: sbiw {i}, 1",
44+
"brne 1b",
45+
i = inout(reg_iw) cycles => _,
46+
)
47+
}
48+
// Allow compilation even on non-avr targets, for testing purposes
49+
}

src/lib.rs

Lines changed: 14 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
#![feature(asm_experimental_arch)]
2-
31
#![no_std]
4-
52
#![crate_name = "avr_delay"]
63

4+
#![feature(asm_experimental_arch)]
75
#[allow(unused_imports)]
86
use core::arch::asm;
97

8+
mod delay_impl;
9+
1010
/// This library is intended to provide a busy-wait delay
1111
/// similar to the one provided by the arduino c++ utilities
1212
/// If you need accurate time keeping you should consider a
@@ -15,109 +15,32 @@ use core::arch::asm;
1515
// This library does all of the busy-wait loop in rust.
1616
// We pack as much of the looping as possible into asm!
1717
// so that we can count cycles.
18-
//
19-
// Ignoring the overhead, which may be significant:
20-
// An arduino runs at 16MHZ. Each asm loop is 4 cycles.
21-
// so each loop is 0.25 us.
22-
//
23-
// the overhead of delay() seems to be about 13 cycles
24-
// initially, and then 11 cycles per outer loop. We ignore
25-
// all that.
2618

27-
/// Internal function to implement a variable busy-wait loop. It is not recommended to use this function directly.
19+
/// Internal function to implement a variable busy-wait loop. Even if count isn't
20+
/// known at compile time, this function shouldn't have too much overhead.
2821
/// # Arguments
2922
/// * 'count' - a u32, the number of times to cycle the loop.
3023
#[inline(always)]
3124
pub fn delay(count: u32) {
32-
delay_count_32(count);
25+
delay_impl::delay_count_32(count);
3326
}
3427

3528
///delay for N miliseconds
3629
/// # Arguments
37-
/// * 'ms' - an u32, number of milliseconds to busy-wait
30+
/// * 'ms' - a u32, number of milliseconds to busy-wait. This should be known at
31+
/// compile time, otherwise the delay may be much longer than specified.
3832
#[inline(always)]
3933
pub fn delay_ms(ms: u32) {
40-
// microseconds
41-
let us = ms * 1000;
42-
delay_us(us);
34+
let ticks: u64 = (u64::from(avr_config::CPU_FREQUENCY_HZ) * u64::from(ms)) / 4_000;
35+
delay_impl::delay_count_48(ticks);
4336
}
4437

4538
///delay for N microseconds
4639
/// # Arguments
47-
/// * 'ms' - an u32, number of microseconds to busy-wait
40+
/// * 'ms' - a u32, number of microseconds to busy-wait. This should be known at
41+
/// compile time, otherwise the delay may be much longer than specified.
4842
#[inline(always)]
4943
pub fn delay_us(us: u32) {
50-
// picoseconds
51-
let ps = us * 1000;
52-
let ps_lp = 1000000000 / (avr_config::CPU_FREQUENCY_HZ / 4);
53-
let loops = (ps / ps_lp) as u32;
54-
delay(loops);
55-
}
56-
57-
/// Internal function to implement a variable busy-wait loop.
58-
/// # Arguments
59-
/// * 'count' - a u32, the number of times to cycle the loop (4 clock cycles per loop).
60-
#[inline(always)]
61-
pub fn delay_count_32(count: u32) {
62-
let mut outer_count: u16 = (count >> 16) as u16;
63-
let inner_count: u16 = count as u16;
64-
if inner_count != 0 {
65-
delay_loop_4_cycles(inner_count);
66-
}
67-
while outer_count != 0 {
68-
delay_loop_4_cycles(0);
69-
outer_count -= 1;
70-
}
71-
}
72-
73-
/// Internal function to implement a variable busy-wait loop.
74-
/// # Arguments
75-
/// * 'count' - a u64, the number of times to cycle the loop (4 clock cycles per loop). *The top 16 bits are ignored.*
76-
#[inline(always)]
77-
pub fn delay_count_48(count: u64) {
78-
let mut outer_count: u32 = (count >> 16) as u32;
79-
let inner_count: u16 = count as u16;
80-
if inner_count != 0 {
81-
delay_loop_4_cycles(inner_count);
82-
}
83-
while outer_count != 0 {
84-
delay_loop_4_cycles(0);
85-
outer_count -= 1;
86-
}
87-
}
88-
89-
/// Internal function to implement a 16-bit busy-wait loop in assembly.
90-
/// Delays for 4 cycles per iteration, not including setup overhead.
91-
/// Up to 2^16 iterations (the value 2^16 would have to be passed as 0).
92-
/// # Arguments
93-
/// * 'cycles' - a u16, the number of times to cycle the loop.
94-
#[inline(always)]
95-
#[allow(unused_variables, unused_mut, unused_assignments, dead_code)]
96-
fn delay_loop_4_cycles(mut cycles: u16) {
97-
#[cfg(target_arch = "avr")]
98-
unsafe {
99-
asm!("1: sbiw {i}, 1",
100-
"brne 1b",
101-
i = inout(reg_iw) cycles => _,
102-
)
103-
}
104-
// Allow compilation even on non-avr targets, for testing purposes
105-
}
106-
107-
/// Internal function to implement an 8-bit busy-wait loop in assembly.
108-
/// Delays for 3 cycles per iteration, not including setup overhead.
109-
/// Up to 2^8 iterations (the value 2^8 would have to be passed as 0).
110-
/// # Arguments
111-
/// * 'cycles' - a u8, the number of times to cycle the loop.
112-
#[inline(always)]
113-
#[allow(unused_variables, unused_mut, unused_assignments, dead_code)]
114-
fn delay_loop_3_cycles(mut cycles: u8) {
115-
#[cfg(target_arch = "avr")]
116-
unsafe {
117-
asm!("1: dec {i}",
118-
"brne 1b",
119-
i = inout(reg) cycles => _,
120-
)
121-
}
122-
// Allow compilation even on non-avr targets, for testing purposes
44+
let ticks: u64 = (u64::from(avr_config::CPU_FREQUENCY_HZ) * u64::from(us)) / 4_000_000;
45+
delay_impl::delay_count_48(ticks);
12346
}

0 commit comments

Comments
 (0)