Skip to content

Cycle accurate implementation #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Makefile useful during development.
# `make asm` compiles examples/codegen.rs to assembly.
# The output can then be reviewed for correctness.

NV?=nightly
override FLAGS += -Z build-std=core -Z build-std-features=panic_immediate_abort --release
MCU?=avr-atmega328p
AVR_CPU_FREQUENCY_HZ?=16000000
export AVR_CPU_FREQUENCY_HZ

build:
cargo +$(NV) build $(FLAGS) --target=$(MCU).json -v
cargo +$(NV) build --example codegen $(FLAGS) --target=$(MCU).json -v

asm:
cargo +$(NV) rustc --example codegen $(FLAGS) --target=$(MCU).json -- --emit asm
@echo target/$(MCU)/release/examples/*.s

asmclean:
-rm target/*/release/deps/*.s
27 changes: 13 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,35 @@

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

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:
The intent of this library is to provide avr specific delay routines similar to the ones provided by the arduino library.

## `$AVR_CPU_FREQUENCY_HZ`

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.

Example:

```bash
export AVR_CPU_FREQUENCY_HZ=16000000
cargo build -Z build-std=core --target avr-atmega328p.json --release
```

```rust
delay(count: u32)
```

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.
## API

```rust
delay_us(us: u32)
delay_cycles<const CYCLES: u64>()
delay_us<const US: u64>()
delay_ms<const MS: u64>()
delay_sec<const SEC: u64>()
```

delay _us_ microseconds
`delay_cycles` accepts 0 to 25_769_803_784 cycles (almost 18 minutes at 24Mhz).

The other functions convert time to cycles by using CPU_FREQUENCY_HZ.

```rust
delay_ms(ms: u32)
delay_ms<42>(); // delay by 42ms (exactly 1_008_000 cycles at 24Mhz).
```

delay _ms_ milliseconds
## Example

A simple example of how to use it follows.

Expand Down Expand Up @@ -64,7 +63,7 @@ extern crate avr_delay;

use arduino::{DDRB, PORTB};
use core::ptr::write_volatile;
use avr_delay::{delay, delay_ms, delay_us};
use avr_delay::delay_ms;

#[no_mangle]
pub extern fn main() {
Expand All @@ -73,7 +72,7 @@ pub extern fn main() {
loop {
out = out ^ 0xff;
unsafe { write_volatile(PORTB, out) }
delay_ms(1000000);
delay_ms<1000000>();
}
}

Expand Down
143 changes: 143 additions & 0 deletions examples/codegen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#![no_std]
#![no_main]

extern crate avr_std_stub;

use avr_delay::delay_cycles;

#[no_mangle]
fn main() {}

/*

Interesting corner case values. They are picked to be right around the switch between lower to
higher number of bits for the dealy counter.

#!/bin/bash
while read i; do
echo "#[inline(never)] #[no_mangle] pub fn test_${i}() { delay_cycles::<${i}>(); }"
done <<EOF
0
1
2
3
4
5
6
7
8
9
11
12
767
768
769
770
771
772
773
774
262_144
262_145
262_146
262_147
262_148
262_149
262_150
262_151
262_152
262_153
262_154
262_155
83_886_081
83_886_082
83_886_083
83_886_084
83_886_085
83_886_086
83_886_087
83_886_088
83_886_089
83_886_090
83_886_091
83_886_092
83_886_093
83_886_094
83_886_095
25_769_803_778
25_769_803_779
25_769_803_780
25_769_803_783
25_769_803_784
EOF

*/

#[inline(never)] #[no_mangle] pub fn test_0() { delay_cycles::<0>(); }
#[inline(never)] #[no_mangle] pub fn test_1() { delay_cycles::<1>(); }
#[inline(never)] #[no_mangle] pub fn test_2() { delay_cycles::<2>(); }
#[inline(never)] #[no_mangle] pub fn test_3() { delay_cycles::<3>(); }
#[inline(never)] #[no_mangle] pub fn test_4() { delay_cycles::<4>(); }
#[inline(never)] #[no_mangle] pub fn test_5() { delay_cycles::<5>(); }
#[inline(never)] #[no_mangle] pub fn test_6() { delay_cycles::<6>(); }
#[inline(never)] #[no_mangle] pub fn test_7() { delay_cycles::<7>(); }
#[inline(never)] #[no_mangle] pub fn test_8() { delay_cycles::<8>(); }
#[inline(never)] #[no_mangle] pub fn test_9() { delay_cycles::<9>(); }
#[inline(never)] #[no_mangle] pub fn test_11() { delay_cycles::<11>(); }
#[inline(never)] #[no_mangle] pub fn test_12() { delay_cycles::<12>(); }
#[inline(never)] #[no_mangle] pub fn test_767() { delay_cycles::<767>(); }
#[inline(never)] #[no_mangle] pub fn test_768() { delay_cycles::<768>(); }
#[inline(never)] #[no_mangle] pub fn test_769() { delay_cycles::<769>(); }
#[inline(never)] #[no_mangle] pub fn test_770() { delay_cycles::<770>(); }
#[inline(never)] #[no_mangle] pub fn test_771() { delay_cycles::<771>(); }
#[inline(never)] #[no_mangle] pub fn test_772() { delay_cycles::<772>(); }
#[inline(never)] #[no_mangle] pub fn test_773() { delay_cycles::<773>(); }
#[inline(never)] #[no_mangle] pub fn test_774() { delay_cycles::<774>(); }
#[inline(never)] #[no_mangle] pub fn test_262_144() { delay_cycles::<262_144>(); }
#[inline(never)] #[no_mangle] pub fn test_262_145() { delay_cycles::<262_145>(); }
#[inline(never)] #[no_mangle] pub fn test_262_146() { delay_cycles::<262_146>(); }
#[inline(never)] #[no_mangle] pub fn test_262_147() { delay_cycles::<262_147>(); }
#[inline(never)] #[no_mangle] pub fn test_262_148() { delay_cycles::<262_148>(); }
#[inline(never)] #[no_mangle] pub fn test_262_149() { delay_cycles::<262_149>(); }
#[inline(never)] #[no_mangle] pub fn test_262_150() { delay_cycles::<262_150>(); }
#[inline(never)] #[no_mangle] pub fn test_262_151() { delay_cycles::<262_151>(); }
#[inline(never)] #[no_mangle] pub fn test_262_152() { delay_cycles::<262_152>(); }
#[inline(never)] #[no_mangle] pub fn test_262_153() { delay_cycles::<262_153>(); }
#[inline(never)] #[no_mangle] pub fn test_262_154() { delay_cycles::<262_154>(); }
#[inline(never)] #[no_mangle] pub fn test_262_155() { delay_cycles::<262_155>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_081() { delay_cycles::<83_886_081>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_082() { delay_cycles::<83_886_082>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_083() { delay_cycles::<83_886_083>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_084() { delay_cycles::<83_886_084>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_085() { delay_cycles::<83_886_085>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_086() { delay_cycles::<83_886_086>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_087() { delay_cycles::<83_886_087>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_088() { delay_cycles::<83_886_088>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_089() { delay_cycles::<83_886_089>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_090() { delay_cycles::<83_886_090>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_091() { delay_cycles::<83_886_091>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_092() { delay_cycles::<83_886_092>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_093() { delay_cycles::<83_886_093>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_094() { delay_cycles::<83_886_094>(); }
#[inline(never)] #[no_mangle] pub fn test_83_886_095() { delay_cycles::<83_886_095>(); }
#[inline(never)] #[no_mangle] pub fn test_25_769_803_778() { delay_cycles::<25_769_803_778>(); }
#[inline(never)] #[no_mangle] pub fn test_25_769_803_779() { delay_cycles::<25_769_803_779>(); }
#[inline(never)] #[no_mangle] pub fn test_25_769_803_780() { delay_cycles::<25_769_803_780>(); }
#[inline(never)] #[no_mangle] pub fn test_25_769_803_783() { delay_cycles::<25_769_803_783>(); }
#[inline(never)] #[no_mangle] pub fn test_25_769_803_784() { delay_cycles::<25_769_803_784>(); }

// This shouldn't compile, but we don't have static assertion yet. The code produced is still
// correct. But it costs more than calling delay_cycles twice.
#[inline(never)] #[no_mangle] pub fn test_25_769_803_785_bad() { delay_cycles::<25_769_803_785>(); }

// This shouldn't compile, but we don't have static assertion yet. The code produced is still
// correct. But it costs more than calling delay_cycles twice.
#[inline(never)] #[no_mangle] pub fn test_25_853_952_778_bad() { delay_cycles::<25_853_952_778>(); }

// This shouldn't compile, but we don't have static assertion yet. The code produced is still
// correct. But it costs more than calling delay_cycles twice. This is the absolute limit.
#[inline(never)] #[no_mangle] pub fn test_25_853_952_779_bad() { delay_cycles::<25_853_952_779>(); }

// This shouldn't compile, but we don't have static assertion yet. This does overflow and should
// produces the same function as 25_769_803_778.
#[inline(never)] #[no_mangle] pub fn test_25_853_952_780_overflow() { delay_cycles::<25_853_952_780>(); }
2 changes: 1 addition & 1 deletion examples/milliseconds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ extern crate avr_std_stub;

#[no_mangle]
fn main() {
avr_delay::delay_ms(4500);
avr_delay::delay_ms::<4500>();
}
Loading