|
10 | 10 | /// hardware timer.
|
11 | 11 |
|
12 | 12 | // This library does all of the busy-wait loop in rust.
|
13 |
| -// We pack as much of the looping as possible into asm! |
| 13 | +// We pack as much of the looping as possible into llvm_asm! |
14 | 14 | // so that we can count cycles.
|
15 | 15 | //
|
16 | 16 | // Ignoring the overhead, which may be significant:
|
|
21 | 21 | // initially, and then 11 cycles per outer loop. We ignore
|
22 | 22 | // all that.
|
23 | 23 |
|
24 |
| -/// Internal function to implement a variable busy-wait loop. |
| 24 | +///delay for N milliseconds |
25 | 25 | /// # Arguments
|
26 |
| -/// * 'count' - an i32, the number of times to cycle the loop. |
27 |
| -pub fn delay(count: u32) { |
28 |
| - // Our asm busy-wait takes a 16 bit word as an argument, |
29 |
| - // so the max number of loops is 2^16 |
30 |
| - let outer_count = count / 65536; |
31 |
| - let last_count = ((count % 65536)+1) as u16; |
32 |
| - for _ in 0..outer_count { |
33 |
| - // Each loop through should be 4 cycles. |
34 |
| - unsafe {llvm_asm!("1: sbiw $0,1 |
35 |
| - brne 1b" |
36 |
| - : |
37 |
| - : "w" (0) |
38 |
| - : |
39 |
| - :)} |
40 |
| - } |
41 |
| - unsafe {llvm_asm!("1: sbiw $0,1 |
42 |
| - brne 1b" |
43 |
| - : |
44 |
| - : "w" (last_count) |
45 |
| - : |
46 |
| - :)} |
47 |
| -} |
48 |
| - |
49 |
| -///delay for N miliseconds |
50 |
| -/// # Arguments |
51 |
| -/// * 'ms' - an u32, number of milliseconds to busy-wait |
| 26 | +/// * 'ms' - a u32, number of milliseconds to busy-wait |
| 27 | +#[inline(always)] |
52 | 28 | pub fn delay_ms(ms: u32) {
|
53 |
| - // microseconds |
54 |
| - let us = ms * 1000; |
55 |
| - delay_us(us); |
| 29 | + let ticks: u64 = (u64::from(avr_config::CPU_FREQUENCY_HZ) * u64::from(ms)) / 4_000; |
| 30 | + internal_delay_functions::delay(ticks); |
56 | 31 | }
|
57 | 32 |
|
58 | 33 | ///delay for N microseconds
|
59 | 34 | /// # Arguments
|
60 |
| -/// * 'ms' - an u32, number of microseconds to busy-wait |
| 35 | +/// * 'ms' - a u32, number of microseconds to busy-wait |
| 36 | +#[inline(always)] |
61 | 37 | pub fn delay_us(us: u32) {
|
62 |
| - // picoseconds |
63 |
| - let ps = us * 1000; |
64 |
| - let ps_lp = 1000000000 / (avr_config::CPU_FREQUENCY_HZ / 4); |
65 |
| - let loops = (ps / ps_lp) as u32; |
66 |
| - delay(loops); |
| 38 | + let ticks: u64 = (u64::from(avr_config::CPU_FREQUENCY_HZ) * u64::from(us)) / 4_000_000; |
| 39 | + internal_delay_functions::delay(ticks); |
67 | 40 | }
|
68 | 41 |
|
69 |
| -#[cfg(test)] |
70 |
| -mod tests { |
71 |
| - #[test] |
72 |
| - fn it_works() { |
73 |
| - assert_eq!(2 + 2, 4); |
| 42 | +/// Functions used internally for our busy-wait loop. |
| 43 | +/// |
| 44 | +/// These are not primarily intended to be used in user code, but are left public for |
| 45 | +/// use in making longer or more precise delays. |
| 46 | +pub mod internal_delay_functions { |
| 47 | + /// Internal function to implement a variable busy-wait loop. |
| 48 | + /// Delays for up up to 2^48 iterations, not including setup overhead. |
| 49 | + /// # Arguments |
| 50 | + /// * 'count' - a u64, the number of times to iterate the loop. |
| 51 | + /// The top 16 bits of count are ignored. |
| 52 | + /// |
| 53 | + #[inline(always)] |
| 54 | + pub fn delay(count: u64) { |
| 55 | + // Casting truncates, so this is equivalent to `(count & 0xFFFF) as u16` |
| 56 | + let remaining_count: u16 = count as u16; |
| 57 | + // if remaining_count is zero, calling delay_loop_4_cycles would delay for 2^16 cycles, |
| 58 | + // so we don't loop in this case |
| 59 | + if remaining_count != 0 { |
| 60 | + delay_loop_4_cycles(remaining_count); |
| 61 | + } |
| 62 | + // Casting truncates, so this is equivalent to `((count >> 16) & 0xFFFF_FFFF) as u32` |
| 63 | + let outer_count: u32 = (count >> 16) as u32; |
| 64 | + for _ in 0..outer_count { |
| 65 | + // Each loop through should be 4 cycles, so we're getting 262,144 cycles per outer loop. |
| 66 | + delay_loop_4_cycles(0); |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + /// Internal function to implement a 16-bit busy-wait loop in assembly. |
| 71 | + /// Delays for 4 cycles per iteration, not including setup overhead. |
| 72 | + /// Up to 2^16 iterations (the value 2^16 would have to be passed as 0). |
| 73 | + /// # Arguments |
| 74 | + /// * 'count' - a u16, the number of times to cycle the loop. |
| 75 | + #[inline(always)] |
| 76 | + #[allow(unused_assignments)] |
| 77 | + fn delay_loop_4_cycles(mut count: u16) { |
| 78 | + unsafe { |
| 79 | + llvm_asm!( |
| 80 | + "1: sbiw $0,1\n\tbrne 1b" |
| 81 | + : "=w" (count) |
| 82 | + : "0" (count) |
| 83 | + : |
| 84 | + : "volatile" |
| 85 | + ); |
| 86 | + } |
74 | 87 | }
|
75 | 88 | }
|
76 |
| - |
|
0 commit comments