Compare commits

...

4 Commits

11 changed files with 366 additions and 28 deletions

1
Cargo.lock generated
View File

@ -373,6 +373,7 @@ dependencies = [
"cortex-m-rt",
"cortex-m-semihosting 0.5.0",
"fugit",
"ieee802_3_miim",
"log",
"miniconf",
"nb 1.1.0",

View File

@ -23,7 +23,8 @@ bare-metal = "1"
nb = "1"
cortex-m-log = { version = "0.7.0", features = ["log-integration", "semihosting"] }
stm32f4xx-hal = { version = "0.14.0", features = ["rt", "stm32f407", "usb_fs"] }
stm32-eth = { version = "0.5.2", features = ["stm32f407"] }
stm32-eth = { version = "0.5.2", features = ["stm32f407", "smoltcp-phy", "smoltcp"] }
ieee802_3_miim = "0.8.0"
smoltcp = { version = "0.10.0", default-features = false, features = ["proto-ipv4", "socket-tcp", "log", "medium-ethernet"] }
uom = { version = "0.30", default-features = false, features = ["autoconvert", "si", "f64", "use_serde"] }
num-traits = { version = "0.2.15", default-features = false, features = ["libm"] }

14
echo_eth_test.py Normal file
View File

@ -0,0 +1,14 @@
# echo-client.py
import socket
#192, 168, 1, 132
HOST = "192.168.1.132" # The server's hostname or IP address
PORT = 1337 # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b"Hello, world")
data = s.recv(1024)
print(f"Received {data!r}")

View File

@ -4,8 +4,10 @@ use crate::laser_diode::ld_ctrl::{*};
use crate::laser_diode::laser_diode::LdDrive;
use crate::thermostat::max1968::MAX1968;
use crate::thermostat::thermostat::Thermostat;
use crate::net::net::ServerHandle;
use stm32_eth;
use fugit::ExtU32;
use log::info;
use log::{info, debug};
use stm32f4xx_hal::{
pac::{CorePeripherals, Peripherals},
rcc::RccExt,
@ -41,7 +43,7 @@ pub fn bootup(
sys_timer::setup(core_perif.SYST, clocks);
let (_eth_pins, usb, current_source_phy, ad7172_phy, max1968_phy, pd_mon_phy) = gpio::setup(
let (eth_pins, eth_mgmt_pins, usb, current_source_phy, ad7172_phy, max1968_phy, pd_mon_phy) = gpio::setup(
clocks,
perif.TIM4,
perif.GPIOA,
@ -59,29 +61,38 @@ pub fn bootup(
usb::State::setup(usb);
debug!("Setting up TEC");
let tec_driver = MAX1968::new(max1968_phy, perif.ADC1);
let mut thermostat = Thermostat::new(tec_driver, ad7172_phy);
thermostat.setup();
thermostat.power_up();
thermostat.calibrate_dac_value();
thermostat.set_i(ElectricCurrent::new::<ampere>(1.0));
debug!("Setting up Laser Driver");
let current_source = LdCtrl::new(current_source_phy);
let mut laser = LdDrive::new(current_source, perif.ADC2, pd_mon_phy);
laser.setup();
laser.ld_open();
laser.set_ld_drive_current_limit(ElectricCurrent::new::<ampere>(0.2));
laser.ld_set_i(ElectricCurrent::new::<ampere>(0.15));
laser.set_pd_i_limit(ElectricCurrent::new::<milliampere>(2.5));
laser.power_up();
let tec_driver = MAX1968::new(max1968_phy, perif.ADC1);
let mut thermostat = Thermostat::new(tec_driver, ad7172_phy);
thermostat.setup();
thermostat.power_up();
thermostat.calibrate_dac_value();
thermostat.set_i(ElectricCurrent::new::<ampere>(1.0));
laser.set_pd_mon_calibrated_vdda(thermostat.get_calibrated_vdda());
laser.power_up();
debug!("Setting up Internal Flash Driver");
let flash_store = flash_store::store(perif.FLASH);
debug!("Setting up ETH");
let ethernet_parts_in = stm32_eth::PartsIn {
dma: perif.ETHERNET_DMA,
mac: perif.ETHERNET_MAC,
mmc: perif.ETHERNET_MMC,
ptp: perif.ETHERNET_PTP,
};
ServerHandle::new(eth_pins, eth_mgmt_pins, ethernet_parts_in, clocks);
debug!("Setting Watchdog");
let mut wd = IndependentWatchdog::new(perif.IWDG);
wd.start(WATCHDOG_PERIOD.millis());
wd.feed();

View File

@ -4,9 +4,10 @@ use crate::laser_diode::ld_pwr_exc_protector::LdPwrExcProtectorPhy;
use crate::thermostat::ad5680;
use crate::thermostat::max1968::{self, MAX1968PinSet, MAX1968Phy, PWM_FREQ_KHZ};
use crate::thermostat::ad7172;
use crate::net::net::EthernetMgmtPins;
use stm32_eth::EthPins;
use stm32f4xx_hal::{
gpio::{gpioa::*, gpiob::*, gpioc::*, gpiog::*, GpioExt, Input},
gpio::{gpioa::*, gpiob::*, gpioc::*, GpioExt, Input, Speed},
otg_fs::USB,
pac::{
GPIOA, GPIOB, GPIOC, GPIOD, GPIOG, OTG_FS_DEVICE, OTG_FS_GLOBAL, OTG_FS_PWRCLK, SPI1, SPI2, SPI3,
@ -18,7 +19,7 @@ use stm32f4xx_hal::{
};
pub type EthernetPins =
EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PG13<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PB12<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
pub fn setup(
clocks: Clocks,
@ -36,6 +37,7 @@ pub fn setup(
otg_fs_pwrclk: OTG_FS_PWRCLK,
) -> (
EthernetPins,
EthernetMgmtPins,
USB,
LdCtrlPhy<ld_ctrl::Channel0>,
ad7172::AdcPhy,
@ -61,11 +63,18 @@ pub fn setup(
ref_clk: gpioa.pa1,
crs: gpioa.pa7,
tx_en: gpiob.pb11,
tx_d0: gpiog.pg13,
tx_d0: gpiob.pb12,
tx_d1: gpiob.pb13,
rx_d0: gpioc.pc4,
rx_d1: gpioc.pc5,
};
let mut eth_mgmt_pins = EthernetMgmtPins {
mdio: gpioa.pa2.into_alternate::<11>(),
mdc: gpioc.pc1.into_alternate::<11>(),
};
eth_mgmt_pins.mdio.set_speed(Speed::VeryHigh);
eth_mgmt_pins.mdc.set_speed(Speed::VeryHigh);
let current_source_phy = LdCtrlPhy {
dac: max5719::Dac::new(Spi::new(
@ -82,6 +91,7 @@ pub fn setup(
gpiob.pb14.into_push_pull_output(),
),
current_source_short_pin: gpioa.pa4.into_push_pull_output(),
termination_status_pin: gpiod.pd7.internal_pull_up(true),
};
let pd_mon_phy = LdPwrExcProtectorPhy {
@ -136,5 +146,5 @@ pub fn setup(
gpioa.pa15.into_push_pull_output(),
).unwrap();
(eth_pins, usb, current_source_phy, ad7172_phy, max1968_phy, pd_mon_phy)
(eth_pins, eth_mgmt_pins, usb, current_source_phy, ad7172_phy, max1968_phy, pd_mon_phy)
}

View File

@ -174,4 +174,8 @@ impl LdDrive{
pub fn set_pd_i_limit(&mut self, i: ElectricCurrent){
LdPwrExcProtector::set_trigger_threshold_v(i / Settings::PD_MON_TRANSCONDUCTANCE);
}
pub fn get_term_status(&mut self)->bool{
self.ctrl.get_term_status()
}
}

View File

@ -1,6 +1,6 @@
use stm32f4xx_hal::{
gpio::{gpioa::*, gpiob::*, gpiod::*, Alternate, Output, PushPull},
hal::{blocking::spi::Transfer, digital::v2::OutputPin},
gpio::{gpioa::*, gpiob::*, gpiod::*, Alternate, Input, Output, PushPull},
hal::{blocking::spi::Transfer, digital::{v2::OutputPin, v2::InputPin}},
pac::SPI2,
spi::{NoMiso, Spi, TransferModeNormal},
};
@ -15,6 +15,7 @@ use crate::laser_diode::laser_diode::TransimpedanceUnit;
pub trait ChannelPins {
type CurrentSourceShort: OutputPin;
type TerminationStatus: InputPin;
type Max5719Load: OutputPin;
type Max5719Cs: OutputPin;
type Max5719Spi: Transfer<u8>;
@ -23,11 +24,13 @@ pub trait ChannelPins {
pub struct LdCtrlPhy<C: ChannelPins> {
pub dac: Dac<C::Max5719Spi, C::Max5719Cs, C::Max5719Load>,
pub current_source_short_pin: C::CurrentSourceShort,
pub termination_status_pin: C::TerminationStatus
}
pub struct Channel0;
impl ChannelPins for Channel0 {
type CurrentSourceShort = PA4<Output<PushPull>>;
type TerminationStatus = PD7<Input>;
type Max5719Load = DacLoad;
type Max5719Cs = DacCs;
type Max5719Spi = DacSpi;
@ -58,6 +61,10 @@ impl LdCtrl {
self.phy.current_source_short_pin.set_high();
}
pub fn get_term_status(&mut self)-> bool{
self.phy.termination_status_pin.is_high()
}
pub fn set_dac(&mut self, voltage: ElectricPotential, dac_out_v_max: ElectricPotential) -> ElectricPotential {
let value = ((voltage / dac_out_v_max).get::<ratio>()
* (max5719::MAX_VALUE as f64)) as u32;

View File

@ -8,6 +8,7 @@ mod device;
mod laser_diode;
mod thermostat;
mod pid;
mod net;
use device::{boot::bootup, log_setup, sys_timer};
use uom::fmt::DisplayStyle::Abbreviation;
@ -84,6 +85,7 @@ fn main() -> ! {
info!("pd_mon_v: {:?}", volt_fmt.with(laser.pd_mon_status().v));
info!("power_excursion: {:?}", laser.pd_mon_status().pwr_excursion);
info!("Termination Status: {:?}", laser.get_term_status());
sys_timer::sleep(500);
}
}

1
src/net/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod net;

289
src/net/net.rs Normal file
View File

@ -0,0 +1,289 @@
use crate::device::sys_timer;
use log::{debug, info, warn};
use smoltcp::{
iface::{
self, Interface, SocketHandle, SocketSet, SocketStorage
},
socket::tcp::{State, SocketBuffer, Socket},
wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr},
time::Instant,
};
use stm32_eth::{
Parts, EthPins, PartsIn,
dma::{
TxRingEntry, RxRingEntry, EthernetDMA
}};
use stm32f4xx_hal::{
gpio::{gpioa::*, gpiob::*, gpioc::*, Alternate, Input},
rcc::Clocks,
interrupt,
};
const IPV4_ADDR: (u8, u8, u8, u8) = (192, 168, 1, 132);
const IP_INIT: IpCidr = IpCidr::Ipv4(Ipv4Cidr::new(
Ipv4Address::new(IPV4_ADDR.0, IPV4_ADDR.1, IPV4_ADDR.2, IPV4_ADDR.3),
24,
));
const ADDRESS: (IpAddress, u16) = (
IpAddress::Ipv4(Ipv4Address::new(
IPV4_ADDR.0,
IPV4_ADDR.1,
IPV4_ADDR.2,
IPV4_ADDR.3,
)),
1337,
);
const MAC: [u8; 6] = [0x02, 0x5f, 0x25, 0x37, 0x93, 0x0e];
pub struct ServerHandle {
socket_handle: SocketHandle,
socket_set: SocketSet<'static>,
iface: EthInterface,
dma: EthernetDMA<'static, 'static>,
}
pub type EthernetPins =
EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PB12<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
pub struct EthernetMgmtPins {
pub mdio: PA2<Alternate<11>>,
pub mdc: PC1<Alternate<11>>,
}
pub type EthInterface = Interface;
static mut RX_RING: Option<[RxRingEntry; 8]> = None;
static mut TX_RING: Option<[TxRingEntry; 2]> = None;
static mut SOCKET_STORAGE: Option<[SocketStorage<'static>; 1]> = None;
static mut TCP_SOCKET_STORAGE : Option<TcpSocketStorage> = None;
#[derive(Copy, Clone)]
pub struct TcpSocketStorage {
rx_storage: [u8; 2048],
tx_storage: [u8; 2048],
}
impl TcpSocketStorage {
const fn new() -> Self {
Self {
rx_storage: [0; 2048],
tx_storage: [0; 2048],
}
}
}
fn now_fn() -> smoltcp::time::Instant {
Instant::from_millis(i64::from(sys_timer::now()))
}
static mut SERVER_HANDLE : Option<ServerHandle> = None;
impl ServerHandle {
pub fn new (eth_pins: EthernetPins,
eth_mgmt_pins: EthernetMgmtPins,
ethernet_parts_in: PartsIn,
clocks: Clocks,
) {
let rx_ring = unsafe { RX_RING.get_or_insert(Default::default()) };
let tx_ring = unsafe { TX_RING.get_or_insert(Default::default()) };
let tcp_socket_storage = unsafe { TCP_SOCKET_STORAGE.get_or_insert(TcpSocketStorage::new()) };
let socket_storage = unsafe { SOCKET_STORAGE.get_or_insert([SocketStorage::EMPTY; 1]) };
let Parts {
mut dma,
mac,
#[cfg(feature = "ptp")]
..
} = stm32_eth::new_with_mii(
ethernet_parts_in,
&mut rx_ring[..],
&mut tx_ring[..],
clocks,
eth_pins,
eth_mgmt_pins.mdio,
eth_mgmt_pins.mdc
).unwrap();
let mut routes = smoltcp::iface::Routes::new();
routes
.add_default_ipv4_route(Ipv4Address::new(192, 168, 1, 1))
.ok();
dma.enable_interrupt();
let rx_buffer = SocketBuffer::new(&mut tcp_socket_storage.rx_storage[..]);
let tx_buffer = SocketBuffer::new(&mut tcp_socket_storage.tx_storage[..]);
let socket = Socket::new(rx_buffer, tx_buffer);
let config = iface::Config::new(EthernetAddress::from_bytes(&MAC).into());
let mut iface = Interface::new(config, &mut &mut dma, smoltcp::time::Instant::ZERO);
iface.set_hardware_addr(EthernetAddress(MAC).into());
iface.update_ip_addrs(|addr| {
addr.push(IP_INIT).unwrap();
});
let mut sockets = SocketSet::new(&mut socket_storage[..]);
let tcp_handle = sockets.add(socket);
let socket = sockets.get_mut::<Socket>(tcp_handle);
socket.listen(ADDRESS).ok();
iface.poll(Instant::from_millis(i64::from(sys_timer::now())), &mut &mut dma, &mut sockets);
let server = ServerHandle {
socket_handle: tcp_handle,
socket_set: sockets,
iface: iface,
dma: dma,
};
if let Ok(mut phy) = EthernetPhy::from_miim(mac, 0) {
info!(
"Resetting PHY as an extra step. Type: {}",
phy.ident_string()
);
phy.phy_init();
} else {
info!("Not resetting unsupported PHY.");
}
unsafe {
SERVER_HANDLE = Some(server);
}
}
pub fn poll(&mut self, buffer: &mut [u8]) {
self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set);
let socket = self.socket_set.get_mut::<Socket>(self.socket_handle);
if let Ok(recv_bytes) = socket.recv_slice(buffer) {
if recv_bytes > 0 {
socket.send_slice(&buffer[..recv_bytes]).ok();
info!("Echoed {} bytes.", recv_bytes);
}
}
if !socket.is_listening() && !socket.is_open() || socket.state() == State::CloseWait {
socket.abort();
socket.listen(ADDRESS).ok();
warn!("Disconnected... Reopening listening socket.");
}
self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set);
}
}
use ieee802_3_miim::{
phy::{
lan87xxa::{LAN8720A, LAN8742A},
BarePhy, KSZ8081R,
},
Miim, Pause, Phy,
};
/// An ethernet PHY
pub enum EthernetPhy<M: Miim> {
/// LAN8720A
LAN8720A(LAN8720A<M>),
/// LAN8742A
LAN8742A(LAN8742A<M>),
/// KSZ8081R
KSZ8081R(KSZ8081R<M>),
}
impl<M: Miim> Phy<M> for EthernetPhy<M> {
fn best_supported_advertisement(&self) -> ieee802_3_miim::AutoNegotiationAdvertisement {
unimplemented!()
}
fn get_miim(&mut self) -> &mut M {
match self {
EthernetPhy::LAN8720A(phy) => phy.get_miim(),
EthernetPhy::LAN8742A(phy) => phy.get_miim(),
EthernetPhy::KSZ8081R(phy) => phy.get_miim(),
}
}
fn get_phy_addr(&self) -> u8 {
match self {
EthernetPhy::LAN8720A(phy) => phy.get_phy_addr(),
EthernetPhy::LAN8742A(phy) => phy.get_phy_addr(),
EthernetPhy::KSZ8081R(phy) => phy.get_phy_addr(),
}
}
}
impl<M: Miim> EthernetPhy<M> {
/// Attempt to create one of the known PHYs from the given
/// MIIM.
///
/// Returns an error if the PHY does not support the extended register
/// set, or if the PHY's identifier does not correspond to a known PHY.
pub fn from_miim(miim: M, phy_addr: u8) -> Result<Self, M> {
let mut bare = BarePhy::new(miim, phy_addr, Pause::NoPause);
let phy_ident = if let Some(id) = bare.phy_ident() {
id.raw_u32()
} else {
return Err(bare.release());
};
let miim = bare.release();
match phy_ident & 0xFFFFFFF0 {
0x0007C0F0 => Ok(Self::LAN8720A(LAN8720A::new(miim, phy_addr))),
0x0007C130 => Ok(Self::LAN8742A(LAN8742A::new(miim, phy_addr))),
0x00221560 => Ok(Self::KSZ8081R(KSZ8081R::new(miim, phy_addr))),
_ => Err(miim),
}
}
/// Get a string describing the type of PHY
pub const fn ident_string(&self) -> &'static str {
match self {
EthernetPhy::LAN8720A(_) => "LAN8720A",
EthernetPhy::LAN8742A(_) => "LAN8742A",
EthernetPhy::KSZ8081R(_) => "KSZ8081R",
}
}
/// Initialize the PHY
pub fn phy_init(&mut self) {
match self {
EthernetPhy::LAN8720A(phy) => phy.phy_init(),
EthernetPhy::LAN8742A(phy) => phy.phy_init(),
EthernetPhy::KSZ8081R(phy) => {
phy.set_autonegotiation_advertisement(phy.best_supported_advertisement());
}
}
}
#[allow(dead_code)]
pub fn speed(&mut self) -> Option<ieee802_3_miim::phy::PhySpeed> {
match self {
EthernetPhy::LAN8720A(phy) => phy.link_speed(),
EthernetPhy::LAN8742A(phy) => phy.link_speed(),
EthernetPhy::KSZ8081R(phy) => phy.link_speed(),
}
}
#[allow(dead_code)]
pub fn release(self) -> M {
match self {
EthernetPhy::LAN8720A(phy) => phy.release(),
EthernetPhy::LAN8742A(phy) => phy.release(),
EthernetPhy::KSZ8081R(phy) => phy.release(),
}
}
}
/// Potentially wake up from `wfi()`, set the interrupt pending flag,
/// clear interrupt flags.
#[interrupt]
fn ETH() {
let interrupt_reason = stm32_eth::eth_interrupt_handler();
debug!("Ethernet Interrupt{:?}", interrupt_reason);
unsafe{
if let Some(ref mut server_handle ) = SERVER_HANDLE {
let mut data : [u8; 512] = [0u8; 512];
server_handle.poll(&mut data);
}
else {
panic!("Interrupt is called before init");
}
}
}

View File

@ -6,7 +6,7 @@ use crate::thermostat::max1968::{MAX1968, AdcReadTarget, PwmPinsEnum};
use crate::thermostat::ad7172;
use crate::thermostat::pid_state::PidState;
use crate::thermostat::steinhart_hart;
use log::info;
use log::debug;
use uom::si::{
electric_current::ampere,
electric_potential::volt,
@ -167,7 +167,6 @@ impl Thermostat{
}
fn set_center_pt(&mut self, value: ElectricPotential){
info!("set center pt: {:?}", value);
self.tec_setting.center_pt = value;
}
@ -233,14 +232,14 @@ impl Thermostat{
/// VREF measurement can introduce significant noise at the current output, degrading the stabilily performance of the
/// thermostat.
pub fn calibrate_dac_value(&mut self) {
const STEPS: i32 = 18;
let target_voltage = self.max1968.adc_read(AdcReadTarget::VREF, 64);
let mut start_value = 1;
let mut best_error = ElectricPotential::new::<volt>(100.0);
for step in (0..18).rev() {
info!("Step: {} Calibrating", step);
for step in (0..STEPS).rev() {
debug!("TEC VREF Calibrating: Step {}/{}", step, STEPS);
let mut prev_value = start_value;
for value in (start_value..=ad5680::MAX_VALUE).step_by(1 << step) {
info!("Calibrating: Value: {:?}", value);
self.max1968.phy.dac.set(value).unwrap();
sys_timer::sleep(5);
@ -258,7 +257,6 @@ impl Thermostat{
prev_value = value;
}
}
info!("Best Error: {:?}", best_error);
}
pub fn pid_engaged(&mut self) -> bool {