Skip to content
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

Add RTICv2 example with multiple groups #133

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions examples/rtic-stm32/.cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-rs run --chip STM32F429ZITx"
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
]


[build]
target = "thumbv7em-none-eabi"
2 changes: 2 additions & 0 deletions examples/rtic-stm32/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
Cargo.lock
28 changes: 28 additions & 0 deletions examples/rtic-stm32/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
version = "0.1.0"
name = "stm32-rtic"
edition = "2021"
resolver = "2"

[dependencies]
volatile-register = "0.2"
aligned = "0.4"
stm32f4xx-hal = { version = "0.14", features = ["stm32f429"] }
stm32f4 = { version = "0.15" }
ieee802_3_miim = "0.8"
defmt = { version = "0.3" }
futures = { version = "0.3", default-features = false, features = [
"async-await",
] }
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
fugit = "0.3"
defmt-rtt = "0.4"
panic-probe = { version = "0.3", features = ["print-defmt"] }
systick-monotonic = "1.0"
rtic = { version = "2.0.1", features = ["thumbv7-backend"] }
stm32-eth = { version = "0.5.2", default-features = false, features = ["defmt", "stm32f429", "async-await"] }

[profile.release]
debug = 2
lto = true
4 changes: 4 additions & 0 deletions examples/rtic-stm32/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[toolchain]
channel = "nightly"
components = ["llvm-tools"]
targets = ["thumbv7em-none-eabi"]
284 changes: 284 additions & 0 deletions examples/rtic-stm32/src/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
//! Common features used in examples.
//!
//! Note that this module isn't an example by itself.

use defmt_rtt as _;
use panic_probe as _;

use stm32_eth::{
hal::{
gpio::{GpioExt, *},
rcc::Clocks,
},
EthPins, PartsIn,
};

use fugit::RateExtU32;
use stm32_eth::hal::rcc::RccExt;

/// Setup the clocks and return clocks and a GPIO struct that
/// can be used to set up all of the pins.
///
/// This configures HCLK to be at least 25 MHz, which is the minimum required
/// for ethernet operation to be valid.
pub fn setup_peripherals(p: stm32_eth::stm32::Peripherals) -> (Clocks, Gpio, PartsIn) {
let ethernet = PartsIn {
dma: p.ETHERNET_DMA,
mac: p.ETHERNET_MAC,
mmc: p.ETHERNET_MMC,
#[cfg(feature = "ptp")]
ptp: p.ETHERNET_PTP,
};

let rcc = p.RCC.constrain();

let clocks = rcc.cfgr.sysclk(96.MHz()).hclk(96.MHz());

#[cfg(feature = "stm32f4xx-hal")]
let clocks = {
if cfg!(hse = "bypass") {
clocks.use_hse(8.MHz()).bypass_hse_oscillator()
} else if cfg!(hse = "oscillator") {
clocks.use_hse(8.MHz())
} else {
clocks
}
};

#[cfg(feature = "stm32f7xx-hal")]
let clocks = {
if cfg!(hse = "bypass") {
clocks.hse(stm32_eth::hal::rcc::HSEClock::new(
8.MHz(),
stm32_eth::hal::rcc::HSEClockMode::Bypass,
))
} else if cfg!(hse = "oscillator") {
clocks.hse(stm32_eth::hal::rcc::HSEClock::new(
8.MHz(),
stm32_eth::hal::rcc::HSEClockMode::Oscillator,
))
} else {
clocks
}
};

let clocks = clocks.freeze();

let gpio = Gpio {
gpioa: p.GPIOA.split(),
gpiob: p.GPIOB.split(),
gpioc: p.GPIOC.split(),
gpiog: p.GPIOG.split(),
};

(clocks, gpio, ethernet)
}

pub struct Gpio {
pub gpioa: gpioa::Parts,
pub gpiob: gpiob::Parts,
pub gpioc: gpioc::Parts,
pub gpiog: gpiog::Parts,
}

pub type RefClk = PA1<Input>;
pub type Crs = PA7<Input>;
pub type TxD1 = PB13<Input>;
pub type RxD0 = PC4<Input>;
pub type RxD1 = PC5<Input>;

#[cfg(not(pins = "nucleo"))]
pub type TxEn = PB11<Input>;
#[cfg(not(pins = "nucleo"))]
pub type TxD0 = PB12<Input>;

#[cfg(pins = "nucleo")]
pub type TxEn = PG11<Input>;
#[cfg(pins = "nucleo")]
pub type TxD0 = PG13<Input>;

pub type Mdio = PA2<Alternate<11>>;
pub type Mdc = PC1<Alternate<11>>;

#[cfg(not(pps = "alternate"))]
pub type Pps = PB5<Output<PushPull>>;

#[cfg(pps = "alternate")]
pub type Pps = PG8<Output<PushPull>>;

pub fn setup_pins(
gpio: Gpio,
) -> (
EthPins<RefClk, Crs, TxEn, TxD0, TxD1, RxD0, RxD1>,
Mdio,
Mdc,
Pps,
) {
#[allow(unused_variables)]
let Gpio {
gpioa,
gpiob,
gpioc,
gpiog,
} = gpio;

let ref_clk = gpioa.pa1.into_floating_input();
let crs = gpioa.pa7.into_floating_input();
let tx_d1 = gpiob.pb13.into_floating_input();
let rx_d0 = gpioc.pc4.into_floating_input();
let rx_d1 = gpioc.pc5.into_floating_input();

#[cfg(not(pins = "nucleo"))]
let (tx_en, tx_d0) = (
gpiob.pb11.into_floating_input(),
gpiob.pb12.into_floating_input(),
);

#[cfg(pins = "nucleo")]
let (tx_en, tx_d0) = {
(
gpiog.pg11.into_floating_input(),
gpiog.pg13.into_floating_input(),
)
};

#[cfg(feature = "stm32f4xx-hal")]
let (mdio, mdc) = {
let mut mdio = gpioa.pa2.into_alternate();
mdio.set_speed(Speed::VeryHigh);
let mut mdc = gpioc.pc1.into_alternate();
mdc.set_speed(Speed::VeryHigh);
(mdio, mdc)
};

#[cfg(any(feature = "stm32f7xx-hal"))]
let (mdio, mdc) = (
gpioa.pa2.into_alternate().set_speed(Speed::VeryHigh),
gpioc.pc1.into_alternate().set_speed(Speed::VeryHigh),
);

#[cfg(not(pps = "alternate"))]
let pps = gpiob.pb5.into_push_pull_output();
#[cfg(pps = "alternate")]
let pps = gpiog.pg8.into_push_pull_output();

(
EthPins {
ref_clk,
crs,
tx_en,
tx_d0,
tx_d1,
rx_d0,
rx_d1,
},
mdio,
mdc,
pps,
)
}

use ieee802_3_miim::{
phy::{
lan87xxa::{LAN8720A, LAN8742A},
BarePhy, KSZ8081R,
},
Miim, Pause, Phy,
};

/// An ethernet PHY
pub enum EthernetPhy<M: Miim> {
/// LAN8720A
LAN8720A(LAN8720A<M>),
/// LAN8742A
LAN8742A(LAN8742A<M>),
/// KSZ8081R
KSZ8081R(KSZ8081R<M>),
}

impl<M: Miim> Phy<M> for EthernetPhy<M> {
fn best_supported_advertisement(&self) -> ieee802_3_miim::AutoNegotiationAdvertisement {
match self {
EthernetPhy::LAN8720A(phy) => phy.best_supported_advertisement(),
EthernetPhy::LAN8742A(phy) => phy.best_supported_advertisement(),
EthernetPhy::KSZ8081R(phy) => phy.best_supported_advertisement(),
}
}

fn get_miim(&mut self) -> &mut M {
match self {
EthernetPhy::LAN8720A(phy) => phy.get_miim(),
EthernetPhy::LAN8742A(phy) => phy.get_miim(),
EthernetPhy::KSZ8081R(phy) => phy.get_miim(),
}
}

fn get_phy_addr(&self) -> u8 {
match self {
EthernetPhy::LAN8720A(phy) => phy.get_phy_addr(),
EthernetPhy::LAN8742A(phy) => phy.get_phy_addr(),
EthernetPhy::KSZ8081R(phy) => phy.get_phy_addr(),
}
}
}

impl<M: Miim> EthernetPhy<M> {
/// Attempt to create one of the known PHYs from the given
/// MIIM.
///
/// Returns an error if the PHY does not support the extended register
/// set, or if the PHY's identifier does not correspond to a known PHY.
pub fn from_miim(miim: M, phy_addr: u8) -> Result<Self, M> {
let mut bare = BarePhy::new(miim, phy_addr, Pause::NoPause);
let phy_ident = if let Some(id) = bare.phy_ident() {
id.raw_u32()
} else {
return Err(bare.release());
};
let miim = bare.release();
match phy_ident & 0xFFFFFFF0 {
0x0007C0F0 => Ok(Self::LAN8720A(LAN8720A::new(miim, phy_addr))),
0x0007C130 => Ok(Self::LAN8742A(LAN8742A::new(miim, phy_addr))),
0x00221560 => Ok(Self::KSZ8081R(KSZ8081R::new(miim, phy_addr))),
_ => Err(miim),
}
}

/// Get a string describing the type of PHY
pub const fn ident_string(&self) -> &'static str {
match self {
EthernetPhy::LAN8720A(_) => "LAN8720A",
EthernetPhy::LAN8742A(_) => "LAN8742A",
EthernetPhy::KSZ8081R(_) => "KSZ8081R",
}
}

/// Initialize the PHY
pub fn phy_init(&mut self) {
match self {
EthernetPhy::LAN8720A(phy) => phy.phy_init(),
EthernetPhy::LAN8742A(phy) => phy.phy_init(),
EthernetPhy::KSZ8081R(phy) => {
phy.set_autonegotiation_advertisement(phy.best_supported_advertisement());
}
}
}

#[allow(dead_code)]
pub fn speed(&mut self) -> Option<ieee802_3_miim::phy::PhySpeed> {
match self {
EthernetPhy::LAN8720A(phy) => phy.link_speed(),
EthernetPhy::LAN8742A(phy) => phy.link_speed(),
EthernetPhy::KSZ8081R(phy) => phy.link_speed(),
}
}

#[allow(dead_code)]
pub fn release(self) -> M {
match self {
EthernetPhy::LAN8720A(phy) => phy.release(),
EthernetPhy::LAN8742A(phy) => phy.release(),
EthernetPhy::KSZ8081R(phy) => phy.release(),
}
}
}
Loading