This commit is contained in:
parent
6ecd55ef25
commit
25521b3772
@ -25,7 +25,7 @@ stm32h7xx-hal = { version="0.16", features= ["stm32h743v", "ethernet"] }
|
||||
[dependencies.smoltcp]
|
||||
version = "0.11.0"
|
||||
default-features = false
|
||||
features = ["medium-ethernet", "proto-ipv4", "socket-raw"]
|
||||
features = ["medium-ethernet", "proto-ipv4", "socket-raw", "socket-dhcpv4"]
|
||||
|
||||
[dependencies.rtic]
|
||||
version = "2"
|
||||
|
@ -1,10 +1,15 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use rtic::app;
|
||||
use rtic_monotonics::systick::Systick;
|
||||
use rtic_monotonics::Monotonic;
|
||||
use satrs_stm32h7_nucleo_rtic as _; // global logger + panicking-behavior + memory layout
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
use smoltcp::iface::{Config, Interface, SocketSet, SocketStorage};
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::{HardwareAddress, IpAddress, IpCidr};
|
||||
use stm32h7xx_hal::ethernet;
|
||||
|
||||
const DEFAULT_BLINK_FREQ_MS: u32 = 1000;
|
||||
@ -13,11 +18,61 @@ const DEFAULT_BLINK_FREQ_MS: u32 = 1000;
|
||||
#[link_section = ".sram3.eth"]
|
||||
static mut DES_RING: MaybeUninit<ethernet::DesRing<4, 4>> = MaybeUninit::uninit();
|
||||
|
||||
// This data will be held by Net through a mutable reference
|
||||
pub struct NetStorageStatic<'a> {
|
||||
socket_storage: [SocketStorage<'a>; 8],
|
||||
}
|
||||
// MaybeUninit allows us write code that is correct even if STORE is not
|
||||
// initialised by the runtime
|
||||
static mut STORE: MaybeUninit<NetStorageStatic> = MaybeUninit::uninit();
|
||||
|
||||
/// Locally administered MAC address
|
||||
const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
|
||||
|
||||
pub struct Net<'a> {
|
||||
iface: Interface,
|
||||
ethdev: ethernet::EthernetDMA<4, 4>,
|
||||
sockets: SocketSet<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Net<'a> {
|
||||
pub fn new(
|
||||
store: &'a mut NetStorageStatic<'a>,
|
||||
mut ethdev: ethernet::EthernetDMA<4, 4>,
|
||||
ethernet_addr: HardwareAddress,
|
||||
now: Instant,
|
||||
) -> Self {
|
||||
let config = Config::new(ethernet_addr);
|
||||
let mut iface = Interface::new(config, &mut ethdev, now);
|
||||
// Set IP address
|
||||
iface.update_ip_addrs(|addrs| {
|
||||
let _ = addrs.push(IpCidr::new(IpAddress::v4(192, 168, 1, 99), 0));
|
||||
});
|
||||
|
||||
let sockets = SocketSet::new(&mut store.socket_storage[..]);
|
||||
|
||||
Net::<'a> {
|
||||
iface,
|
||||
ethdev,
|
||||
sockets,
|
||||
}
|
||||
}
|
||||
|
||||
/// Polls on the ethernet interface. You should refer to the smoltcp
|
||||
/// documentation for poll() to understand how to call poll efficiently
|
||||
pub fn poll(&mut self) -> bool {
|
||||
let uptime = Systick::now() - Systick::ZERO;
|
||||
let timestamp = smoltcp::time::Instant::from_millis(uptime.to_millis());
|
||||
|
||||
self.iface
|
||||
.poll(timestamp, &mut self.ethdev, &mut self.sockets)
|
||||
}
|
||||
}
|
||||
|
||||
#[app(device = stm32h7xx_hal::stm32, peripherals = true)]
|
||||
mod app {
|
||||
use core::ptr::addr_of_mut;
|
||||
|
||||
use super::*;
|
||||
use rtic_monotonics::systick::fugit::MillisDurationU32;
|
||||
use rtic_monotonics::systick::Systick;
|
||||
@ -40,6 +95,7 @@ mod app {
|
||||
struct Local {
|
||||
leds: BlinkyLeds,
|
||||
link_led: Pin<'B', 0, Output>,
|
||||
net: Net<'static>,
|
||||
phy: ethernet::phy::LAN8742A<EthernetMAC>,
|
||||
}
|
||||
|
||||
@ -72,7 +128,8 @@ mod app {
|
||||
systick_mono_token,
|
||||
);
|
||||
|
||||
// Those are used in the example, I am not fully sure what they are good for.
|
||||
// Those are used in the smoltcp of the stm32h7xx-hal , I am not fully sure what they are
|
||||
// good for.
|
||||
cx.core.SCB.enable_icache();
|
||||
cx.core.DWT.enable_cycle_counter();
|
||||
|
||||
@ -101,7 +158,7 @@ mod app {
|
||||
let rmii_txd1 = gpiob.pb13.into_alternate::<11>();
|
||||
|
||||
let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS);
|
||||
let (_eth_dma, eth_mac) = ethernet::new(
|
||||
let (eth_dma, eth_mac) = ethernet::new(
|
||||
cx.device.ETHERNET_MAC,
|
||||
cx.device.ETHERNET_MTL,
|
||||
cx.device.ETHERNET_DMA,
|
||||
@ -116,8 +173,8 @@ mod app {
|
||||
rmii_txd0,
|
||||
rmii_txd1,
|
||||
),
|
||||
// SAFETY: We do not move the returned DMA struct anymore, so this should be safe
|
||||
// according to the docs.
|
||||
// SAFETY: We do not move the returned DMA struct across thread boundaries, so this
|
||||
// should be safe according to the docs.
|
||||
unsafe { DES_RING.assume_init_mut() },
|
||||
mac_addr,
|
||||
ccdr.peripheral.ETH1MAC,
|
||||
@ -134,6 +191,22 @@ mod app {
|
||||
cortex_m::peripheral::NVIC::unmask(Interrupt::ETH);
|
||||
}
|
||||
|
||||
// unsafe: mutable reference to static storage, we only do this once
|
||||
let store = unsafe {
|
||||
let store_ptr = STORE.as_mut_ptr();
|
||||
|
||||
// Initialise the socket_storage field. Using `write` instead of
|
||||
// assignment via `=` to not call `drop` on the old, uninitialised
|
||||
// value
|
||||
addr_of_mut!((*store_ptr).socket_storage).write([SocketStorage::EMPTY; 8]);
|
||||
|
||||
// Now that all fields are initialised we can safely use
|
||||
// assume_init_mut to return a mutable reference to STORE
|
||||
STORE.assume_init_mut()
|
||||
};
|
||||
|
||||
let net = Net::new(store, eth_dma, mac_addr.into(), Instant::ZERO);
|
||||
|
||||
eth_link_check::spawn().expect("eth link check failed");
|
||||
blink::spawn().expect("spawning blink task failed");
|
||||
(
|
||||
@ -144,6 +217,7 @@ mod app {
|
||||
Local {
|
||||
link_led,
|
||||
leds,
|
||||
net,
|
||||
phy: lan8742a,
|
||||
},
|
||||
)
|
||||
@ -181,11 +255,12 @@ mod app {
|
||||
}
|
||||
}
|
||||
|
||||
#[task(binds=ETH)]
|
||||
fn eth_isr(_: eth_isr::Context) {
|
||||
#[task(binds=ETH, local=[net])]
|
||||
fn eth_isr(cx: eth_isr::Context) {
|
||||
// SAFETY: We do not write the register mentioned inside the docs anywhere else.
|
||||
unsafe {
|
||||
ethernet::interrupt_handler();
|
||||
}
|
||||
cx.local.net.poll();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user