thermostat/src/main.rs

151 lines
3.9 KiB
Rust
Raw Normal View History

2019-03-07 23:27:33 +08:00
#![no_std]
#![no_main]
2019-03-19 04:40:03 +08:00
#![deny(warnings, unused)]
2019-03-07 23:27:33 +08:00
2019-03-15 02:58:41 +08:00
#[cfg(not(feature = "semihosting"))]
2019-04-27 21:23:50 +08:00
use panic_abort as _;
2019-03-15 02:58:41 +08:00
#[cfg(feature = "semihosting")]
2019-04-27 21:23:50 +08:00
use panic_semihosting as _;
2019-03-07 23:27:33 +08:00
2019-04-27 21:23:50 +08:00
use log::{info, warn};
2019-03-15 02:58:41 +08:00
use core::fmt::Write;
2019-03-12 01:23:52 +08:00
use cortex_m::asm::wfi;
2019-03-07 23:27:33 +08:00
use cortex_m_rt::entry;
2019-03-12 01:23:52 +08:00
use embedded_hal::watchdog::{WatchdogEnable, Watchdog};
use stm32f4xx_hal::{
rcc::RccExt,
gpio::GpioExt,
watchdog::IndependentWatchdog,
time::U32Ext,
stm32::{CorePeripherals, Peripherals},
};
use smoltcp::{
time::Instant,
wire::EthernetAddress,
};
2019-03-12 01:23:52 +08:00
2020-03-09 07:27:35 +08:00
mod pins;
2019-03-12 01:23:52 +08:00
mod adc_input;
use adc_input::AdcInput;
2019-03-13 05:52:39 +08:00
mod net;
mod server;
use server::Server;
2019-03-15 01:13:25 +08:00
mod timer;
2019-03-19 04:41:51 +08:00
/// Interval at which to sample the ADC input and broadcast to all
/// clients.
///
/// This should be a multiple of the `TIMER_RATE`.
2019-03-15 01:13:25 +08:00
const OUTPUT_INTERVAL: u32 = 1000;
2019-03-07 23:27:33 +08:00
#[cfg(not(feature = "generate-hwaddr"))]
const NET_HWADDR: [u8; 6] = [0x02, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
2019-03-15 02:58:41 +08:00
#[cfg(not(feature = "semihosting"))]
fn init_log() {}
#[cfg(feature = "semihosting")]
fn init_log() {
use log::LevelFilter;
use cortex_m_log::log::{Logger, init};
use cortex_m_log::printer::semihosting::{InterruptOk, hio::HStdout};
static mut LOGGER: Option<Logger<InterruptOk<HStdout>>> = None;
let logger = Logger {
inner: InterruptOk::<_>::stdout().expect("semihosting stdout"),
level: LevelFilter::Info,
};
let logger = unsafe {
LOGGER.get_or_insert(logger)
};
init(logger).expect("set logger");
}
2019-03-19 04:41:51 +08:00
/// Initialization and main loop
2019-03-07 23:27:33 +08:00
#[entry]
fn main() -> ! {
2019-03-15 02:58:41 +08:00
init_log();
2019-06-01 10:14:32 +08:00
info!("Thermostat firmware");
2019-03-12 01:23:52 +08:00
let mut cp = CorePeripherals::take().unwrap();
2019-03-13 05:52:39 +08:00
cp.SCB.enable_icache();
cp.SCB.enable_dcache(&mut cp.CPUID);
2019-03-12 01:23:52 +08:00
let dp = Peripherals::take().unwrap();
stm32_eth::setup(&dp.RCC, &dp.SYSCFG);
2019-03-15 01:13:25 +08:00
let clocks = dp.RCC.constrain()
2019-03-12 01:23:52 +08:00
.cfgr
.sysclk(168.mhz())
.hclk(168.mhz())
.pclk1(32.mhz())
.pclk2(64.mhz())
2019-03-12 01:23:52 +08:00
.freeze();
let mut wd = IndependentWatchdog::new(dp.IWDG);
2019-03-15 05:01:01 +08:00
wd.start(1000u32.ms());
2019-03-12 01:23:52 +08:00
wd.feed();
let gpioa = dp.GPIOA.split();
let gpiob = dp.GPIOB.split();
let gpioc = dp.GPIOC.split();
let gpiog = dp.GPIOG.split();
2019-03-15 02:58:41 +08:00
info!("ADC init");
let mut adc_input = AdcInput::new(dp.ADC1, gpioa.pa3);
2019-03-13 05:52:39 +08:00
2019-03-15 02:58:41 +08:00
info!("Eth setup");
2020-03-09 07:27:35 +08:00
pins::setup_ethernet(
gpioa.pa1, gpioa.pa2, gpioc.pc1, gpioa.pa7,
gpioc.pc4, gpioc.pc5, gpiob.pb11, gpiog.pg13,
gpiob.pb13
2019-03-12 01:23:52 +08:00
);
2019-03-15 01:13:25 +08:00
2019-03-15 02:58:41 +08:00
info!("Timer setup");
2019-03-15 01:13:25 +08:00
timer::setup(cp.SYST, clocks);
#[cfg(not(feature = "generate-hwaddr"))]
let hwaddr = EthernetAddress(NET_HWADDR);
#[cfg(feature = "generate-hwaddr")]
let hwaddr = {
let uid = stm32f4xx_hal::signature::Uid::get();
EthernetAddress(hash2hwaddr::generate_hwaddr(uid))
};
info!("Net hwaddr: {}", hwaddr);
2019-03-15 02:58:41 +08:00
info!("Net startup");
2020-03-09 07:07:56 +08:00
net::run(dp.ETHERNET_MAC, dp.ETHERNET_DMA, hwaddr, |iface| {
2019-03-19 03:02:57 +08:00
Server::run(iface, |server| {
let mut last_output = 0_u32;
loop {
let now = timer::now().0;
2019-04-27 21:25:27 +08:00
let instant = Instant::from_millis(i64::from(now));
cortex_m::interrupt::free(net::clear_pending);
server.poll(instant)
.unwrap_or_else(|e| {
warn!("poll: {:?}", e);
});
2019-03-19 03:02:57 +08:00
let now = timer::now().0;
if now - last_output >= OUTPUT_INTERVAL {
let adc_value = adc_input.read();
2019-04-27 21:25:27 +08:00
writeln!(server, "t={},pa3={}\r", now, adc_value).unwrap();
2019-03-19 03:02:57 +08:00
last_output = now;
}
// Update watchdog
wd.feed();
cortex_m::interrupt::free(|cs| {
if !net::is_pending(cs) {
// Wait for interrupts
wfi();
}
2019-03-15 01:13:25 +08:00
});
}
2019-03-19 03:02:57 +08:00
});
});
2019-03-15 03:43:35 +08:00
unreachable!()
2019-03-07 23:27:33 +08:00
}