From 362cf3c4114d75b7514770cf6d6de059fe06db47 Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Tue, 29 Dec 2020 11:47:02 +0800 Subject: [PATCH] Use RTIC framework on the examples * tcp_stm32f407 no longer obtains IP address from environment variables. --- Cargo.lock | 93 +++++++++ Cargo.toml | 1 + README.md | 6 +- examples/tcp_stm32f407.rs | 429 +++++++++++++++++++------------------- examples/tx_stm32f407.rs | 230 +++++++++++--------- shell.nix | 13 +- 6 files changed, 451 insertions(+), 321 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b9d77d..8cb42d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + [[package]] name = "bare-metal" version = "0.2.5" @@ -106,6 +112,32 @@ dependencies = [ "syn", ] +[[package]] +name = "cortex-m-rtic" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30efcb6b7920d9016182c485687f0012487032a14c415d2fce6e9862ef8260e" +dependencies = [ + "cortex-m 0.6.2", + "cortex-m-rt", + "cortex-m-rtic-macros", + "heapless", + "rtic-core", + "version_check", +] + +[[package]] +name = "cortex-m-rtic-macros" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1a6a4c9550373038c0e21a78d44d529bd697c25bbf6b8004bddc6e63b119c7" +dependencies = [ + "proc-macro2", + "quote", + "rtic-syntax", + "syn", +] + [[package]] name = "embedded-hal" version = "0.2.4" @@ -123,6 +155,7 @@ dependencies = [ "aligned 0.3.2", "cortex-m 0.5.10", "cortex-m-rt", + "cortex-m-rtic", "embedded-hal", "log", "panic-itm", @@ -149,6 +182,43 @@ dependencies = [ "typenum", ] +[[package]] +name = "hash32" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + +[[package]] +name = "heapless" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74911a68a1658cfcfb61bc0ccfbd536e3b6e906f8c2f7883ee50157e3e2184f1" +dependencies = [ + "as-slice", + "generic-array 0.13.2", + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "indexmap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "log" version = "0.4.8" @@ -209,6 +279,23 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +[[package]] +name = "rtic-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd58a6949de8ff797a346a28d9f13f7b8f54fa61bb5e3cb0985a4efb497a5ef" + +[[package]] +name = "rtic-syntax" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8152fcaa845720d61e6cc570548b89144c2c307f18a480bbd97e55e9f6eeff04" +dependencies = [ + "indexmap", + "proc-macro2", + "syn", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -308,6 +395,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c" +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + [[package]] name = "void" version = "1.0.2" diff --git a/Cargo.toml b/Cargo.toml index bd68952..b0680ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ embedded-hal = "0.2" stm32f4xx-hal = { version = "0.8" , optional = true } smoltcp = { version = "0.6.0", default-features = false, features = ["proto-ipv4", "proto-ipv6", "socket-icmp", "socket-udp", "socket-tcp", "log", "verbose", "ethernet"], optional = true } log = "0.4" +cortex-m-rtic = "0.5.3" [features] smoltcp-phy = ["smoltcp"] diff --git a/README.md b/README.md index 169fc3a..c5ae652 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,9 @@ This program demonstrates the TCP connectivity using **smoltcp** on an STM32F407 [nix-shell]$ run-tmux-env ``` -3. When the `tmux` session is ready, on the top-right pane, compile and run the example program. Choose your own IPv4 address and prefix length: +3. When the `tmux` session is ready, on the top-right pane, compile and run the example program. The default IP address is 192.168.1.77, which can be edited in the source file `examples/tcp_stm32f407.rs`. ```sh - [nix-shell]$ tcp_stm32f407 + [nix-shell]$ tcp_stm32f407 ``` 4. To test the TCP ports, switch to the bottom-right pane (with Ctrl+B, followed by an arrow key) and use utilities like NetCat (`nc`): @@ -97,7 +97,7 @@ This program demonstrates the TCP connectivity using **smoltcp** on an STM32F407 #### Expected Output -(Note: the IP address, MAC address and timestamps shown below are examples only.) +(Note: the MAC address and timestamps shown below are examples only.) ITM output at the initial state: ``` diff --git a/examples/tcp_stm32f407.rs b/examples/tcp_stm32f407.rs index be37669..1b81cad 100644 --- a/examples/tcp_stm32f407.rs +++ b/examples/tcp_stm32f407.rs @@ -1,257 +1,266 @@ #![no_std] #![no_main] -use core::env; - extern crate panic_itm; use cortex_m::{iprintln, iprint}; -use cortex_m_rt::entry; -use embedded_hal::digital::v2::OutputPin; -use embedded_hal::blocking::delay::DelayMs; +use embedded_hal::{ + digital::v2::OutputPin, + blocking::delay::DelayMs +}; use stm32f4xx_hal::{ rcc::RccExt, gpio::GpioExt, time::U32Ext, - stm32::{CorePeripherals, Peripherals}, + stm32::ITM, delay::Delay, spi::Spi, time::Hertz }; use enc424j600; -use enc424j600::EthController; -use enc424j600::smoltcp_phy; +use enc424j600::{smoltcp_phy, EthController}; use smoltcp::wire::{ - EthernetAddress, IpAddress, IpCidr + EthernetAddress, IpAddress, IpCidr, Ipv6Cidr }; -use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder}; +use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, EthernetInterface}; use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer}; -use smoltcp::time::{Instant, Duration}; use core::str; use core::fmt::Write; -use core::cell::RefCell; -use cortex_m::interrupt::Mutex; -use cortex_m_rt::exception; +use rtic::cyccnt::Instant; + +/// use stm32f4xx_hal::{ - rcc::Clocks, - time::MilliSeconds, - timer::{Timer, Event as TimerEvent}, - stm32::SYST + stm32::SPI1, + gpio::{ + gpioa::{PA5, PA6, PA7, PA4}, + Alternate, AF5, Output, PushPull + } }; -/// Rate in Hz -const TIMER_RATE: u32 = 20; -/// Interval duration in milliseconds -const TIMER_DELTA: u32 = 1000 / TIMER_RATE; -/// Elapsed time in milliseconds -static TIMER_MS: Mutex> = Mutex::new(RefCell::new(0)); +type BoosterSpiEth = enc424j600::SpiEth< + Spi>, PA6>, PA7>)>, + PA4>>; -/// Setup SysTick exception -fn timer_setup(syst: SYST, clocks: Clocks) { - let mut timer = Timer::syst(syst, TIMER_RATE.hz(), clocks); - timer.listen(TimerEvent::TimeOut); +pub struct NetStorage { + ip_addrs: [IpCidr; 1], + neighbor_cache: [Option<(IpAddress, smoltcp::iface::Neighbor)>; 8], } -/// SysTick exception (Timer) -#[exception] -fn SysTick() { - cortex_m::interrupt::free(|cs| { - *TIMER_MS.borrow(cs) - .borrow_mut() += TIMER_DELTA; - }); -} +static mut NET_STORE: NetStorage = NetStorage { + // Placeholder for the real IP address, which is initialized at runtime. + ip_addrs: [IpCidr::Ipv6( + Ipv6Cidr::SOLICITED_NODE_PREFIX, + )], + neighbor_cache: [None; 8], +}; -/// Obtain current time in milliseconds -pub fn timer_now() -> MilliSeconds { - let ms = cortex_m::interrupt::free(|cs| { - *TIMER_MS.borrow(cs) - .borrow() - }); - ms.ms() -} +#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] +const APP: () = { + struct Resources { + eth_iface: EthernetInterface< + 'static, + 'static, + 'static, + smoltcp_phy::SmoltcpDevice>, + itm: ITM + } -#[entry] -fn main() -> ! { - let mut cp = CorePeripherals::take().unwrap(); - cp.SCB.enable_icache(); - cp.SCB.enable_dcache(&mut cp.CPUID); + #[init()] + fn init(mut c: init::Context) -> init::LateResources { + c.core.SCB.enable_icache(); + c.core.SCB.enable_dcache(&mut c.core.CPUID); - let dp = Peripherals::take().unwrap(); - let clocks = dp.RCC.constrain() - .cfgr - .sysclk(168.mhz()) - .hclk(168.mhz()) - .pclk1(32.mhz()) - .pclk2(64.mhz()) - .freeze(); + // Enable monotonic timer CYCCNT + c.core.DWT.enable_cycle_counter(); + c.core.DCB.enable_trace(); - // Init ITM & use Stimulus Port 0 - let mut itm = cp.ITM; - let stim0 = &mut itm.stim[0]; + let clocks = c.device.RCC.constrain() + .cfgr + .sysclk(168.mhz()) + .hclk(168.mhz()) + .pclk1(42.mhz()) + .require_pll48clk() + .freeze(); + let mut delay = Delay::new(c.core.SYST, clocks); - iprintln!(stim0, - "Eth TCP Server on STM32-F407 via NIC100/ENC424J600"); + // Init ITM + let mut itm = c.core.ITM; + let stim0 = &mut itm.stim[0]; - // Get IP address from args - let arg_ip_raw = env!("ENC424J600_TCP_IP"); - let mut arg_ip_str = arg_ip_raw.split('.'); - let mut arg_ip: [u8; 4] = [0; 4]; - for i in 0..4 { - match arg_ip_str.next() { - Some(x) => { - match x.parse() { - Ok(x_) => { arg_ip[i] = x_ }, - Err(_) => { panic!("IPv4 address invalid!") } + iprintln!(stim0, + "Eth TCP Server on STM32-F407 via NIC100/ENC424J600"); + + // NIC100 / ENC424J600 Set-up + let spi1 = c.device.SPI1; + let gpioa = c.device.GPIOA.split(); + // Mapping: see Table 9, STM32F407ZG Manual + let spi1_sck = gpioa.pa5.into_alternate_af5(); + let spi1_miso = gpioa.pa6.into_alternate_af5(); + let spi1_mosi = gpioa.pa7.into_alternate_af5(); + let spi1_nss = gpioa.pa4.into_push_pull_output(); + // Map SPISEL: see Table 1, NIC100 Manual + let mut spisel = gpioa.pa1.into_push_pull_output(); + spisel.set_high().unwrap(); + delay.delay_ms(1_u32); + spisel.set_low().unwrap(); + + // Create SPI1 for HAL + let eth_iface = { + let mut spi_eth = { + let spi_eth_port = Spi::spi1( + spi1, (spi1_sck, spi1_miso, spi1_mosi), + enc424j600::spi::interfaces::SPI_MODE, + Hertz(enc424j600::spi::interfaces::SPI_CLOCK_FREQ), + clocks); + enc424j600::SpiEth::new(spi_eth_port, spi1_nss) + }; + + // Init controller + match spi_eth.init_dev(&mut delay) { + Ok(_) => { + iprintln!(stim0, "Initializing Ethernet...") } - }, - None => { panic!("IPv4 address invalid!") } - } - } - // Get IP prefix length from args - let arg_ip_pref_raw = env!("ENC424J600_TCP_PREF"); - let mut arg_ip_pref: u8 = 0; - match arg_ip_pref_raw.parse() { - Ok(x) => { arg_ip_pref = x }, - Err(_) => { panic!("IP prefix length invalid!") } - } + Err(_) => { + panic!("Ethernet initialization failed!") + } + } - // NIC100 / ENC424J600 Set-up - let spi1 = dp.SPI1; - let gpioa = dp.GPIOA.split(); - let mut delay = Delay::new(cp.SYST, clocks); - // Mapping: see Table 9, STM32F407ZG Manual - let spi1_sck = gpioa.pa5.into_alternate_af5(); - let spi1_miso = gpioa.pa6.into_alternate_af5(); - let spi1_mosi = gpioa.pa7.into_alternate_af5(); - let spi1_nss = gpioa.pa4.into_push_pull_output(); - // Map SPISEL: see Table 1, NIC100 Manual - let mut spisel = gpioa.pa1.into_push_pull_output(); - spisel.set_high().unwrap(); - delay.delay_ms(1_u32); - spisel.set_low().unwrap(); - // Create SPI1 for HAL - let spi_eth_port = Spi::spi1( - spi1, (spi1_sck, spi1_miso, spi1_mosi), - enc424j600::spi::interfaces::SPI_MODE, - Hertz(enc424j600::spi::interfaces::SPI_CLOCK_FREQ), - clocks); - let mut spi_eth = enc424j600::SpiEth::new(spi_eth_port, spi1_nss); - // Init - match spi_eth.init_dev(&mut delay) { - Ok(_) => { - iprintln!(stim0, "Ethernet initialized") - } - Err(_) => { - panic!("Ethernet initialization failed!") - } - } + // Read MAC + let mut eth_mac_addr: [u8; 6] = [0; 6]; + spi_eth.read_from_mac(&mut eth_mac_addr); + for i in 0..6 { + let byte = eth_mac_addr[i]; + match i { + 0 => iprint!(stim0, "MAC Address = {:02x}-", byte), + 1..=4 => iprint!(stim0, "{:02x}-", byte), + 5 => iprint!(stim0, "{:02x}\n", byte), + _ => () + }; + } - // Setup SysTick - // Reference to stm32-eth:examples/ip.rs - timer_setup(delay.free(), clocks); - iprintln!(stim0, "Timer initialized"); + // Init Rx/Tx buffers + spi_eth.init_rxbuf(); + spi_eth.init_txbuf(); + iprintln!(stim0, "Ethernet controller initialized"); - // Read MAC - let mut eth_mac_addr: [u8; 6] = [0; 6]; - spi_eth.read_from_mac(&mut eth_mac_addr); - for i in 0..6 { - let byte = eth_mac_addr[i]; - match i { - 0 => iprint!(stim0, "MAC Address = {:02x}-", byte), - 1..=4 => iprint!(stim0, "{:02x}-", byte), - 5 => iprint!(stim0, "{:02x}\n", byte), - _ => () + // Init smoltcp interface + let eth_iface = { + let device = smoltcp_phy::SmoltcpDevice::new(spi_eth); + + let store = unsafe { &mut NET_STORE }; + store.ip_addrs[0] = IpCidr::new(IpAddress::v4(192, 168, 1, 77), 24); + let neighbor_cache = NeighborCache::new(&mut store.neighbor_cache[..]); + + EthernetInterfaceBuilder::new(device) + .ethernet_addr(EthernetAddress(eth_mac_addr)) + .neighbor_cache(neighbor_cache) + .ip_addrs(&mut store.ip_addrs[..]) + .finalize() + }; + iprintln!(stim0, "Ethernet interface initialized"); + + eth_iface }; + + init::LateResources { + eth_iface, + itm + } } - // Init Rx/Tx buffers - spi_eth.init_rxbuf(); - spi_eth.init_txbuf(); + #[idle(resources=[eth_iface, itm])] + fn idle(c: idle::Context) -> ! { + let stim0 = &mut c.resources.itm.stim[0]; + let iface = c.resources.eth_iface; - // Copied / modified from smoltcp: - // examples/loopback.rs, examples/multicast.rs - let device = smoltcp_phy::SmoltcpDevice::new(spi_eth); - let mut neighbor_cache_entries = [None; 16]; - let neighbor_cache = NeighborCache::new(&mut neighbor_cache_entries[..]); - let ip_addr = IpCidr::new(IpAddress::v4( - arg_ip[0], arg_ip[1], arg_ip[2], arg_ip[3]), arg_ip_pref); - let mut ip_addrs = [ip_addr]; - let mut iface = EthernetInterfaceBuilder::new(device) - .ethernet_addr(EthernetAddress(eth_mac_addr)) - .neighbor_cache(neighbor_cache) - .ip_addrs(&mut ip_addrs[..]) - .finalize(); - - // Copied / modified from smoltcp: - // examples/loopback.rs - let echo_socket = { - static mut TCP_SERVER_RX_DATA: [u8; 1024] = [0; 1024]; - static mut TCP_SERVER_TX_DATA: [u8; 1024] = [0; 1024]; - let tcp_rx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_RX_DATA[..] }); - let tcp_tx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_TX_DATA[..] }); - TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer) - }; - let greet_socket = { - static mut TCP_SERVER_RX_DATA: [u8; 256] = [0; 256]; - static mut TCP_SERVER_TX_DATA: [u8; 256] = [0; 256]; - let tcp_rx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_RX_DATA[..] }); - let tcp_tx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_TX_DATA[..] }); - TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer) - }; - let mut socket_set_entries = [None, None]; - let mut socket_set = SocketSet::new(&mut socket_set_entries[..]); - let echo_handle = socket_set.add(echo_socket); - let greet_handle = socket_set.add(greet_socket); - iprintln!(stim0, "TCP sockets will listen at {}", ip_addr); - - // Copied / modified from: - // smoltcp:examples/loopback.rs, examples/server.rs; - // stm32-eth:examples/ip.rs, - // git.m-labs.hk/M-Labs/tnetplug - loop { - let now = timer_now().0; - let instant = Instant::from_millis(now as i64); - match iface.poll(&mut socket_set, instant) { - Ok(_) => { - }, - Err(e) => { - iprintln!(stim0, "[{}] Poll error: {:?}", instant, e) - } - } - // Control the "echoing" socket (:1234) + // Copied / modified from smoltcp: + // examples/loopback.rs + let echo_socket = { + static mut TCP_SERVER_RX_DATA: [u8; 1024] = [0; 1024]; + static mut TCP_SERVER_TX_DATA: [u8; 1024] = [0; 1024]; + let tcp_rx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_RX_DATA[..] }); + let tcp_tx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_TX_DATA[..] }); + TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer) + }; + let greet_socket = { + static mut TCP_SERVER_RX_DATA: [u8; 256] = [0; 256]; + static mut TCP_SERVER_TX_DATA: [u8; 256] = [0; 256]; + let tcp_rx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_RX_DATA[..] }); + let tcp_tx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_TX_DATA[..] }); + TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer) + }; + let mut socket_set_entries = [None, None]; + let mut socket_set = SocketSet::new(&mut socket_set_entries[..]); + let echo_handle = socket_set.add(echo_socket); + let greet_handle = socket_set.add(greet_socket); { - let mut socket = socket_set.get::(echo_handle); - if !socket.is_open() { - iprintln!(stim0, - "[{}] Listening to port 1234 for echoing, time-out in 10s", instant); - socket.listen(1234).unwrap(); - socket.set_timeout(Some(Duration::from_millis(10000))); - } - if socket.can_recv() { - iprintln!(stim0, - "[{}] Received packet: {:?}", instant, socket.recv(|buffer| { - (buffer.len(), str::from_utf8(buffer).unwrap()) - })); - } + let store = unsafe { &mut NET_STORE }; + iprintln!(stim0, + "TCP sockets will listen at {}", store.ip_addrs[0].address()); } - // Control the "greeting" socket (:4321) - { - let mut socket = socket_set.get::(greet_handle); - if !socket.is_open() { - iprintln!(stim0, - "[{}] Listening to port 4321 for greeting, \ - please connect to the port", instant); - socket.listen(4321).unwrap(); - } - if socket.can_send() { - let greeting = "Welcome to the server demo for STM32-F407!"; - write!(socket, "{}\n", greeting).unwrap(); - iprintln!(stim0, - "[{}] Greeting sent, socket closed", instant); - socket.close(); + // Copied / modified from: + // smoltcp:examples/loopback.rs, examples/server.rs; + // stm32-eth:examples/ip.rs, + // git.m-labs.hk/M-Labs/tnetplug + let mut time = 0u32; + let mut next_ms = Instant::now(); + use rtic::cyccnt::U32Ext; + next_ms += 168_000_u32.cycles(); + loop { + // Poll + let tick = Instant::now() > next_ms; + if tick { + next_ms += 168_000_u32.cycles(); + time += 1; + } + let instant = smoltcp::time::Instant::from_millis(time as i64); + match iface.poll(&mut socket_set, instant) { + Ok(_) => { + }, + Err(e) => { + iprintln!(stim0, "[{}] Poll error: {:?}", instant, e) + } + } + // Control the "echoing" socket (:1234) + { + let mut socket = socket_set.get::(echo_handle); + if !socket.is_open() { + iprintln!(stim0, + "[{}] Listening to port 1234 for echoing, time-out in 10s", instant); + socket.listen(1234).unwrap(); + socket.set_timeout(Some(smoltcp::time::Duration::from_millis(10000))); + } + if socket.can_recv() { + iprintln!(stim0, + "[{}] Received packet: {:?}", instant, socket.recv(|buffer| { + (buffer.len(), str::from_utf8(buffer).unwrap()) + })); + } + } + // Control the "greeting" socket (:4321) + { + let mut socket = socket_set.get::(greet_handle); + if !socket.is_open() { + iprintln!(stim0, + "[{}] Listening to port 4321 for greeting, \ + please connect to the port", instant); + socket.listen(4321).unwrap(); + } + + if socket.can_send() { + let greeting = "Welcome to the server demo for STM32-F407!"; + write!(socket, "{}\n", greeting).unwrap(); + iprintln!(stim0, + "[{}] Greeting sent, socket closed", instant); + socket.close(); + } } } } -} + + extern "C" { + fn EXTI0(); + } +}; diff --git a/examples/tx_stm32f407.rs b/examples/tx_stm32f407.rs index 84b5e84..4dd10ac 100644 --- a/examples/tx_stm32f407.rs +++ b/examples/tx_stm32f407.rs @@ -4,14 +4,15 @@ extern crate panic_itm; use cortex_m::{iprintln, iprint}; -use cortex_m_rt::entry; -use embedded_hal::digital::v2::OutputPin; -use embedded_hal::blocking::delay::DelayMs; +use embedded_hal::{ + digital::v2::OutputPin, + blocking::delay::DelayMs +}; use stm32f4xx_hal::{ rcc::RccExt, gpio::GpioExt, time::U32Ext, - stm32::{CorePeripherals, Peripherals}, + stm32::ITM, delay::Delay, spi::Spi, time::Hertz @@ -19,106 +20,141 @@ use stm32f4xx_hal::{ use enc424j600; use enc424j600::EthController; -#[entry] -fn main() -> ! { - let mut cp = CorePeripherals::take().unwrap(); - cp.SCB.enable_icache(); - cp.SCB.enable_dcache(&mut cp.CPUID); +/// +use stm32f4xx_hal::{ + stm32::SPI1, + gpio::{ + gpioa::{PA5, PA6, PA7, PA4}, + Alternate, AF5, Output, PushPull + }, +}; +type BoosterSpiEth = enc424j600::SpiEth< + Spi>, PA6>, PA7>)>, + PA4>>; - let dp = Peripherals::take().unwrap(); - let clocks = dp.RCC.constrain() - .cfgr - .sysclk(168.mhz()) - .hclk(168.mhz()) - .pclk1(32.mhz()) - .pclk2(64.mhz()) - .freeze(); - let mut delay = Delay::new(cp.SYST, clocks); - - // Init ITM & use Stimulus Port 0 - let mut itm = cp.ITM; - let stim0 = &mut itm.stim[0]; - - iprintln!(stim0, - "Eth TX Pinging on STM32-F407 via NIC100/ENC424J600"); - - // NIC100 / ENC424J600 Set-up - let spi1 = dp.SPI1; - let gpioa = dp.GPIOA.split(); - // Mapping: see Table 9, STM32F407ZG Manual - let spi1_sck = gpioa.pa5.into_alternate_af5(); - let spi1_miso = gpioa.pa6.into_alternate_af5(); - let spi1_mosi = gpioa.pa7.into_alternate_af5(); - let spi1_nss = gpioa.pa4.into_push_pull_output(); - // Map SPISEL: see Table 1, NIC100 Manual - let mut spisel = gpioa.pa1.into_push_pull_output(); - spisel.set_high().unwrap(); - delay.delay_ms(1_u32); - spisel.set_low().unwrap(); - // Create SPI1 for HAL - let spi_eth_port = Spi::spi1( - spi1, (spi1_sck, spi1_miso, spi1_mosi), - enc424j600::spi::interfaces::SPI_MODE, - Hertz(enc424j600::spi::interfaces::SPI_CLOCK_FREQ), - clocks); - let mut spi_eth = enc424j600::SpiEth::new(spi_eth_port, spi1_nss); - // Init - match spi_eth.init_dev(&mut delay) { - Ok(_) => { - iprintln!(stim0, "Ethernet initialized") - } - Err(_) => { - panic!("Ethernet initialization failed!") - } +#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] +const APP: () = { + struct Resources { + spi_eth: BoosterSpiEth, + delay: Delay, + itm: ITM, } - // Read MAC - let mut eth_mac_addr: [u8; 6] = [0; 6]; - spi_eth.read_from_mac(&mut eth_mac_addr); - for i in 0..6 { - let byte = eth_mac_addr[i]; - match i { - 0 => iprint!(stim0, "MAC Address = {:02x}-", byte), - 1..=4 => iprint!(stim0, "{:02x}-", byte), - 5 => iprint!(stim0, "{:02x}\n", byte), - _ => () + #[init()] + fn init(mut c: init::Context) -> init::LateResources { + c.core.SCB.enable_icache(); + c.core.SCB.enable_dcache(&mut c.core.CPUID); + + let clocks = c.device.RCC.constrain() + .cfgr + .sysclk(168.mhz()) + .hclk(168.mhz()) + //.pclk1(32.mhz()) + .pclk1(42.mhz()) + //.pclk2(64.mhz()) + .require_pll48clk() + .freeze(); + let mut delay = Delay::new(c.core.SYST, clocks); + + // Init ITM + let mut itm = c.core.ITM; + let stim0 = &mut itm.stim[0]; + iprintln!(stim0, + "Eth TX Pinging on STM32-F407 via NIC100/ENC424J600"); + + // NIC100 / ENC424J600 Set-up + let spi1 = c.device.SPI1; + let gpioa = c.device.GPIOA.split(); + // Mapping: see Table 9, STM32F407ZG Manual + let spi1_sck = gpioa.pa5.into_alternate_af5(); + let spi1_miso = gpioa.pa6.into_alternate_af5(); + let spi1_mosi = gpioa.pa7.into_alternate_af5(); + let spi1_nss = gpioa.pa4.into_push_pull_output(); + // Map SPISEL: see Table 1, NIC100 Manual + let mut spisel = gpioa.pa1.into_push_pull_output(); + spisel.set_high().unwrap(); + delay.delay_ms(1_u32); + spisel.set_low().unwrap(); + // Create SPI1 for HAL + let mut spi_eth = { + let spi_eth_port = Spi::spi1( + spi1, (spi1_sck, spi1_miso, spi1_mosi), + enc424j600::spi::interfaces::SPI_MODE, + Hertz(enc424j600::spi::interfaces::SPI_CLOCK_FREQ), + clocks); + enc424j600::SpiEth::new(spi_eth_port, spi1_nss) }; - } - // Init Rx/Tx buffers - spi_eth.init_rxbuf(); - spi_eth.init_txbuf(); - // Testing Eth TX - let eth_tx_dat: [u8; 64] = [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x60, - 0x6e, 0x44, 0x42, 0x95, 0x08, 0x06, 0x00, 0x01, - 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x08, 0x60, - 0x6e, 0x44, 0x42, 0x95, 0xc0, 0xa8, 0x01, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, - 0x01, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x69, 0xd0, 0x85, 0x9f - ]; - loop { - let mut eth_tx_packet = enc424j600::tx::TxPacket::new(); - eth_tx_packet.update_frame(ð_tx_dat, 64); - iprint!(stim0, - "Sending packet (len={:}): ", eth_tx_packet.get_frame_length()); - for i in 0..20 { - let byte = eth_tx_packet.get_frame_byte(i); + // Init + match spi_eth.init_dev(&mut delay) { + Ok(_) => { + iprintln!(stim0, "Initializing Ethernet...") + } + Err(_) => { + panic!("Ethernet initialization failed!") + } + } + + // Read MAC + let mut eth_mac_addr: [u8; 6] = [0; 6]; + spi_eth.read_from_mac(&mut eth_mac_addr); + for i in 0..6 { + let byte = eth_mac_addr[i]; match i { - 0 => iprint!(stim0, "dest={:02x}-", byte), - 6 => iprint!(stim0, "src={:02x}-", byte), - 12 => iprint!(stim0, "data={:02x}", byte), - 1..=4 | 7..=10 => iprint!(stim0, "{:02x}-", byte), - 13..=14 | 16..=18 => iprint!(stim0, "{:02x}", byte), - 5 | 11 | 15 => iprint!(stim0, "{:02x} ", byte), - 19 => iprint!(stim0, "{:02x} ...\n", byte), + 0 => iprint!(stim0, "MAC Address = {:02x}-", byte), + 1..=4 => iprint!(stim0, "{:02x}-", byte), + 5 => iprint!(stim0, "{:02x}\n", byte), _ => () }; } - spi_eth.send_raw_packet(ð_tx_packet); - iprintln!(stim0, "Packet sent"); - delay.delay_ms(100_u32); + + // Init Rx/Tx buffers + spi_eth.init_rxbuf(); + spi_eth.init_txbuf(); + iprintln!(stim0, "Ethernet controller initialized"); + + init::LateResources { + spi_eth, + delay, + itm, + } } -} + + #[idle(resources=[spi_eth, delay, itm])] + fn idle(c: idle::Context) -> ! { + let stim0 = &mut c.resources.itm.stim[0]; + // Testing Eth TX + let eth_tx_dat: [u8; 64] = [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x60, + 0x6e, 0x44, 0x42, 0x95, 0x08, 0x06, 0x00, 0x01, + 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x08, 0x60, + 0x6e, 0x44, 0x42, 0x95, 0xc0, 0xa8, 0x01, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, + 0x01, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x69, 0xd0, 0x85, 0x9f + ]; + loop { + let mut eth_tx_packet = enc424j600::tx::TxPacket::new(); + eth_tx_packet.update_frame(ð_tx_dat, 64); + iprint!(stim0, + "Sending packet (len={:}): ", eth_tx_packet.get_frame_length()); + for i in 0..20 { + let byte = eth_tx_packet.get_frame_byte(i); + match i { + 0 => iprint!(stim0, "dest={:02x}-", byte), + 6 => iprint!(stim0, "src={:02x}-", byte), + 12 => iprint!(stim0, "data={:02x}", byte), + 1..=4 | 7..=10 => iprint!(stim0, "{:02x}-", byte), + 13..=14 | 16..=18 => iprint!(stim0, "{:02x}", byte), + 5 | 11 | 15 => iprint!(stim0, "{:02x} ", byte), + 19 => iprint!(stim0, "{:02x} ...\n", byte), + _ => () + }; + } + c.resources.spi_eth.send_raw_packet(ð_tx_packet); + iprintln!(stim0, "Packet sent"); + c.resources.delay.delay_ms(100_u32); + } + } +}; diff --git a/shell.nix b/shell.nix index 377aec3..8f5b837 100644 --- a/shell.nix +++ b/shell.nix @@ -22,9 +22,8 @@ let echo "[Examples]" echo " tx_stm32f407" echo " - Run tx_stm32f407 example." - echo " tcp_stm32f407 " - echo " - Run tcp_stm32f407 example with the IPv4" - echo " address (dot-separated) and prefix length ." + echo " tcp_stm32f407" + echo " - Run tcp_stm32f407 example." echo "" echo "[Workspace]" echo " run-tmux-env" @@ -98,14 +97,6 @@ let cargo run --release --example=tx_stm32f407 --features=stm32f407 ''; exTcpStm32f407 = writeShellScriptBin "tcp_stm32f407" '' - if [[ $1 = "" ]] || [[ $2 = "" ]] - then - echo "Arguments or are missing." - exit - fi - touch ./examples/tcp_stm32f407.rs - export ENC424J600_TCP_IP=$1 - export ENC424J600_TCP_PREF=$2 cargo run --release --example=tcp_stm32f407 --features=stm32f407,smoltcp-phy-all ''; in