pounder_test/src/main.rs

844 lines
27 KiB
Rust
Raw Normal View History

2019-03-18 19:56:26 +08:00
#![no_std]
#![no_main]
#![feature(asm)]
// Enable returning `!`
#![feature(never_type)]
#[cfg(not(feature = "semihosting"))]
extern crate panic_abort;
#[cfg(feature = "semihosting")]
extern crate panic_semihosting;
#[macro_use]
extern crate log;
2019-03-19 23:27:22 +08:00
use core::ptr;
2019-04-30 19:42:05 +08:00
use core::sync::atomic::{AtomicU32, AtomicBool, Ordering};
2019-05-24 00:57:00 +08:00
use core::fmt::Write;
2019-05-31 00:03:48 +08:00
use cortex_m_rt::{exception};
use stm32h7::stm32h7x3::{self as stm32, interrupt};
2019-05-28 02:43:39 +08:00
use heapless::{String, Vec, consts::*};
2019-03-18 19:56:26 +08:00
use smoltcp as net;
2019-05-24 00:57:00 +08:00
use serde::{Serialize, Deserialize};
use serde_json_core::{ser::to_string, de::from_slice};
mod eth;
2019-03-28 02:48:22 +08:00
mod iir;
use iir::*;
2019-03-18 19:56:26 +08:00
#[cfg(not(feature = "semihosting"))]
fn init_log() {}
#[cfg(feature = "semihosting")]
fn init_log() {
use log::LevelFilter;
2019-05-31 00:03:48 +08:00
use cortex_m_log::log::{Logger, init as init_log};
2019-03-18 19:56:26 +08:00
use cortex_m_log::printer::semihosting::{InterruptOk, hio::HStdout};
static mut LOGGER: Option<Logger<InterruptOk<HStdout>>> = None;
let logger = Logger {
2019-04-13 00:13:18 +08:00
inner: InterruptOk::<_>::stdout().unwrap(),
2019-03-18 19:56:26 +08:00
level: LevelFilter::Info,
};
let logger = unsafe {
LOGGER.get_or_insert(logger)
};
2019-05-31 00:03:48 +08:00
init_log(logger).unwrap();
2019-03-18 19:56:26 +08:00
}
// Pull in build information (from `built` crate)
mod build_info {
#![allow(dead_code)]
2019-05-24 00:57:00 +08:00
// include!(concat!(env!("OUT_DIR"), "/built.rs"));
2019-03-18 19:56:26 +08:00
}
2019-03-21 01:52:46 +08:00
fn pwr_setup(pwr: &stm32::PWR) {
2019-03-28 02:19:32 +08:00
// go to VOS1 voltage scale for high perf
pwr.cr3.write(|w|
2019-05-06 16:48:22 +08:00
w.scuen().set_bit()
2019-03-19 00:57:00 +08:00
.ldoen().set_bit()
.bypass().clear_bit()
);
while pwr.csr1.read().actvosrdy().bit_is_clear() {}
pwr.d3cr.write(|w| unsafe { w.vos().bits(0b11) }); // vos1
while pwr.d3cr.read().vosrdy().bit_is_clear() {}
2019-03-21 01:52:46 +08:00
}
2019-03-19 00:57:00 +08:00
2019-03-21 01:52:46 +08:00
fn rcc_reset(rcc: &stm32::RCC) {
2019-03-19 00:57:00 +08:00
// Reset all peripherals
rcc.ahb1rstr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
rcc.ahb1rstr.write(|w| unsafe { w.bits(0)});
rcc.apb1lrstr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
rcc.apb1lrstr.write(|w| unsafe { w.bits(0)});
2019-03-19 03:10:36 +08:00
rcc.apb1hrstr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
rcc.apb1hrstr.write(|w| unsafe { w.bits(0)});
2019-03-19 00:57:00 +08:00
rcc.ahb2rstr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
rcc.ahb2rstr.write(|w| unsafe { w.bits(0)});
rcc.apb2rstr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
rcc.apb2rstr.write(|w| unsafe { w.bits(0)});
2019-03-19 03:10:36 +08:00
// do not reset the cpu
rcc.ahb3rstr.write(|w| unsafe { w.bits(0x7FFF_FFFF) });
2019-03-19 00:57:00 +08:00
rcc.ahb3rstr.write(|w| unsafe { w.bits(0)});
rcc.apb3rstr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
rcc.apb3rstr.write(|w| unsafe { w.bits(0)});
rcc.ahb4rstr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
rcc.ahb4rstr.write(|w| unsafe { w.bits(0)});
rcc.apb4rstr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
rcc.apb4rstr.write(|w| unsafe { w.bits(0)});
2019-03-21 01:52:46 +08:00
}
2019-03-19 00:57:00 +08:00
2019-03-21 01:52:46 +08:00
fn rcc_pll_setup(rcc: &stm32::RCC, flash: &stm32::FLASH) {
2019-05-07 02:10:25 +08:00
// Switch to HSI to mess with HSE
rcc.cr.modify(|_, w| w.hsion().on());
while rcc.cr.read().hsirdy().is_not_ready() {}
rcc.cfgr.modify(|_, w| w.sw().hsi());
while !rcc.cfgr.read().sws().is_hsi() {}
rcc.cr.write(|w| w.hsion().on());
2019-03-19 00:57:00 +08:00
rcc.cfgr.reset();
// Ensure HSE is on and stable
2019-03-19 23:27:22 +08:00
rcc.cr.modify(|_, w|
2019-05-07 02:10:25 +08:00
w.hseon().on()
.hsebyp().not_bypassed());
while !rcc.cr.read().hserdy().is_ready() {}
2019-03-19 00:57:00 +08:00
2019-05-07 02:10:25 +08:00
rcc.pllckselr.modify(|_, w|
w.pllsrc().hse()
2019-03-19 00:57:00 +08:00
.divm1().bits(1) // ref prescaler
2019-03-19 23:27:22 +08:00
.divm2().bits(1) // ref prescaler
2019-05-07 02:10:25 +08:00
);
2019-03-19 00:57:00 +08:00
// Configure PLL1: 8MHz /1 *100 /2 = 400 MHz
2019-05-07 02:10:25 +08:00
rcc.pllcfgr.modify(|_, w|
w.pll1vcosel().wide_vco() // 192-836 MHz VCO
.pll1rge().range8() // 8-16 MHz PFD
.pll1fracen().reset()
.divp1en().enabled()
.pll2vcosel().medium_vco() // 150-420 MHz VCO
.pll2rge().range8() // 8-16 MHz PFD
.pll2fracen().reset()
.divp2en().enabled()
.divq2en().enabled()
);
2019-03-19 00:57:00 +08:00
rcc.pll1divr.write(|w| unsafe {
w.divn1().bits(100 - 1) // feebdack divider
2019-05-07 02:10:25 +08:00
.divp1().div2() // p output divider
2019-03-19 00:57:00 +08:00
});
2019-05-07 02:10:25 +08:00
rcc.cr.modify(|_, w| w.pll1on().on());
while !rcc.cr.read().pll1rdy().is_ready() {}
2019-03-19 00:57:00 +08:00
2019-03-19 23:27:22 +08:00
// Configure PLL2: 8MHz /1 *25 / 2 = 100 MHz
2019-03-19 00:57:00 +08:00
rcc.pll2divr.write(|w| unsafe {
2019-03-19 23:27:22 +08:00
w.divn1().bits(25 - 1) // feebdack divider
2019-03-19 00:57:00 +08:00
.divp1().bits(2 - 1) // p output divider
.divq1().bits(2 - 1) // q output divider
});
2019-05-07 02:10:25 +08:00
rcc.cr.modify(|_, w| w.pll2on().on());
while !rcc.cr.read().pll2rdy().is_ready() {}
2019-03-19 00:57:00 +08:00
2019-03-20 05:52:48 +08:00
// hclk 200 MHz, pclk 100 MHz
2019-05-07 02:10:25 +08:00
rcc.d1cfgr.write(|w|
w.d1cpre().div1() // sys_ck not divided
.hpre().div2() // rcc_hclk3 = sys_d1cpre_ck / 2
.d1ppre().div2() // rcc_pclk3 = rcc_hclk3 / 2
);
rcc.d2cfgr.write(|w|
w.d2ppre1().div2() // rcc_pclk1 = rcc_hclk3 / 2
.d2ppre2().div2() // rcc_pclk2 = rcc_hclk3 / 2
);
rcc.d3cfgr.write(|w|
w.d3ppre().div2() // rcc_pclk4 = rcc_hclk3 / 2
);
2019-03-19 00:57:00 +08:00
// 2 wait states, 0b10 programming delay
// 185-210 MHz
flash.acr.write(|w| unsafe {
w.wrhighfreq().bits(2)
.latency().bits(2)
});
while flash.acr.read().latency().bits() != 2 {}
2019-03-21 01:52:46 +08:00
// CSI for I/O compensationc ell
2019-05-07 02:10:25 +08:00
rcc.cr.modify(|_, w| w.csion().on());
while !rcc.cr.read().csirdy().is_ready() {}
2019-03-21 01:52:46 +08:00
2019-03-19 23:27:22 +08:00
// Set system clock to pll1_p
2019-05-07 02:10:25 +08:00
rcc.cfgr.modify(|_, w| w.sw().pll1());
while !rcc.cfgr.read().sws().is_pll1() {}
2019-03-19 00:57:00 +08:00
2019-05-07 02:10:25 +08:00
rcc.d1ccipr.write(|w| w.ckpersel().hse());
rcc.d2ccip1r.modify(|_, w|
w.spi123sel().pll2_p()
.spi45sel().pll2_q()
);
rcc.d3ccipr.modify(|_, w| w.spi6sel().pll2_q());
2019-03-21 01:52:46 +08:00
}
2019-03-20 18:29:13 +08:00
2019-03-21 01:52:46 +08:00
fn io_compensation_setup(syscfg: &stm32::SYSCFG) {
2019-03-20 18:29:13 +08:00
syscfg.cccsr.modify(|_, w|
w.en().set_bit()
.cs().clear_bit()
.hslv().clear_bit()
);
while syscfg.cccsr.read().ready().bit_is_clear() {}
2019-03-21 01:52:46 +08:00
}
2019-03-20 18:29:13 +08:00
2019-03-21 01:52:46 +08:00
fn gpio_setup(gpioa: &stm32::GPIOA, gpiob: &stm32::GPIOB, gpiod: &stm32::GPIOD,
2019-03-28 20:04:25 +08:00
gpioe: &stm32::GPIOE, gpiof: &stm32::GPIOF, gpiog: &stm32::GPIOG) {
2019-03-19 00:57:00 +08:00
// FP_LED0
gpiod.otyper.modify(|_, w| w.ot5().push_pull());
gpiod.moder.modify(|_, w| w.moder5().output());
2019-03-28 02:24:58 +08:00
gpiod.odr.modify(|_, w| w.odr5().clear_bit());
2019-03-19 00:57:00 +08:00
// FP_LED1
gpiod.otyper.modify(|_, w| w.ot6().push_pull());
gpiod.moder.modify(|_, w| w.moder6().output());
2019-03-28 02:24:58 +08:00
gpiod.odr.modify(|_, w| w.odr6().clear_bit());
2019-03-19 00:57:00 +08:00
2019-03-19 03:10:36 +08:00
// LED_FP2
2019-03-19 00:57:00 +08:00
gpiog.otyper.modify(|_, w| w.ot4().push_pull());
gpiog.moder.modify(|_, w| w.moder4().output());
2019-03-28 02:24:58 +08:00
gpiog.odr.modify(|_, w| w.odr4().clear_bit());
2019-03-19 00:57:00 +08:00
2019-03-19 03:10:36 +08:00
// LED_FP3
2019-03-19 00:57:00 +08:00
gpiod.otyper.modify(|_, w| w.ot12().push_pull());
gpiod.moder.modify(|_, w| w.moder12().output());
2019-03-28 02:24:58 +08:00
gpiod.odr.modify(|_, w| w.odr12().clear_bit());
2019-03-19 00:57:00 +08:00
2019-03-19 03:10:36 +08:00
// AFE0_A0,1: PG2,PG3
gpiog.otyper.modify(|_, w|
w.ot2().push_pull()
.ot3().push_pull()
);
gpiog.moder.modify(|_, w|
w.moder2().output()
.moder3().output()
);
2019-03-20 05:52:55 +08:00
gpiog.odr.modify(|_, w|
w.odr2().clear_bit()
.odr3().clear_bit()
2019-03-19 03:10:36 +08:00
);
2019-03-28 20:04:25 +08:00
// ADC0
2019-03-19 03:10:36 +08:00
// SCK: PG11
gpiog.moder.modify(|_, w| w.moder11().alternate());
gpiog.otyper.modify(|_, w| w.ot11().push_pull());
2019-03-19 23:27:22 +08:00
gpiog.ospeedr.modify(|_, w| w.ospeedr11().very_high_speed());
2019-03-19 03:10:36 +08:00
gpiog.afrh.modify(|_, w| w.afr11().af5());
// MOSI: PD7
// MISO: PA6
gpioa.moder.modify(|_, w| w.moder6().alternate());
gpioa.afrl.modify(|_, w| w.afr6().af5());
// NSS: PG10
gpiog.moder.modify(|_, w| w.moder10().alternate());
gpiog.otyper.modify(|_, w| w.ot10().push_pull());
2019-03-19 23:27:22 +08:00
gpiog.ospeedr.modify(|_, w| w.ospeedr10().very_high_speed());
2019-03-19 03:10:36 +08:00
gpiog.afrh.modify(|_, w| w.afr10().af5());
2019-03-28 20:04:25 +08:00
// DAC0
2019-03-19 23:27:22 +08:00
// SCK: PB10
gpiob.moder.modify(|_, w| w.moder10().alternate());
gpiob.otyper.modify(|_, w| w.ot10().push_pull());
gpiob.ospeedr.modify(|_, w| w.ospeedr10().very_high_speed());
gpiob.afrh.modify(|_, w| w.afr10().af5());
// MOSI: PB15
gpiob.moder.modify(|_, w| w.moder15().alternate());
gpiob.otyper.modify(|_, w| w.ot15().push_pull());
gpiob.ospeedr.modify(|_, w| w.ospeedr15().very_high_speed());
gpiob.afrh.modify(|_, w| w.afr15().af5());
// MISO: PB14
// NSS: PB9
gpiob.moder.modify(|_, w| w.moder9().alternate());
gpiob.otyper.modify(|_, w| w.ot9().push_pull());
gpiob.ospeedr.modify(|_, w| w.ospeedr9().very_high_speed());
gpiob.afrh.modify(|_, w| w.afr9().af5());
// DAC0_LDAC: PE11
gpioe.moder.modify(|_, w| w.moder11().output());
gpioe.otyper.modify(|_, w| w.ot11().push_pull());
gpioe.odr.modify(|_, w| w.odr11().clear_bit());
2019-03-28 20:04:25 +08:00
2019-03-19 23:27:22 +08:00
// DAC_CLR: PE12
gpioe.moder.modify(|_, w| w.moder12().output());
gpioe.otyper.modify(|_, w| w.ot12().push_pull());
gpioe.odr.modify(|_, w| w.odr12().set_bit());
2019-03-28 20:04:25 +08:00
2019-03-29 16:37:40 +08:00
// AFE1_A0,1: PD14,PD15
gpiod.otyper.modify(|_, w|
w.ot14().push_pull()
.ot15().push_pull()
);
gpiod.moder.modify(|_, w|
w.moder14().output()
.moder15().output()
);
gpiod.odr.modify(|_, w|
w.odr14().clear_bit()
.odr15().clear_bit()
);
2019-03-28 20:04:25 +08:00
// ADC1
// SCK: PF6
gpiof.moder.modify(|_, w| w.moder7().alternate());
gpiof.otyper.modify(|_, w| w.ot7().push_pull());
gpiof.ospeedr.modify(|_, w| w.ospeedr7().very_high_speed());
gpiof.afrl.modify(|_, w| w.afr7().af5());
// MOSI: PF9
// MISO: PF7
gpiof.moder.modify(|_, w| w.moder8().alternate());
gpiof.afrh.modify(|_, w| w.afr8().af5());
// NSS: PF8
gpiof.moder.modify(|_, w| w.moder6().alternate());
gpiof.otyper.modify(|_, w| w.ot6().push_pull());
gpiof.ospeedr.modify(|_, w| w.ospeedr6().very_high_speed());
gpiof.afrl.modify(|_, w| w.afr6().af5());
// DAC1
// SCK: PE2
gpioe.moder.modify(|_, w| w.moder2().alternate());
gpioe.otyper.modify(|_, w| w.ot2().push_pull());
gpioe.ospeedr.modify(|_, w| w.ospeedr2().very_high_speed());
gpioe.afrl.modify(|_, w| w.afr2().af5());
// MOSI: PE6
gpioe.moder.modify(|_, w| w.moder6().alternate());
gpioe.otyper.modify(|_, w| w.ot6().push_pull());
gpioe.ospeedr.modify(|_, w| w.ospeedr6().very_high_speed());
gpioe.afrl.modify(|_, w| w.afr6().af5());
// MISO: PE5
// NSS: PE4
gpioe.moder.modify(|_, w| w.moder4().alternate());
gpioe.otyper.modify(|_, w| w.ot4().push_pull());
gpioe.ospeedr.modify(|_, w| w.ospeedr4().very_high_speed());
gpioe.afrl.modify(|_, w| w.afr4().af5());
// DAC1_LDAC: PE15
gpioe.moder.modify(|_, w| w.moder15().output());
gpioe.otyper.modify(|_, w| w.ot15().push_pull());
gpioe.odr.modify(|_, w| w.odr15().clear_bit());
2019-03-21 01:52:46 +08:00
}
2019-03-19 23:27:22 +08:00
2019-03-28 20:04:25 +08:00
// ADC0
2019-03-21 01:52:46 +08:00
fn spi1_setup(spi1: &stm32::SPI1) {
2019-05-07 01:09:49 +08:00
spi1.cfg1.modify(|_, w|
w.mbr().div4()
2019-03-21 01:52:46 +08:00
.dsize().bits(16 - 1)
2019-05-06 16:47:49 +08:00
.fthlv().one_frame()
2019-05-07 01:09:49 +08:00
);
spi1.cfg2.modify(|_, w|
w.afcntr().controlled()
.ssom().not_asserted()
.ssoe().enabled()
.ssiop().active_low()
.ssm().disabled()
.cpol().idle_high()
.cpha().second_edge()
.lsbfrst().msbfirst()
.master().master()
.sp().motorola()
.comm().receiver()
.ioswp().disabled()
.midi().bits(0)
.mssi().bits(6)
);
spi1.cr2.modify(|_, w| w.tsize().bits(1));
2019-03-21 01:52:46 +08:00
spi1.cr1.write(|w| w.spe().set_bit());
}
2019-03-20 05:52:48 +08:00
2019-03-28 20:04:25 +08:00
// ADC1
fn spi5_setup(spi5: &stm32::SPI5) {
2019-05-07 01:09:49 +08:00
spi5.cfg1.modify(|_, w|
w.mbr().div4()
2019-03-28 20:04:25 +08:00
.dsize().bits(16 - 1)
2019-05-06 16:47:49 +08:00
.fthlv().one_frame()
2019-05-07 01:09:49 +08:00
);
spi5.cfg2.modify(|_, w|
w.afcntr().controlled()
.ssom().not_asserted()
.ssoe().enabled()
.ssiop().active_low()
.ssm().disabled()
.cpol().idle_high()
.cpha().second_edge()
.lsbfrst().msbfirst()
.master().master()
.sp().motorola()
.comm().receiver()
.ioswp().disabled()
.midi().bits(0)
.mssi().bits(6)
);
spi5.cr2.modify(|_, w| w.tsize().bits(1));
2019-03-28 20:04:25 +08:00
spi5.cr1.write(|w| w.spe().set_bit());
}
// DAC0
2019-03-21 01:52:46 +08:00
fn spi2_setup(spi2: &stm32::SPI2) {
2019-05-07 01:09:49 +08:00
spi2.cfg1.modify(|_, w|
w.mbr().div2()
2019-03-19 23:27:22 +08:00
.dsize().bits(16 - 1)
2019-05-06 16:47:49 +08:00
.fthlv().one_frame()
2019-05-07 01:09:49 +08:00
);
spi2.cfg2.modify(|_, w|
w.afcntr().controlled()
.ssom().not_asserted()
.ssoe().enabled()
.ssiop().active_low()
.ssm().disabled()
.cpol().idle_low()
.cpha().first_edge()
.lsbfrst().msbfirst()
.master().master()
.sp().motorola()
.comm().transmitter()
.ioswp().disabled()
.midi().bits(0)
.mssi().bits(0)
);
2019-04-29 02:44:38 +08:00
spi2.cr2.modify(|_, w| w.tsize().bits(0));
spi2.cr1.write(|w| w.spe().enabled());
spi2.cr1.modify(|_, w| w.cstart().started());
2019-03-28 20:04:25 +08:00
}
// DAC1
fn spi4_setup(spi4: &stm32::SPI4) {
2019-05-07 01:09:49 +08:00
spi4.cfg1.modify(|_, w|
w.mbr().div2()
2019-03-28 20:04:25 +08:00
.dsize().bits(16 - 1)
2019-05-06 16:47:49 +08:00
.fthlv().one_frame()
2019-05-07 01:09:49 +08:00
);
spi4.cfg2.modify(|_, w|
w.afcntr().controlled()
.ssom().not_asserted()
.ssoe().enabled()
.ssiop().active_low()
.ssm().disabled()
.cpol().idle_low()
.cpha().first_edge()
.lsbfrst().msbfirst()
.master().master()
.sp().motorola()
.comm().transmitter()
.ioswp().disabled()
.midi().bits(0)
.mssi().bits(0)
);
spi4.cr2.modify(|_, w| w.tsize().bits(0));
2019-04-29 02:44:38 +08:00
spi4.cr1.write(|w| w.spe().enabled());
spi4.cr1.modify(|_, w| w.cstart().started());
2019-03-21 01:52:46 +08:00
}
2019-03-27 17:36:07 +08:00
fn tim2_setup(tim2: &stm32::TIM2) {
2019-03-28 02:19:32 +08:00
tim2.psc.write(|w| unsafe { w.psc().bits(200 - 1) }); // from 200 MHz
tim2.arr.write(|w| unsafe { w.bits(2 - 1) }); // µs
2019-04-15 21:29:46 +08:00
tim2.dier.write(|w| w.ude().set_bit());
2019-03-28 02:19:32 +08:00
tim2.egr.write(|w| w.ug().set_bit());
tim2.cr1.modify(|_, w|
w.dir().clear_bit() // up
.cen().set_bit()); // enable
2019-03-27 17:36:07 +08:00
}
2019-04-15 21:29:46 +08:00
fn dma1_setup(dma1: &stm32::DMA1, dmamux1: &stm32::DMAMUX1, ma: usize, pa0: usize, pa1: usize) {
2019-05-06 16:47:49 +08:00
dma1.st[0].cr.modify(|_, w| w.en().clear_bit());
while dma1.st[0].cr.read().en().bit_is_set() {}
2019-03-27 17:36:07 +08:00
2019-05-07 01:09:49 +08:00
dma1.st[0].par.write(|w| unsafe { w.bits(pa0 as u32) });
dma1.st[0].m0ar.write(|w| unsafe { w.bits(ma as u32) });
2019-05-06 16:47:49 +08:00
dma1.st[0].ndtr.write(|w| unsafe { w.ndt().bits(1) });
2019-05-07 01:09:49 +08:00
dmamux1.ccr[0].modify(|_, w| w.dmareq_id().tim2_up());
2019-05-06 16:47:49 +08:00
dma1.st[0].cr.modify(|_, w| unsafe {
2019-04-15 23:14:02 +08:00
w.pl().bits(0b01) // medium
2019-03-27 17:36:07 +08:00
.circ().set_bit() // reload ndtr
.msize().bits(0b10) // 32
.minc().clear_bit()
.mburst().bits(0b00)
.psize().bits(0b10) // 32
.pinc().clear_bit()
.pburst().bits(0b00)
.dbm().clear_bit()
2019-03-28 02:19:32 +08:00
.dir().bits(0b01) // memory_to_peripheral
2019-03-27 17:36:07 +08:00
.pfctrl().clear_bit() // dma is FC
});
2019-05-06 16:47:49 +08:00
dma1.st[0].fcr.modify(|_, w| w.dmdis().clear_bit());
dma1.st[0].cr.modify(|_, w| w.en().set_bit());
2019-04-15 21:29:46 +08:00
2019-05-06 16:47:49 +08:00
dma1.st[1].cr.modify(|_, w| w.en().clear_bit());
while dma1.st[1].cr.read().en().bit_is_set() {}
2019-04-15 21:29:46 +08:00
2019-05-07 01:09:49 +08:00
dma1.st[1].par.write(|w| unsafe { w.bits(pa1 as u32) });
dma1.st[1].m0ar.write(|w| unsafe { w.bits(ma as u32) });
2019-05-06 16:47:49 +08:00
dma1.st[1].ndtr.write(|w| unsafe { w.ndt().bits(1) });
2019-05-07 01:09:49 +08:00
dmamux1.ccr[1].modify(|_, w| w.dmareq_id().tim2_up());
2019-05-06 16:47:49 +08:00
dma1.st[1].cr.modify(|_, w| unsafe {
2019-04-15 23:14:02 +08:00
w.pl().bits(0b01) // medium
2019-04-15 21:29:46 +08:00
.circ().set_bit() // reload ndtr
.msize().bits(0b10) // 32
.minc().clear_bit()
.mburst().bits(0b00)
.psize().bits(0b10) // 32
.pinc().clear_bit()
.pburst().bits(0b00)
.dbm().clear_bit()
.dir().bits(0b01) // memory_to_peripheral
.pfctrl().clear_bit() // dma is FC
});
2019-05-06 16:47:49 +08:00
dma1.st[1].fcr.modify(|_, w| w.dmdis().clear_bit());
dma1.st[1].cr.modify(|_, w| w.en().set_bit());
2019-03-27 17:36:07 +08:00
}
2019-05-31 00:03:48 +08:00
const SCALE: f32 = ((1 << 15) - 1) as f32;
2019-03-25 17:08:27 +08:00
2019-04-28 19:37:14 +08:00
#[link_section = ".sram1.datspi"]
2019-04-29 02:44:38 +08:00
static mut DAT: u32 = 0x201; // EN | CSTART
2019-03-27 17:36:07 +08:00
2019-04-30 19:42:05 +08:00
static ETHERNET_PENDING: AtomicBool = AtomicBool::new(true);
2019-04-30 19:42:05 +08:00
const TCP_RX_BUFFER_SIZE: usize = 8192;
const TCP_TX_BUFFER_SIZE: usize = 8192;
macro_rules! create_socket {
($set:ident, $rx_storage:ident, $tx_storage:ident, $target:ident) => (
let mut $rx_storage = [0; TCP_RX_BUFFER_SIZE];
let mut $tx_storage = [0; TCP_TX_BUFFER_SIZE];
let tcp_rx_buffer = net::socket::TcpSocketBuffer::new(&mut $rx_storage[..]);
let tcp_tx_buffer = net::socket::TcpSocketBuffer::new(&mut $tx_storage[..]);
let tcp_socket = net::socket::TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
let $target = $set.add(tcp_socket);
)
}
2019-05-31 00:03:48 +08:00
#[rtfm::app(device = stm32h7::stm32h7x3)]
const APP: () = {
static SPI: (stm32::SPI1, stm32::SPI2, stm32::SPI4, stm32::SPI5) = ();
2019-05-31 05:50:18 +08:00
static ETHERNET_PERIPH: (stm32::ETHERNET_MAC, stm32::ETHERNET_DMA, stm32::ETHERNET_MTL) = ();
2019-05-31 00:03:48 +08:00
static mut IIR_STATE: [IIRState; 2] = [[0.; 5]; 2];
static mut IIR_CH: [IIR; 2] = [
IIR {
ba: [0., 0., 0., 0., 0.],
y_offset: 0.,
y_min: -SCALE - 1.,
y_max: SCALE
};
2];
2019-05-31 04:57:41 +08:00
#[link_section = ".sram3.eth"]
static mut ETHERNET: eth::Device = eth::Device::new();
2019-05-31 00:03:48 +08:00
2019-05-31 00:18:59 +08:00
#[init(schedule = [tick])]
2019-05-31 00:03:48 +08:00
fn init(c: init::Context) -> init::LateResources {
let dp = c.device;
let cp = c.core;
let rcc = dp.RCC;
rcc_reset(&rcc);
init_log();
// info!("Version {} {}", build_info::PKG_VERSION, build_info::GIT_VERSION.unwrap());
// info!("Built on {}", build_info::BUILT_TIME_UTC);
// info!("{} {}", build_info::RUSTC_VERSION, build_info::TARGET);
pwr_setup(&dp.PWR);
rcc_pll_setup(&rcc, &dp.FLASH);
rcc.apb4enr.modify(|_, w| w.syscfgen().set_bit());
io_compensation_setup(&dp.SYSCFG);
cp.SCB.enable_icache();
// TODO: ETH DMA coherence issues
// cp.SCB.enable_dcache(&mut cp.CPUID);
// cp.DWT.enable_cycle_counter();
rcc.ahb4enr.modify(|_, w|
w.gpioaen().set_bit()
.gpioben().set_bit()
.gpiocen().set_bit()
.gpioden().set_bit()
.gpioeen().set_bit()
.gpiofen().set_bit()
.gpiogen().set_bit()
);
gpio_setup(&dp.GPIOA, &dp.GPIOB, &dp.GPIOD, &dp.GPIOE, &dp.GPIOF, &dp.GPIOG);
rcc.apb1lenr.modify(|_, w| w.spi2en().set_bit());
let spi2 = dp.SPI2;
spi2_setup(&spi2);
rcc.apb2enr.modify(|_, w| w.spi4en().set_bit());
let spi4 = dp.SPI4;
spi4_setup(&spi4);
rcc.apb2enr.modify(|_, w| w.spi1en().set_bit());
let spi1 = dp.SPI1;
spi1_setup(&spi1);
spi1.ier.write(|w| w.eotie().set_bit());
rcc.apb2enr.modify(|_, w| w.spi5en().set_bit());
let spi5 = dp.SPI5;
spi5_setup(&spi5);
// spi5.ier.write(|w| w.eotie().set_bit());
rcc.ahb2enr.modify(|_, w|
w
.sram1en().set_bit()
.sram2en().set_bit()
.sram3en().set_bit()
);
rcc.ahb1enr.modify(|_, w| w.dma1en().set_bit());
// init SRAM1 rodata can't load with sram1 disabled
unsafe { DAT = 0x201 }; // EN | CSTART
cortex_m::asm::dsb();
let dat_addr = unsafe { &DAT as *const _ } as usize;
cp.SCB.clean_dcache_by_address(dat_addr, 4);
dma1_setup(&dp.DMA1, &dp.DMAMUX1, dat_addr,
&spi1.cr1 as *const _ as usize,
&spi5.cr1 as *const _ as usize);
rcc.apb1lenr.modify(|_, w| w.tim2en().set_bit());
// work around the SPI stall erratum
let dbgmcu = dp.DBGMCU;
dbgmcu.apb1lfz1.modify(|_, w| w.tim2().set_bit());
2019-05-31 04:57:41 +08:00
tim2_setup(&dp.TIM2);
2019-05-31 00:03:48 +08:00
eth::setup(&rcc, &dp.SYSCFG);
eth::setup_pins(&dp.GPIOA, &dp.GPIOB, &dp.GPIOC, &dp.GPIOG);
2019-05-31 04:57:41 +08:00
c.schedule.tick(rtfm::Instant::now()).unwrap();
init::LateResources {
SPI: (spi1, spi2, spi4, spi5),
ETHERNET_PERIPH: (dp.ETHERNET_MAC, dp.ETHERNET_DMA, dp.ETHERNET_MTL),
}
}
2019-05-31 05:50:18 +08:00
#[idle(resources = [ETHERNET, ETHERNET_PERIPH, IIR_STATE])]
2019-05-31 04:57:41 +08:00
fn idle(c: idle::Context) -> ! {
let (MAC, DMA, MTL) = c.resources.ETHERNET_PERIPH;
2019-05-31 00:03:48 +08:00
let hardware_addr = net::wire::EthernetAddress([0x10, 0xE2, 0xD5, 0x00, 0x03, 0x00]);
2019-05-31 04:57:41 +08:00
unsafe { c.resources.ETHERNET.init(hardware_addr, MAC, DMA, MTL) };
2019-05-31 00:03:48 +08:00
let mut neighbor_cache_storage = [None; 8];
let neighbor_cache = net::iface::NeighborCache::new(&mut neighbor_cache_storage[..]);
let local_addr = net::wire::IpAddress::v4(10, 0, 16, 99);
let mut ip_addrs = [net::wire::IpCidr::new(local_addr, 24)];
2019-05-31 04:57:41 +08:00
let mut iface = net::iface::EthernetInterfaceBuilder::new(c.resources.ETHERNET)
2019-05-31 00:03:48 +08:00
.ethernet_addr(hardware_addr)
.neighbor_cache(neighbor_cache)
.ip_addrs(&mut ip_addrs[..])
.finalize();
let mut socket_set_entries: [_; 8] = Default::default();
let mut sockets = net::socket::SocketSet::new(&mut socket_set_entries[..]);
create_socket!(sockets, tcp_rx_storage0, tcp_tx_storage0, tcp_handle0);
create_socket!(sockets, tcp_rx_storage0, tcp_tx_storage0, tcp_handle1);
2019-05-31 04:57:41 +08:00
// unsafe { eth::enable_interrupt(DMA); }
let mut last = 0u32;
let mut last_iter = rtfm::Instant::now();
//let mut server = Server::new();
2019-05-31 05:50:18 +08:00
let mut iir_state: resources::IIR_STATE = c.resources.IIR_STATE;
2019-05-31 00:03:48 +08:00
loop {
2019-05-31 04:57:41 +08:00
// if ETHERNET_PENDING.swap(false, Ordering::Relaxed) { }
let mut time = last;
if rtfm::Instant::now() >= last_iter + 200_000.cycles() {
last_iter += 200_000.cycles();
time += 1;
}
{
let socket = &mut *sockets.get::<net::socket::TcpSocket>(tcp_handle0);
if !(socket.is_open() || socket.is_listening()) {
socket.listen(1234).unwrap_or_else(|e| warn!("TCP listen error: {:?}", e));
2019-05-31 05:50:18 +08:00
} else if time != last && socket.can_send() {
2019-05-31 04:57:41 +08:00
last = time;
2019-05-31 05:50:18 +08:00
let s = iir_state.lock(|iir_state| Status {
t: time,
x0: iir_state[0][0],
y0: iir_state[0][2],
x1: iir_state[1][0],
y1: iir_state[1][2]
});
reply(socket, &s);
2019-05-31 04:57:41 +08:00
}
}
{
let socket = &mut *sockets.get::<net::socket::TcpSocket>(tcp_handle1);
if !(socket.is_open() || socket.is_listening()) {
socket.listen(1235).unwrap_or_else(|e| warn!("TCP listen error: {:?}", e));
} else {
//server.handle_command(socket);
}
}
if !match iface.poll(&mut sockets, net::time::Instant::from_millis(time as i64)) {
Ok(changed) => changed,
Err(net::Error::Unrecognized) => true,
Err(e) => { info!("iface poll error: {:?}", e); true }
} {
// cortex_m::asm::wfi();
}
2019-05-31 00:03:48 +08:00
}
}
2019-04-28 19:37:14 +08:00
2019-05-31 05:50:18 +08:00
#[task(priority = 1, schedule = [tick])]
2019-05-31 00:18:59 +08:00
fn tick(c: tick::Context) {
2019-05-31 04:57:41 +08:00
static mut TIME: u32 = 0;
*TIME += 1;
2019-05-31 00:18:59 +08:00
const PERIOD: u32 = 200_000_000;
c.schedule.tick(c.scheduled + PERIOD.cycles()).unwrap();
}
2019-05-31 00:03:48 +08:00
// seems to slow it down
// #[link_section = ".data.spi1"]
2019-05-31 05:50:18 +08:00
#[interrupt(resources = [SPI, IIR_STATE, IIR_CH], priority = 2)]
2019-05-31 00:03:48 +08:00
fn SPI1(c: SPI1::Context) {
#[cfg(feature = "bkpt")]
cortex_m::asm::bkpt();
let (spi1, spi2, spi4, spi5) = c.resources.SPI;
let iir_ch = c.resources.IIR_CH;
2019-05-31 05:50:18 +08:00
let mut iir_state = c.resources.IIR_STATE;
2019-05-31 00:03:48 +08:00
let sr = spi1.sr.read();
if sr.eot().bit_is_set() {
2019-05-31 04:57:41 +08:00
spi1.ifcr.write(|w| w.eotc().set_bit());
}
2019-05-31 00:03:48 +08:00
if sr.rxp().bit_is_set() {
let rxdr = &spi1.rxdr as *const _ as *const u16;
let a = unsafe { ptr::read_volatile(rxdr) };
let x0 = f32::from(a as i16);
2019-05-31 00:18:59 +08:00
let y0 = iir_ch[0].update(&mut iir_state[0], x0);
2019-05-31 00:03:48 +08:00
let d = y0 as i16 as u16 ^ 0x8000;
let txdr = &spi2.txdr as *const _ as *mut u16;
unsafe { ptr::write_volatile(txdr, d) };
2019-05-28 02:43:39 +08:00
}
2019-05-31 00:03:48 +08:00
let sr = spi5.sr.read();
if sr.eot().bit_is_set() {
2019-05-31 04:57:41 +08:00
spi5.ifcr.write(|w| w.eotc().set_bit());
}
2019-05-31 00:03:48 +08:00
if sr.rxp().bit_is_set() {
let rxdr = &spi5.rxdr as *const _ as *const u16;
let a = unsafe { ptr::read_volatile(rxdr) };
let x0 = f32::from(a as i16);
2019-05-31 00:18:59 +08:00
let y0 = iir_ch[1].update(&mut iir_state[1], x0);
2019-05-31 00:03:48 +08:00
let d = y0 as i16 as u16 ^ 0x8000;
let txdr = &spi4.txdr as *const _ as *mut u16;
unsafe { ptr::write_volatile(txdr, d) };
}
#[cfg(feature = "bkpt")]
cortex_m::asm::bkpt();
2019-03-18 19:56:26 +08:00
}
2019-05-31 00:03:48 +08:00
2019-05-31 04:57:41 +08:00
/*
#[interrupt(resources = [ETHERNET_PERIPH], priority = 1)]
fn ETH(c: ETH::Context) {
let dma = &c.resources.ETHERNET_PERIPH.1;
2019-05-31 00:03:48 +08:00
ETHERNET_PENDING.store(true, Ordering::Relaxed);
unsafe { eth::interrupt_handler(dma) }
}
2019-05-31 04:57:41 +08:00
*/
2019-05-31 00:03:48 +08:00
extern "C" {
2019-05-31 04:57:41 +08:00
// hw interrupt handlers for RTFM to use for scheduling tasks
// one per priority
2019-05-31 00:03:48 +08:00
fn DCMI();
fn JPEG();
fn SDMMC();
}
};
2019-05-28 02:43:39 +08:00
#[derive(Deserialize,Serialize)]
struct Request {
2019-05-28 18:15:15 +08:00
channel: u8,
2019-05-24 00:57:00 +08:00
iir: IIR,
}
2019-05-28 02:43:39 +08:00
#[derive(Serialize)]
struct Response<'a> {
code: i32,
message: &'a str,
}
2019-05-31 04:57:41 +08:00
#[derive(Serialize)]
struct Status {
t: u32,
x0: f32,
y0: f32,
x1: f32,
y1: f32
2019-05-28 02:43:39 +08:00
}
2019-05-28 18:59:26 +08:00
struct Server {
data: Vec<u8, U256>,
discard: bool,
}
2019-05-31 04:57:41 +08:00
fn reply<T: Serialize>(socket: &mut net::socket::TcpSocket, msg: &T) {
let mut u: String<U128> = to_string(msg).unwrap();
u.push('\n').unwrap();
socket.write_str(&u).unwrap();
}
2019-05-28 18:59:26 +08:00
impl Server {
fn new() -> Self {
Self { data: Vec::new(), discard: false }
}
fn handle_command(&mut self, socket: &mut net::socket::TcpSocket) {
while socket.can_recv() {
let found = socket.recv(|buf| {
let (len, found) = match buf.iter().position(|&c| c as char == '\n') {
Some(end) => (end + 1, true),
None => (buf.len(), false),
};
if self.data.len() + len >= self.data.capacity() {
self.discard = true;
self.data.clear();
} else if !self.discard && len > 0 {
self.data.extend_from_slice(&buf[..len - 1]).unwrap();
}
(len, found)
}).unwrap();
if !found {
continue;
2019-05-28 02:43:39 +08:00
}
2019-05-28 18:59:26 +08:00
let resp = if self.discard {
self.discard = false;
Response{ code: 520, message: "command buffer overflow" }
2019-05-28 02:43:39 +08:00
} else {
2019-05-28 18:59:26 +08:00
match from_slice::<Request>(&self.data) {
2019-05-28 02:43:39 +08:00
Ok(request) => {
2019-05-28 18:15:15 +08:00
if request.channel > 1 {
2019-05-28 18:59:26 +08:00
Response{ code: 530, message: "invalid channel" }
2019-05-28 18:15:15 +08:00
} else {
2019-05-31 04:57:41 +08:00
//unsafe { IIR_CH[request.channel as usize] = request.iir; };
2019-05-28 18:15:15 +08:00
Response{ code: 200, message: "ok" }
}
2019-05-28 02:43:39 +08:00
},
Err(err) => {
2019-05-28 18:59:26 +08:00
warn!("parse error {:?}", err);
2019-05-28 02:43:39 +08:00
Response{ code: 550, message: "parse error" }
},
}
};
2019-05-28 18:59:26 +08:00
self.data.clear();
reply(socket, &resp);
2019-05-28 02:43:39 +08:00
socket.close();
}
}
}
2019-05-24 00:57:00 +08:00
2019-03-18 19:56:26 +08:00
#[exception]
fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! {
panic!("HardFault at {:#?}", ef);
}
#[exception]
fn DefaultHandler(irqn: i16) {
panic!("Unhandled exception (IRQn = {})", irqn);
}