1
+ //! An abstraction layer for ethernet periperhals embedded in STM32 processors.
2
+ //!
3
+ //! For initialisation, see [`new_no_smi`], [`new_borrowed_smi`], and [`new_owned_smi`]
1
4
#![ no_std]
2
5
3
6
/// Re-export
@@ -28,6 +31,8 @@ mod ring;
28
31
pub mod smi;
29
32
pub use ring:: RingEntry ;
30
33
mod desc;
34
+ mod mac;
35
+ pub use mac:: * ;
31
36
mod rx;
32
37
pub use rx:: { RxDescriptor , RxError , RxRingEntry } ;
33
38
use rx:: { RxPacket , RxRing } ;
@@ -47,6 +52,11 @@ mod smoltcp_phy;
47
52
#[ cfg( feature = "smoltcp-phy" ) ]
48
53
pub use smoltcp_phy:: { EthRxToken , EthTxToken } ;
49
54
55
+ #[ cfg( feature = "phy" ) ]
56
+ mod phy;
57
+ #[ cfg( feature = "phy" ) ]
58
+ pub use phy:: * ;
59
+
50
60
/// From the datasheet: *VLAN Frame maxsize = 1522*
51
61
const MTU : usize = 1522 ;
52
62
@@ -74,11 +84,57 @@ pub struct EthernetDMA<'rx, 'tx> {
74
84
rx_ring : RxRing < ' rx > ,
75
85
tx_ring : TxRing < ' tx > ,
76
86
}
77
- /// Ethernet media access control (MAC).
78
- pub struct EthernetMAC {
79
- eth_mac : ETHERNET_MAC ,
87
+
88
+ macro_rules! new {
89
+ ( $name: ident, $smi_ty: ty) => {
90
+ /// Create and initialise the ethernet driver.
91
+ ///
92
+ /// Initialize and start tx and rx DMA engines.
93
+ /// Sets up the peripheral clocks and GPIO configuration,
94
+ /// and configures the ETH MAC and DMA peripherals.
95
+ /// Automatically sets slew rate to VeryHigh.
96
+ /// If you wish to use another configuration, please see
97
+ /// [new_unchecked](new_unchecked).
98
+ ///
99
+ /// This method does not initialise the external PHY.
100
+ ///
101
+ /// Interacting with a PHY can be done through a struct that implementes the
102
+ /// [`smi::StationManagement`] trait.
103
+ ///
104
+ /// In the case of `new_borrowed_smi` you may access SMI through the [`EthernetMAC::smi`] function.
105
+ ///
106
+ /// In the case of `new_no_smi`, the SMI may be accessed by constructing a new [`smi::Smi`] before passing
107
+ /// the `ETHERNET_MAC` to the `new_no_smi` function.
108
+ pub fn $name<' rx, ' tx, REFCLK , CRS , TXEN , TXD0 , TXD1 , RXD0 , RXD1 >(
109
+ eth_mac: ETHERNET_MAC ,
110
+ eth_mmc: ETHERNET_MMC ,
111
+ eth_dma: ETHERNET_DMA ,
112
+ rx_buffer: & ' rx mut [ RxRingEntry ] ,
113
+ tx_buffer: & ' tx mut [ TxRingEntry ] ,
114
+ clocks: Clocks ,
115
+ pins: EthPins <REFCLK , CRS , TXEN , TXD0 , TXD1 , RXD0 , RXD1 >,
116
+ ) -> Result <( EthernetDMA <' rx, ' tx>, EthernetMAC <$smi_ty>) , WrongClock >
117
+ where
118
+ REFCLK : RmiiRefClk + AlternateVeryHighSpeed ,
119
+ CRS : RmiiCrsDv + AlternateVeryHighSpeed ,
120
+ TXEN : RmiiTxEN + AlternateVeryHighSpeed ,
121
+ TXD0 : RmiiTxD0 + AlternateVeryHighSpeed ,
122
+ TXD1 : RmiiTxD1 + AlternateVeryHighSpeed ,
123
+ RXD0 : RmiiRxD0 + AlternateVeryHighSpeed ,
124
+ RXD1 : RmiiRxD1 + AlternateVeryHighSpeed ,
125
+ {
126
+ pins. setup_pins( ) ;
127
+
128
+ let eth_mac = EthernetMAC :: <$smi_ty>:: new( eth_mac) ;
129
+
130
+ unsafe { new_unchecked( eth_mac, eth_mmc, eth_dma, rx_buffer, tx_buffer, clocks) }
131
+ }
132
+ } ;
80
133
}
81
134
135
+ new ! ( new_no_smi, NoSmi ) ;
136
+ new ! ( new_borrowed_smi, BorrowedSmi ) ;
137
+
82
138
/// Create and initialise the ethernet driver.
83
139
///
84
140
/// Initialize and start tx and rx DMA engines.
@@ -88,25 +144,32 @@ pub struct EthernetMAC {
88
144
/// If you wish to use another configuration, please see
89
145
/// [new_unchecked](new_unchecked).
90
146
///
91
- /// This method does not initialise the external PHY. However it does return an
92
- /// [EthernetMAC](EthernetMAC) which implements the
93
- /// [StationManagement](smi::StationManagement) trait. This can be used to
94
- /// communicate with the external PHY.
147
+ /// This method does not initialise the external PHY. The SMI for the external PHY
148
+ /// can be accessed through a struct that implements the [`smi::StationManagement`] trait,
149
+ /// which [`EthernetMAC<OwnedSmi>`] does.
95
150
///
96
151
/// # Note
97
152
/// - Make sure that the buffers reside in a memory region that is
98
153
/// accessible by the peripheral. Core-Coupled Memory (CCM) is
99
154
/// usually not accessible.
100
155
/// - HCLK must be at least 25 MHz.
101
- pub fn new < ' rx , ' tx , REFCLK , CRS , TXEN , TXD0 , TXD1 , RXD0 , RXD1 > (
156
+ pub fn new_owned_smi < ' rx , ' tx , REFCLK , CRS , TXEN , TXD0 , TXD1 , RXD0 , RXD1 , MDIO , MDC > (
102
157
eth_mac : ETHERNET_MAC ,
103
158
eth_mmc : ETHERNET_MMC ,
104
159
eth_dma : ETHERNET_DMA ,
105
160
rx_buffer : & ' rx mut [ RxRingEntry ] ,
106
161
tx_buffer : & ' tx mut [ TxRingEntry ] ,
107
162
clocks : Clocks ,
108
163
pins : EthPins < REFCLK , CRS , TXEN , TXD0 , TXD1 , RXD0 , RXD1 > ,
109
- ) -> Result < ( EthernetDMA < ' rx , ' tx > , EthernetMAC ) , WrongClock >
164
+ mdio : MDIO ,
165
+ mdc : MDC ,
166
+ ) -> Result <
167
+ (
168
+ EthernetDMA < ' rx , ' tx > ,
169
+ EthernetMAC < crate :: mac:: OwnedSmi < MDIO , MDC > > ,
170
+ ) ,
171
+ WrongClock ,
172
+ >
110
173
where
111
174
REFCLK : RmiiRefClk + AlternateVeryHighSpeed ,
112
175
CRS : RmiiCrsDv + AlternateVeryHighSpeed ,
@@ -115,8 +178,13 @@ where
115
178
TXD1 : RmiiTxD1 + AlternateVeryHighSpeed ,
116
179
RXD0 : RmiiRxD0 + AlternateVeryHighSpeed ,
117
180
RXD1 : RmiiRxD1 + AlternateVeryHighSpeed ,
181
+ MDIO : smi:: MdioPin ,
182
+ MDC : smi:: MdcPin ,
118
183
{
119
184
pins. setup_pins ( ) ;
185
+
186
+ let eth_mac = EthernetMAC :: new_owned ( eth_mac, mdio, mdc) ;
187
+
120
188
unsafe { new_unchecked ( eth_mac, eth_mmc, eth_dma, rx_buffer, tx_buffer, clocks) }
121
189
}
122
190
@@ -132,16 +200,18 @@ where
132
200
/// accessible by the peripheral. Core-Coupled Memory (CCM) is
133
201
/// usually not accessible.
134
202
/// - HCLK must be at least 25MHz.
135
- pub unsafe fn new_unchecked < ' rx , ' tx > (
136
- eth_mac : ETHERNET_MAC ,
203
+ pub unsafe fn new_unchecked < ' rx , ' tx , Smi > (
204
+ eth_mac_in : EthernetMAC < Smi > ,
137
205
eth_mmc : ETHERNET_MMC ,
138
206
eth_dma : ETHERNET_DMA ,
139
207
rx_buffer : & ' rx mut [ RxRingEntry ] ,
140
208
tx_buffer : & ' tx mut [ TxRingEntry ] ,
141
209
clocks : Clocks ,
142
- ) -> Result < ( EthernetDMA < ' rx , ' tx > , EthernetMAC ) , WrongClock > {
210
+ ) -> Result < ( EthernetDMA < ' rx , ' tx > , EthernetMAC < Smi > ) , WrongClock > {
143
211
setup:: setup ( ) ;
144
212
213
+ let eth_mac = & eth_mac_in. eth_mac ;
214
+
145
215
let clock_frequency = clocks. hclk ( ) . to_Hz ( ) ;
146
216
147
217
let clock_range = match clock_frequency {
@@ -270,12 +340,11 @@ pub unsafe fn new_unchecked<'rx, 'tx>(
270
340
rx_ring : RxRing :: new ( rx_buffer) ,
271
341
tx_ring : TxRing :: new ( tx_buffer) ,
272
342
} ;
273
- let mac = EthernetMAC { eth_mac } ;
274
343
275
344
dma. rx_ring . start ( & dma. eth_dma ) ;
276
345
dma. tx_ring . start ( & dma. eth_dma ) ;
277
346
278
- Ok ( ( dma, mac ) )
347
+ Ok ( ( dma, eth_mac_in ) )
279
348
}
280
349
281
350
impl < ' rx , ' tx > EthernetDMA < ' rx , ' tx > {
@@ -343,28 +412,6 @@ impl<'rx, 'tx> EthernetDMA<'rx, 'tx> {
343
412
}
344
413
}
345
414
346
- #[ cfg( feature = "smi" ) ]
347
- impl EthernetMAC {
348
- /// Borrow access to the MAC's SMI.
349
- ///
350
- /// Allows for controlling and monitoring any PHYs that may be accessible via the MDIO/MDC
351
- /// pins.
352
- ///
353
- /// Exclusive access to the `MDIO` and `MDC` is required to ensure that are not used elsewhere
354
- /// for the duration of SMI communication.
355
- pub fn smi < ' eth , ' pins , Mdio , Mdc > (
356
- & ' eth mut self ,
357
- mdio : & ' pins mut Mdio ,
358
- mdc : & ' pins mut Mdc ,
359
- ) -> smi:: Smi < ' eth , ' pins , Mdio , Mdc >
360
- where
361
- Mdio : smi:: MdioPin ,
362
- Mdc : smi:: MdcPin ,
363
- {
364
- smi:: Smi :: new ( & self . eth_mac . macmiiar , & self . eth_mac . macmiidr , mdio, mdc)
365
- }
366
- }
367
-
368
415
/// A summary of the reasons for the interrupt
369
416
/// that occured
370
417
pub struct InterruptReasonSummary {
0 commit comments