forked from M-Labs/kirdy
blinky, working systick and delay
This commit is contained in:
parent
710b3ff5d5
commit
fc90593f84
|
@ -41,6 +41,12 @@ dependencies = [
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bare-metal"
|
name = "bare-metal"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
@ -253,12 +259,16 @@ dependencies = [
|
||||||
"cortex-m-log",
|
"cortex-m-log",
|
||||||
"cortex-m-rt",
|
"cortex-m-rt",
|
||||||
"cortex-m-semihosting 0.5.0",
|
"cortex-m-semihosting 0.5.0",
|
||||||
|
"fugit",
|
||||||
"log",
|
"log",
|
||||||
"nb 1.0.0",
|
"nb 1.0.0",
|
||||||
|
"num-traits",
|
||||||
"panic-halt",
|
"panic-halt",
|
||||||
"smoltcp",
|
"smoltcp",
|
||||||
"stm32-eth",
|
"stm32-eth",
|
||||||
"stm32f4xx-hal",
|
"stm32f4xx-hal",
|
||||||
|
"usb-device",
|
||||||
|
"usbd-serial",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -267,6 +277,12 @@ version = "0.2.135"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
|
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libm"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.17"
|
version = "0.4.17"
|
||||||
|
@ -297,6 +313,16 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
|
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"libm",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_threads"
|
name = "num_threads"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
@ -482,6 +508,17 @@ version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
|
checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "usbd-serial"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db75519b86287f12dcf0d171c7cf4ecc839149fe9f3b720ac4cfce52959e1dfe"
|
||||||
|
dependencies = [
|
||||||
|
"embedded-hal 0.2.7",
|
||||||
|
"nb 0.1.3",
|
||||||
|
"usb-device",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcell"
|
name = "vcell"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
|
|
@ -25,6 +25,10 @@ cortex-m-log = { version = "0.7.0", features = ["log-integration", "semihosting"
|
||||||
stm32f4xx-hal = { version = "0.13.2", features = ["rt", "stm32f407", "usb_fs"] }
|
stm32f4xx-hal = { version = "0.13.2", features = ["rt", "stm32f407", "usb_fs"] }
|
||||||
stm32-eth = { version = "0.3.0", features = ["stm32f407"] }
|
stm32-eth = { version = "0.3.0", features = ["stm32f407"] }
|
||||||
smoltcp = { version = "0.8.0", default-features = false, features = ["proto-ipv4", "socket-tcp", "log", "medium-ethernet"] }
|
smoltcp = { version = "0.8.0", default-features = false, features = ["proto-ipv4", "socket-tcp", "log", "medium-ethernet"] }
|
||||||
|
num-traits = { version = "0.2.15", default-features = false, features = ["libm"] }
|
||||||
|
usb-device = "0.2.9"
|
||||||
|
usbd-serial = "0.1.1"
|
||||||
|
fugit = "0.3.6"
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -18,16 +18,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1659446231,
|
"lastModified": 1666164185,
|
||||||
"narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=",
|
"narHash": "sha256-5v+YB4ijeUfg5LCz9ck4gIpCPhIS+qn02OyPJO48bCE=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "eabc38219184cc3e04a974fe31857d8e0eac098d",
|
"rev": "c5203abb1329f7ea084c04acda330ca75d5b9fb5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-21.11",
|
"ref": "nixos-22.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
description = "Firmware for kirdy";
|
description = "Firmware for kirdy";
|
||||||
|
|
||||||
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-21.11;
|
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-22.05;
|
||||||
inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; };
|
inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; };
|
||||||
|
|
||||||
outputs = { self, nixpkgs, mozilla-overlay }:
|
outputs = { self, nixpkgs, mozilla-overlay }:
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
use stm32f4xx_hal::{
|
||||||
|
adc::Adc,
|
||||||
|
gpio::{
|
||||||
|
AF5, Alternate, AlternateOD, Analog, Floating, Input,
|
||||||
|
gpioa::*,
|
||||||
|
gpiob::*,
|
||||||
|
gpioc::*,
|
||||||
|
gpioe::*,
|
||||||
|
gpiof::*,
|
||||||
|
gpiog::*,
|
||||||
|
GpioExt,
|
||||||
|
Output, PushPull,
|
||||||
|
},
|
||||||
|
hal::{self, blocking::spi::Transfer, digital::v2::OutputPin},
|
||||||
|
otg_fs::USB,
|
||||||
|
rcc::Clocks,
|
||||||
|
pwm::{self, PwmChannels},
|
||||||
|
spi::{Spi, NoMiso, TransferModeNormal},
|
||||||
|
pac::{
|
||||||
|
ADC1,
|
||||||
|
GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG,
|
||||||
|
OTG_FS_GLOBAL, OTG_FS_DEVICE, OTG_FS_PWRCLK,
|
||||||
|
SPI1, SPI2, SPI3,
|
||||||
|
TIM4
|
||||||
|
},
|
||||||
|
timer::Timer,
|
||||||
|
time::U32Ext,
|
||||||
|
};
|
||||||
|
|
||||||
|
use stm32_eth::EthPins;
|
||||||
|
pub type EthernetPins = EthPins<
|
||||||
|
PA1<Input<Floating>>,
|
||||||
|
PA7<Input<Floating>>,
|
||||||
|
PB11<Input<Floating>>,
|
||||||
|
PG13<Input<Floating>>,
|
||||||
|
PB13<Input<Floating>>,
|
||||||
|
PC4<Input<Floating>>,
|
||||||
|
PC5<Input<Floating>>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
impl thermostatPins for thermostat {
|
||||||
|
type DacSpi = Dac0Spi;
|
||||||
|
type DacSync = PE4<Output<PushPull>>;
|
||||||
|
type Shdn = PE10<Output<PushPull>>;
|
||||||
|
type VRefPin = PA0<Analog>;
|
||||||
|
type ItecPin = PA6<Analog>;
|
||||||
|
type DacFeedbackPin = PA4<Analog>;
|
||||||
|
type TecUMeasPin = PC2<Analog>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct thermostatPinSet {
|
||||||
|
pub dac_spi: Transfer<u8>,
|
||||||
|
pub dac_sync: OutputPin,
|
||||||
|
pub shdn: OutputPin,
|
||||||
|
pub vref_pin: VRefPin,
|
||||||
|
pub itec_pin: ItecPin,
|
||||||
|
pub dac_feedback_pin: DacFeedbackPin,
|
||||||
|
pub tec_u_meas_pin: TecUMeasPin,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Pins {
|
||||||
|
pub thermostat: thermostatPinSet,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pins {
|
||||||
|
|
||||||
|
pub fn setup(
|
||||||
|
clocks: Clocks,
|
||||||
|
tim4: TIM4,
|
||||||
|
gpioa: GPIOA, gpiob: GPIOB, gpioc: GPIOC, gpiod: GPIOD, gpioe: GPIOE, gpiof: GPIOF, gpiog: GPIOG,
|
||||||
|
spi1: SPI1, spi2: SPI2, spi3: SPI3,
|
||||||
|
adc1: ADC1,
|
||||||
|
otg_fs_global: OTG_FS_GLOBAL, otg_fs_device: OTG_FS_DEVICE, otg_fs_pwrclk: OTG_FS_PWRCLK,
|
||||||
|
) -> (Self, EthernetPins, USB) {
|
||||||
|
let gpioa = gpioa.split();
|
||||||
|
let gpiob = gpiob.split();
|
||||||
|
let gpioc = gpioc.split();
|
||||||
|
let gpiod = gpiod.split();
|
||||||
|
let gpioe = gpioe.split();
|
||||||
|
let gpiof = gpiof.split();
|
||||||
|
let gpiog = gpiog.split();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,14 @@
|
||||||
|
#[cfg(not(feature = "semihosting"))]
|
||||||
|
use super::usb;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "semihosting"))]
|
||||||
|
pub fn init_log() {
|
||||||
|
static USB_LOGGER: usb::Logger = usb::Logger;
|
||||||
|
let _ = log::set_logger(&USB_LOGGER);
|
||||||
|
log::set_max_level(log::LevelFilter::Debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "semihosting")]
|
||||||
pub fn init_log() {
|
pub fn init_log() {
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use cortex_m_log::log::{Logger, init};
|
use cortex_m_log::log::{Logger, init};
|
|
@ -0,0 +1,4 @@
|
||||||
|
pub mod log;
|
||||||
|
pub mod usb;
|
||||||
|
pub mod timer;
|
||||||
|
// pub mod init_gpio;
|
|
@ -0,0 +1,51 @@
|
||||||
|
use core::cell::RefCell;
|
||||||
|
use core::ops::Deref;
|
||||||
|
use cortex_m::interrupt::Mutex;
|
||||||
|
use cortex_m::peripheral::syst::SystClkSource;
|
||||||
|
use cortex_m_rt::exception;
|
||||||
|
use stm32f4xx_hal::{
|
||||||
|
rcc::Clocks,
|
||||||
|
pac::SYST,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Rate in Hz
|
||||||
|
const TIMER_RATE: u32 = 1000;
|
||||||
|
/// Interval duration in milliseconds
|
||||||
|
const TIMER_DELTA: u32 = 1000 / TIMER_RATE;
|
||||||
|
/// Elapsed time in milliseconds
|
||||||
|
static TIMER_MS: Mutex<RefCell<u32>> = Mutex::new(RefCell::new(0));
|
||||||
|
|
||||||
|
/// Setup SysTick exception
|
||||||
|
pub fn setup(mut syst: SYST, clocks: Clocks) {
|
||||||
|
syst.set_clock_source(SystClkSource::Core);
|
||||||
|
syst.set_reload(clocks.hclk().to_Hz() / TIMER_RATE - 1);
|
||||||
|
syst.enable_counter();
|
||||||
|
syst.enable_interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SysTick exception (Timer)
|
||||||
|
#[exception]
|
||||||
|
fn SysTick() {
|
||||||
|
cortex_m::interrupt::free(|cs| {
|
||||||
|
*TIMER_MS.borrow(cs)
|
||||||
|
.borrow_mut() += TIMER_DELTA;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Obtain current time in milliseconds
|
||||||
|
pub fn now() -> u32 {
|
||||||
|
cortex_m::interrupt::free(|cs| {
|
||||||
|
*TIMER_MS.borrow(cs)
|
||||||
|
.borrow()
|
||||||
|
.deref()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// block for `amount` milliseconds
|
||||||
|
pub fn sleep(amount: u32) {
|
||||||
|
if amount == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let start = now();
|
||||||
|
while now() - start <= amount - 1 {}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
use core::{fmt::{self, Write}, mem::MaybeUninit};
|
||||||
|
use cortex_m::interrupt::free;
|
||||||
|
use stm32f4xx_hal::{
|
||||||
|
otg_fs::{USB, UsbBus as Bus},
|
||||||
|
pac::{interrupt, Interrupt, NVIC},
|
||||||
|
};
|
||||||
|
use usb_device::{
|
||||||
|
class_prelude::{UsbBusAllocator},
|
||||||
|
prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid},
|
||||||
|
};
|
||||||
|
use usbd_serial::SerialPort;
|
||||||
|
use log::{Record, Log, Metadata};
|
||||||
|
|
||||||
|
static mut EP_MEMORY: [u32; 1024] = [0; 1024];
|
||||||
|
|
||||||
|
static mut BUS: MaybeUninit<UsbBusAllocator<Bus<USB>>> = MaybeUninit::uninit();
|
||||||
|
// static mut SERIAL_DEV: Option<(SerialPort<'static, Bus<USB>>, UsbDevice<'static, Bus<USB>>)> = None;
|
||||||
|
static mut STATE: Option<State> = None;
|
||||||
|
|
||||||
|
pub struct State {
|
||||||
|
serial: SerialPort<'static, Bus<USB>>,
|
||||||
|
dev: UsbDevice<'static, Bus<USB>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn setup(usb: USB) {
|
||||||
|
unsafe { BUS.write(Bus::new(usb, &mut EP_MEMORY)) };
|
||||||
|
|
||||||
|
let bus = unsafe { BUS.assume_init_ref() };
|
||||||
|
let serial = SerialPort::new(bus);
|
||||||
|
let dev = UsbDeviceBuilder::new(bus, UsbVidPid(0x16c0, 0x27dd))
|
||||||
|
.manufacturer("M-Labs")
|
||||||
|
.product("thermostat")
|
||||||
|
.device_release(0x20)
|
||||||
|
.self_powered(true)
|
||||||
|
.device_class(usbd_serial::USB_CLASS_CDC)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
free(|_| {
|
||||||
|
unsafe { STATE = Some(State { serial, dev }); }
|
||||||
|
});
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
NVIC::unmask(Interrupt::OTG_FS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get() -> Option<&'static mut Self> {
|
||||||
|
unsafe { STATE.as_mut() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll() {
|
||||||
|
if let Some(ref mut s) = Self::get() {
|
||||||
|
if s.dev.poll(&mut [&mut s.serial]) {
|
||||||
|
// discard any input
|
||||||
|
let mut buf = [0u8; 64];
|
||||||
|
let _ = s.serial.read(&mut buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interrupt]
|
||||||
|
fn OTG_FS() {
|
||||||
|
free(|_| {
|
||||||
|
State::poll();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Logger;
|
||||||
|
|
||||||
|
impl Log for Logger {
|
||||||
|
fn enabled(&self, _: &Metadata) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&self, record: &Record) {
|
||||||
|
if self.enabled(record.metadata()) {
|
||||||
|
let mut output = SerialOutput;
|
||||||
|
let _ = writeln!(&mut output, "{} - {}", record.level(), record.args());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&self) {
|
||||||
|
if let Some(ref mut state) = State::get() {
|
||||||
|
let _ = free(|_| state.serial.flush());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerialOutput;
|
||||||
|
|
||||||
|
impl Write for SerialOutput {
|
||||||
|
fn write_str(&mut self, s: &str) -> core::result::Result<(), core::fmt::Error> {
|
||||||
|
if let Some(ref mut state) = State::get() {
|
||||||
|
for chunk in s.as_bytes().chunks(16) {
|
||||||
|
free(|_| state.serial.write(chunk))
|
||||||
|
.map_err(|_| fmt::Error)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
51
src/main.rs
51
src/main.rs
|
@ -3,16 +3,57 @@
|
||||||
|
|
||||||
use panic_halt as _;
|
use panic_halt as _;
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use stm32f4xx_hal as _;
|
use stm32f4xx_hal::{
|
||||||
use log::{info};
|
watchdog::IndependentWatchdog,
|
||||||
|
rcc::RccExt,
|
||||||
|
pac::{CorePeripherals, Peripherals},
|
||||||
|
time::MegaHertz, prelude::_stm32f4xx_hal_gpio_GpioExt,
|
||||||
|
};
|
||||||
|
use log::info;
|
||||||
|
use fugit::ExtU32;
|
||||||
|
mod device;
|
||||||
|
use device::log::init_log;
|
||||||
|
// use setup::init_gpio::Pins;
|
||||||
|
|
||||||
mod init_log;
|
use device::timer;
|
||||||
use init_log::init_log;
|
|
||||||
|
#[cfg(not(feature = "semihosting"))]
|
||||||
|
const WATCHDOG_PERIOD: u32 = 1000;
|
||||||
|
#[cfg(feature = "semihosting")]
|
||||||
|
const WATCHDOG_PERIOD: u32 = 30000;
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
init_log();
|
init_log();
|
||||||
info!("Kirdy init");
|
info!("Kirdy init");
|
||||||
|
|
||||||
loop {}
|
let mut core_perif = CorePeripherals::take().unwrap();
|
||||||
|
core_perif.SCB.enable_icache();
|
||||||
|
core_perif.SCB.enable_dcache(&mut core_perif.CPUID);
|
||||||
|
|
||||||
|
let perif = Peripherals::take().unwrap();
|
||||||
|
let clocks = perif.RCC.constrain()
|
||||||
|
.cfgr
|
||||||
|
.use_hse(MegaHertz::from_raw(8).convert())
|
||||||
|
.sysclk(MegaHertz::from_raw(168).convert())
|
||||||
|
.hclk(MegaHertz::from_raw(168).convert())
|
||||||
|
.pclk1(MegaHertz::from_raw(32).convert())
|
||||||
|
.pclk2(MegaHertz::from_raw(64).convert())
|
||||||
|
.freeze();
|
||||||
|
|
||||||
|
let mut wd = IndependentWatchdog::new(perif.IWDG);
|
||||||
|
wd.start(WATCHDOG_PERIOD.millis());
|
||||||
|
wd.feed();
|
||||||
|
|
||||||
|
timer::setup(core_perif.SYST, clocks);
|
||||||
|
|
||||||
|
let gpioc = perif.GPIOC.split();
|
||||||
|
let mut pc9 = gpioc.pc9.into_push_pull_output();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
pc9.toggle();
|
||||||
|
timer::sleep(1);
|
||||||
|
wd.feed();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue