2
2
#![ no_std]
3
3
#![ crate_name = "avr_delay" ]
4
4
5
- use core :: arch :: asm ;
5
+ mod delay_impl ;
6
6
7
7
/// This library is intended to provide a busy-wait delay
8
8
/// similar to the one provided by the arduino c++ utilities
@@ -12,60 +12,47 @@ use core::arch::asm;
12
12
// This library does all of the busy-wait loop in rust.
13
13
// We pack as much of the looping as possible into asm!
14
14
// so that we can count cycles.
15
- //
16
- // Ignoring the overhead, which may be significant:
17
- // An arduino runs at 16MHZ. Each asm loop is 4 cycles.
18
- // so each loop is 0.25 us.
19
- //
20
- // the overhead of delay() seems to be about 13 cycles
21
- // initially, and then 11 cycles per outer loop. We ignore
22
- // all that.
23
15
24
- /// Internal function to implement a variable busy-wait loop.
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.
25
18
/// # Arguments
26
- /// * 'count' - a u64 , the number of times to cycle the loop.
19
+ /// * 'count' - an u32 , the number of times to cycle the loop.
27
20
#[ 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
- }
21
+ pub fn delay ( count : u32 ) {
22
+ delay_impl:: delay_count_32 ( count) ;
49
23
}
50
24
51
25
///delay for N milliseconds
52
26
/// # Arguments
53
- /// * 'ms' - an u64, 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.
54
29
#[ inline( always) ]
55
- pub fn delay_ms ( ms : u64 ) {
56
- // microseconds
57
- let us = ms * 1000 ;
58
- delay_us ( us) ;
30
+ pub fn delay_ms ( ms : u32 ) {
31
+ const GCD : u32 = gcd ( avr_config:: CPU_FREQUENCY_HZ , 4_000 ) ;
32
+ const NUMERATOR : u32 = avr_config:: CPU_FREQUENCY_HZ / GCD ;
33
+ const DENOMINATOR : u32 = 4_000 / GCD ;
34
+ let ticks: u64 = ( u64:: from ( ms) * u64:: from ( NUMERATOR ) ) / u64:: from ( DENOMINATOR ) ;
35
+ delay_impl:: delay_count_48 ( ticks) ;
59
36
}
60
37
61
38
///delay for N microseconds
62
39
/// # Arguments
63
- /// * 'us' - an u64, number of microseconds to busy-wait
40
+ /// * 'ms' - an u32, number of microseconds to busy-wait. This should be known at
41
+ /// compile time, otherwise the delay may be much longer than specified.
64
42
#[ 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;
68
- delay ( loops) ;
43
+ pub fn delay_us ( us : u32 ) {
44
+ const GCD : u32 = gcd ( avr_config:: CPU_FREQUENCY_HZ , 4_000_000 ) ;
45
+ const NUMERATOR : u32 = avr_config:: CPU_FREQUENCY_HZ / GCD ;
46
+ const DENOMINATOR : u32 = 4_000_000 / GCD ;
47
+ let ticks: u64 = ( u64:: from ( us) * u64:: from ( NUMERATOR ) ) / u64:: from ( DENOMINATOR ) ;
48
+ delay_impl:: delay_count_48 ( ticks) ;
49
+ }
50
+
51
+ const fn gcd ( mut a : u32 , mut b : u32 ) -> u32 {
52
+ while b != 0 {
53
+ ( a, b) = ( b, a % b) ;
54
+ }
55
+ return a;
69
56
}
70
57
71
58
#[ cfg( test) ]
0 commit comments