#![no_main] #![no_std] use core::sync::atomic::{AtomicU32, Ordering}; #[macro_use] extern crate log; use cortex_m; use cortex_m::asm::nop; use cortex_m_rt::{ entry, exception, }; extern crate smoltcp; use stm32h7xx_hal::ethernet; use stm32h7xx_hal::gpio::Speed; use stm32h7xx_hal::hal::digital::v2::{ OutputPin, InputPin, }; use stm32h7xx_hal::rcc::CoreClocks; use stm32h7xx_hal::{pac, prelude::*, spi, stm32, stm32::interrupt}; use Speed::*; use core::{ str, fmt::Write }; use core::mem::uninitialized; // Exception: no phy::wait //use smoltcp::phy::wait as phy_wait; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}; use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, Routes}; use smoltcp::socket::SocketSet; use smoltcp::socket::{SocketHandle, TcpSocket, TcpSocketBuffer}; use smoltcp::time::{Duration, Instant}; // use smoltcp::log; // Use embedded-nal to access smoltcp use embedded_nal::TcpStack; use firmware; use firmware::{ attenuator::Attenuator, config_register::{ ConfigRegister, CFGMask, StatusMask, }, dds::{ DDS, DDSCFRMask, }, cpld::{ CPLD, }, scpi::{ HelloWorldCommand, Channel0SwitchCommand, Channel1SwitchCommand, Channel2SwitchCommand, Channel3SwitchCommand, ClockSourceCommand, ClockDivisionCommand, }, Urukul, scpi_root, recursive_scpi_tree }; use scpi::prelude::*; use scpi::ieee488::commands::*; use scpi::scpi::commands::*; use scpi::{ ieee488_cls, ieee488_ese, ieee488_esr, ieee488_idn, ieee488_opc, ieee488_rst, ieee488_sre, ieee488_stb, ieee488_tst, ieee488_wai, nquery, //Helpers qonly, scpi_crate_version, scpi_status, scpi_system, }; #[path = "util/logger.rs"] mod logger; /// Configure SYSTICK for 1ms timebase fn systick_init(syst: &mut stm32::SYST, clocks: CoreClocks) { let c_ck_mhz = clocks.c_ck().0 / 1_000_000; let syst_calib = 0x3E8; syst.set_clock_source(cortex_m::peripheral::syst::SystClkSource::Core); syst.set_reload((syst_calib * c_ck_mhz) - 1); syst.enable_interrupt(); syst.enable_counter(); } /// ====================================================================== /// Entry point /// ====================================================================== /// TIME is an atomic u32 that counts milliseconds. Although not used /// here, it is very useful to have for network protocols static TIME: AtomicU32 = AtomicU32::new(0); /// Locally administered MAC address const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".sram3.eth"] static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new(); // Theoratical maximum number of socket that can be handled const SOCKET_COUNT: usize = 2; // Give buffer sizes of transmitting and receiving TCP packets const BUFFER_SIZE: usize = 2048; // the program entry point #[entry] fn main() -> ! { // logger::semihosting_init(); let mut cp = cortex_m::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap(); // Initialise power... let pwr = dp.PWR.constrain(); let vos = pwr.freeze(); // Initialise SRAM3 dp.RCC.ahb2enr.modify(|_, w| w.sram3en().set_bit()); // Initialise clocks... let rcc = dp.RCC.constrain(); let ccdr = rcc .use_hse(8.mhz()) .sys_ck(200.mhz()) .hclk(200.mhz()) .pll1_r_ck(400.mhz()) // for TRACECK .pll1_q_ck(48.mhz()) // for SPI .freeze(vos, &dp.SYSCFG); unsafe { logger::enable_itm(&dp.DBGMCU, &mut cp.DCB, &mut cp.ITM); } // Get the delay provider. let delay = cp.SYST.delay(ccdr.clocks); // Initialise system... cp.SCB.invalidate_icache(); cp.SCB.enable_icache(); cp.DWT.enable_cycle_counter(); // Initialise IO... let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB); let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC); let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD); let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE); let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF); let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG); // gpiob.pb3.into_alternate_af0().set_speed(Speed::VeryHigh); logger::init(); // Setup CDONE for checking let fpga_cdone = gpiod.pd15.into_pull_up_input(); match fpga_cdone.is_high() { Ok(true) => debug!("FPGA is ready."), Ok(_) => debug!("FPGA is in reset state."), Err(_) => debug!("Error: Cannot read C_DONE"), }; // Setup Urukul /* * Using SPI1, AF5 * SCLK -> PA5 * MOSI -> PB5 * MISO -> PA6 * CS -> 0: PB12, 1: PA15, 2: PC7 */ let sclk = gpioa.pa5.into_alternate_af5(); let mosi = gpiob.pb5.into_alternate_af5(); let miso = gpioa.pa6.into_alternate_af5(); let (cs0, cs1, cs2) = ( gpiob.pb12.into_push_pull_output(), gpioa.pa15.into_push_pull_output(), gpioc.pc7.into_push_pull_output(), ); /* * I/O_Update -> PB15 */ let io_update = gpiob.pb15.into_push_pull_output(); let spi = dp.SPI1.spi( (sclk, miso, mosi), spi::MODE_0, 3.mhz(), ccdr.peripheral.SPI1, &ccdr.clocks, ); let switch = CPLD::new(spi, (cs0, cs1, cs2), io_update); let parts = switch.split(); let mut urukul = Urukul::new( parts.spi1, parts.spi2, parts.spi3, parts.spi4, parts.spi5, parts.spi6, parts.spi7, [25_000_000, 25_000_000, 25_000_000, 25_000_000] ); // Setup ethernet pins setup_ethernet_pins( gpioa.pa1, gpioa.pa2, gpioc.pc1, gpioa.pa7, gpioc.pc4, gpioc.pc5, gpiog.pg11, gpiog.pg13, gpiob.pb13 ); // Initialise ethernet... assert_eq!(ccdr.clocks.hclk().0, 200_000_000); // HCLK 200MHz assert_eq!(ccdr.clocks.pclk1().0, 100_000_000); // PCLK 100MHz assert_eq!(ccdr.clocks.pclk2().0, 100_000_000); // PCLK 100MHz assert_eq!(ccdr.clocks.pclk4().0, 100_000_000); // PCLK 100MHz let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); let (_eth_dma, mut eth_mac) = unsafe { ethernet::new_unchecked( dp.ETHERNET_MAC, dp.ETHERNET_MTL, dp.ETHERNET_DMA, &mut DES_RING, mac_addr.clone(), ) }; unsafe { ethernet::enable_interrupt(); cp.NVIC.set_priority(stm32::Interrupt::ETH, 196); // Mid prio cortex_m::peripheral::NVIC::unmask(stm32::Interrupt::ETH); } // ---------------------------------------------------------- // Begin periodic tasks systick_init(&mut delay.free(), ccdr.clocks); unsafe { cp.SCB.shpr[15 - 4].write(128); } // systick exception priority // ---------------------------------------------------------- // Main application loop // Setup addresses, maybe not MAC? // MAC is set up in prior let local_addr = IpAddress::v4(192, 168, 1, 200); let mut ip_addrs = [IpCidr::new(local_addr, 24)]; // let neighbor_cache = NeighborCache::new(BTreeMap::new()); let mut neighbor_storage = [None; 16]; let neighbor_cache = NeighborCache::new(&mut neighbor_storage[..]); // Device? _eth_dma, as it implements phy::device let mut iface = EthernetInterfaceBuilder::new(_eth_dma) .ethernet_addr(mac_addr) .neighbor_cache(neighbor_cache) .ip_addrs(&mut ip_addrs[..]) .finalize(); // SCPI configs let tree = scpi_root!( ["EXAMple"] => { "HELLO" => { "WORLD" => HelloWorldCommand } }, "CHANNEL0" => { "SWitch" => Channel0SwitchCommand }, "CHANNEL1" => { "SWitch" => Channel1SwitchCommand }, "CHANNEL2" => { "SWitch" => Channel2SwitchCommand }, "CHANNEL3" => { "SWitch" => Channel3SwitchCommand }, "CLOCK" => { "SOURCE" => ClockSourceCommand, "DIVision" => ClockDivisionCommand } ); // Device was declared in prior let mut errors = ArrayErrorQueue::<[Error; 10]>::new(); let mut context = Context::new(&mut urukul, &mut errors, tree); //Response bytebuffer let mut buf = ArrayVecFormatter::<[u8; 256]>::new(); // SCPI configs END // TCP socket buffers let mut rx_storage = [0; BUFFER_SIZE]; let mut tx_storage = [0; BUFFER_SIZE]; // Setup TCP sockets let tcp1_rx_buffer = TcpSocketBuffer::new(&mut rx_storage[..]); let tcp1_tx_buffer = TcpSocketBuffer::new(&mut tx_storage[..]); let mut tcp1_socket = TcpSocket::new(tcp1_rx_buffer, tcp1_tx_buffer); // Setup a silent socket let mut silent_rx_storage = [0; BUFFER_SIZE]; let mut silent_tx_storage = [0; BUFFER_SIZE]; let silent_rx_buffer = TcpSocketBuffer::new(&mut silent_rx_storage[..]); let silent_tx_buffer = TcpSocketBuffer::new(&mut silent_tx_storage[..]); let mut silent_socket = TcpSocket::new(silent_rx_buffer, silent_tx_buffer); // Socket storage let mut sockets_storage = [ None, None ]; let mut sockets = SocketSet::new(&mut sockets_storage[..]); let tcp1_handle = sockets.add(tcp1_socket); let silent_handle = sockets.add(silent_socket); let mut handles: [SocketHandle; SOCKET_COUNT] = unsafe { uninitialized() }; let mut eth_up = false; loop { let _time = TIME.load(Ordering::Relaxed); let eth_last = eth_up; match iface.poll(&mut sockets, Instant::from_millis(_time as i64)) { Ok(_) => { eth_up = true; }, Err(e) => { eth_up = false; }, }; // SCPI interaction socket (:7000) { let mut socket = sockets.get::(silent_handle); if !socket.is_open() { socket.listen(7000).unwrap(); socket.set_timeout(Some(Duration::from_millis(1000000))); } if socket.can_recv() { let mut data = socket.recv(|buffer| { (buffer.len(), buffer) }).unwrap(); if str::from_utf8(data).unwrap().trim() == "quit" { socket.close(); socket.abort(); continue; } let result = context.run(data, &mut buf); if let Err(err) = result { writeln!(socket, "{}", str::from_utf8(err.get_message()).unwrap()).unwrap(); } else { write!(socket, "{}", str::from_utf8(buf.as_slice()).unwrap()).unwrap(); } } } } } use stm32h7xx_hal::gpio::{ gpioa::{PA1, PA2, PA7}, gpiob::{PB13}, gpioc::{PC1, PC4, PC5}, gpiog::{PG11, PG13}, Speed::VeryHigh, }; /* * Migrated ethernet setup pins */ pub fn setup_ethernet_pins( pa1: PA1, pa2: PA2, pc1: PC1, pa7: PA7, pc4: PC4, pc5: PC5, pg11: PG11, pg13: PG13, pb13: PB13 ) { pa1.into_alternate_af11().set_speed(VeryHigh); pa2.into_alternate_af11().set_speed(VeryHigh); pc1.into_alternate_af11().set_speed(VeryHigh); pa7.into_alternate_af11().set_speed(VeryHigh); pc4.into_alternate_af11().set_speed(VeryHigh); pc5.into_alternate_af11().set_speed(VeryHigh); pg11.into_alternate_af11().set_speed(VeryHigh); pg13.into_alternate_af11().set_speed(VeryHigh); pb13.into_alternate_af11().set_speed(VeryHigh); } #[interrupt] fn ETH() { unsafe { ethernet::interrupt_handler() } } #[exception] fn SysTick() { TIME.fetch_add(1, Ordering::Relaxed); } #[exception] fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! { panic!("HardFault at {:#?}", ef); } #[exception] fn DefaultHandler(irqn: i16) { panic!("Unhandled exception (IRQn = {})", irqn); }