2019-03-07 23:27:33 +08:00
|
|
|
#![no_std]
|
|
|
|
#![no_main]
|
2020-03-12 06:17:17 +08:00
|
|
|
// TODO: #![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,
|
|
|
|
watchdog::IndependentWatchdog,
|
|
|
|
time::U32Ext,
|
|
|
|
stm32::{CorePeripherals, Peripherals},
|
|
|
|
};
|
2019-03-22 00:41:33 +08:00
|
|
|
use smoltcp::{
|
|
|
|
time::Instant,
|
|
|
|
wire::EthernetAddress,
|
|
|
|
};
|
2019-03-12 01:23:52 +08:00
|
|
|
|
2020-03-12 07:50:24 +08:00
|
|
|
mod init_log;
|
|
|
|
use init_log::init_log;
|
2020-03-09 07:27:35 +08:00
|
|
|
mod pins;
|
2020-03-12 06:16:48 +08:00
|
|
|
use pins::Pins;
|
|
|
|
mod ad7172;
|
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
|
|
|
|
2020-03-12 06:17:34 +08:00
|
|
|
#[cfg(not(feature = "semihosting"))]
|
|
|
|
const WATCHDOG_INTERVAL: u32 = 100;
|
|
|
|
#[cfg(feature = "semihosting")]
|
|
|
|
const WATCHDOG_INTERVAL: u32 = 10_000;
|
|
|
|
|
2019-03-22 00:41: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
|
|
|
|
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
|
2019-03-19 05:04:34 +08:00
|
|
|
.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);
|
2020-03-12 06:17:34 +08:00
|
|
|
wd.start(WATCHDOG_INTERVAL.ms());
|
2019-03-12 01:23:52 +08:00
|
|
|
wd.feed();
|
|
|
|
|
2020-03-12 06:16:48 +08:00
|
|
|
let pins = Pins::setup(clocks, dp.GPIOA, dp.GPIOB, dp.GPIOC, dp.GPIOG, dp.SPI2);
|
2019-03-12 01:23:52 +08:00
|
|
|
|
2020-03-12 06:16:48 +08:00
|
|
|
let mut adc = ad7172::Adc::new(pins.adc_spi, pins.adc_nss).unwrap();
|
2019-03-15 01:13:25 +08:00
|
|
|
|
|
|
|
timer::setup(cp.SYST, clocks);
|
|
|
|
|
2019-03-22 00:41:33 +08:00
|
|
|
#[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));
|
2019-03-19 04:17:27 +08:00
|
|
|
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 {
|
2020-03-12 06:16:48 +08:00
|
|
|
// let adc_value = adc_input.read();
|
|
|
|
writeln!(server, "t={},pa3={}\r", now, 0.0 /*adc_value*/).unwrap();
|
2019-03-19 03:02:57 +08:00
|
|
|
last_output = now;
|
|
|
|
}
|
|
|
|
|
2020-03-12 07:44:15 +08:00
|
|
|
if let Some(channel) = adc.data_ready().unwrap() {
|
|
|
|
let data = adc.read_data().unwrap();
|
|
|
|
info!("ADC {}: {:08X}", channel, data);
|
|
|
|
}
|
|
|
|
|
2019-03-19 03:02:57 +08:00
|
|
|
// Update watchdog
|
|
|
|
wd.feed();
|
|
|
|
|
2020-03-12 07:44:15 +08:00
|
|
|
// 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
|
|
|
|
2019-03-19 04:17:27 +08:00
|
|
|
unreachable!()
|
2019-03-07 23:27:33 +08:00
|
|
|
}
|