forked from stm32-rs/stm32h7xx-hal
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'stm32-rs:master' into ptp
- Loading branch information
Showing
9 changed files
with
357 additions
and
44 deletions.
There are no files selected for viewing
This file contains 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 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 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(); | ||
Check failure on line 50 in examples/ethernet-rtic-nucleo-h723zg.rs GitHub Actions / check (stable, stm32h735)
|
||
|
||
/// Net storage with static initialisation - another global singleton | ||
pub struct NetStorageStatic<'a> { | ||
socket_storage: [SocketStorage<'a>; 8], | ||
} | ||
|
||
static mut STORE: NetStorageStatic = NetStorageStatic { | ||
socket_storage: [SocketStorage::EMPTY; 8], | ||
}; | ||
|
||
pub struct Net<'a> { | ||
iface: Interface, | ||
ethdev: ethernet::EthernetDMA<4, 4>, | ||
Check failure on line 63 in examples/ethernet-rtic-nucleo-h723zg.rs GitHub Actions / check (stable, stm32h735)
|
||
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 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 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
Oops, something went wrong.