Skip to content

Commit bfb3262

Browse files
committed
Better overall configuration step
1 parent a139265 commit bfb3262

File tree

4 files changed

+86
-34
lines changed

4 files changed

+86
-34
lines changed

examples/ip.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use cortex_m::asm;
77
use cortex_m_rt::{entry, exception};
88
use stm32f4xx_hal::{
99
gpio::GpioExt,
10+
prelude::*,
1011
stm32::{interrupt, CorePeripherals, Peripherals, SYST},
1112
};
1213

@@ -22,7 +23,7 @@ use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
2223
use smoltcp::time::Instant;
2324
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address};
2425

25-
use stm32_eth::{Eth, EthPins, RingEntry};
26+
use stm32_eth::{Eth, EthPins, PhyAddress, RingEntry};
2627

2728
static mut LOGGER: HioLogger = HioLogger {};
2829

@@ -59,10 +60,13 @@ fn main() -> ! {
5960
let p = Peripherals::take().unwrap();
6061
let mut cp = CorePeripherals::take().unwrap();
6162

63+
let rcc = p.RCC.constrain();
64+
// HCLK must be between 25MHz and 168MHz to use the ethernet peripheral
65+
let clocks = rcc.cfgr.sysclk(32.mhz()).hclk(32.mhz()).freeze();
66+
6267
setup_systick(&mut cp.SYST);
6368

6469
writeln!(stdout, "Enabling ethernet...").unwrap();
65-
stm32_eth::setup();
6670
let gpioa = p.GPIOA.split();
6771
let gpiob = p.GPIOB.split();
6872
let gpioc = p.GPIOC.split();
@@ -79,7 +83,6 @@ fn main() -> ! {
7983
rx_d0: gpioc.pc4,
8084
rx_d1: gpioc.pc5,
8185
};
82-
eth_pins.setup();
8386

8487
let mut rx_ring: [RingEntry<_>; 8] = Default::default();
8588
let mut tx_ring: [RingEntry<_>; 2] = Default::default();
@@ -88,7 +91,11 @@ fn main() -> ! {
8891
p.ETHERNET_DMA,
8992
&mut rx_ring[..],
9093
&mut tx_ring[..],
91-
);
94+
PhyAddress::_0,
95+
clocks,
96+
eth_pins,
97+
)
98+
.unwrap();
9299
eth.enable_interrupt();
93100

94101
let local_addr = Ipv4Address::new(10, 0, 0, 1);

examples/pktgen.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ use cortex_m::asm;
1111
use cortex_m::interrupt::Mutex;
1212
use stm32f4xx_hal::{
1313
gpio::GpioExt,
14+
prelude::*,
1415
stm32::{interrupt, CorePeripherals, Peripherals, SYST},
1516
};
1617

1718
use core::fmt::Write;
1819
use cortex_m_semihosting::hio;
1920

20-
use stm32_eth::{Eth, EthPins, RingEntry, TxError};
21+
use stm32_eth::{Eth, EthPins, PhyAddress, RingEntry, TxError};
2122

2223
const SRC_MAC: [u8; 6] = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
2324
const DST_MAC: [u8; 6] = [0x00, 0x00, 0xBE, 0xEF, 0xDE, 0xAD];
@@ -33,10 +34,13 @@ fn main() -> ! {
3334
let p = Peripherals::take().unwrap();
3435
let mut cp = CorePeripherals::take().unwrap();
3536

37+
let rcc = p.RCC.constrain();
38+
// HCLK must be between 25MHz and 168MHz to use the ethernet peripheral
39+
let clocks = rcc.cfgr.sysclk(32.mhz()).hclk(32.mhz()).freeze();
40+
3641
setup_systick(&mut cp.SYST);
3742

3843
writeln!(stdout, "Enabling ethernet...").unwrap();
39-
stm32_eth::setup();
4044
let gpioa = p.GPIOA.split();
4145
let gpiob = p.GPIOB.split();
4246
let gpioc = p.GPIOC.split();
@@ -53,7 +57,6 @@ fn main() -> ! {
5357
rx_d0: gpioc.pc4,
5458
rx_d1: gpioc.pc5,
5559
};
56-
eth_pins.setup();
5760

5861
let mut rx_ring: [RingEntry<_>; 16] = Default::default();
5962
let mut tx_ring: [RingEntry<_>; 8] = Default::default();
@@ -62,7 +65,11 @@ fn main() -> ! {
6265
p.ETHERNET_DMA,
6366
&mut rx_ring[..],
6467
&mut tx_ring[..],
65-
);
68+
PhyAddress::_0,
69+
clocks,
70+
eth_pins,
71+
)
72+
.unwrap();
6673
eth.enable_interrupt();
6774

6875
// Main loop

src/lib.rs

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
pub use stm32f4xx_hal as hal;
55
/// Re-export
66
pub use stm32f4xx_hal::stm32;
7-
use stm32f4xx_hal::stm32::{Interrupt, ETHERNET_DMA, ETHERNET_MAC, NVIC};
7+
use stm32f4xx_hal::{
8+
rcc::Clocks,
9+
stm32::{Interrupt, ETHERNET_DMA, ETHERNET_MAC, NVIC},
10+
};
811

912
pub mod phy;
1013
use phy::{Phy, PhyStatus};
@@ -19,7 +22,11 @@ mod tx;
1922
pub use tx::{TxDescriptor, TxError};
2023
use tx::{TxRing, TxRingEntry};
2124
mod setup;
22-
pub use setup::{setup, EthPins};
25+
pub use setup::EthPins;
26+
use setup::{
27+
AlternateVeryHighSpeed, RmiiCrsDv, RmiiRefClk, RmiiRxD0, RmiiRxD1, RmiiTxD0, RmiiTxD1,
28+
RmiiTxEN, MDC, MDIO,
29+
};
2330

2431
#[cfg(feature = "smoltcp-phy")]
2532
pub use smoltcp;
@@ -28,11 +35,9 @@ mod smoltcp_phy;
2835
#[cfg(feature = "smoltcp-phy")]
2936
pub use smoltcp_phy::{EthRxToken, EthTxToken};
3037

31-
const PHY_ADDR: u8 = 0;
3238
/// From the datasheet: *VLAN Frame maxsize = 1522*
3339
const MTU: usize = 1522;
3440

35-
#[allow(dead_code)]
3641
mod consts {
3742
/* For HCLK 60-100 MHz */
3843
pub const ETH_MACMIIAR_CR_HCLK_DIV_42: u8 = 0;
@@ -47,52 +52,85 @@ mod consts {
4752
}
4853
use self::consts::*;
4954

50-
/// Ethernet driver for *STM32* chips with a *LAN8742*
51-
/// [`Phy`](phy/struct.Phy.html) like they're found on STM Nucleo-144
52-
/// boards.
55+
/// HCLK must be between 25MHz and 168MHz to use the ethernet peripheral.
56+
#[derive(Debug)]
57+
pub struct WrongClock;
58+
59+
/// Initial PHY address, must be zero or one.
60+
#[derive(Copy, Clone, Debug)]
61+
#[repr(u8)]
62+
pub enum PhyAddress {
63+
_0 = 0,
64+
_1 = 1,
65+
}
66+
67+
/// Ethernet driver for *STM32* chips with a RMII [`Phy`](phy/struct.Phy.html).
5368
pub struct Eth<'rx, 'tx> {
5469
eth_mac: ETHERNET_MAC,
5570
eth_dma: ETHERNET_DMA,
5671
rx_ring: RxRing<'rx>,
5772
tx_ring: TxRing<'tx>,
73+
phy_address: PhyAddress,
5874
}
5975

6076
impl<'rx, 'tx> Eth<'rx, 'tx> {
6177
/// Initialize and start tx and rx DMA engines.
6278
///
63-
/// You must call [`setup()`](fn.setup.html) before to initialize
64-
/// the hardware!
65-
///
6679
/// Make sure that the buffers reside in a memory region that is
6780
/// accessible by the peripheral. Core-Coupled Memory (CCM) is
68-
/// usually not.
81+
/// usually not accessible. Also, HCLK must be between 25MHz and 168MHz to use the ethernet
82+
/// peripheral.
6983
///
7084
/// Other than that, initializes and starts the Ethernet hardware
7185
/// so that you can [`send()`](#method.send) and
7286
/// [`recv_next()`](#method.recv_next).
73-
pub fn new(
87+
pub fn new<REFCLK, IO, CLK, CRS, TXEN, TXD0, TXD1, RXD0, RXD1>(
7488
eth_mac: ETHERNET_MAC,
7589
eth_dma: ETHERNET_DMA,
7690
rx_buffer: &'rx mut [RxRingEntry],
7791
tx_buffer: &'tx mut [TxRingEntry],
78-
) -> Self {
92+
phy_address: PhyAddress,
93+
clocks: Clocks,
94+
pins: EthPins<REFCLK, IO, CLK, CRS, TXEN, TXD0, TXD1, RXD0, RXD1>,
95+
) -> Result<Self, WrongClock>
96+
where
97+
REFCLK: RmiiRefClk + AlternateVeryHighSpeed,
98+
IO: MDIO + AlternateVeryHighSpeed,
99+
CLK: MDC + AlternateVeryHighSpeed,
100+
CRS: RmiiCrsDv + AlternateVeryHighSpeed,
101+
TXEN: RmiiTxEN + AlternateVeryHighSpeed,
102+
TXD0: RmiiTxD0 + AlternateVeryHighSpeed,
103+
TXD1: RmiiTxD1 + AlternateVeryHighSpeed,
104+
RXD0: RmiiRxD0 + AlternateVeryHighSpeed,
105+
RXD1: RmiiRxD1 + AlternateVeryHighSpeed,
106+
{
107+
setup::setup();
108+
pins.setup_pins();
79109
let mut eth = Eth {
80110
eth_mac,
81111
eth_dma,
82112
rx_ring: RxRing::new(rx_buffer),
83113
tx_ring: TxRing::new(tx_buffer),
114+
phy_address,
84115
};
85-
eth.init();
116+
eth.init(clocks)?;
86117
eth.rx_ring.start(&eth.eth_dma);
87118
eth.tx_ring.start(&eth.eth_dma);
88-
eth
119+
Ok(eth)
89120
}
90121

91-
fn init(&mut self) -> &Self {
122+
fn init(&mut self, clocks: Clocks) -> Result<(), WrongClock> {
123+
let clock_range = match clocks.hclk().0 {
124+
60_000_000..=99_000_000 => ETH_MACMIIAR_CR_HCLK_DIV_42,
125+
100_000_000..=149_000_000 => ETH_MACMIIAR_CR_HCLK_DIV_62,
126+
25_000_000..=34_000_000 => ETH_MACMIIAR_CR_HCLK_DIV_16,
127+
35_000_000..=59_000_000 => ETH_MACMIIAR_CR_HCLK_DIV_26,
128+
150_000_000..=168_000_000 => ETH_MACMIIAR_CR_HCLK_DIV_102,
129+
_ => return Err(WrongClock),
130+
};
92131
self.reset_dma_and_wait();
93132

94133
// set clock range in MAC MII address register
95-
let clock_range = ETH_MACMIIAR_CR_HCLK_DIV_16;
96134
self.eth_mac
97135
.macmiiar
98136
.modify(|_, w| unsafe { w.cr().bits(clock_range) });
@@ -179,8 +217,7 @@ impl<'rx, 'tx> Eth<'rx, 'tx> {
179217
.usp()
180218
.set_bit()
181219
});
182-
183-
self
220+
Ok(())
184221
}
185222

186223
/// reset DMA bus mode register
@@ -226,7 +263,11 @@ impl<'rx, 'tx> Eth<'rx, 'tx> {
226263

227264
/// Construct a PHY driver
228265
pub fn get_phy(&self) -> Phy {
229-
Phy::new(&self.eth_mac.macmiiar, &self.eth_mac.macmiidr, PHY_ADDR)
266+
Phy::new(
267+
&self.eth_mac.macmiiar,
268+
&self.eth_mac.macmiidr,
269+
self.phy_address as u8,
270+
)
230271
}
231272

232273
/// Obtain PHY status

src/setup.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,8 @@ const ETH_TX_BIT: u8 = 26;
1818
const ETH_RX_BIT: u8 = 27;
1919
const MII_RMII_BIT: u8 = 23;
2020

21-
/// Initialize GPIO pins. Enable syscfg and ethernet clocks. Reset the
22-
/// Ethernet MAC.
23-
///
24-
/// If supported, you should also call `setup_pins()`.
25-
pub fn setup() {
21+
// Enable syscfg and ethernet clocks. Reset the Ethernet MAC.
22+
pub(crate) fn setup() {
2623
unsafe {
2724
//NOTE(unsafe) This will only be used for atomic writes with no side-effects
2825
let rcc = &*RCC::ptr();
@@ -116,7 +113,7 @@ where
116113
///
117114
/// This function consumes the pins so that you cannot use them
118115
/// anywhere else by accident.
119-
pub fn setup(self) {
116+
pub fn setup_pins(self) {
120117
self.ref_clk.into_af11_very_high_speed();
121118
self.md_io.into_af11_very_high_speed();
122119
self.md_clk.into_af11_very_high_speed();

0 commit comments

Comments
 (0)