4
4
pub use stm32f4xx_hal as hal;
5
5
/// Re-export
6
6
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
+ } ;
8
11
9
12
pub mod phy;
10
13
use phy:: { Phy , PhyStatus } ;
@@ -19,7 +22,11 @@ mod tx;
19
22
pub use tx:: { TxDescriptor , TxError } ;
20
23
use tx:: { TxRing , TxRingEntry } ;
21
24
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
+ } ;
23
30
24
31
#[ cfg( feature = "smoltcp-phy" ) ]
25
32
pub use smoltcp;
@@ -28,11 +35,9 @@ mod smoltcp_phy;
28
35
#[ cfg( feature = "smoltcp-phy" ) ]
29
36
pub use smoltcp_phy:: { EthRxToken , EthTxToken } ;
30
37
31
- const PHY_ADDR : u8 = 0 ;
32
38
/// From the datasheet: *VLAN Frame maxsize = 1522*
33
39
const MTU : usize = 1522 ;
34
40
35
- #[ allow( dead_code) ]
36
41
mod consts {
37
42
/* For HCLK 60-100 MHz */
38
43
pub const ETH_MACMIIAR_CR_HCLK_DIV_42 : u8 = 0 ;
@@ -47,52 +52,85 @@ mod consts {
47
52
}
48
53
use self :: consts:: * ;
49
54
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).
53
68
pub struct Eth < ' rx , ' tx > {
54
69
eth_mac : ETHERNET_MAC ,
55
70
eth_dma : ETHERNET_DMA ,
56
71
rx_ring : RxRing < ' rx > ,
57
72
tx_ring : TxRing < ' tx > ,
73
+ phy_address : PhyAddress ,
58
74
}
59
75
60
76
impl < ' rx , ' tx > Eth < ' rx , ' tx > {
61
77
/// Initialize and start tx and rx DMA engines.
62
78
///
63
- /// You must call [`setup()`](fn.setup.html) before to initialize
64
- /// the hardware!
65
- ///
66
79
/// Make sure that the buffers reside in a memory region that is
67
80
/// 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.
69
83
///
70
84
/// Other than that, initializes and starts the Ethernet hardware
71
85
/// so that you can [`send()`](#method.send) and
72
86
/// [`recv_next()`](#method.recv_next).
73
- pub fn new (
87
+ pub fn new < REFCLK , IO , CLK , CRS , TXEN , TXD0 , TXD1 , RXD0 , RXD1 > (
74
88
eth_mac : ETHERNET_MAC ,
75
89
eth_dma : ETHERNET_DMA ,
76
90
rx_buffer : & ' rx mut [ RxRingEntry ] ,
77
91
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 ( ) ;
79
109
let mut eth = Eth {
80
110
eth_mac,
81
111
eth_dma,
82
112
rx_ring : RxRing :: new ( rx_buffer) ,
83
113
tx_ring : TxRing :: new ( tx_buffer) ,
114
+ phy_address,
84
115
} ;
85
- eth. init ( ) ;
116
+ eth. init ( clocks ) ? ;
86
117
eth. rx_ring . start ( & eth. eth_dma ) ;
87
118
eth. tx_ring . start ( & eth. eth_dma ) ;
88
- eth
119
+ Ok ( eth)
89
120
}
90
121
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
+ } ;
92
131
self . reset_dma_and_wait ( ) ;
93
132
94
133
// set clock range in MAC MII address register
95
- let clock_range = ETH_MACMIIAR_CR_HCLK_DIV_16 ;
96
134
self . eth_mac
97
135
. macmiiar
98
136
. modify ( |_, w| unsafe { w. cr ( ) . bits ( clock_range) } ) ;
@@ -179,8 +217,7 @@ impl<'rx, 'tx> Eth<'rx, 'tx> {
179
217
. usp ( )
180
218
. set_bit ( )
181
219
} ) ;
182
-
183
- self
220
+ Ok ( ( ) )
184
221
}
185
222
186
223
/// reset DMA bus mode register
@@ -226,7 +263,11 @@ impl<'rx, 'tx> Eth<'rx, 'tx> {
226
263
227
264
/// Construct a PHY driver
228
265
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
+ )
230
271
}
231
272
232
273
/// Obtain PHY status
0 commit comments