Skip to content

Commit 48faff1

Browse files
authored
Merge pull request #28 from bombela/cycacc
Cycle accurate implementation
2 parents 6ba963c + 073c91a commit 48faff1

File tree

6 files changed

+496
-74
lines changed

6 files changed

+496
-74
lines changed

Makefile

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Makefile useful during development.
2+
# `make asm` compiles examples/codegen.rs to assembly.
3+
# The output can then be reviewed for correctness.
4+
5+
NV?=nightly
6+
override FLAGS += -Z build-std=core -Z build-std-features=panic_immediate_abort --release
7+
MCU?=avr-atmega328p
8+
AVR_CPU_FREQUENCY_HZ?=16000000
9+
export AVR_CPU_FREQUENCY_HZ
10+
11+
build:
12+
cargo +$(NV) build $(FLAGS) --target=$(MCU).json -v
13+
cargo +$(NV) build --example codegen $(FLAGS) --target=$(MCU).json -v
14+
15+
asm:
16+
cargo +$(NV) rustc --example codegen $(FLAGS) --target=$(MCU).json -- --emit asm
17+
@echo target/$(MCU)/release/examples/*.s
18+
19+
asmclean:
20+
-rm target/*/release/deps/*.s

README.md

+13-14
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,35 @@
55

66
[API Documentation](https://docs.rs/avr_delay/)
77

8-
The intent of this library is to provide avr specific delay routines similar to the ones provided by the arduino library. The public functions are:
8+
The intent of this library is to provide avr specific delay routines similar to the ones provided by the arduino library.
99

1010
## `$AVR_CPU_FREQUENCY_HZ`
1111

1212
This crate uses the [`avr-config`](https://crates.io/crates/avr-config) crate for fetching the CPU frequency. As such, the `AVR_CPU_FREQUENCY_HZ` environment variable will need to be set when compiling your crate for AVR.
1313

14-
Example:
15-
1614
```bash
1715
export AVR_CPU_FREQUENCY_HZ=16000000
1816
cargo build -Z build-std=core --target avr-atmega328p.json --release
1917
```
2018

21-
```rust
22-
delay(count: u32)
23-
```
24-
25-
is a raw delay loop. Each loop is 4 cycles. The asm section can loop 65536 times. Initial overhead is about 13 cycles. Each outer loop has an overhead of about 11 cycles.
19+
## API
2620

2721
```rust
28-
delay_us(us: u32)
22+
delay_cycles<const CYCLES: u64>()
23+
delay_us<const US: u64>()
24+
delay_ms<const MS: u64>()
25+
delay_sec<const SEC: u64>()
2926
```
3027

31-
delay _us_ microseconds
28+
`delay_cycles` accepts 0 to 25_769_803_784 cycles (almost 18 minutes at 24Mhz).
29+
30+
The other functions convert time to cycles by using CPU_FREQUENCY_HZ.
3231

3332
```rust
34-
delay_ms(ms: u32)
33+
delay_ms<42>(); // delay by 42ms (exactly 1_008_000 cycles at 24Mhz).
3534
```
3635

37-
delay _ms_ milliseconds
36+
## Example
3837

3938
A simple example of how to use it follows.
4039

@@ -64,7 +63,7 @@ extern crate avr_delay;
6463

6564
use arduino::{DDRB, PORTB};
6665
use core::ptr::write_volatile;
67-
use avr_delay::{delay, delay_ms, delay_us};
66+
use avr_delay::delay_ms;
6867

6968
#[no_mangle]
7069
pub extern fn main() {
@@ -73,7 +72,7 @@ pub extern fn main() {
7372
loop {
7473
out = out ^ 0xff;
7574
unsafe { write_volatile(PORTB, out) }
76-
delay_ms(1000000);
75+
delay_ms<1000000>();
7776
}
7877
}
7978

examples/codegen.rs

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
extern crate avr_std_stub;
5+
6+
use avr_delay::delay_cycles;
7+
8+
#[no_mangle]
9+
fn main() {}
10+
11+
/*
12+
13+
Interesting corner case values. They are picked to be right around the switch between lower to
14+
higher number of bits for the dealy counter.
15+
16+
#!/bin/bash
17+
while read i; do
18+
echo "#[inline(never)] #[no_mangle] pub fn test_${i}() { delay_cycles::<${i}>(); }"
19+
done <<EOF
20+
0
21+
1
22+
2
23+
3
24+
4
25+
5
26+
6
27+
7
28+
8
29+
9
30+
11
31+
12
32+
767
33+
768
34+
769
35+
770
36+
771
37+
772
38+
773
39+
774
40+
262_144
41+
262_145
42+
262_146
43+
262_147
44+
262_148
45+
262_149
46+
262_150
47+
262_151
48+
262_152
49+
262_153
50+
262_154
51+
262_155
52+
83_886_081
53+
83_886_082
54+
83_886_083
55+
83_886_084
56+
83_886_085
57+
83_886_086
58+
83_886_087
59+
83_886_088
60+
83_886_089
61+
83_886_090
62+
83_886_091
63+
83_886_092
64+
83_886_093
65+
83_886_094
66+
83_886_095
67+
25_769_803_778
68+
25_769_803_779
69+
25_769_803_780
70+
25_769_803_783
71+
25_769_803_784
72+
EOF
73+
74+
*/
75+
76+
#[inline(never)] #[no_mangle] pub fn test_0() { delay_cycles::<0>(); }
77+
#[inline(never)] #[no_mangle] pub fn test_1() { delay_cycles::<1>(); }
78+
#[inline(never)] #[no_mangle] pub fn test_2() { delay_cycles::<2>(); }
79+
#[inline(never)] #[no_mangle] pub fn test_3() { delay_cycles::<3>(); }
80+
#[inline(never)] #[no_mangle] pub fn test_4() { delay_cycles::<4>(); }
81+
#[inline(never)] #[no_mangle] pub fn test_5() { delay_cycles::<5>(); }
82+
#[inline(never)] #[no_mangle] pub fn test_6() { delay_cycles::<6>(); }
83+
#[inline(never)] #[no_mangle] pub fn test_7() { delay_cycles::<7>(); }
84+
#[inline(never)] #[no_mangle] pub fn test_8() { delay_cycles::<8>(); }
85+
#[inline(never)] #[no_mangle] pub fn test_9() { delay_cycles::<9>(); }
86+
#[inline(never)] #[no_mangle] pub fn test_11() { delay_cycles::<11>(); }
87+
#[inline(never)] #[no_mangle] pub fn test_12() { delay_cycles::<12>(); }
88+
#[inline(never)] #[no_mangle] pub fn test_767() { delay_cycles::<767>(); }
89+
#[inline(never)] #[no_mangle] pub fn test_768() { delay_cycles::<768>(); }
90+
#[inline(never)] #[no_mangle] pub fn test_769() { delay_cycles::<769>(); }
91+
#[inline(never)] #[no_mangle] pub fn test_770() { delay_cycles::<770>(); }
92+
#[inline(never)] #[no_mangle] pub fn test_771() { delay_cycles::<771>(); }
93+
#[inline(never)] #[no_mangle] pub fn test_772() { delay_cycles::<772>(); }
94+
#[inline(never)] #[no_mangle] pub fn test_773() { delay_cycles::<773>(); }
95+
#[inline(never)] #[no_mangle] pub fn test_774() { delay_cycles::<774>(); }
96+
#[inline(never)] #[no_mangle] pub fn test_262_144() { delay_cycles::<262_144>(); }
97+
#[inline(never)] #[no_mangle] pub fn test_262_145() { delay_cycles::<262_145>(); }
98+
#[inline(never)] #[no_mangle] pub fn test_262_146() { delay_cycles::<262_146>(); }
99+
#[inline(never)] #[no_mangle] pub fn test_262_147() { delay_cycles::<262_147>(); }
100+
#[inline(never)] #[no_mangle] pub fn test_262_148() { delay_cycles::<262_148>(); }
101+
#[inline(never)] #[no_mangle] pub fn test_262_149() { delay_cycles::<262_149>(); }
102+
#[inline(never)] #[no_mangle] pub fn test_262_150() { delay_cycles::<262_150>(); }
103+
#[inline(never)] #[no_mangle] pub fn test_262_151() { delay_cycles::<262_151>(); }
104+
#[inline(never)] #[no_mangle] pub fn test_262_152() { delay_cycles::<262_152>(); }
105+
#[inline(never)] #[no_mangle] pub fn test_262_153() { delay_cycles::<262_153>(); }
106+
#[inline(never)] #[no_mangle] pub fn test_262_154() { delay_cycles::<262_154>(); }
107+
#[inline(never)] #[no_mangle] pub fn test_262_155() { delay_cycles::<262_155>(); }
108+
#[inline(never)] #[no_mangle] pub fn test_83_886_081() { delay_cycles::<83_886_081>(); }
109+
#[inline(never)] #[no_mangle] pub fn test_83_886_082() { delay_cycles::<83_886_082>(); }
110+
#[inline(never)] #[no_mangle] pub fn test_83_886_083() { delay_cycles::<83_886_083>(); }
111+
#[inline(never)] #[no_mangle] pub fn test_83_886_084() { delay_cycles::<83_886_084>(); }
112+
#[inline(never)] #[no_mangle] pub fn test_83_886_085() { delay_cycles::<83_886_085>(); }
113+
#[inline(never)] #[no_mangle] pub fn test_83_886_086() { delay_cycles::<83_886_086>(); }
114+
#[inline(never)] #[no_mangle] pub fn test_83_886_087() { delay_cycles::<83_886_087>(); }
115+
#[inline(never)] #[no_mangle] pub fn test_83_886_088() { delay_cycles::<83_886_088>(); }
116+
#[inline(never)] #[no_mangle] pub fn test_83_886_089() { delay_cycles::<83_886_089>(); }
117+
#[inline(never)] #[no_mangle] pub fn test_83_886_090() { delay_cycles::<83_886_090>(); }
118+
#[inline(never)] #[no_mangle] pub fn test_83_886_091() { delay_cycles::<83_886_091>(); }
119+
#[inline(never)] #[no_mangle] pub fn test_83_886_092() { delay_cycles::<83_886_092>(); }
120+
#[inline(never)] #[no_mangle] pub fn test_83_886_093() { delay_cycles::<83_886_093>(); }
121+
#[inline(never)] #[no_mangle] pub fn test_83_886_094() { delay_cycles::<83_886_094>(); }
122+
#[inline(never)] #[no_mangle] pub fn test_83_886_095() { delay_cycles::<83_886_095>(); }
123+
#[inline(never)] #[no_mangle] pub fn test_25_769_803_778() { delay_cycles::<25_769_803_778>(); }
124+
#[inline(never)] #[no_mangle] pub fn test_25_769_803_779() { delay_cycles::<25_769_803_779>(); }
125+
#[inline(never)] #[no_mangle] pub fn test_25_769_803_780() { delay_cycles::<25_769_803_780>(); }
126+
#[inline(never)] #[no_mangle] pub fn test_25_769_803_783() { delay_cycles::<25_769_803_783>(); }
127+
#[inline(never)] #[no_mangle] pub fn test_25_769_803_784() { delay_cycles::<25_769_803_784>(); }
128+
129+
// This shouldn't compile, but we don't have static assertion yet. The code produced is still
130+
// correct. But it costs more than calling delay_cycles twice.
131+
#[inline(never)] #[no_mangle] pub fn test_25_769_803_785_bad() { delay_cycles::<25_769_803_785>(); }
132+
133+
// This shouldn't compile, but we don't have static assertion yet. The code produced is still
134+
// correct. But it costs more than calling delay_cycles twice.
135+
#[inline(never)] #[no_mangle] pub fn test_25_853_952_778_bad() { delay_cycles::<25_853_952_778>(); }
136+
137+
// This shouldn't compile, but we don't have static assertion yet. The code produced is still
138+
// correct. But it costs more than calling delay_cycles twice. This is the absolute limit.
139+
#[inline(never)] #[no_mangle] pub fn test_25_853_952_779_bad() { delay_cycles::<25_853_952_779>(); }
140+
141+
// This shouldn't compile, but we don't have static assertion yet. This does overflow and should
142+
// produces the same function as 25_769_803_778.
143+
#[inline(never)] #[no_mangle] pub fn test_25_853_952_780_overflow() { delay_cycles::<25_853_952_780>(); }

examples/milliseconds.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ extern crate avr_std_stub;
55

66
#[no_mangle]
77
fn main() {
8-
avr_delay::delay_ms(4500);
8+
avr_delay::delay_ms::<4500>();
99
}

0 commit comments

Comments
 (0)