finish ethernet test

This commit is contained in:
Zheng-Jiakun 2021-07-29 15:57:52 +08:00
parent 093fceb853
commit ee394a3ea7
4 changed files with 499 additions and 50 deletions

5
.gitignore vendored
View File

@ -1,2 +1,3 @@
/target
/stm32f1xx-hal
target/
stm32f1xx-hal/
*.jdebug*

176
Cargo.lock generated
View File

@ -2,6 +2,12 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aligned"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39da9b88ae1a81c03c9c082b8db83f1d0e93914126041962af61034ab44c4a5"
[[package]]
name = "aligned"
version = "0.3.5"
@ -23,6 +29,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"
@ -38,6 +50,18 @@ version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cast"
version = "0.2.7"
@ -47,13 +71,31 @@ dependencies = [
"rustc_version 0.4.0",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cortex-m"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59971a5cf4dacacaf738dd9d8660875118fce790f800f661893eb20894c1d622"
dependencies = [
"aligned 0.2.0",
"bare-metal",
"cortex-m 0.6.7",
"volatile-register",
]
[[package]]
name = "cortex-m"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9075300b07c6a56263b9b582c214d0ff037b00d45ec9fde1cc711490c56f1bb9"
dependencies = [
"aligned",
"aligned 0.3.5",
"bare-metal",
"bitfield",
"cortex-m 0.7.3",
@ -93,6 +135,32 @@ dependencies = [
"syn",
]
[[package]]
name = "cortex-m-rtic"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9845c4c7f7af19e216a2d00345f7f1507b8907b85cd551e403d68baeec342bb3"
dependencies = [
"cortex-m 0.6.7",
"cortex-m-rt",
"cortex-m-rtic-macros",
"heapless",
"rtic-core",
"version_check",
]
[[package]]
name = "cortex-m-rtic-macros"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc874eda99515b15e67f03562726a530388f454431096d30131051b52b840559"
dependencies = [
"proc-macro2",
"quote",
"rtic-syntax",
"syn",
]
[[package]]
name = "embedded-hal"
version = "0.2.5"
@ -103,6 +171,18 @@ dependencies = [
"void",
]
[[package]]
name = "enc424j600"
version = "0.2.0"
source = "git+https://git.m-labs.hk/M-Labs/ENC424J600.git#fbcc3778d27cfbeec7a1395c9b13a00c8a26af9a"
dependencies = [
"aligned 0.3.5",
"cortex-m 0.5.11",
"embedded-hal",
"smoltcp",
"volatile-register",
]
[[package]]
name = "generic-array"
version = "0.12.4"
@ -131,6 +211,58 @@ dependencies = [
"version_check",
]
[[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.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heapless"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422"
dependencies = [
"as-slice",
"generic-array 0.14.4",
"hash32",
"stable_deref_trait",
]
[[package]]
name = "indexmap"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "managed"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
[[package]]
name = "nb"
version = "0.1.3"
@ -152,6 +284,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
[[package]]
name = "panic-itm"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d577d97d1b31268087b6dddf2470e6794ef5eee87d9dca7fcd0481695391a4c"
dependencies = [
"cortex-m 0.7.3",
]
[[package]]
name = "proc-macro2"
version = "1.0.28"
@ -176,6 +317,23 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f"
[[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"
@ -215,6 +373,17 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "smoltcp"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e4a069bef843d170df47e7c0a8bf8d037f217d9f5b325865acc3e466ffe40d3"
dependencies = [
"bitflags",
"byteorder",
"managed",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
@ -266,9 +435,14 @@ version = "0.1.0"
dependencies = [
"cortex-m 0.6.7",
"cortex-m-rt",
"cortex-m-rtic",
"embedded-hal",
"enc424j600",
"log",
"nb 0.1.3",
"panic-halt",
"panic-itm",
"smoltcp",
"stm32f1xx-hal",
]

View File

@ -8,11 +8,16 @@ edition = "2018"
[dependencies]
embedded-hal = "0.2.3"
nb = "0.1.2"
cortex-m = "0.6.2"
cortex-m = {version = "0.6.2"}
cortex-m-rt = "0.6.11"
cortex-m-rtic = { version = "0.5.3"}
panic-itm = { version = "0.4" }
log = { version = "0.4" }
smoltcp = { version = "0.7.0", default-features = false, features = [ "socket-raw", "proto-ipv4", "proto-ipv6" ]}
# Panic behaviour, see https://crates.io/keywords/panic-impl for alternatives
panic-halt = "0.2.0"
stm32f1xx-hal = {version = "0.6.1", features = ["rt", "stm32f103", "high"]}
enc424j600 = { git = "https://git.m-labs.hk/M-Labs/ENC424J600.git", features = ["smoltcp-examples", "cortex-m-cpu"]}
[dependencies.stm32f1xx-hal]
version = "0.6.1"
features = ["rt", "stm32f103", "high"]

View File

@ -1,52 +1,321 @@
//! Blinks an LED
//!
//! This assumes that a LED is connected to pc0 as is the case on the blue pill board.
//!
//! Note: Without additional hardware, PC0 should not be used to drive an LED, see page 5.1.2 of
//! the reference manual for an explanation. This is not an issue on the blue pill.
#![deny(unsafe_code)]
#![no_std]
#![no_main]
use panic_halt as _;
extern crate panic_itm;
use cortex_m::{iprintln, iprint};
use nb::block;
use embedded_hal::{
digital::v2::OutputPin,
// blocking::delay::DelayMs
};
// use stm32f1xx_hal::spi::SpiRegisterBlock;
use stm32f1xx_hal::{
afio::AfioExt,
rcc::RccExt,
flash::FlashExt,
gpio::GpioExt,
time::U32Ext,
stm32::ITM,
delay::Delay,
spi::Spi,
// time::Hertz
};
use enc424j600::smoltcp_phy;
use cortex_m_rt::entry;
use embedded_hal::digital::v2::OutputPin;
use stm32f1xx_hal::{pac, prelude::*, timer::Timer};
use smoltcp::wire::{
EthernetAddress, IpAddress, IpCidr, Ipv6Cidr
};
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, EthernetInterface};
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
use core::str;
use core::fmt::Write;
#[entry]
fn main() -> ! {
// Get access to the core peripherals from the cortex-m crate
let cp = cortex_m::Peripherals::take().unwrap();
// Get access to the device specific peripherals from the peripheral access crate
let dp = pac::Peripherals::take().unwrap();
/// Timer
use core::cell::RefCell;
use cortex_m::interrupt::Mutex;
use cortex_m_rt::exception;
use stm32f1xx_hal::{
rcc::Clocks,
time::MilliSeconds,
timer::{Timer, Event as TimerEvent},
stm32::SYST
};
use smoltcp::time::Instant;
// Take ownership over the raw flash and rcc devices and convert them into the corresponding
// HAL structs
let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();
/// 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));
// Freeze the configuration of all the clocks in the system and store the frozen frequencies in
// `clocks`
let clocks = rcc.cfgr.freeze(&mut flash.acr);
// Acquire the GPIOC peripheral
let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
// Configure gpio C pin 0 as a push-pull output. The `crl` register is passed to the function
// in order to configure the port. For pins 0-7, crl should be passed instead.
let mut led = gpioc.pc0.into_push_pull_output(&mut gpioc.crl);
// Configure the syst timer to trigger an update every second
let mut timer = Timer::syst(cp.SYST, &clocks).start_count_down(1.hz());
// Wait for the timer to trigger an update and change the state of the LED
loop {
block!(timer.wait()).unwrap();
led.set_high().unwrap();
block!(timer.wait()).unwrap();
led.set_low().unwrap();
}
/// Setup SysTick exception
fn timer_setup(syst: SYST, clocks: Clocks) {
let timer = Timer::syst(syst, &clocks);
timer.start_count_down(TIMER_RATE.hz()).listen(TimerEvent::Update);
}
/// SysTick exception (Timer)
#[exception]
fn SysTick() {
cortex_m::interrupt::free(|cs| {
*TIMER_MS.borrow(cs)
.borrow_mut() += TIMER_DELTA;
});
}
/// Obtain current time in milliseconds
pub fn timer_now() -> MilliSeconds {
let ms = cortex_m::interrupt::free(|cs| {
*TIMER_MS.borrow(cs)
.borrow()
});
ms.ms()
}
///spi
use stm32f1xx_hal::{
stm32::SPI1,
spi::Spi1Remap,
gpio::{
gpiob::{PB3, PB4, PB5},
gpioc::PC13,
Alternate, Output, PushPull, Input, Floating
}
};
type SpiEth = enc424j600::Enc424j600<
Spi<SPI1, Spi1Remap, (PB3<Alternate<PushPull>>, PB4<Input<Floating>>, PB5<Alternate<PushPull>>)>,
PC13<Output<PushPull>>
>;
pub struct NetStorage {
ip_addrs: [IpCidr; 1],
neighbor_cache: [Option<(IpAddress, smoltcp::iface::Neighbor)>; 8],
}
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],
};
#[rtic::app(device = stm32f1xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
const APP: () = {
struct Resources {
eth_iface: EthernetInterface<
'static,
smoltcp_phy::SmoltcpDevice<SpiEth>>,
itm: ITM
}
#[init()]
fn init(mut c: init::Context) -> init::LateResources {
c.core.SCB.enable_icache();
c.core.SCB.enable_dcache(&mut c.core.CPUID);
// Enable monotonic timer CYCCNT
c.core.DWT.enable_cycle_counter();
c.core.DCB.enable_trace();
let mut flash = c.device.FLASH.constrain();
let mut rcc = c.device.RCC.constrain();
let clocks = rcc
.cfgr
.use_hse(8.mhz())
.sysclk(72.mhz())
.hclk(72.mhz())
.pclk1(36.mhz())
.pclk2(72.mhz())
.freeze(&mut flash.acr);
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 TCP Server on STM32-F103 via NIC100/ENC424J600");
// NIC100 / ENC424J600 Set-up
let spi1 = c.device.SPI1;
let gpioa = c.device.GPIOA.split(&mut rcc.apb2);
let mut gpiob = c.device.GPIOB.split(&mut rcc.apb2);
let mut gpioc = c.device.GPIOC.split(&mut rcc.apb2);
let mut afio = c.device.AFIO.constrain(&mut rcc.apb2);
let (_pa15, pb3, pb4) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4);
let spi1_sck = pb3.into_alternate_push_pull(&mut gpiob.crl);
let spi1_miso = pb4;//.into_floating_input(&mut gpiob.crl);
let spi1_mosi = gpiob.pb5.into_alternate_push_pull(&mut gpiob.crl);
let spi1_nss = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
// Create SPI1 for HAL
let eth_iface = {
let mut spi_eth = {
let spi_eth_port = Spi::spi1(
spi1,
(spi1_sck, spi1_miso, spi1_mosi),
&mut afio.mapr,
enc424j600::spi::interfaces::SPI_MODE,
// Hertz(enc424j600::spi::interfaces::SPI_CLOCK_FREQ),
9.mhz(),
clocks,
&mut rcc.apb2,);
SpiEth::new(spi_eth_port, spi1_nss)
.cpu_freq_mhz(72)
};
// Init controller
match spi_eth.reset(&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_mac_addr(&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 Rx/Tx buffers
spi_eth.init_rxbuf();
spi_eth.init_txbuf();
iprintln!(stim0, "Ethernet controller initialized");
// 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, 88), 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");
let mut led = gpioc.pc0.into_push_pull_output(&mut gpioc.crl);
led.set_high().unwrap();
eth_iface
};
// Setup SysTick after releasing SYST from Delay
// Reference to stm32-eth:examples/ip.rs
timer_setup(delay.free(), clocks);
iprintln!(stim0, "Timer initialized");
init::LateResources {
eth_iface,
itm
}
}
#[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
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 store = unsafe { &mut NET_STORE };
iprintln!(stim0,
"TCP sockets will listen at {}", store.ip_addrs[0].address());
}
// Copied / modified from:
// smoltcp:examples/loopback.rs, examples/server.rs;
// stm32-eth:examples/ip.rs,
// git.m-labs.hk/M-Labs/tnetplug
loop {
// Poll
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);
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 STM32F103!";
write!(socket, "{}\n", greeting).unwrap();
iprintln!(stim0,
"[{}] Greeting sent, socket closed", instant);
socket.close();
}
}
}
}
extern "C" {
fn EXTI0();
}
};