From 3b83b6560f5928505a3e9bc53ad03f8c1bb56f2c Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 2 Sep 2020 11:00:04 +0800 Subject: [PATCH] tcp_client: init --- .cargo/config | 2 +- Cargo.toml | 6 + examples/tcp_client.rs | 261 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 examples/tcp_client.rs diff --git a/.cargo/config b/.cargo/config index 86b3292..c0ce242 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,5 +1,5 @@ [target.thumbv7em-none-eabihf] -runner = "gdb -q -x gdb_config/openocd.gdb" +runner = "gdb -q -x gdb_config/fpga_config.gdb" rustflags = [ "-C", "link-arg=-Tlink.x", ] diff --git a/Cargo.toml b/Cargo.toml index 38d9e78..48beb79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ lexical-core = { version="0.7.1", features=["radix"], default-features=false } libm = "0.2.0" embedded-nal = "0.1.0" minimq = "0.1.0" +enum-iterator = "0.6.0" +heapless = "0.5.5" +generic-array = "0.14.3" # Logging and Panicking panic-itm = "0.4.1" @@ -33,6 +36,9 @@ name = "ethernet" [[example]] name = "fpga_config" +[[example]] +name = "tcp_client" + # Uncomment for the allocator example. # alloc-cortex-m = "0.3.5" diff --git a/examples/tcp_client.rs b/examples/tcp_client.rs new file mode 100644 index 0000000..c6b07b1 --- /dev/null +++ b/examples/tcp_client.rs @@ -0,0 +1,261 @@ +#![no_std] +#![no_main] + +use smoltcp as net; +use stm32h7_ethernet as ethernet; +use stm32h7xx_hal::{gpio::Speed, prelude::*, spi, pac}; +use embedded_hal::{blocking::spi::Transfer}; + +use heapless::{consts, String}; + +use cortex_m; +use cortex_m_rt::{ + entry, + exception, +}; +use cortex_m_semihosting::hprintln; + +use panic_halt as _; + +use rtic::cyccnt::{Instant, U32Ext}; + +use minimq::{ + embedded_nal::{IpAddr, Ipv4Addr}, + MqttClient, QoS, +}; + +use firmware::nal_tcp_client::{NetworkStack, NetStorage, NetworkInterface}; +use firmware::{Urukul}; +use firmware::cpld::{CPLD}; + +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], +}; + +#[link_section = ".sram3.eth"] +static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new(); + +macro_rules! add_socket { + ($sockets:ident, $tx_storage:ident, $rx_storage:ident) => { + let mut $rx_storage = [0; 4096]; + let mut $tx_storage = [0; 4096]; + + let tcp_socket = { + let tx_buffer = net::socket::TcpSocketBuffer::new(&mut $tx_storage[..]); + let rx_buffer = net::socket::TcpSocketBuffer::new(&mut $rx_storage[..]); + + net::socket::TcpSocket::new(tx_buffer, rx_buffer) + }; + + let _handle = $sockets.add(tcp_socket); + }; +} + +pub type UrukulType = Urukul< + firmware::spi_slave::SPISlave< + 'static, + firmware::cpld::CPLD< + stm32h7xx_hal::spi::Spi, + stm32h7xx_hal::gpio::gpiob::PB12>, + stm32h7xx_hal::gpio::gpioa::PA15>, + stm32h7xx_hal::gpio::gpioc::PC7>, + stm32h7xx_hal::gpio::gpiob::PB15> + >, + stm32h7xx_hal::spi::Spi, + stm32h7xx_hal::gpio::gpiob::PB12>, + stm32h7xx_hal::gpio::gpioa::PA15>, + stm32h7xx_hal::gpio::gpioc::PC7>, + stm32h7xx_hal::gpio::gpiob::PB15> + > +>; + +pub type CPLDType = CPLD< + stm32h7xx_hal::spi::Spi, + stm32h7xx_hal::gpio::gpiob::PB12>, + stm32h7xx_hal::gpio::gpioa::PA15>, + stm32h7xx_hal::gpio::gpioc::PC7>, + stm32h7xx_hal::gpio::gpiob::PB15> +>; + +pub type IoUpdateType = stm32h7xx_hal::gpio::gpiob::PB15>; +pub type SpiType = stm32h7xx_hal::spi::Spi; +pub type PartsType = firmware::spi_slave::Parts< + 'static, + firmware::cpld::CPLD< + stm32h7xx_hal::spi::Spi, + stm32h7xx_hal::gpio::gpiob::PB12>, + stm32h7xx_hal::gpio::gpioa::PA15>, + stm32h7xx_hal::gpio::gpioc::PC7>, + stm32h7xx_hal::gpio::gpiob::PB15> + >, + stm32h7xx_hal::spi::Spi, + stm32h7xx_hal::gpio::gpiob::PB12>, + stm32h7xx_hal::gpio::gpioa::PA15>, + stm32h7xx_hal::gpio::gpioc::PC7>, + stm32h7xx_hal::gpio::gpiob::PB15> +>; + +#[entry] +fn main() -> ! { + let mut cp = cortex_m::Peripherals::take().unwrap(); + let dp = pac::Peripherals::take().unwrap(); + + cp.DWT.enable_cycle_counter(); + + // Enable SRAM3 for the descriptor ring. + dp.RCC.ahb2enr.modify(|_, w| w.sram3en().set_bit()); + + let rcc = dp.RCC.constrain(); + let pwr = dp.PWR.constrain(); + let vos = pwr.freeze(); + + let ccdr = rcc + .sysclk(400.mhz()) + .hclk(200.mhz()) + .per_ck(100.mhz()) + .pll1_q_ck(48.mhz()) // for SPI + .pll2_p_ck(100.mhz()) + .pll2_q_ck(100.mhz()) + .freeze(vos, &dp.SYSCFG); + + 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); + + // Configure ethernet IO + { + let _rmii_refclk = gpioa.pa1.into_alternate_af11().set_speed(Speed::VeryHigh); + let _rmii_mdio = gpioa.pa2.into_alternate_af11().set_speed(Speed::VeryHigh); + let _rmii_mdc = gpioc.pc1.into_alternate_af11().set_speed(Speed::VeryHigh); + let _rmii_crs_dv = gpioa.pa7.into_alternate_af11().set_speed(Speed::VeryHigh); + let _rmii_rxd0 = gpioc.pc4.into_alternate_af11().set_speed(Speed::VeryHigh); + let _rmii_rxd1 = gpioc.pc5.into_alternate_af11().set_speed(Speed::VeryHigh); + let _rmii_tx_en = gpiog.pg11.into_alternate_af11().set_speed(Speed::VeryHigh); + let _rmii_txd0 = gpiog.pg13.into_alternate_af11().set_speed(Speed::VeryHigh); + let _rmii_txd1 = gpiob.pb13.into_alternate_af11().set_speed(Speed::VeryHigh); + } + + // Configure ethernet + let mut net_interface = { + let mac_addr = net::wire::EthernetAddress([0xAC, 0x6F, 0x7A, 0xDE, 0xD6, 0xC8]); + let (eth_dma, _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() } + + let store = unsafe { &mut NET_STORE }; + + store.ip_addrs[0] = net::wire::IpCidr::new(net::wire::IpAddress::v4(192, 168, 1, 200), 24); + + let neighbor_cache = net::iface::NeighborCache::new(&mut store.neighbor_cache[..]); + + net::iface::EthernetInterfaceBuilder::new(eth_dma) + .ethernet_addr(mac_addr) + .neighbor_cache(neighbor_cache) + .ip_addrs(&mut store.ip_addrs[..]) + .finalize() + }; + + /* + * Using SPI1, AF5 + * SCLK -> PA5 + * MOSI -> PB5 + * MISO -> PA6 + * CS -> 0: PB12, 1: PA15, 2: PC7 + * I/O_Update -> PB15 + */ + 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(), + ); + + 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 cpld = CPLD::new(spi, (cs0, cs1, cs2), io_update); + let parts = cpld.split(); + + let 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] + ); + + cp.SCB.enable_icache(); + + let mut time: u32 = 0; + let mut next_ms = Instant::now(); + + next_ms += 400_00.cycles(); + + let mut socket_set_entries: [_; 8] = Default::default(); + let mut sockets = net::socket::SocketSet::new(&mut socket_set_entries[..]); + add_socket!(sockets, rx_storage, tx_storage); + + let tcp_stack = NetworkStack::new(&mut net_interface, sockets); + let mut client = MqttClient::::new( + IpAddr::V4(Ipv4Addr::new(192, 168, 1, 125)), + "nucleo", + tcp_stack, + ) + .unwrap(); + + loop { + let tick = Instant::now() > next_ms; + + if tick { + next_ms += 400_000.cycles(); + time += 1; + } + + if tick && (time % 1000) == 0 { + client + .publish("nucleo", "Hello, World!".as_bytes(), QoS::AtMostOnce, &[]) + .unwrap(); + } + + client + .poll(|_client, topic, message, _properties| match topic { + _ => hprintln!("On '{:?}', received: {:?}", topic, message).unwrap(), + }) + .unwrap(); + + // Update the TCP stack. + let sleep = client.network_stack.update(time); + if sleep { + //cortex_m::asm::wfi(); + cortex_m::asm::nop(); + } + + match client.is_connected() { + true => hprintln!("Connected"), + false => hprintln!("No Connection"), + }.unwrap(); + } +} \ No newline at end of file