ETH link checker works
All checks were successful
Rust/sat-rs/pipeline/head This commit looks good

This commit is contained in:
Robin Müller 2024-05-20 20:05:39 +02:00
parent 2bd5191100
commit 6ecd55ef25
Signed by: muellerr
GPG Key ID: A649FB78196E3849
2 changed files with 115 additions and 13 deletions

View File

@ -27,7 +27,6 @@ version = "0.11.0"
default-features = false default-features = false
features = ["medium-ethernet", "proto-ipv4", "socket-raw"] features = ["medium-ethernet", "proto-ipv4", "socket-raw"]
optional = true
[dependencies.rtic] [dependencies.rtic]
version = "2" version = "2"
features = ["thumbv7-backend"] features = ["thumbv7-backend"]

View File

@ -1,36 +1,50 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
use core::mem::MaybeUninit;
use rtic::app; use rtic::app;
use satrs_stm32h7_nucleo_rtic as _; // global logger + panicking-behavior + memory layout use satrs_stm32h7_nucleo_rtic as _; // global logger + panicking-behavior + memory layout
use stm32h7xx_hal::ethernet;
const DEFAULT_BLINK_FREQ_MS: u32 = 1000; const DEFAULT_BLINK_FREQ_MS: u32 = 1000;
/// Ethernet descriptor rings are a global singleton
#[link_section = ".sram3.eth"]
static mut DES_RING: MaybeUninit<ethernet::DesRing<4, 4>> = MaybeUninit::uninit();
/// Locally administered MAC address
const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
#[app(device = stm32h7xx_hal::stm32, peripherals = true)] #[app(device = stm32h7xx_hal::stm32, peripherals = true)]
mod app { mod app {
use super::*; use super::*;
use rtic_monotonics::systick::fugit::MillisDurationU32; use rtic_monotonics::systick::fugit::MillisDurationU32;
use rtic_monotonics::systick::Systick; use rtic_monotonics::systick::Systick;
use stm32h7xx_hal::ethernet::{EthernetMAC, PHY};
use stm32h7xx_hal::gpio::{Output, Pin}; use stm32h7xx_hal::gpio::{Output, Pin};
use stm32h7xx_hal::prelude::*; use stm32h7xx_hal::prelude::*;
use stm32h7xx_hal::stm32::Interrupt;
#[shared] #[shared]
struct Shared { struct Shared {
blink_freq: MillisDurationU32, blink_freq: MillisDurationU32,
eth_link_up: bool,
} }
struct Leds { struct BlinkyLeds {
led0: Pin<'B', 0, Output>,
led1: Pin<'B', 7, Output>, led1: Pin<'B', 7, Output>,
led2: Pin<'B', 14, Output>, led2: Pin<'B', 14, Output>,
} }
#[local] #[local]
struct Local { struct Local {
leds: Leds, leds: BlinkyLeds,
link_led: Pin<'B', 0, Output>,
phy: ethernet::phy::LAN8742A<EthernetMAC>,
} }
#[init] #[init]
fn init(cx: init::Context) -> (Shared, Local) { fn init(mut cx: init::Context) -> (Shared, Local) {
defmt::println!("Starting sat-rs demo application for the STM32H743ZIT"); defmt::println!("Starting sat-rs demo application for the STM32H743ZIT");
let pwr = cx.device.PWR.constrain(); let pwr = cx.device.PWR.constrain();
@ -58,18 +72,80 @@ mod app {
systick_mono_token, systick_mono_token,
); );
let gpiob = cx.device.GPIOB.split(ccdr.peripheral.GPIOB); // Those are used in the example, I am not fully sure what they are good for.
let led0 = gpiob.pb0.into_push_pull_output(); cx.core.SCB.enable_icache();
let led1 = gpiob.pb7.into_push_pull_output(); cx.core.DWT.enable_cycle_counter();
let led2 = gpiob.pb14.into_push_pull_output();
let leds = Leds { led0, led1, led2 };
let gpioa = cx.device.GPIOA.split(ccdr.peripheral.GPIOA);
let gpiob = cx.device.GPIOB.split(ccdr.peripheral.GPIOB);
let gpioc = cx.device.GPIOC.split(ccdr.peripheral.GPIOC);
let gpiog = cx.device.GPIOG.split(ccdr.peripheral.GPIOG);
let link_led = gpiob.pb0.into_push_pull_output();
let mut led1 = gpiob.pb7.into_push_pull_output();
let mut led2 = gpiob.pb14.into_push_pull_output();
// Criss-cross pattern looks cooler.
led1.set_high();
led2.set_low();
let leds = BlinkyLeds { led1, led2 };
let rmii_ref_clk = gpioa.pa1.into_alternate::<11>();
let rmii_mdio = gpioa.pa2.into_alternate::<11>();
let rmii_mdc = gpioc.pc1.into_alternate::<11>();
let rmii_crs_dv = gpioa.pa7.into_alternate::<11>();
let rmii_rxd0 = gpioc.pc4.into_alternate::<11>();
let rmii_rxd1 = gpioc.pc5.into_alternate::<11>();
let rmii_tx_en = gpiog.pg11.into_alternate::<11>();
let rmii_txd0 = gpiog.pg13.into_alternate::<11>();
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(
cx.device.ETHERNET_MAC,
cx.device.ETHERNET_MTL,
cx.device.ETHERNET_DMA,
(
rmii_ref_clk,
rmii_mdio,
rmii_mdc,
rmii_crs_dv,
rmii_rxd0,
rmii_rxd1,
rmii_tx_en,
rmii_txd0,
rmii_txd1,
),
// SAFETY: We do not move the returned DMA struct anymore, so this should be safe
// according to the docs.
unsafe { DES_RING.assume_init_mut() },
mac_addr,
ccdr.peripheral.ETH1MAC,
&ccdr.clocks,
);
// Initialise ethernet PHY...
let mut lan8742a = ethernet::phy::LAN8742A::new(eth_mac.set_phy_addr(0));
lan8742a.phy_reset();
lan8742a.phy_init();
unsafe {
ethernet::enable_interrupt();
cx.core.NVIC.set_priority(Interrupt::ETH, 196); // Mid prio
cortex_m::peripheral::NVIC::unmask(Interrupt::ETH);
}
eth_link_check::spawn().expect("eth link check failed");
blink::spawn().expect("spawning blink task failed"); blink::spawn().expect("spawning blink task failed");
( (
Shared { Shared {
blink_freq: MillisDurationU32::from_ticks(DEFAULT_BLINK_FREQ_MS), blink_freq: MillisDurationU32::from_ticks(DEFAULT_BLINK_FREQ_MS),
eth_link_up: false,
},
Local {
link_led,
leds,
phy: lan8742a,
}, },
Local { leds },
) )
} }
@ -77,12 +153,39 @@ mod app {
async fn blink(mut cx: blink::Context) { async fn blink(mut cx: blink::Context) {
let leds = cx.local.leds; let leds = cx.local.leds;
loop { loop {
defmt::info!("toggling LEDs");
leds.led0.toggle();
leds.led1.toggle(); leds.led1.toggle();
leds.led2.toggle(); leds.led2.toggle();
let current_blink_freq = cx.shared.blink_freq.lock(|current| *current); let current_blink_freq = cx.shared.blink_freq.lock(|current| *current);
Systick::delay(current_blink_freq).await; Systick::delay(current_blink_freq).await;
} }
} }
#[task(local=[link_led, phy], shared=[eth_link_up])]
async fn eth_link_check(mut cx: eth_link_check::Context) {
let phy = cx.local.phy;
let link_led = cx.local.link_led;
loop {
let link_was_up = cx.shared.eth_link_up.lock(|link_up| *link_up);
if phy.poll_link() {
if !link_was_up {
link_led.set_high();
cx.shared.eth_link_up.lock(|link_up| *link_up = true);
defmt::info!("Ethernet link up");
}
} else if link_was_up {
link_led.set_low();
cx.shared.eth_link_up.lock(|link_up| *link_up = false);
defmt::info!("Ethernet link down");
}
Systick::delay(100.millis()).await;
}
}
#[task(binds=ETH)]
fn eth_isr(_: eth_isr::Context) {
// SAFETY: We do not write the register mentioned inside the docs anywhere else.
unsafe {
ethernet::interrupt_handler();
}
}
} }