#![no_main] #![no_std] use core::sync::atomic::{AtomicU32, Ordering}; // extern crate cortex_m; use panic_semihosting as _; use cortex_m; use cortex_m::asm::nop; use cortex_m_rt::{ entry, exception, }; use cortex_m_semihosting::hprintln; extern crate smoltcp; // Ethernet crate for STM32H7 has been merged into HAL in the latest commit extern crate stm32h7_ethernet as 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 libm::round; use core::{ str, fmt::Write }; use core::mem::uninitialized; 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 embedded_nal::TcpStack; use firmware; use firmware::{ attenuator::Attenuator, config_register::{ ConfigRegister, CFGMask, StatusMask, }, dds::{ DDS, DDSCFRMask, }, cpld::{ CPLD, }, Urukul, }; use scpi::prelude::*; /// 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() -> ! { 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 .sys_ck(200.mhz()) .hclk(200.mhz()) .pll1_r_ck(100.mhz()) // for TRACECK .pll1_q_ck(48.mhz()) // for SPI .freeze(vos, &dp.SYSCFG); // Get the delay provider. let delay = cp.SYST.delay(ccdr.clocks); // Initialise system... cp.SCB.invalidate_icache(); cp.SCB.enable_icache(); // TODO: ETH DMA coherence issues // cp.SCB.enable_dcache(&mut cp.CPUID); 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); // let mut link_led = gpiob.pb0.into_push_pull_output(); // LED1, green // let mut status_led = gpioe.pe1.into_push_pull_output(); // LD2, yellow // let mut listen_led = gpiob.pb14.into_push_pull_output(); // LD3, red // link_led.set_low().ok(); // status_led.set_low().ok(); // listen_led.set_low().ok(); // Setup CDONE for checking let fpga_cdone = gpiod.pd15.into_pull_up_input(); match fpga_cdone.is_high() { Ok(true) => hprintln!("FPGA is ready."), Ok(_) => hprintln!("FPGA is in reset state."), Err(_) => hprintln!("Error: Cannot read C_DONE"), }.unwrap(); // 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::ethernet_init( 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[..]); // Routes let default_v4_gw = Ipv4Address::new(192, 168, 1, 1); let mut routes_storage = [None; 8]; let mut routes = Routes::new(&mut routes_storage[..]); routes.add_default_ipv4_route(default_v4_gw).unwrap(); // 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[..]) .routes(routes) .finalize(); // SCPI configs // 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 let server_socket = { static mut server_rx_storage :[u8; BUFFER_SIZE] = [0; BUFFER_SIZE]; static mut server_tx_storage :[u8; BUFFER_SIZE] = [0; BUFFER_SIZE]; let server_rx_buffer = TcpSocketBuffer::new( unsafe { &mut server_rx_storage[..] } ); let server_tx_buffer = TcpSocketBuffer::new( unsafe { &mut server_tx_storage[..] } ); TcpSocket::new(server_rx_buffer, server_tx_buffer) }; // Setup a silent socket let client_socket = { static mut client_rx_storage :[u8; BUFFER_SIZE] = [0; BUFFER_SIZE]; static mut client_tx_storage :[u8; BUFFER_SIZE] = [0; BUFFER_SIZE]; let client_rx_buffer = TcpSocketBuffer::new( unsafe { &mut client_rx_storage[..] } ); let client_tx_buffer = TcpSocketBuffer::new( unsafe { &mut client_tx_storage[..] } ); TcpSocket::new(client_rx_buffer, client_tx_buffer) }; // Socket storage let mut sockets_storage: [_; 2] = Default::default(); let mut socket_set = SocketSet::new(&mut sockets_storage[..]); let server_handle = socket_set.add(server_socket); let client_handle = socket_set.add(client_socket); loop { let _time = TIME.load(Ordering::Relaxed); match iface.poll(&mut socket_set, Instant::from_millis(_time as i64)) { Ok(_) => { // hprintln!("Ethernet up").unwrap(); }, Err(e) => { hprintln!("Ethernet down!").unwrap(); }, }; // Conenct to TCP server through port 49500 { let mut socket = socket_set.get::(server_handle); if !socket.is_active() && !socket.is_listening(){ socket.listen(7777).unwrap(); hprintln!("Server listening").unwrap(); } // hprintln!("listener state :{}", socket.state()).unwrap(); if socket.can_recv() { hprintln!("{:?}", str::from_utf8(socket.recv(|data| { (data.len(), data) }).unwrap()).unwrap()).unwrap(); } } { let mut socket = socket_set.get::(client_handle); if !socket.is_open() || !socket.can_send() { socket.abort(); socket.close(); // hprintln!("reset state: {}", socket.state()).unwrap(); socket.connect((IpAddress::v4(192, 168, 1, 200), 1883), (IpAddress::Unspecified, 45000)).unwrap(); // hprintln!("post connect state: {}", socket.state()).unwrap(); } // hprintln!("client state: {}", socket.state()).unwrap(); if socket.can_send() { socket.send_slice(b"regards from socket").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); }