2
2
#![ no_std]
3
3
#![ crate_name = "avr_delay" ]
4
4
5
+ #[ allow( unused_imports) ]
5
6
use core:: arch:: asm;
6
7
7
8
/// This library is intended to provide a busy-wait delay
@@ -21,53 +22,103 @@ use core::arch::asm;
21
22
// initially, and then 11 cycles per outer loop. We ignore
22
23
// all that.
23
24
24
- /// Internal function to implement a variable busy-wait loop.
25
+ /// Internal function to implement a variable busy-wait loop. It is not recommended to use this function directly.
25
26
/// # Arguments
26
- /// * 'count' - a u64 , the number of times to cycle the loop.
27
+ /// * 'count' - an u32 , the number of times to cycle the loop.
27
28
#[ inline( always) ]
28
- pub fn delay ( count : u64 ) {
29
- // Our asm busy-wait takes a 16 bit word as an argument,
30
- // so the max number of loops is 2^16
31
- let outer_count = count / 65536 ;
32
- let last_count = ( ( count % 65536 ) + 1 ) as u16 ;
33
- for _ in 0 ..outer_count {
34
- // Each loop through should be 4 cycles.
35
- let zero = 0u16 ;
36
- unsafe {
37
- asm ! ( "1: sbiw {i}, 1" ,
38
- "brne 1b" ,
39
- i = inout( reg_iw) zero => _,
40
- )
41
- }
42
- }
43
- unsafe {
44
- asm ! ( "1: sbiw {i}, 1" ,
45
- "brne 1b" ,
46
- i = inout( reg_iw) last_count => _,
47
- )
48
- }
29
+ pub fn delay ( count : u32 ) {
30
+ delay_count_32 ( count) ;
49
31
}
50
32
51
33
///delay for N milliseconds
52
34
/// # Arguments
53
- /// * 'ms' - an u64 , number of milliseconds to busy-wait
35
+ /// * 'ms' - an u32 , number of milliseconds to busy-wait
54
36
#[ inline( always) ]
55
- pub fn delay_ms ( ms : u64 ) {
37
+ pub fn delay_ms ( ms : u32 ) {
56
38
// microseconds
57
39
let us = ms * 1000 ;
58
40
delay_us ( us) ;
59
41
}
60
42
61
43
///delay for N microseconds
62
44
/// # Arguments
63
- /// * 'us ' - an u64 , number of microseconds to busy-wait
45
+ /// * 'ms ' - an u32 , number of microseconds to busy-wait
64
46
#[ inline( always) ]
65
- pub fn delay_us ( us : u64 ) {
66
- let us_in_loop = ( avr_config:: CPU_FREQUENCY_HZ / 1000000 / 4 ) as u64 ;
67
- let loops = us * us_in_loop;
47
+ 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 ;
68
52
delay ( loops) ;
69
53
}
70
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
+ }
120
+ }
121
+
71
122
#[ cfg( test) ]
72
123
mod tests {
73
124
#[ test]
0 commit comments