-
Notifications
You must be signed in to change notification settings - Fork 115
H723 ethernet #445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
H723 ethernet #445
Changes from 7 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
c221c51
Move ethernet DMA reset slightly earlier to eliminate freeze on h723
jlogan03 6b21ffc
add example that brings up the ethernet link on the nucleo-h723zg
jlogan03 2c835a2
run cargo fmt
jlogan03 0acd636
update example docstring
jlogan03 e8269a3
add feature overrides for new example
jlogan03 8f57225
Merge branch 'stm32-rs:master' into h723_ethernet
jlogan03 ff7efaa
update example for compatibility with smoltcp 0.10.x
jlogan03 d2a215e
remove defunct comment
jlogan03 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
//! Demo for Nucleo-H723ZG eval board using the Real Time for the Masses | ||
//! (RTIC) framework. | ||
//! | ||
//! This demo responds to pings on 192.168.1.99 (IP address hardcoded below) | ||
//! | ||
//! We use the SysTick timer to create a 1ms timebase for use with smoltcp. | ||
//! | ||
//! The ethernet ring buffers are placed in AXI SRAM, where they can be | ||
//! accessed by both the core and the Ethernet DMA. | ||
//! | ||
//! Run like | ||
//! | ||
//! `cargo flash --example ethernet-rtic-nucleo-h723zg --features=ethernet,stm32h735 --chip=STM32H723ZGTx` | ||
#![deny(warnings)] | ||
#![no_main] | ||
#![no_std] | ||
|
||
#[macro_use] | ||
#[allow(unused)] | ||
mod utilities; | ||
|
||
use core::sync::atomic::AtomicU32; | ||
|
||
use smoltcp::iface::{Config, Interface, SocketSet, SocketStorage}; | ||
use smoltcp::time::Instant; | ||
use smoltcp::wire::{HardwareAddress, IpAddress, IpCidr}; | ||
|
||
use stm32h7xx_hal::{ethernet, rcc::CoreClocks, stm32}; | ||
|
||
/// Configure SYSTICK for 1ms timebase | ||
fn systick_init(mut syst: stm32::SYST, clocks: CoreClocks) { | ||
let c_ck_mhz = clocks.c_ck().to_MHz(); | ||
|
||
let syst_calib = 0x3E8; | ||
|
||
syst.set_clock_source(cortex_m::peripheral::syst::SystClkSource::Core); | ||
syst.set_reload((syst_calib * c_ck_mhz) - 1); | ||
syst.enable_interrupt(); | ||
syst.enable_counter(); | ||
} | ||
|
||
/// TIME is an atomic u32 that counts milliseconds. | ||
static TIME: AtomicU32 = AtomicU32::new(0); | ||
|
||
/// Locally administered MAC address | ||
const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; | ||
|
||
/// Ethernet descriptor rings are a global singleton | ||
#[link_section = ".axisram.eth"] | ||
static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new(); | ||
|
||
/// Net storage with static initialisation - another global singleton | ||
pub struct NetStorageStatic<'a> { | ||
socket_storage: [SocketStorage<'a>; 8], | ||
} | ||
static mut STORE: NetStorageStatic = NetStorageStatic { | ||
// Garbage | ||
socket_storage: [SocketStorage::EMPTY; 8], | ||
}; | ||
|
||
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, | ||
) -> Self { | ||
let config = Config::new(ethernet_addr); | ||
|
||
let mut iface = Interface::new(config, &mut ethdev, Instant::ZERO); | ||
// 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, now: i64) { | ||
let timestamp = Instant::from_millis(now); | ||
|
||
self.iface | ||
.poll(timestamp, &mut self.ethdev, &mut self.sockets); | ||
} | ||
} | ||
|
||
#[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true)] | ||
mod app { | ||
use stm32h7xx_hal::{ethernet, ethernet::PHY, gpio, prelude::*}; | ||
|
||
use super::*; | ||
use core::sync::atomic::Ordering; | ||
|
||
#[shared] | ||
struct SharedResources {} | ||
#[local] | ||
struct LocalResources { | ||
net: Net<'static>, | ||
lan8742a: ethernet::phy::LAN8742A<ethernet::EthernetMAC>, | ||
link_led: gpio::gpioe::PE1<gpio::Output<gpio::PushPull>>, | ||
} | ||
|
||
#[init] | ||
fn init( | ||
mut ctx: init::Context, | ||
) -> (SharedResources, LocalResources, init::Monotonics) { | ||
utilities::logger::init(); | ||
// Initialise power... | ||
let pwr = ctx.device.PWR.constrain(); | ||
let pwrcfg = pwr.ldo().freeze(); // nucleo-h723zg board doesn't have SMPS | ||
|
||
// Initialise clocks... | ||
let rcc = ctx.device.RCC.constrain(); | ||
let ccdr = rcc | ||
.sys_ck(200.MHz()) | ||
.hclk(200.MHz()) | ||
.freeze(pwrcfg, &ctx.device.SYSCFG); | ||
|
||
// Initialise system... | ||
ctx.core.SCB.invalidate_icache(); | ||
ctx.core.SCB.enable_icache(); | ||
// TODO: ETH DMA coherence issues | ||
// ctx.core.SCB.enable_dcache(&mut ctx.core.CPUID); | ||
ctx.core.DWT.enable_cycle_counter(); | ||
|
||
// Initialise IO... | ||
let gpioa = ctx.device.GPIOA.split(ccdr.peripheral.GPIOA); | ||
let gpioc = ctx.device.GPIOC.split(ccdr.peripheral.GPIOC); | ||
let gpioe = ctx.device.GPIOE.split(ccdr.peripheral.GPIOE); | ||
let gpiob = ctx.device.GPIOB.split(ccdr.peripheral.GPIOB); | ||
let mut link_led = gpioe.pe1.into_push_pull_output(); // USR LED1 | ||
link_led.set_high(); | ||
|
||
let rmii_ref_clk = gpioa.pa1.into_alternate(); | ||
let rmii_mdio = gpioa.pa2.into_alternate(); | ||
let rmii_mdc = gpioc.pc1.into_alternate(); | ||
let rmii_crs_dv = gpioa.pa7.into_alternate(); | ||
let rmii_rxd0 = gpioc.pc4.into_alternate(); | ||
let rmii_rxd1 = gpioc.pc5.into_alternate(); | ||
let rmii_tx_en = gpiob.pb11.into_alternate(); | ||
let rmii_txd0 = gpiob.pb12.into_alternate(); | ||
let rmii_txd1 = gpiob.pb13.into_alternate(); | ||
|
||
// Initialise ethernet... | ||
assert_eq!(ccdr.clocks.hclk().raw(), 200_000_000); // HCLK 200MHz | ||
assert_eq!(ccdr.clocks.pclk1().raw(), 100_000_000); // PCLK 100MHz | ||
assert_eq!(ccdr.clocks.pclk2().raw(), 100_000_000); // PCLK 100MHz | ||
assert_eq!(ccdr.clocks.pclk4().raw(), 100_000_000); // PCLK 100MHz | ||
|
||
let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); | ||
let (eth_dma, eth_mac) = unsafe { | ||
ethernet::new( | ||
ctx.device.ETHERNET_MAC, | ||
ctx.device.ETHERNET_MTL, | ||
ctx.device.ETHERNET_DMA, | ||
( | ||
rmii_ref_clk, | ||
rmii_mdio, | ||
rmii_mdc, | ||
rmii_crs_dv, | ||
rmii_rxd0, | ||
rmii_rxd1, | ||
rmii_tx_en, | ||
rmii_txd0, | ||
rmii_txd1, | ||
), | ||
&mut DES_RING, | ||
mac_addr, | ||
ccdr.peripheral.ETH1MAC, | ||
&ccdr.clocks, | ||
) | ||
}; | ||
|
||
// Initialise ethernet PHY... | ||
let mut lan8742a = ethernet::phy::LAN8742A::new(eth_mac); | ||
lan8742a.phy_reset(); | ||
lan8742a.phy_init(); | ||
// The eth_dma should not be used until the PHY reports the link is up | ||
|
||
unsafe { ethernet::enable_interrupt() }; | ||
|
||
// unsafe: mutable reference to static storage, we only do this once | ||
let store = unsafe { &mut STORE }; | ||
let net = Net::new(store, eth_dma, mac_addr.into()); | ||
|
||
// 1ms tick | ||
systick_init(ctx.core.SYST, ccdr.clocks); | ||
|
||
( | ||
SharedResources {}, | ||
LocalResources { | ||
net, | ||
lan8742a, | ||
link_led, | ||
}, | ||
init::Monotonics(), | ||
) | ||
} | ||
|
||
#[idle(local = [lan8742a, link_led])] | ||
fn idle(ctx: idle::Context) -> ! { | ||
loop { | ||
// Ethernet | ||
match ctx.local.lan8742a.poll_link() { | ||
true => ctx.local.link_led.set_low(), | ||
_ => ctx.local.link_led.set_high(), | ||
} | ||
} | ||
} | ||
|
||
#[task(binds = ETH, local = [net])] | ||
fn ethernet_event(ctx: ethernet_event::Context) { | ||
unsafe { ethernet::interrupt_handler() } | ||
|
||
let time = TIME.load(Ordering::Relaxed); | ||
ctx.local.net.poll(time as i64); | ||
} | ||
|
||
#[task(binds = SysTick, priority=15)] | ||
fn systick_tick(_: systick_tick::Context) { | ||
TIME.fetch_add(1, Ordering::Relaxed); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.