Skip to content

Commit 258f391

Browse files
lord-nestappersg
authored andcommitted
Add delay_count and delay_loop internal functions
Move delay loop into internal functions . Refactor the assembly loop into its own function, to allow easier reuse in the below functions. . Add internal delay functions calling the assembly loop function. One function uses a 32 bit counter, and the other uses a 48 bit counter. These functions will be used to reactor delay_ms and delay_us to prevent overflow. . Refactor delay to use the internal delay functions.
1 parent 8ec7a7c commit 258f391

File tree

1 file changed

+80
-29
lines changed

1 file changed

+80
-29
lines changed

src/lib.rs

Lines changed: 80 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![no_std]
33
#![crate_name = "avr_delay"]
44

5+
#[allow(unused_imports)]
56
use core::arch::asm;
67

78
/// This library is intended to provide a busy-wait delay
@@ -21,53 +22,103 @@ use core::arch::asm;
2122
// initially, and then 11 cycles per outer loop. We ignore
2223
// all that.
2324

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.
2526
/// # 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.
2728
#[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);
4931
}
5032

5133
///delay for N milliseconds
5234
/// # Arguments
53-
/// * 'ms' - an u64, number of milliseconds to busy-wait
35+
/// * 'ms' - an u32, number of milliseconds to busy-wait
5436
#[inline(always)]
55-
pub fn delay_ms(ms: u64) {
37+
pub fn delay_ms(ms: u32) {
5638
// microseconds
5739
let us = ms * 1000;
5840
delay_us(us);
5941
}
6042

6143
///delay for N microseconds
6244
/// # Arguments
63-
/// * 'us' - an u64, number of microseconds to busy-wait
45+
/// * 'ms' - an u32, number of microseconds to busy-wait
6446
#[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;
6852
delay(loops);
6953
}
7054

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+
71122
#[cfg(test)]
72123
mod tests {
73124
#[test]

0 commit comments

Comments
 (0)