-
Notifications
You must be signed in to change notification settings - Fork 231
/
Copy pathuno-millis.rs
93 lines (78 loc) · 3.17 KB
/
uno-millis.rs
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/*!
* A basic implementation of the `millis()` function from Arduino:
*
* https://www.arduino.cc/reference/en/language/functions/time/millis/
*
* Uses timer TC0 and one of its interrupts to update a global millisecond
* counter. A walkthough of this code is available here:
*
* https://blog.rahix.de/005-avr-hal-millis/
*/
#![no_std]
#![no_main]
#![feature(abi_avr_interrupt)]
use arduino_hal::prelude::*;
use core::cell;
use panic_halt as _;
use embedded_hal_v0::serial::Read;
// Possible Values:
//
// ╔═══════════╦══════════════╦═══════════════════╗
// ║ PRESCALER ║ TIMER_COUNTS ║ Overflow Interval ║
// ╠═══════════╬══════════════╬═══════════════════╣
// ║ 64 ║ 250 ║ 1 ms ║
// ║ 256 ║ 125 ║ 2 ms ║
// ║ 256 ║ 250 ║ 4 ms ║
// ║ 1024 ║ 125 ║ 8 ms ║
// ║ 1024 ║ 250 ║ 16 ms ║
// ╚═══════════╩══════════════╩═══════════════════╝
const PRESCALER: u32 = 1024;
const TIMER_COUNTS: u32 = 125;
const MILLIS_INCREMENT: u32 = PRESCALER * TIMER_COUNTS / 16000;
static MILLIS_COUNTER: avr_device::interrupt::Mutex<cell::Cell<u32>> =
avr_device::interrupt::Mutex::new(cell::Cell::new(0));
fn millis_init(tc0: arduino_hal::pac::TC0) {
// Configure the timer for the above interval (in CTC mode)
// and enable its interrupt.
tc0.tccr0a.write(|w| w.wgm0().ctc());
tc0.ocr0a.write(|w| w.bits(TIMER_COUNTS as u8));
tc0.tccr0b.write(|w| match PRESCALER {
8 => w.cs0().prescale_8(),
64 => w.cs0().prescale_64(),
256 => w.cs0().prescale_256(),
1024 => w.cs0().prescale_1024(),
_ => panic!(),
});
tc0.timsk0.write(|w| w.ocie0a().set_bit());
// Reset the global millisecond counter
avr_device::interrupt::free(|cs| {
MILLIS_COUNTER.borrow(cs).set(0);
});
}
#[avr_device::interrupt(atmega328p)]
fn TIMER0_COMPA() {
avr_device::interrupt::free(|cs| {
let counter_cell = MILLIS_COUNTER.borrow(cs);
let counter = counter_cell.get();
counter_cell.set(counter + MILLIS_INCREMENT);
})
}
fn millis() -> u32 {
avr_device::interrupt::free(|cs| MILLIS_COUNTER.borrow(cs).get())
}
// ----------------------------------------------------------------------------
#[arduino_hal::entry]
fn main() -> ! {
let dp = arduino_hal::Peripherals::take().unwrap();
let pins = arduino_hal::pins!(dp);
let mut serial = arduino_hal::default_serial!(dp, pins, 57600);
millis_init(dp.TC0);
// Enable interrupts globally
unsafe { avr_device::interrupt::enable() };
// Wait for a character and print current time once it is received
loop {
let b = nb::block!(serial.read()).unwrap_infallible();
let time = millis();
ufmt::uwriteln!(&mut serial, "Got {} after {} ms!\r", b, time).unwrap_infallible();
}
}