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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#![allow(unexpected_cfgs)]
#[cfg(all(not(feature = "timer-legacy"), esp_idf_soc_gptimer_supported))]
mod example {
use std::num::NonZeroU32;
use std::time::Duration;
use esp_idf_hal::task::notification::Notification;
use esp_idf_hal::timer::config::{AlarmConfig, TimerConfig};
use esp_idf_hal::timer::*;
pub fn run() -> anyhow::Result<()> {
// It is necessary to call this function once. Otherwise some patches to the runtime
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
esp_idf_hal::sys::link_patches();
// A safer abstraction over FreeRTOS/ESP-IDF task notifications.
let notification = Notification::new();
let mut timer = TimerDriver::new(&TimerConfig::default())?;
timer.subscribe_default()?;
timer.enable()?;
// Every half a second
timer.set_alarm_action(Some(&AlarmConfig {
alarm_count: timer.duration_to_count(Duration::from_millis(500))?,
auto_reload_on_alarm: true,
..Default::default()
}))?;
timer.start()?;
let notifier = notification.notifier();
// SAFETY: make sure the `Notification` object is not dropped while the subscription is active
unsafe {
timer.subscribe(move |_| {
let bitset = 0b10001010101;
notifier.notify_and_yield(NonZeroU32::new(bitset).unwrap());
})?;
}
loop {
// Notify approach
// The benefit with this approach over checking a global static variable is
// that the scheduler can block the task, and quickly resume it when notified
// so no spinlock is needed / the CPU does not waste cycles.
let bitset = notification.wait(esp_idf_hal::delay::BLOCK);
if let Some(bitset) = bitset {
println!("got event with bits {bitset:#b} from ISR");
}
}
}
}
#[cfg(all(not(feature = "timer-legacy"), esp_idf_soc_gptimer_supported))]
fn main() -> anyhow::Result<()> {
example::run()
}
#[cfg(all(feature = "timer-legacy", not(esp_idf_version_at_least_6_0_0)))]
fn main() -> Result<(), esp_idf_hal::sys::EspError> {
use std::num::NonZeroU32;
use esp_idf_hal::peripherals::*;
use esp_idf_hal::task::notification::Notification;
use esp_idf_hal::timer::*;
// It is necessary to call this function once. Otherwise some patches to the runtime
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
esp_idf_hal::sys::link_patches();
let per = Peripherals::take()?;
// A safer abstraction over FreeRTOS/ESP-IDF task notifications.
let notification = Notification::new();
// BaseClock for the Timer is the APB_CLK that is running on 80MHz at default
// The default clock-divider is -> 80
// default APB clk is available with the APB_CLK_FREQ constant
let timer_conf = config::Config::new().auto_reload(true);
let mut timer = TimerDriver::new(per.timer00, &timer_conf)?;
// Every half a second
timer.set_alarm(timer.tick_hz() / 2)?;
let notifier = notification.notifier();
// Saftey: make sure the `Notification` object is not dropped while the subscription is active
unsafe {
timer.subscribe(move || {
let bitset = 0b10001010101;
notifier.notify_and_yield(NonZeroU32::new(bitset).unwrap());
})?;
}
timer.enable_interrupt()?;
timer.enable_alarm(true)?;
timer.enable(true)?;
loop {
// Notify approach
// The benefit with this approach over checking a global static variable is
// that the scheduler can block the task, and quickly resume it when notified
// so no spinlock is needed / the CPU does not waste cycles.
let bitset = notification.wait(esp_idf_hal::delay::BLOCK);
if let Some(bitset) = bitset {
println!("got event with bits {bitset:#b} from ISR");
}
}
}