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
|
#![no_std]
#![no_main]
#![feature(abi_avr_interrupt)]
#![feature(asm_experimental_arch)]
#![feature(asm_const)]
mod analog;
mod fixpt;
mod hw;
mod mains;
mod mutex;
mod pi;
mod speedo;
mod system;
mod timer;
mod triac;
use crate::{
analog::ac_capture_get,
hw::{interrupt, mcu, ports_init, Peripherals},
mutex::{unwrap_option, MainCtx},
system::{SysPeriph, System},
timer::{timer_init, TimerPeriph, TIMER_PERIPH},
};
static SYSTEM: System = System::new();
fn wdt_init() {
// SAFETY: The asm code only accesses the WDT registers
// which are not accessed from anywhere else in the program.
unsafe {
// Enable WDT with timeout 32.5 ms
core::arch::asm!(
"ldi {tmp}, 0x10", // WDCE=1
"out {WDTCR}, {tmp}",
"ldi {tmp}, 0x19", // WDCE=1, WDE=1, WDP2=0, WDP1=0, WDP0=1
"out {WDTCR}, {tmp}",
tmp = out(reg_upper) _,
WDTCR = const 0x21,
options(nostack, preserves_flags)
);
}
}
fn wdt_poke(_wp: &mcu::WDT) {
avr_device::asm::wdr();
}
#[avr_device::entry]
fn main() -> ! {
wdt_init();
let dp = unwrap_option(Peripherals::take());
let sp = SysPeriph {
AC: dp.AC,
ADC: dp.ADC,
PORTA: dp.PORTA,
PORTB: dp.PORTB,
TC1: dp.TC1,
};
let tp = TimerPeriph { TC0: dp.TC0 };
let init_static_vars = |ctx| {
TIMER_PERIPH.init(ctx, tp);
};
// SAFETY:
// This is the context handle for the main() function.
// Holding a reference to this object proves that the holder
// is running in main() context.
let m = unsafe { MainCtx::new_with_init(init_static_vars) };
ports_init(&sp.PORTA, &sp.PORTB);
timer_init(&m);
SYSTEM.init(&m, &sp);
// SAFETY: This must be after construction of MainCtx
// and after initialization of static MainInit variables.
unsafe { interrupt::enable() };
loop {
let ac_capture = ac_capture_get();
SYSTEM.run(&m, &sp, ac_capture);
wdt_poke(&dp.WDT);
}
}
// vim: ts=4 sw=4 expandtab
|