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
|
use crate::{
fixpt::{fixpt, Fixpt},
mains::{Phase, PhaseUpdate},
mutex::{MainCtx, MutexCell},
system::SysPeriph,
timer::{timer_get_large, LargeTimestamp, RelLargeTimestamp, Timestamp, TIMER_TICK_US},
};
fn time_plus_ms(t: LargeTimestamp, ms: Fixpt) -> LargeTimestamp {
const TICK_US: i16 = TIMER_TICK_US as i16;
let ticks = (ms * fixpt!(1000 / TICK_US)).to_int();
t + RelLargeTimestamp::from_ticks(ticks)
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum TriacState {
Idle,
Triggering,
Triggered,
}
pub struct Triac {
phi_offs_ms: MutexCell<Fixpt>,
state: MutexCell<TriacState>,
trig_time: MutexCell<Timestamp>,
}
impl Triac {
pub const fn new() -> Self {
Self {
phi_offs_ms: MutexCell::new(Fixpt::from_int(20)),
state: MutexCell::new(TriacState::Idle),
trig_time: MutexCell::new(Timestamp::new()),
}
}
pub fn set_phi_offs_ms(&self, m: &MainCtx<'_>, ms: Fixpt) {
self.phi_offs_ms.set(m, ms);
}
fn set_trigger(&self, _m: &MainCtx<'_>, sp: &SysPeriph, trigger: bool) {
let trigger = !trigger; // negative logic at triac gate.
sp.PORTB.portb.modify(|_, w| w.pb3().bit(trigger));
}
pub fn run(&self, m: &MainCtx<'_>, sp: &SysPeriph, phase_update: PhaseUpdate, phase: &Phase) {
let now = timer_get_large(m);
let phi_offs_ms = self.phi_offs_ms.get(m);
let phaseref = match phase {
Phase::Notsync => {
return;
}
Phase::PosHalfwave(phaseref) => phaseref,
Phase::NegHalfwave(phaseref) => phaseref,
};
match self.state.get(m) {
TriacState::Idle => {
let must_trigger = now >= time_plus_ms(*phaseref, phi_offs_ms);
if must_trigger {
self.set_trigger(m, sp, true);
self.state.set(m, TriacState::Triggering);
self.trig_time.set(m, now.into());
} else {
self.set_trigger(m, sp, false);
}
}
TriacState::Triggering => {
if self.trig_time.get(m) >= now.into() {
self.set_trigger(m, sp, false);
self.state.set(m, TriacState::Triggered);
}
if phase_update == PhaseUpdate::Changed {
self.state.set(m, TriacState::Idle);
}
}
TriacState::Triggered => {
if phase_update == PhaseUpdate::Changed {
self.state.set(m, TriacState::Idle);
}
}
}
}
}
// vim: ts=4 sw=4 expandtab
|