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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "0.2.5"
|
||||
|
@ -253,12 +259,16 @@ dependencies = [
|
|||
"cortex-m-log",
|
||||
"cortex-m-rt",
|
||||
"cortex-m-semihosting 0.5.0",
|
||||
"fugit",
|
||||
"log",
|
||||
"nb 1.0.0",
|
||||
"num-traits",
|
||||
"panic-halt",
|
||||
"smoltcp",
|
||||
"stm32-eth",
|
||||
"stm32f4xx-hal",
|
||||
"usb-device",
|
||||
"usbd-serial",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -267,6 +277,12 @@ version = "0.2.135"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
|
@ -297,6 +313,16 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "num_threads"
|
||||
version = "0.1.6"
|
||||
|
@ -482,6 +508,17 @@ version = "0.2.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "vcell"
|
||||
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"] }
|
||||
stm32-eth = { version = "0.3.0", features = ["stm32f407"] }
|
||||
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]
|
||||
|
|
|
@ -18,16 +18,16 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1659446231,
|
||||
"narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=",
|
||||
"lastModified": 1666164185,
|
||||
"narHash": "sha256-5v+YB4ijeUfg5LCz9ck4gIpCPhIS+qn02OyPJO48bCE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "eabc38219184cc3e04a974fe31857d8e0eac098d",
|
||||
"rev": "c5203abb1329f7ea084c04acda330ca75d5b9fb5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-21.11",
|
||||
"ref": "nixos-22.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
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; };
|
||||
|
||||
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() {
|
||||
use log::LevelFilter;
|
||||
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 cortex_m_rt::entry;
|
||||
use stm32f4xx_hal as _;
|
||||
use log::{info};
|
||||
use stm32f4xx_hal::{
|
||||
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 init_log::init_log;
|
||||
use device::timer;
|
||||
|
||||
#[cfg(not(feature = "semihosting"))]
|
||||
const WATCHDOG_PERIOD: u32 = 1000;
|
||||
#[cfg(feature = "semihosting")]
|
||||
const WATCHDOG_PERIOD: u32 = 30000;
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
init_log();
|
||||
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