Use RTIC framework on the examples

* tcp_stm32f407 no longer obtains IP address from environment variables.
pull/3/head
Harry Ho 2020-12-29 11:47:02 +08:00
parent 25e682763c
commit 362cf3c411
6 changed files with 451 additions and 321 deletions

93
Cargo.lock generated
View File

@ -26,6 +26,12 @@ dependencies = [
"stable_deref_trait", "stable_deref_trait",
] ]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]] [[package]]
name = "bare-metal" name = "bare-metal"
version = "0.2.5" version = "0.2.5"
@ -106,6 +112,32 @@ dependencies = [
"syn", "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]] [[package]]
name = "embedded-hal" name = "embedded-hal"
version = "0.2.4" version = "0.2.4"
@ -123,6 +155,7 @@ dependencies = [
"aligned 0.3.2", "aligned 0.3.2",
"cortex-m 0.5.10", "cortex-m 0.5.10",
"cortex-m-rt", "cortex-m-rt",
"cortex-m-rtic",
"embedded-hal", "embedded-hal",
"log", "log",
"panic-itm", "panic-itm",
@ -149,6 +182,43 @@ dependencies = [
"typenum", "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]] [[package]]
name = "log" name = "log"
version = "0.4.8" version = "0.4.8"
@ -209,6 +279,23 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 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]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.2.3" version = "0.2.3"
@ -308,6 +395,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c" checksum = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c"
[[package]]
name = "version_check"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]] [[package]]
name = "void" name = "void"
version = "1.0.2" version = "1.0.2"

View File

@ -15,6 +15,7 @@ embedded-hal = "0.2"
stm32f4xx-hal = { version = "0.8" , optional = true } 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 } 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" log = "0.4"
cortex-m-rtic = "0.5.3"
[features] [features]
smoltcp-phy = ["smoltcp"] smoltcp-phy = ["smoltcp"]

View File

@ -82,9 +82,9 @@ This program demonstrates the TCP connectivity using **smoltcp** on an STM32F407
[nix-shell]$ run-tmux-env [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 ```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`): 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 #### 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: ITM output at the initial state:
``` ```

View File

@ -1,257 +1,266 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use core::env;
extern crate panic_itm; extern crate panic_itm;
use cortex_m::{iprintln, iprint}; use cortex_m::{iprintln, iprint};
use cortex_m_rt::entry; use embedded_hal::{
use embedded_hal::digital::v2::OutputPin; digital::v2::OutputPin,
use embedded_hal::blocking::delay::DelayMs; blocking::delay::DelayMs
};
use stm32f4xx_hal::{ use stm32f4xx_hal::{
rcc::RccExt, rcc::RccExt,
gpio::GpioExt, gpio::GpioExt,
time::U32Ext, time::U32Ext,
stm32::{CorePeripherals, Peripherals}, stm32::ITM,
delay::Delay, delay::Delay,
spi::Spi, spi::Spi,
time::Hertz time::Hertz
}; };
use enc424j600; use enc424j600;
use enc424j600::EthController; use enc424j600::{smoltcp_phy, EthController};
use enc424j600::smoltcp_phy;
use smoltcp::wire::{ 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::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
use smoltcp::time::{Instant, Duration};
use core::str; use core::str;
use core::fmt::Write; use core::fmt::Write;
use core::cell::RefCell; use rtic::cyccnt::Instant;
use cortex_m::interrupt::Mutex;
use cortex_m_rt::exception; ///
use stm32f4xx_hal::{ use stm32f4xx_hal::{
rcc::Clocks, stm32::SPI1,
time::MilliSeconds, gpio::{
timer::{Timer, Event as TimerEvent}, gpioa::{PA5, PA6, PA7, PA4},
stm32::SYST Alternate, AF5, Output, PushPull
}
}; };
/// Rate in Hz type BoosterSpiEth = enc424j600::SpiEth<
const TIMER_RATE: u32 = 20; Spi<SPI1, (PA5<Alternate<AF5>>, PA6<Alternate<AF5>>, PA7<Alternate<AF5>>)>,
/// Interval duration in milliseconds PA4<Output<PushPull>>>;
const TIMER_DELTA: u32 = 1000 / TIMER_RATE;
/// Elapsed time in milliseconds
static TIMER_MS: Mutex<RefCell<u32>> = Mutex::new(RefCell::new(0));
/// Setup SysTick exception pub struct NetStorage {
fn timer_setup(syst: SYST, clocks: Clocks) { ip_addrs: [IpCidr; 1],
let mut timer = Timer::syst(syst, TIMER_RATE.hz(), clocks); neighbor_cache: [Option<(IpAddress, smoltcp::iface::Neighbor)>; 8],
timer.listen(TimerEvent::TimeOut);
} }
/// SysTick exception (Timer) static mut NET_STORE: NetStorage = NetStorage {
#[exception] // Placeholder for the real IP address, which is initialized at runtime.
fn SysTick() { ip_addrs: [IpCidr::Ipv6(
cortex_m::interrupt::free(|cs| { Ipv6Cidr::SOLICITED_NODE_PREFIX,
*TIMER_MS.borrow(cs) )],
.borrow_mut() += TIMER_DELTA; neighbor_cache: [None; 8],
}); };
}
/// Obtain current time in milliseconds #[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
pub fn timer_now() -> MilliSeconds { const APP: () = {
let ms = cortex_m::interrupt::free(|cs| { struct Resources {
*TIMER_MS.borrow(cs) eth_iface: EthernetInterface<
.borrow() 'static,
}); 'static,
ms.ms() 'static,
} smoltcp_phy::SmoltcpDevice<BoosterSpiEth>>,
itm: ITM
}
#[entry] #[init()]
fn main() -> ! { fn init(mut c: init::Context) -> init::LateResources {
let mut cp = CorePeripherals::take().unwrap(); c.core.SCB.enable_icache();
cp.SCB.enable_icache(); c.core.SCB.enable_dcache(&mut c.core.CPUID);
cp.SCB.enable_dcache(&mut cp.CPUID);
let dp = Peripherals::take().unwrap(); // Enable monotonic timer CYCCNT
let clocks = dp.RCC.constrain() c.core.DWT.enable_cycle_counter();
.cfgr c.core.DCB.enable_trace();
.sysclk(168.mhz())
.hclk(168.mhz())
.pclk1(32.mhz())
.pclk2(64.mhz())
.freeze();
// Init ITM & use Stimulus Port 0 let clocks = c.device.RCC.constrain()
let mut itm = cp.ITM; .cfgr
let stim0 = &mut itm.stim[0]; .sysclk(168.mhz())
.hclk(168.mhz())
.pclk1(42.mhz())
.require_pll48clk()
.freeze();
let mut delay = Delay::new(c.core.SYST, clocks);
iprintln!(stim0, // Init ITM
"Eth TCP Server on STM32-F407 via NIC100/ENC424J600"); let mut itm = c.core.ITM;
let stim0 = &mut itm.stim[0];
// Get IP address from args iprintln!(stim0,
let arg_ip_raw = env!("ENC424J600_TCP_IP"); "Eth TCP Server on STM32-F407 via NIC100/ENC424J600");
let mut arg_ip_str = arg_ip_raw.split('.');
let mut arg_ip: [u8; 4] = [0; 4]; // NIC100 / ENC424J600 Set-up
for i in 0..4 { let spi1 = c.device.SPI1;
match arg_ip_str.next() { let gpioa = c.device.GPIOA.split();
Some(x) => { // Mapping: see Table 9, STM32F407ZG Manual
match x.parse() { let spi1_sck = gpioa.pa5.into_alternate_af5();
Ok(x_) => { arg_ip[i] = x_ }, let spi1_miso = gpioa.pa6.into_alternate_af5();
Err(_) => { panic!("IPv4 address invalid!") } 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...")
} }
}, Err(_) => {
None => { panic!("IPv4 address invalid!") } panic!("Ethernet initialization failed!")
} }
} }
// 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!") }
}
// NIC100 / ENC424J600 Set-up // Read MAC
let spi1 = dp.SPI1; let mut eth_mac_addr: [u8; 6] = [0; 6];
let gpioa = dp.GPIOA.split(); spi_eth.read_from_mac(&mut eth_mac_addr);
let mut delay = Delay::new(cp.SYST, clocks); for i in 0..6 {
// Mapping: see Table 9, STM32F407ZG Manual let byte = eth_mac_addr[i];
let spi1_sck = gpioa.pa5.into_alternate_af5(); match i {
let spi1_miso = gpioa.pa6.into_alternate_af5(); 0 => iprint!(stim0, "MAC Address = {:02x}-", byte),
let spi1_mosi = gpioa.pa7.into_alternate_af5(); 1..=4 => iprint!(stim0, "{:02x}-", byte),
let spi1_nss = gpioa.pa4.into_push_pull_output(); 5 => iprint!(stim0, "{:02x}\n", byte),
// 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!")
}
}
// Setup SysTick // Init Rx/Tx buffers
// Reference to stm32-eth:examples/ip.rs spi_eth.init_rxbuf();
timer_setup(delay.free(), clocks); spi_eth.init_txbuf();
iprintln!(stim0, "Timer initialized"); iprintln!(stim0, "Ethernet controller initialized");
// Read MAC // Init smoltcp interface
let mut eth_mac_addr: [u8; 6] = [0; 6]; let eth_iface = {
spi_eth.read_from_mac(&mut eth_mac_addr); let device = smoltcp_phy::SmoltcpDevice::new(spi_eth);
for i in 0..6 {
let byte = eth_mac_addr[i]; let store = unsafe { &mut NET_STORE };
match i { store.ip_addrs[0] = IpCidr::new(IpAddress::v4(192, 168, 1, 77), 24);
0 => iprint!(stim0, "MAC Address = {:02x}-", byte), let neighbor_cache = NeighborCache::new(&mut store.neighbor_cache[..]);
1..=4 => iprint!(stim0, "{:02x}-", byte),
5 => iprint!(stim0, "{:02x}\n", byte), 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 #[idle(resources=[eth_iface, itm])]
spi_eth.init_rxbuf(); fn idle(c: idle::Context) -> ! {
spi_eth.init_txbuf(); let stim0 = &mut c.resources.itm.stim[0];
let iface = c.resources.eth_iface;
// Copied / modified from smoltcp: // Copied / modified from smoltcp:
// examples/loopback.rs, examples/multicast.rs // examples/loopback.rs
let device = smoltcp_phy::SmoltcpDevice::new(spi_eth); let echo_socket = {
let mut neighbor_cache_entries = [None; 16]; static mut TCP_SERVER_RX_DATA: [u8; 1024] = [0; 1024];
let neighbor_cache = NeighborCache::new(&mut neighbor_cache_entries[..]); static mut TCP_SERVER_TX_DATA: [u8; 1024] = [0; 1024];
let ip_addr = IpCidr::new(IpAddress::v4( let tcp_rx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_RX_DATA[..] });
arg_ip[0], arg_ip[1], arg_ip[2], arg_ip[3]), arg_ip_pref); let tcp_tx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_TX_DATA[..] });
let mut ip_addrs = [ip_addr]; TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer)
let mut iface = EthernetInterfaceBuilder::new(device) };
.ethernet_addr(EthernetAddress(eth_mac_addr)) let greet_socket = {
.neighbor_cache(neighbor_cache) static mut TCP_SERVER_RX_DATA: [u8; 256] = [0; 256];
.ip_addrs(&mut ip_addrs[..]) static mut TCP_SERVER_TX_DATA: [u8; 256] = [0; 256];
.finalize(); let tcp_rx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_RX_DATA[..] });
let tcp_tx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_TX_DATA[..] });
// Copied / modified from smoltcp: TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer)
// examples/loopback.rs };
let echo_socket = { let mut socket_set_entries = [None, None];
static mut TCP_SERVER_RX_DATA: [u8; 1024] = [0; 1024]; let mut socket_set = SocketSet::new(&mut socket_set_entries[..]);
static mut TCP_SERVER_TX_DATA: [u8; 1024] = [0; 1024]; let echo_handle = socket_set.add(echo_socket);
let tcp_rx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_RX_DATA[..] }); let greet_handle = socket_set.add(greet_socket);
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)
{ {
let mut socket = socket_set.get::<TcpSocket>(echo_handle); let store = unsafe { &mut NET_STORE };
if !socket.is_open() { iprintln!(stim0,
iprintln!(stim0, "TCP sockets will listen at {}", store.ip_addrs[0].address());
"[{}] 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())
}));
}
} }
// 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() { // Copied / modified from:
let greeting = "Welcome to the server demo for STM32-F407!"; // smoltcp:examples/loopback.rs, examples/server.rs;
write!(socket, "{}\n", greeting).unwrap(); // stm32-eth:examples/ip.rs,
iprintln!(stim0, // git.m-labs.hk/M-Labs/tnetplug
"[{}] Greeting sent, socket closed", instant); let mut time = 0u32;
socket.close(); 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();
}
};

View File

@ -4,14 +4,15 @@
extern crate panic_itm; extern crate panic_itm;
use cortex_m::{iprintln, iprint}; use cortex_m::{iprintln, iprint};
use cortex_m_rt::entry; use embedded_hal::{
use embedded_hal::digital::v2::OutputPin; digital::v2::OutputPin,
use embedded_hal::blocking::delay::DelayMs; blocking::delay::DelayMs
};
use stm32f4xx_hal::{ use stm32f4xx_hal::{
rcc::RccExt, rcc::RccExt,
gpio::GpioExt, gpio::GpioExt,
time::U32Ext, time::U32Ext,
stm32::{CorePeripherals, Peripherals}, stm32::ITM,
delay::Delay, delay::Delay,
spi::Spi, spi::Spi,
time::Hertz time::Hertz
@ -19,106 +20,141 @@ use stm32f4xx_hal::{
use enc424j600; use enc424j600;
use enc424j600::EthController; use enc424j600::EthController;
#[entry] ///
fn main() -> ! { use stm32f4xx_hal::{
let mut cp = CorePeripherals::take().unwrap(); stm32::SPI1,
cp.SCB.enable_icache(); gpio::{
cp.SCB.enable_dcache(&mut cp.CPUID); 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(); #[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
let clocks = dp.RCC.constrain() const APP: () = {
.cfgr struct Resources {
.sysclk(168.mhz()) spi_eth: BoosterSpiEth,
.hclk(168.mhz()) delay: Delay,
.pclk1(32.mhz()) itm: ITM,
.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!")
}
} }
// Read MAC #[init()]
let mut eth_mac_addr: [u8; 6] = [0; 6]; fn init(mut c: init::Context) -> init::LateResources {
spi_eth.read_from_mac(&mut eth_mac_addr); c.core.SCB.enable_icache();
for i in 0..6 { c.core.SCB.enable_dcache(&mut c.core.CPUID);
let byte = eth_mac_addr[i];
match i { let clocks = c.device.RCC.constrain()
0 => iprint!(stim0, "MAC Address = {:02x}-", byte), .cfgr
1..=4 => iprint!(stim0, "{:02x}-", byte), .sysclk(168.mhz())
5 => iprint!(stim0, "{:02x}\n", byte), .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 // Init
spi_eth.init_rxbuf(); match spi_eth.init_dev(&mut delay) {
spi_eth.init_txbuf(); Ok(_) => {
// Testing Eth TX iprintln!(stim0, "Initializing Ethernet...")
let eth_tx_dat: [u8; 64] = [ }
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x60, Err(_) => {
0x6e, 0x44, 0x42, 0x95, 0x08, 0x06, 0x00, 0x01, panic!("Ethernet initialization failed!")
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, // Read MAC
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, let mut eth_mac_addr: [u8; 6] = [0; 6];
0x00, 0x00, 0x00, 0x00, 0x69, 0xd0, 0x85, 0x9f spi_eth.read_from_mac(&mut eth_mac_addr);
]; for i in 0..6 {
loop { let byte = eth_mac_addr[i];
let mut eth_tx_packet = enc424j600::tx::TxPacket::new();
eth_tx_packet.update_frame(&eth_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 { match i {
0 => iprint!(stim0, "dest={:02x}-", byte), 0 => iprint!(stim0, "MAC Address = {:02x}-", byte),
6 => iprint!(stim0, "src={:02x}-", byte), 1..=4 => iprint!(stim0, "{:02x}-", byte),
12 => iprint!(stim0, "data={:02x}", byte), 5 => iprint!(stim0, "{:02x}\n", 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),
_ => () _ => ()
}; };
} }
spi_eth.send_raw_packet(&eth_tx_packet);
iprintln!(stim0, "Packet sent"); // Init Rx/Tx buffers
delay.delay_ms(100_u32); 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(&eth_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(&eth_tx_packet);
iprintln!(stim0, "Packet sent");
c.resources.delay.delay_ms(100_u32);
}
}
};

View File

@ -22,9 +22,8 @@ let
echo "[Examples]" echo "[Examples]"
echo " tx_stm32f407" echo " tx_stm32f407"
echo " - Run tx_stm32f407 example." echo " - Run tx_stm32f407 example."
echo " tcp_stm32f407 <ip> <pref>" echo " tcp_stm32f407"
echo " - Run tcp_stm32f407 example with the IPv4" echo " - Run tcp_stm32f407 example."
echo " address <ip> (dot-separated) and prefix length <pref>."
echo "" echo ""
echo "[Workspace]" echo "[Workspace]"
echo " run-tmux-env" echo " run-tmux-env"
@ -98,14 +97,6 @@ let
cargo run --release --example=tx_stm32f407 --features=stm32f407 cargo run --release --example=tx_stm32f407 --features=stm32f407
''; '';
exTcpStm32f407 = writeShellScriptBin "tcp_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 cargo run --release --example=tcp_stm32f407 --features=stm32f407,smoltcp-phy-all
''; '';
in in