1
+ // cargo build --example arp --features=stm32f407,smi
2
+ // This example uses the STM32F407 and the KSZ8051R as PHY. If necessary the pins,
3
+ // the PHY register addresses and masks have to be adapted, as well as the IPs.
4
+ // With Wireshark, you can see the ARP packets, which should look like this:
5
+ // No. Time Source Destination Protocol Length Info
6
+ // 1 0.000000000 Cetia_ad:be:ef Broadcast ARP 60 Who has 10.0.0.2? Tell 10.0.0.10
7
+
1
8
#![ no_std]
2
9
#![ no_main]
3
10
@@ -10,15 +17,21 @@ use cortex_m_rt::{entry, exception};
10
17
use cortex_m:: asm;
11
18
use cortex_m:: interrupt:: Mutex ;
12
19
use stm32_eth:: {
13
- hal:: gpio:: GpioExt ,
20
+ hal:: gpio:: { GpioExt , Speed } ,
14
21
hal:: rcc:: RccExt ,
15
22
hal:: time:: U32Ext ,
23
+ smi,
16
24
stm32:: { interrupt, CorePeripherals , Peripherals , SYST } ,
17
25
} ;
18
26
19
27
use cortex_m_semihosting:: hprintln;
20
28
21
- use stm32_eth:: { Eth , EthPins , PhyAddress , RingEntry , TxError } ;
29
+ use stm32_eth:: { Eth , EthPins , RingEntry , TxError } ;
30
+
31
+ const PHY_REG_BSR : u8 = 0x01 ;
32
+ const PHY_REG_BSR_UP : u16 = 1 << 2 ;
33
+
34
+ const PHY_ADDR : u8 = 0 ;
22
35
23
36
static TIME : Mutex < RefCell < usize > > = Mutex :: new ( RefCell :: new ( 0 ) ) ;
24
37
static ETH_PENDING : Mutex < RefCell < bool > > = Mutex :: new ( RefCell :: new ( false ) ) ;
@@ -38,75 +51,65 @@ fn main() -> ! {
38
51
let gpioa = p. GPIOA . split ( ) ;
39
52
let gpiob = p. GPIOB . split ( ) ;
40
53
let gpioc = p. GPIOC . split ( ) ;
41
- // let gpiog = p.GPIOG.split();
54
+ let gpiog = p. GPIOG . split ( ) ;
42
55
43
56
let eth_pins = EthPins {
44
57
ref_clk : gpioa. pa1 ,
45
- md_io : gpioa. pa2 ,
46
- md_clk : gpioc. pc1 ,
47
58
crs : gpioa. pa7 ,
48
59
tx_en : gpiob. pb11 ,
49
- tx_d0 : gpiob . pb12 ,
50
- tx_d1 : gpiob . pb13 ,
60
+ tx_d0 : gpiog . pg13 ,
61
+ tx_d1 : gpiog . pg14 ,
51
62
rx_d0 : gpioc. pc4 ,
52
63
rx_d1 : gpioc. pc5 ,
53
64
} ;
54
65
66
+ let mut mdio = gpioa. pa2 . into_alternate ( ) . set_speed ( Speed :: VeryHigh ) ;
67
+ let mut mdc = gpioc. pc1 . into_alternate ( ) . set_speed ( Speed :: VeryHigh ) ;
68
+
69
+ // ETH_PHY_RESET(RST#) PB2 Chip Reset (active-low)
70
+ let _eth_reset = gpiob. pb2 . into_push_pull_output ( ) . set_high ( ) ;
71
+
55
72
let mut rx_ring: [ RingEntry < _ > ; 16 ] = Default :: default ( ) ;
56
73
let mut tx_ring: [ RingEntry < _ > ; 8 ] = Default :: default ( ) ;
57
74
let mut eth = Eth :: new (
58
75
p. ETHERNET_MAC ,
59
76
p. ETHERNET_DMA ,
60
77
& mut rx_ring[ ..] ,
61
78
& mut tx_ring[ ..] ,
62
- PhyAddress :: _1,
63
79
clocks,
64
80
eth_pins,
65
81
)
66
82
. unwrap ( ) ;
67
83
eth. enable_interrupt ( ) ;
68
84
69
- let mut last_status = None ;
85
+ let mut last_link_up = false ;
70
86
71
87
loop {
72
- let status = eth. status ( ) ;
88
+ let link_up = link_detected ( eth. smi ( & mut mdio , & mut mdc ) ) ;
73
89
74
- if last_status
75
- . map ( |last_status| last_status != status)
76
- . unwrap_or ( true )
77
- {
78
- if !status. link_detected ( ) {
79
- hprintln ! ( "Ethernet: no link detected" ) . unwrap ( ) ;
90
+ if link_up != last_link_up {
91
+ if link_up {
92
+ hprintln ! ( "Ethernet: link detected" ) . unwrap ( ) ;
80
93
} else {
81
- hprintln ! (
82
- "Ethernet: link detected with {} Mbps/{}" ,
83
- status. speed( ) ,
84
- match status. is_full_duplex( ) {
85
- Some ( true ) => "FD" ,
86
- Some ( false ) => "HD" ,
87
- None => "?" ,
88
- }
89
- )
90
- . unwrap ( ) ;
94
+ hprintln ! ( "Ethernet: no link detected" ) . unwrap ( ) ;
91
95
}
92
-
93
- last_status = Some ( status) ;
96
+ last_link_up = link_up;
94
97
}
95
98
96
- if status . link_detected ( ) {
99
+ if link_up {
97
100
const SIZE : usize = 42 ;
98
101
99
102
const DST_MAC : [ u8 ; 6 ] = [ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ] ;
100
103
const SRC_MAC : [ u8 ; 6 ] = [ 0x00 , 0x00 , 0xDE , 0xAD , 0xBE , 0xEF ] ;
101
104
const ETH_TYPE : [ u8 ; 2 ] = [ 0x08 , 0x06 ] ; // ARP
102
- const HTYPE : [ u8 ; 2 ] = [ 0x00 , 0x01 ] ;
105
+ const HTYPE : [ u8 ; 2 ] = [ 0x00 , 0x01 ] ; // Hardware Type: ethernet
103
106
const PTYPE : [ u8 ; 2 ] = [ 0x08 , 0x00 ] ; // IP
104
107
const HLEN : [ u8 ; 1 ] = [ 0x06 ] ; // MAC length
105
108
const PLEN : [ u8 ; 1 ] = [ 0x04 ] ; // IPv4
106
- const OPER : [ u8 ; 2 ] = [ 0x00 , 0x01 ] ;
107
- const SENDER_IP : [ u8 ; 4 ] = [ 0xc0 , 0xa8 , 0x01 , 0x64 ] ; // 192.168.1.100
109
+ const OPER : [ u8 ; 2 ] = [ 0x00 , 0x01 ] ; // Operation: request
110
+ const SENDER_IP : [ u8 ; 4 ] = [ 0x0A , 00 , 0x00 , 0x0A ] ; // 10.0.0.10
108
111
const TARGET_MAC : [ u8 ; 6 ] = [ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ] ;
109
- const TARGET_IP : [ u8 ; 4 ] = [ 0xc0 , 0xa8 , 0x01 , 0xFE ] ;
112
+ const TARGET_IP : [ u8 ; 4 ] = [ 0x0A , 0x00 , 0x00 , 0x02 ] ; // 10.0.0.2
110
113
111
114
let r = eth. send ( SIZE , |buf| {
112
115
buf[ 0 ..6 ] . copy_from_slice ( & DST_MAC ) ;
@@ -171,3 +174,12 @@ fn ETH() {
171
174
let p = unsafe { Peripherals :: steal ( ) } ;
172
175
stm32_eth:: eth_interrupt_handler ( & p. ETHERNET_DMA ) ;
173
176
}
177
+
178
+ fn link_detected < Mdio , Mdc > ( smi : smi:: Smi < Mdio , Mdc > ) -> bool
179
+ where
180
+ Mdio : smi:: MdioPin ,
181
+ Mdc : smi:: MdcPin ,
182
+ {
183
+ let status = smi. read ( PHY_ADDR , PHY_REG_BSR ) ;
184
+ ( status & PHY_REG_BSR_UP ) == PHY_REG_BSR_UP
185
+ }
0 commit comments