1
- #![ feature( asm_experimental_arch) ]
2
-
3
1
#![ no_std]
4
-
5
2
#![ crate_name = "avr_delay" ]
6
3
4
+ #![ feature( asm_experimental_arch) ]
7
5
#[ allow( unused_imports) ]
8
6
use core:: arch:: asm;
9
7
8
+ mod delay_impl;
9
+
10
10
/// This library is intended to provide a busy-wait delay
11
11
/// similar to the one provided by the arduino c++ utilities
12
12
/// If you need accurate time keeping you should consider a
@@ -15,109 +15,32 @@ use core::arch::asm;
15
15
// This library does all of the busy-wait loop in rust.
16
16
// We pack as much of the looping as possible into asm!
17
17
// 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.
26
18
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.
28
21
/// # Arguments
29
22
/// * 'count' - a u32, the number of times to cycle the loop.
30
23
#[ inline( always) ]
31
24
pub fn delay ( count : u32 ) {
32
- delay_count_32 ( count) ;
25
+ delay_impl :: delay_count_32 ( count) ;
33
26
}
34
27
35
28
///delay for N miliseconds
36
29
/// # 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.
38
32
#[ inline( always) ]
39
33
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) ;
43
36
}
44
37
45
38
///delay for N microseconds
46
39
/// # 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.
48
42
#[ inline( always) ]
49
43
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) ;
123
46
}
0 commit comments