1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use core::arch::arm::__nop;

/// This function come directly from the [cortex_m
/// crate](https://docs.rs/cortex-m/0.6.2/cortex_m/asm/fn.delay.html)
/// It provide a delay in number of instructions. Use it only if you know what
/// you are doing.
#[inline]
pub fn delay(n: u64) {
    unsafe {
        asm!("1:
                  nop
                  subs $0, $$1
                  bne.n 1b"
                 : "+r"(n / 4 + 1)
                 :
                 :
                 : "volatile");
    }
}

/// This implementation will be more imprecise with lower CPU frequencies and
/// not properly work at all with anything below 5 MHz
#[inline]
pub fn sleep_us(microseconds: u32) {
    (0..microseconds).for_each(|_| {
        let mut inner = crate::mcg::F_CPU / 5_000_000;

        // This loop should take 5 cycles
        while inner != 0 {
            inner -= 1;
            unsafe {
                __nop();
            }
        }
    });
}

/// For milliseconds, this loop approach is not too far off reality as long
/// as it runs uninterrupted.
pub fn sleep_ms(milliseconds: u32) {
    (0..milliseconds).for_each(|_| {
        let mut inner = crate::mcg::F_CPU / 10_000;

        // This loop should take 10 cycles:
        //  inner -= 1     sub: 1 cycle
        //  inner != 0     beq: 1 cycle if not taken
        //  6*nop          nop: 1 cycle
        //  endwhile       b:   1 + (1-3) cycles
        while inner != 0 {
            inner -= 1;
            unsafe {
                __nop(); // 1
                __nop(); // 2
                __nop(); // 3
                __nop(); // 4
                __nop(); // 5
                __nop(); // 6
            }
        }
    });
}