2
2
#![ no_std]
3
3
#![ crate_name = "avr_delay" ]
4
4
5
- #[ allow( unused_imports) ]
6
- use core:: arch:: asm;
5
+ mod delay_impl;
7
6
8
7
/// This library is intended to provide a busy-wait delay
9
8
/// similar to the one provided by the arduino c++ utilities
@@ -13,110 +12,34 @@ use core::arch::asm;
13
12
// This library does all of the busy-wait loop in rust.
14
13
// We pack as much of the looping as possible into asm!
15
14
// so that we can count cycles.
16
- //
17
- // Ignoring the overhead, which may be significant:
18
- // An arduino runs at 16MHZ. Each asm loop is 4 cycles.
19
- // so each loop is 0.25 us.
20
- //
21
- // the overhead of delay() seems to be about 13 cycles
22
- // initially, and then 11 cycles per outer loop. We ignore
23
- // all that.
24
15
25
- /// Internal function to implement a variable busy-wait loop. It is not recommended to use this function directly.
16
+ /// Internal function to implement a variable busy-wait loop. Even if count isn't
17
+ /// known at compile time, this function shouldn't have too much overhead.
26
18
/// # Arguments
27
19
/// * 'count' - an u32, the number of times to cycle the loop.
28
20
#[ inline( always) ]
29
21
pub fn delay ( count : u32 ) {
30
- delay_count_32 ( count) ;
22
+ delay_impl :: delay_count_32 ( count) ;
31
23
}
32
24
33
25
///delay for N milliseconds
34
26
/// # Arguments
35
- /// * 'ms' - an u32, number of milliseconds to busy-wait
27
+ /// * 'ms' - an u32, number of milliseconds to busy-wait. This should be known at
28
+ /// compile time, otherwise the delay may be much longer than specified.
36
29
#[ inline( always) ]
37
30
pub fn delay_ms ( ms : u32 ) {
38
- // microseconds
39
- let us = ms * 1000 ;
40
- delay_us ( us) ;
31
+ let ticks: u64 = ( u64:: from ( avr_config:: CPU_FREQUENCY_HZ ) * u64:: from ( ms) ) / 4_000 ;
32
+ delay_impl:: delay_count_48 ( ticks) ;
41
33
}
42
34
43
35
///delay for N microseconds
44
36
/// # Arguments
45
- /// * 'ms' - an u32, number of microseconds to busy-wait
37
+ /// * 'ms' - an u32, number of microseconds to busy-wait. This should be known at
38
+ /// compile time, otherwise the delay may be much longer than specified.
46
39
#[ inline( always) ]
47
40
pub fn delay_us ( us : u32 ) {
48
- // picoseconds
49
- let ps = us * 1000 ;
50
- let ps_lp = 1000000000 / ( avr_config:: CPU_FREQUENCY_HZ / 4 ) ;
51
- let loops = ( ps / ps_lp) as u32 ;
52
- delay ( loops) ;
53
- }
54
-
55
- /// Internal function to implement a variable busy-wait loop.
56
- /// # Arguments
57
- /// * 'count' - a u32, the number of times to cycle the loop (4 clock cycles per loop).
58
- #[ inline( always) ]
59
- pub fn delay_count_32 ( count : u32 ) {
60
- let mut outer_count: u16 = ( count >> 16 ) as u16 ;
61
- let inner_count: u16 = count as u16 ;
62
- if inner_count != 0 {
63
- delay_loop_4_cycles ( inner_count) ;
64
- }
65
- while outer_count != 0 {
66
- delay_loop_4_cycles ( 0 ) ;
67
- outer_count -= 1 ;
68
- }
69
- }
70
-
71
- /// Internal function to implement a variable busy-wait loop.
72
- /// # Arguments
73
- /// * 'count' - a u64, the number of times to cycle the loop (4 clock cycles per loop). *The top 16 bits are ignored.*
74
- #[ inline( always) ]
75
- pub fn delay_count_48 ( count : u64 ) {
76
- let mut outer_count: u32 = ( count >> 16 ) as u32 ;
77
- let inner_count: u16 = count as u16 ;
78
- if inner_count != 0 {
79
- delay_loop_4_cycles ( inner_count) ;
80
- }
81
- while outer_count != 0 {
82
- delay_loop_4_cycles ( 0 ) ;
83
- outer_count -= 1 ;
84
- }
85
- }
86
-
87
- /// Internal function to implement a 16-bit busy-wait loop in assembly.
88
- /// Delays for 4 cycles per iteration, not including setup overhead.
89
- /// Up to 2^16 iterations (the value 2^16 would have to be passed as 0).
90
- /// # Arguments
91
- /// * 'cycles' - a u16, the number of times to cycle the loop.
92
- #[ inline( always) ]
93
- #[ allow( unused_variables, unused_mut, unused_assignments, dead_code) ]
94
- fn delay_loop_4_cycles ( mut cycles : u16 ) {
95
- #[ cfg( target_arch = "avr" ) ]
96
- unsafe {
97
- asm ! ( "1: sbiw {i}, 1" ,
98
- "brne 1b" ,
99
- i = inout( reg_iw) cycles => _,
100
- )
101
- }
102
- // Allow compilation even on non-avr targets, for testing purposes
103
- }
104
-
105
- /// Internal function to implement an 8-bit busy-wait loop in assembly.
106
- /// Delays for 3 cycles per iteration, not including setup overhead.
107
- /// Up to 2^8 iterations (the value 2^8 would have to be passed as 0).
108
- /// # Arguments
109
- /// * 'cycles' - a u8, the number of times to cycle the loop.
110
- #[ inline( always) ]
111
- #[ allow( unused_variables, unused_mut, unused_assignments, dead_code) ]
112
- fn delay_loop_3_cycles ( mut cycles : u8 ) {
113
- #[ cfg( target_arch = "avr" ) ]
114
- unsafe {
115
- asm ! ( "1: dec {i}" ,
116
- "brne 1b" ,
117
- i = inout( reg) cycles => _,
118
- )
119
- }
41
+ let ticks: u64 = ( u64:: from ( avr_config:: CPU_FREQUENCY_HZ ) * u64:: from ( us) ) / 4_000_000 ;
42
+ delay_impl:: delay_count_48 ( ticks) ;
120
43
}
121
44
122
45
#[ cfg( test) ]
0 commit comments