Use RTIC framework on the examples
* tcp_stm32f407 no longer obtains IP address from environment variables.
This commit is contained in:
parent
25e682763c
commit
362cf3c411
|
@ -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"
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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 <ip> <prefix>
|
||||
[nix-shell]$ tcp_stm32f407
|
||||
```
|
||||
|
||||
4. To test the TCP ports, switch to the bottom-right pane (with <kbd>Ctrl</kbd>+<kbd>B</kbd>, 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:
|
||||
```
|
||||
|
|
|
@ -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<RefCell<u32>> = Mutex::new(RefCell::new(0));
|
||||
type BoosterSpiEth = enc424j600::SpiEth<
|
||||
Spi<SPI1, (PA5<Alternate<AF5>>, PA6<Alternate<AF5>>, PA7<Alternate<AF5>>)>,
|
||||
PA4<Output<PushPull>>>;
|
||||
|
||||
/// 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<BoosterSpiEth>>,
|
||||
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::<TcpSocket>(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::<TcpSocket>(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::<TcpSocket>(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::<TcpSocket>(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();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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<SPI1, (PA5<Alternate<AF5>>, PA6<Alternate<AF5>>, PA7<Alternate<AF5>>)>,
|
||||
PA4<Output<PushPull>>>;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
13
shell.nix
13
shell.nix
|
@ -22,9 +22,8 @@ let
|
|||
echo "[Examples]"
|
||||
echo " tx_stm32f407"
|
||||
echo " - Run tx_stm32f407 example."
|
||||
echo " tcp_stm32f407 <ip> <pref>"
|
||||
echo " - Run tcp_stm32f407 example with the IPv4"
|
||||
echo " address <ip> (dot-separated) and prefix length <pref>."
|
||||
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 <ip> or <pref> 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
|
||||
|
|
Loading…
Reference in New Issue