From abf22676ce1617a6e7d22dd6b7df8eab99f1b283 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 28 Apr 2020 19:07:19 +0200 Subject: [PATCH] Adding refactor to support pounder hardware abstractions --- Cargo.lock | 94 ++++++++++++ Cargo.toml | 18 ++- src/main.rs | 302 +++++++++++++++++++++++++++---------- src/pounder/attenuators.rs | 54 +++++++ src/pounder/error.rs | 9 ++ src/pounder/mod.rs | 148 ++++++++++++++++++ 6 files changed, 544 insertions(+), 81 deletions(-) create mode 100644 src/pounder/attenuators.rs create mode 100644 src/pounder/error.rs create mode 100644 src/pounder/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 3f6481a..2d9234b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,19 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ad9959" +version = "0.1.0" +source = "git+https://github.com/quartiq/ad9959.git?branch=feature/basic-driver#71f96bab751048aa944490b4b56463551025a21f" +dependencies = [ + "bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aligned" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "aligned" version = "0.3.2" @@ -18,6 +32,16 @@ dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "asm-delay" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitrate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "autocfg" version = "1.0.0" @@ -31,11 +55,21 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bit_field" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitrate" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.3.4" @@ -54,6 +88,17 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cortex-m" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aligned 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bare-metal 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cortex-m" version = "0.6.2" @@ -189,6 +234,17 @@ name = "managed" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "mcp23017" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nb" version = "0.1.2" @@ -299,6 +355,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -306,6 +363,8 @@ dependencies = [ name = "stabilizer" version = "0.3.0" dependencies = [ + "ad9959 0.1.0 (git+https://github.com/quartiq/ad9959.git?branch=feature/basic-driver)", + "asm-delay 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "cortex-m 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "cortex-m-log 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "cortex-m-rt 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -313,12 +372,14 @@ dependencies = [ "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "heapless 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mcp23017 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "panic-halt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "panic-semihosting 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde-json-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stm32h7-ethernet 0.1.1", "stm32h7xx-hal 0.4.0 (git+https://github.com/quartiq/stm32h7xx-hal.git?branch=feature/quad-spi)", ] @@ -338,6 +399,16 @@ dependencies = [ "vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "stm32h7-ethernet" +version = "0.1.1" +dependencies = [ + "cortex-m 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stm32h7xx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "stm32h7xx-hal" version = "0.4.0" @@ -353,6 +424,21 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "stm32h7xx-hal" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bare-metal 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m-rt 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "stm32h7 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "1.0.17" @@ -392,14 +478,20 @@ dependencies = [ ] [metadata] +"checksum ad9959 0.1.0 (git+https://github.com/quartiq/ad9959.git?branch=feature/basic-driver)" = "" +"checksum aligned 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d39da9b88ae1a81c03c9c082b8db83f1d0e93914126041962af61034ab44c4a5" "checksum aligned 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eb1ce8b3382016136ab1d31a1b5ce807144f8b7eb2d5f16b2108f0f07edceb94" "checksum as-slice 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37dfb65bc03b2bc85ee827004f14a6817e04160e3b1a28931986a666a9290e70" +"checksum asm-delay 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e0c8eec73de29ae94b2aff405a272304bc286204ddb1cdf20d7e2249078ae20" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum bare-metal 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +"checksum bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum bitrate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c147d86912d04bef727828fda769a76ca81629a46d8ba311a8d58a26aa91473d" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum cortex-m 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0b159a1e8306949579de3698c841dba58058197b65c60807194e4fa1e7a554" "checksum cortex-m 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2954942fbbdd49996704e6f048ce57567c3e1a4e2dc59b41ae9fde06a01fc763" "checksum cortex-m-log 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "978caafe65d1023d38b00c76b83564788fc351d954a5005fb72cf992c0d61458" "checksum cortex-m-rt 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "00d518da72bba39496024b62607c1d8e37bcece44b2536664f1132a73a499a28" @@ -415,6 +507,7 @@ dependencies = [ "checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6" +"checksum mcp23017 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4854484a74b626165c3f3cf5e15bfee2898c6b4d6eccc3ed5ee634850af4dd" "checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc" "checksum panic-halt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" "checksum panic-semihosting 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c03864ac862876c16a308f5286f4aa217f1a69ac45df87ad3cd2847f818a642c" @@ -433,6 +526,7 @@ dependencies = [ "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stm32h7 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b0045066e082648e8a7ab1dd45c92efa8d7bec2beedf72ac7b62563911f82a" "checksum stm32h7xx-hal 0.4.0 (git+https://github.com/quartiq/stm32h7xx-hal.git?branch=feature/quad-spi)" = "" +"checksum stm32h7xx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "689aff61a1cf43e03cf821c5540bb540e6bd04b374e486be23b035c0afc3c15f" "checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" "checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" diff --git a/Cargo.toml b/Cargo.toml index 8d3bc45..e05c09a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,9 +36,25 @@ serde = { version = "1.0", features = ["derive"], default-features = false } heapless = "0.5" serde-json-core = "0.1" cortex-m-rtfm = "0.5" -smoltcp = { version = "0.6", features = ["ethernet", "proto-ipv4", "socket-tcp"], default-features = false } embedded-hal = "0.2.3" nb = "0.1.2" +asm-delay = "0.7.0" +mcp23017 = "0.1.1" + +[dependencies.smoltcp] +version = "0.6" +features = ["ethernet", "proto-ipv4", "socket-tcp", "proto-ipv6"] +default-features = false + +[dependencies.ad9959] +git = "https://github.com/quartiq/ad9959.git" +branch = "feature/basic-driver" + +[dependencies.stm32h7-ethernet] +#git = "https://github.com/quartiq/stm32h7-ethernet.git" +#branch = "feature/device-dependency" +path = "../stm32h7-ethernet" +features = ["stm32h743v"] [dependencies.stm32h7xx-hal] git = "https://github.com/quartiq/stm32h7xx-hal.git" diff --git a/src/main.rs b/src/main.rs index cc07801..1d24d19 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,8 +30,10 @@ extern crate log; use nb; // use core::sync::atomic::{AtomicU32, AtomicBool, Ordering}; +use asm_delay; +use rtfm::cyccnt::{Instant, U32Ext}; use cortex_m_rt::exception; -use cortex_m::asm; +use cortex_m; use stm32h7xx_hal as hal; use stm32h7xx_hal::{ prelude::*, @@ -42,15 +44,31 @@ use embedded_hal::{ digital::v2::OutputPin, }; -/* -use core::fmt::Write; -use heapless::{consts::*, String, Vec}; +use stm32h7_ethernet as ethernet; use smoltcp as net; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json_core::{de::from_slice, ser::to_string}; -*/ + +use core::fmt::Write; +use heapless::{ + consts::*, + String, + //Vec +}; + +use serde::{ + //de::DeserializeOwned, + Deserialize, + Serialize +}; +use serde_json_core::{ + //de::from_slice, + ser::to_string +}; + +#[link_section = ".sram3.eth"] +static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new(); mod eth; +mod pounder; mod iir; use iir::*; @@ -81,30 +99,26 @@ mod build_info { // include!(concat!(env!("OUT_DIR"), "/built.rs")); } +pub struct NetStorage { + ip_addrs: [net::wire::IpCidr; 1], + neighbor_cache: [Option<(net::wire::IpAddress, net::iface::Neighbor)>; 8], +} + +static mut NET_STORE: NetStorage = NetStorage { + // Placeholder for the real IP address, which is initialized at runtime. + ip_addrs: [net::wire::IpCidr::Ipv6(net::wire::Ipv6Cidr::SOLICITED_NODE_PREFIX)], + + neighbor_cache: [None; 8], +}; + const SCALE: f32 = ((1 << 15) - 1) as f32; // static ETHERNET_PENDING: AtomicBool = AtomicBool::new(true); -/* 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); - }; -} -*/ - -#[rtfm::app(device = stm32h7xx_hal::stm32, peripherals = true)] +#[rtfm::app(device = stm32h7xx_hal::stm32, peripherals = true, monotonic = rtfm::cyccnt::CYCCNT)] const APP: () = { struct Resources { adc1: hal::spi::Spi, @@ -113,23 +127,22 @@ const APP: () = { adc2: hal::spi::Spi, dac2: hal::spi::Spi, - _eeprom_i2c: hal::i2c::I2c, + eeprom_i2c: hal::i2c::I2c, dbg_pin: hal::gpio::gpioc::PC6>, dac_pin: hal::gpio::gpiob::PB15>, timer: hal::timer::Timer, + net_interface: net::iface::EthernetInterface<'static, 'static, 'static, + ethernet::EthernetDMA<'static>>, + _eth_mac: ethernet::EthernetMAC, + mac_addr: net::wire::EthernetAddress, - // TODO: Add in pounder hardware resources. + pounder: pounder::PounderDevices, - //ethernet_periph: - // (pac::ETHERNET_MAC, pac::ETHERNET_DMA, pac::ETHERNET_MTL), #[init([[0.; 5]; 2])] iir_state: [IIRState; 2], #[init([IIR { ba: [1., 0., 0., 0., 0.], y_offset: 0., y_min: -SCALE - 1., y_max: SCALE }; 2])] iir_ch: [IIR; 2], - //#[link_section = ".sram3.eth"] - //#[init(eth::Device::new())] - //ethernet: eth::Device, } #[init] @@ -151,6 +164,9 @@ const APP: () = { .pll2_q_ck(100.mhz()) .freeze(vos, &dp.SYSCFG); + // Enable SRAM3 for the ethernet descriptor ring. + clocks.rb.ahb2enr.modify(|_, w| w.sram3en().set_bit()); + clocks.rb.rsr.write(|w| w.rmvf().set_bit()); clocks.rb.d2ccip1r.modify(|_, w| w.spi123sel().pll2_p().spi45sel().pll2_q()); @@ -247,15 +263,63 @@ const APP: () = { dp.SPI5.spi((spi_sck, spi_miso, hal::spi::NoMosi), config, 25.mhz(), &clocks) }; - // Instantiate the QUADSPI pins and peripheral interface. + let pounder_devices = { + let ad9959 = { + let qspi_interface = { + // Instantiate the QUADSPI pins and peripheral interface. + // TODO: Place these into a pins structure that is provided to the QSPI + // constructor. + let _qspi_clk = gpiob.pb2.into_alternate_af9(); + let _qspi_ncs = gpioc.pc11.into_alternate_af9(); + let _qspi_io0 = gpioe.pe7.into_alternate_af10(); + let _qspi_io1 = gpioe.pe8.into_alternate_af10(); + let _qspi_io2 = gpioe.pe9.into_alternate_af10(); + let _qspi_io3 = gpioe.pe10.into_alternate_af10(); - // TODO: Place these into a pins structure that is provided to the QSPI constructor. - let _qspi_clk = gpiob.pb2.into_alternate_af9(); - let _qspi_ncs = gpioc.pc11.into_alternate_af9(); - let _qspi_io0 = gpioe.pe7.into_alternate_af10(); - let _qspi_io1 = gpioe.pe8.into_alternate_af10(); - let _qspi_io2 = gpioe.pe9.into_alternate_af10(); - let _qspi_io3 = gpioe.pe10.into_alternate_af10(); + let qspi = hal::qspi::Qspi::new(dp.QUADSPI, &mut clocks, 10.mhz()).unwrap(); + pounder::QspiInterface {qspi} + }; + + let mut reset_pin = gpioa.pa0.into_push_pull_output(); + let io_update = gpiog.pg7.into_push_pull_output(); + + + let delay = { + let frequency_hz = clocks.clocks.c_ck().0; + asm_delay::AsmDelay::new(asm_delay::bitrate::Hertz (frequency_hz)) + }; + + ad9959::Ad9959::new(qspi_interface, + &mut reset_pin, + io_update, + delay, + ad9959::Mode::FourBitSerial, + 100_000_000).unwrap() + }; + + let io_expander = { + let sda = gpiob.pb7.into_alternate_af4().set_open_drain(); + let scl = gpiob.pb8.into_alternate_af4().set_open_drain(); + let i2c1 = dp.I2C1.i2c((scl, sda), 100.khz(), &clocks); + mcp23017::MCP23017::default(i2c1).unwrap() + }; + + let spi = { + let spi_mosi = gpiod.pd7.into_alternate_af5(); + let spi_miso = gpioa.pa6.into_alternate_af5(); + let spi_sck = gpiog.pg11.into_alternate_af5(); + + let config = hal::spi::Config::new(hal::spi::Mode{ + polarity: hal::spi::Polarity::IdleHigh, + phase: hal::spi::Phase::CaptureOnSecondTransition, + }) + .frame_size(8); + + dp.SPI1.spi((spi_sck, spi_miso, spi_mosi), config, 25.mhz(), &clocks) + }; + + pounder::PounderDevices::new(io_expander, ad9959, spi).unwrap() + }; let mut fp_led_0 = gpiod.pd5.into_push_pull_output(); let mut fp_led_1 = gpiod.pd6.into_push_pull_output(); @@ -267,45 +331,63 @@ const APP: () = { fp_led_2.set_low().unwrap(); fp_led_3.set_low().unwrap(); - let _i2c1 = { - let sda = gpiob.pb7.into_alternate_af4().set_open_drain(); - let scl = gpiob.pb8.into_alternate_af4().set_open_drain(); - dp.I2C1.i2c((scl, sda), 100.khz(), &clocks) - }; - - let i2c2 = { + let mut eeprom_i2c = { let sda = gpiof.pf0.into_alternate_af4().set_open_drain(); let scl = gpiof.pf1.into_alternate_af4().set_open_drain(); dp.I2C2.i2c((scl, sda), 100.khz(), &clocks) }; // Configure ethernet pins. + { + // Reset the PHY before configuring pins. + let mut eth_phy_nrst = gpioe.pe3.into_push_pull_output(); + eth_phy_nrst.set_high().unwrap(); + eth_phy_nrst.set_low().unwrap(); + eth_phy_nrst.set_high().unwrap(); + let _rmii_ref_clk = gpioa.pa1.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); + let _rmii_mdio = gpioa.pa2.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); + let _rmii_mdc = gpioc.pc1.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); + let _rmii_crs_dv = gpioa.pa7.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); + let _rmii_rxd0 = gpioc.pc4.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); + let _rmii_rxd1 = gpioc.pc5.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); + let _rmii_tx_en = gpiob.pb11.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); + let _rmii_txd0 = gpiob.pb12.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); + let _rmii_txd1 = gpiog.pg14.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); + } - // Reset the PHY before configuring pins. - let mut eth_phy_nrst = gpioe.pe3.into_push_pull_output(); - eth_phy_nrst.set_high().unwrap(); - eth_phy_nrst.set_low().unwrap(); - eth_phy_nrst.set_high().unwrap(); - let _rmii_ref_clk = gpioa.pa1.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); - let _rmii_mdio = gpioa.pa2.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); - let _rmii_mdc = gpioc.pc1.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); - let _rmii_crs_dv = gpioa.pa7.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); - let _rmii_rxd0 = gpioc.pc4.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); - let _rmii_rxd1 = gpioc.pc5.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); - let _rmii_tx_en = gpiob.pb11.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); - let _rmii_txd0 = gpiob.pb12.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); - let _rmii_txd1 = gpiog.pg14.into_alternate_af11().set_speed(hal::gpio::Speed::VeryHigh); + let mac_addr = match eeprom::read_eui48(&mut eeprom_i2c) { + Err(_) => { + info!("Could not read EEPROM, using default MAC address"); + net::wire::EthernetAddress([0x10, 0xE2, 0xD5, 0x00, 0x03, 0x00]) + } + Ok(raw_mac) => net::wire::EthernetAddress(raw_mac), + }; - // TODO: Configure the ethernet controller - // Enable the ethernet peripheral. - //clocks.apb4.enr().modify(|_, w| w.syscfgen().set_bit()); - //clocks.ahb1.enr().modify(|_, w| { - // w.eth1macen().set_bit() - // .eth1txen().set_bit() - // .eth1rxen().set_bit() - //}); + let (network_interface, eth_mac) = { + // Configure the ethernet controller + let (eth_dma, eth_mac) = unsafe { + ethernet::ethernet_init( + dp.ETHERNET_MAC, + dp.ETHERNET_MTL, + dp.ETHERNET_DMA, + &mut DES_RING, + mac_addr.clone()) + }; - //dp.SYSCFG.pmcr.modify(|_, w| unsafe { w.epis().bits(0b100) }); // RMII + let store = unsafe { &mut NET_STORE }; + + store.ip_addrs[0] = net::wire::IpCidr::new(net::wire::IpAddress::v4(10, 0, 16, 99), 24); + + let neighbor_cache = net::iface::NeighborCache::new(&mut store.neighbor_cache[..]); + + let interface = net::iface::EthernetInterfaceBuilder::new(eth_dma) + .ethernet_addr(mac_addr) + .neighbor_cache(neighbor_cache) + .ip_addrs(&mut store.ip_addrs[..]) + .finalize(); + + (interface, eth_mac) + }; cp.SCB.enable_icache(); @@ -314,6 +396,9 @@ const APP: () = { // info!("Built on {}", build_info::BUILT_TIME_UTC); // info!("{} {}", build_info::RUSTC_VERSION, build_info::TARGET); + // Utilize the cycle counter for RTFM scheduling. + cp.DWT.enable_cycle_counter(); + let mut debug_pin = gpioc.pc6.into_push_pull_output(); debug_pin.set_low().unwrap(); @@ -333,13 +418,12 @@ const APP: () = { dbg_pin: debug_pin, dac_pin: dac_pin, timer: timer2, + pounder: pounder_devices, - _eeprom_i2c: i2c2, -// ethernet_periph: ( -// dp.ETHERNET_MAC, -// dp.ETHERNET_DMA, -// dp.ETHERNET_MTL, -// ), + eeprom_i2c: eeprom_i2c, + net_interface: network_interface, + _eth_mac: eth_mac, + mac_addr: mac_addr, } } @@ -386,11 +470,69 @@ const APP: () = { cortex_m::asm::bkpt(); } - #[idle] - fn idle(_c: idle::Context) -> ! { - // TODO Implement and poll ethernet interface. + #[idle(resources=[net_interface, mac_addr, iir_state])] + fn idle(mut c: idle::Context) -> ! { + + let interface = c.resources.net_interface; + let mut socket_set_entries: [_; 8] = Default::default(); + let mut sockets = net::socket::SocketSet::new(&mut socket_set_entries[..]); + + let mut rx_storage = [0; TCP_RX_BUFFER_SIZE]; + let mut tx_storage = [0; TCP_TX_BUFFER_SIZE]; + let tcp_handle0 = { + 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); + sockets.add(tcp_socket) + }; + + let mut time = 0u32; + let mut next_ms = Instant::now(); + + // TODO: Replace with reference to CPU clock from CCDR. + next_ms += 400_000.cycles(); + loop { - asm::nop(); + let tick = Instant::now() > next_ms; + + if tick { + next_ms += 400_000.cycles(); + time += 1; + } + + { + let mut socket = sockets.get::(tcp_handle0); + if socket.state() == net::socket::TcpState::CloseWait { + socket.close(); + } else if !(socket.is_open() || socket.is_listening()) { + socket + .listen(1234) + .unwrap_or_else(|e| warn!("TCP listen error: {:?}", e)); + } else if tick && socket.can_send() { + let s = c.resources.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], + }); + json_reply(&mut socket, &s); + } + } + + let sleep = match interface.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 + } + }; + + if sleep { + cortex_m::asm::wfi(); + } } } @@ -515,7 +657,6 @@ const APP: () = { } }; -/* #[derive(Deserialize, Serialize)] struct Request { channel: u8, @@ -543,6 +684,7 @@ fn json_reply(socket: &mut net::socket::TcpSocket, msg: &T) { socket.write_str(&u).unwrap(); } +/* struct Server { data: Vec, discard: bool, diff --git a/src/pounder/attenuators.rs b/src/pounder/attenuators.rs new file mode 100644 index 0000000..b8569d8 --- /dev/null +++ b/src/pounder/attenuators.rs @@ -0,0 +1,54 @@ +use super::error::Error; + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy)] +pub enum Channel { + One = 0, + Two = 1, + Three = 2, + Four = 3, +} + +pub trait AttenuatorInterface { + fn modify(&mut self, attenuation: f32, channel: Channel) -> Result { + if attenuation > 31.5 { + return Err(Error::Bounds); + } + + // Calculate the attenuation code to program into the attenuator. + let attenuation_code = (attenuation * 2.0) as u8; + + // Read all the channels, modify the channel of interest, and write all the channels back. + // This ensures the staging register and the output register are always in sync. + let mut channels = [0_u8; 4]; + self.read_all(&mut channels)?; + channels[channel as usize] = attenuation_code; + self.write_all(&channels)?; + + // Finally, latch the output of the updated channel to force it into an active state. + self.latch(channel)?; + + Ok(attenuation_code as f32 / 2.0) + } + + fn read(&mut self, channel: Channel) -> Result { + let mut channels = [0_u8; 4]; + + // Reading the data always shifts data out of the staging registers, so we perform a + // duplicate write-back to ensure the staging register is always equal to the output + // register. + self.read_all(&mut channels)?; + self.write_all(&channels)?; + + // Convert the desired channel code into dB of attenuation. + let attenuation_code = channels[channel as usize]; + + Ok(attenuation_code as f32 / 2.0) + } + + fn reset(&mut self) -> Result<(), Error>; + + fn latch(&mut self, channel: Channel) -> Result<(), Error>; + fn read_all(&mut self, channels: &mut [u8; 4]) -> Result<(), Error>; + fn write_all(&mut self, channels: &[u8; 4]) -> Result<(), Error>; +} diff --git a/src/pounder/error.rs b/src/pounder/error.rs new file mode 100644 index 0000000..56a9e09 --- /dev/null +++ b/src/pounder/error.rs @@ -0,0 +1,9 @@ +#[derive(Debug)] +pub enum Error { + Spi, + I2c, + DDS, + Qspi, + Bounds, + InvalidAddress, +} diff --git a/src/pounder/mod.rs b/src/pounder/mod.rs new file mode 100644 index 0000000..bcd24bd --- /dev/null +++ b/src/pounder/mod.rs @@ -0,0 +1,148 @@ +use mcp23017; +use ad9959; + +pub mod error; +pub mod attenuators; + +use super::hal; + +use error::Error; +use attenuators::{AttenuatorInterface, Channel}; + +use embedded_hal::blocking::spi::Transfer; + +#[allow(dead_code)] +const OSC_EN_N_PIN: u8 = 8 + 7; + +const EXT_CLK_SEL_PIN: u8 = 8 + 6; + +const ATT_RST_N_PIN: u8 = 8 + 5; + +const ATT_LE0_PIN: u8 = 8 + 0; +const ATT_LE1_PIN: u8 = 8 + 1; +const ATT_LE2_PIN: u8 = 8 + 2; +const ATT_LE3_PIN: u8 = 8 + 3; + +pub struct QspiInterface { + pub qspi: hal::qspi::Qspi, +} + +impl ad9959::Interface for QspiInterface { + type Error = Error; + + fn configure_mode(&mut self, mode: ad9959::Mode) -> Result<(), Error> { + let result = match mode { + ad9959::Mode::SingleBitTwoWire | ad9959::Mode::SingleBitThreeWire => + self.qspi.configure_mode(hal::qspi::QspiMode::OneBit), + ad9959::Mode::TwoBitSerial => self.qspi.configure_mode(hal::qspi::QspiMode::TwoBit), + ad9959::Mode::FourBitSerial => self.qspi.configure_mode(hal::qspi::QspiMode::FourBit), + }; + + result.map_err(|_| Error::Qspi) + } + + fn write(&mut self, addr: u8, data: &[u8]) -> Result<(), Error> { + if (addr & 0x80) != 0 { + return Err(Error::InvalidAddress); + } + + self.qspi.write(addr, &data).map_err(|_| Error::Qspi) + } + + fn read(&mut self, addr: u8, mut dest: &mut [u8]) -> Result<(), Error> { + if (addr & 0x80) != 0 { + return Err(Error::InvalidAddress); + } + self.qspi.read(0x80_u8 | addr, &mut dest).map_err(|_| Error::Qspi) + } +} + +pub struct PounderDevices { + pub ad9959: ad9959::Ad9959>>, + mcp23017: mcp23017::MCP23017>, + attenuator_spi: hal::spi::Spi +} + +impl PounderDevices +where + DELAY: embedded_hal::blocking::delay::DelayMs, +{ + pub fn new(mcp23017: mcp23017::MCP23017>, + ad9959: ad9959::Ad9959>>, + attenuator_spi: hal::spi::Spi) -> Result { + let mut devices = Self { + mcp23017, + ad9959, + attenuator_spi + }; + + // Configure power-on-default state for pounder. All LEDs are on, on-board oscillator + // selected, attenuators out of reset. + devices.mcp23017.write_gpioa(0xF).map_err(|_| Error::I2c)?; + devices.mcp23017.write_gpiob(1_u8.wrapping_shl(5)).map_err(|_| Error::I2c)?; + devices.mcp23017.all_pin_mode(mcp23017::PinMode::OUTPUT).map_err(|_| Error::I2c)?; + + devices.select_onboard_clock()?; + + Ok(devices) + } + + pub fn select_external_clock(&mut self, frequency: u32) -> Result<(), Error>{ + self.mcp23017.digital_write(EXT_CLK_SEL_PIN, 1).map_err(|_| Error::I2c)?; + self.ad9959.set_clock_frequency(frequency).map_err(|_| Error::DDS)?; + + Ok(()) + } + + pub fn select_onboard_clock(&mut self) -> Result<(), Error> { + self.mcp23017.digital_write(EXT_CLK_SEL_PIN, 0).map_err(|_| Error::I2c)?; + self.ad9959.set_clock_frequency(100_000_000).map_err(|_| Error::DDS)?; + + Ok(()) + } +} + +impl AttenuatorInterface for PounderDevices +{ + fn reset(&mut self) -> Result<(), Error> { + self.mcp23017.digital_write(ATT_RST_N_PIN, 1).map_err(|_| Error::I2c)?; + // TODO: Delay here. + self.mcp23017.digital_write(ATT_RST_N_PIN, 0).map_err(|_| Error::I2c)?; + + Ok(()) + } + + fn latch(&mut self, channel: Channel) -> Result<(), Error> { + let pin = match channel { + Channel::One => ATT_LE0_PIN, + Channel::Two => ATT_LE1_PIN, + Channel::Three => ATT_LE2_PIN, + Channel::Four => ATT_LE3_PIN, + }; + + self.mcp23017.digital_write(pin, 1).map_err(|_| Error::I2c)?; + // TODO: Delay here. + self.mcp23017.digital_write(pin, 0).map_err(|_| Error::I2c)?; + + Ok(()) + } + + fn read_all(&mut self, channels: &mut [u8; 4]) -> Result<(), Error> { + self.attenuator_spi.transfer(channels).map_err(|_| Error::Spi)?; + + Ok(()) + } + + fn write_all(&mut self, channels: &[u8; 4]) -> Result<(), Error> { + let mut result = [0_u8; 4]; + result.clone_from_slice(channels); + self.attenuator_spi.transfer(&mut result).map_err(|_| Error::Spi)?; + + Ok(()) + } +}