Skip to content

Commit 0ab4556

Browse files
authored
Merge pull request #26 from jiayihu/arp-example
Add ARP examples
2 parents db6c118 + 18e2c25 commit 0ab4556

File tree

3 files changed

+354
-0
lines changed

3 files changed

+354
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ required-features = [
7474
"smoltcp/log", "smoltcp/verbose"
7575
]
7676

77+
[[example]]
78+
name = "arp-smoltcp"
79+
required-features = ["stm32f429", "smoltcp-phy"]
80+
7781
[profile.release]
7882
debug = 2
7983
lto = true

examples/arp-smoltcp.rs

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
extern crate panic_itm;
5+
6+
use core::cell::RefCell;
7+
use core::default::Default;
8+
use cortex_m_rt::{entry, exception};
9+
10+
use cortex_m::asm;
11+
use cortex_m::interrupt::Mutex;
12+
use stm32_eth::{
13+
hal::gpio::GpioExt,
14+
hal::rcc::RccExt,
15+
hal::time::U32Ext,
16+
stm32::{interrupt, CorePeripherals, Peripherals, SYST},
17+
};
18+
19+
use cortex_m_semihosting::hprintln;
20+
21+
use smoltcp::wire::{
22+
ArpOperation, ArpPacket, ArpRepr, EthernetAddress, EthernetFrame, EthernetProtocol,
23+
EthernetRepr, Ipv4Address,
24+
};
25+
use stm32_eth::{Eth, EthPins, PhyAddress, RingEntry, TxError};
26+
27+
static TIME: Mutex<RefCell<usize>> = Mutex::new(RefCell::new(0));
28+
static ETH_PENDING: Mutex<RefCell<bool>> = Mutex::new(RefCell::new(false));
29+
30+
#[entry]
31+
fn main() -> ! {
32+
let p = Peripherals::take().unwrap();
33+
let mut cp = CorePeripherals::take().unwrap();
34+
35+
let rcc = p.RCC.constrain();
36+
// HCLK must be at least 25MHz to use the ethernet peripheral
37+
let clocks = rcc.cfgr.sysclk(32.mhz()).hclk(32.mhz()).freeze();
38+
39+
setup_systick(&mut cp.SYST);
40+
41+
hprintln!("Enabling ethernet...").unwrap();
42+
let gpioa = p.GPIOA.split();
43+
let gpiob = p.GPIOB.split();
44+
let gpioc = p.GPIOC.split();
45+
// let gpiog = p.GPIOG.split();
46+
47+
let eth_pins = EthPins {
48+
ref_clk: gpioa.pa1,
49+
md_io: gpioa.pa2,
50+
md_clk: gpioc.pc1,
51+
crs: gpioa.pa7,
52+
tx_en: gpiob.pb11,
53+
tx_d0: gpiob.pb12,
54+
tx_d1: gpiob.pb13,
55+
rx_d0: gpioc.pc4,
56+
rx_d1: gpioc.pc5,
57+
};
58+
59+
let mut rx_ring: [RingEntry<_>; 16] = Default::default();
60+
let mut tx_ring: [RingEntry<_>; 8] = Default::default();
61+
let mut eth = Eth::new(
62+
p.ETHERNET_MAC,
63+
p.ETHERNET_DMA,
64+
&mut rx_ring[..],
65+
&mut tx_ring[..],
66+
PhyAddress::_1,
67+
clocks,
68+
eth_pins,
69+
)
70+
.unwrap();
71+
eth.enable_interrupt();
72+
73+
let mut last_status = None;
74+
75+
loop {
76+
let status = eth.status();
77+
78+
if last_status
79+
.map(|last_status| last_status != status)
80+
.unwrap_or(true)
81+
{
82+
if !status.link_detected() {
83+
hprintln!("Ethernet: no link detected").unwrap();
84+
} else {
85+
hprintln!(
86+
"Ethernet: link detected with {} Mbps/{}",
87+
status.speed(),
88+
match status.is_full_duplex() {
89+
Some(true) => "FD",
90+
Some(false) => "HD",
91+
None => "?",
92+
}
93+
)
94+
.unwrap();
95+
}
96+
97+
last_status = Some(status);
98+
}
99+
100+
if status.link_detected() {
101+
const SIZE: usize = 14 + 28; // ETH + ARP
102+
103+
let src_mac = EthernetAddress::from_bytes(&[0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]);
104+
105+
let arp_buffer = [0; 28];
106+
let mut packet =
107+
ArpPacket::new_checked(arp_buffer).expect("ArpPacket: buffer size is not correct");
108+
let arp = ArpRepr::EthernetIpv4 {
109+
operation: ArpOperation::Request,
110+
source_hardware_addr: src_mac,
111+
source_protocol_addr: Ipv4Address::new(192, 168, 1, 100),
112+
target_hardware_addr: EthernetAddress::from_bytes(&[0x00; 6]),
113+
target_protocol_addr: Ipv4Address::new(192, 168, 1, 254),
114+
};
115+
arp.emit(&mut packet);
116+
117+
let eth_buffer = [0; SIZE]; // ETH + ARP
118+
let mut frame = EthernetFrame::new_checked(eth_buffer)
119+
.expect("EthernetFrame: buffer size is not correct");
120+
let header = EthernetRepr {
121+
src_addr: src_mac,
122+
dst_addr: EthernetAddress::BROADCAST,
123+
ethertype: EthernetProtocol::Arp,
124+
};
125+
header.emit(&mut frame);
126+
frame.payload_mut().copy_from_slice(&packet.into_inner());
127+
128+
let r = eth.send(SIZE, |buf| {
129+
buf[0..SIZE].copy_from_slice(&frame.into_inner());
130+
});
131+
132+
match r {
133+
Ok(()) => {
134+
hprintln!("ARP-smoltcp sent").unwrap();
135+
}
136+
Err(TxError::WouldBlock) => hprintln!("ARP failed").unwrap(),
137+
}
138+
} else {
139+
hprintln!("Down").unwrap();
140+
}
141+
142+
cortex_m::interrupt::free(|cs| {
143+
let mut eth_pending = ETH_PENDING.borrow(cs).borrow_mut();
144+
*eth_pending = false;
145+
146+
if !*eth_pending {
147+
asm::wfi();
148+
}
149+
});
150+
}
151+
}
152+
153+
fn setup_systick(syst: &mut SYST) {
154+
syst.set_reload(100 * SYST::get_ticks_per_10ms());
155+
syst.enable_counter();
156+
syst.enable_interrupt();
157+
}
158+
159+
#[exception]
160+
fn SysTick() {
161+
cortex_m::interrupt::free(|cs| {
162+
let mut time = TIME.borrow(cs).borrow_mut();
163+
*time += 1;
164+
})
165+
}
166+
167+
#[interrupt]
168+
fn ETH() {
169+
cortex_m::interrupt::free(|cs| {
170+
let mut eth_pending = ETH_PENDING.borrow(cs).borrow_mut();
171+
*eth_pending = true;
172+
});
173+
174+
// Clear interrupt flags
175+
let p = unsafe { Peripherals::steal() };
176+
stm32_eth::eth_interrupt_handler(&p.ETHERNET_DMA);
177+
}

examples/arp.rs

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
extern crate panic_itm;
5+
6+
use core::cell::RefCell;
7+
use core::default::Default;
8+
use cortex_m_rt::{entry, exception};
9+
10+
use cortex_m::asm;
11+
use cortex_m::interrupt::Mutex;
12+
use stm32_eth::{
13+
hal::gpio::GpioExt,
14+
hal::rcc::RccExt,
15+
hal::time::U32Ext,
16+
stm32::{interrupt, CorePeripherals, Peripherals, SYST},
17+
};
18+
19+
use cortex_m_semihosting::hprintln;
20+
21+
use stm32_eth::{Eth, EthPins, PhyAddress, RingEntry, TxError};
22+
23+
static TIME: Mutex<RefCell<usize>> = Mutex::new(RefCell::new(0));
24+
static ETH_PENDING: Mutex<RefCell<bool>> = Mutex::new(RefCell::new(false));
25+
26+
#[entry]
27+
fn main() -> ! {
28+
let p = Peripherals::take().unwrap();
29+
let mut cp = CorePeripherals::take().unwrap();
30+
31+
let rcc = p.RCC.constrain();
32+
// HCLK must be at least 25MHz to use the ethernet peripheral
33+
let clocks = rcc.cfgr.sysclk(32.mhz()).hclk(32.mhz()).freeze();
34+
35+
setup_systick(&mut cp.SYST);
36+
37+
hprintln!("Enabling ethernet...").unwrap();
38+
let gpioa = p.GPIOA.split();
39+
let gpiob = p.GPIOB.split();
40+
let gpioc = p.GPIOC.split();
41+
// let gpiog = p.GPIOG.split();
42+
43+
let eth_pins = EthPins {
44+
ref_clk: gpioa.pa1,
45+
md_io: gpioa.pa2,
46+
md_clk: gpioc.pc1,
47+
crs: gpioa.pa7,
48+
tx_en: gpiob.pb11,
49+
tx_d0: gpiob.pb12,
50+
tx_d1: gpiob.pb13,
51+
rx_d0: gpioc.pc4,
52+
rx_d1: gpioc.pc5,
53+
};
54+
55+
let mut rx_ring: [RingEntry<_>; 16] = Default::default();
56+
let mut tx_ring: [RingEntry<_>; 8] = Default::default();
57+
let mut eth = Eth::new(
58+
p.ETHERNET_MAC,
59+
p.ETHERNET_DMA,
60+
&mut rx_ring[..],
61+
&mut tx_ring[..],
62+
PhyAddress::_1,
63+
clocks,
64+
eth_pins,
65+
)
66+
.unwrap();
67+
eth.enable_interrupt();
68+
69+
let mut last_status = None;
70+
71+
loop {
72+
let status = eth.status();
73+
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();
80+
} 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();
91+
}
92+
93+
last_status = Some(status);
94+
}
95+
96+
if status.link_detected() {
97+
const SIZE: usize = 42;
98+
99+
const DST_MAC: [u8; 6] = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
100+
const SRC_MAC: [u8; 6] = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
101+
const ETH_TYPE: [u8; 2] = [0x08, 0x06]; // ARP
102+
const HTYPE: [u8; 2] = [0x00, 0x01];
103+
const PTYPE: [u8; 2] = [0x08, 0x00]; // IP
104+
const HLEN: [u8; 1] = [0x06]; // MAC length
105+
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
108+
const TARGET_MAC: [u8; 6] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
109+
const TARGET_IP: [u8; 4] = [0xc0, 0xa8, 0x01, 0xFE];
110+
111+
let r = eth.send(SIZE, |buf| {
112+
buf[0..6].copy_from_slice(&DST_MAC);
113+
buf[6..12].copy_from_slice(&SRC_MAC);
114+
buf[12..14].copy_from_slice(&ETH_TYPE);
115+
buf[14..16].copy_from_slice(&HTYPE);
116+
117+
buf[16..18].copy_from_slice(&PTYPE);
118+
buf[18..19].copy_from_slice(&HLEN);
119+
buf[19..20].copy_from_slice(&PLEN);
120+
buf[20..22].copy_from_slice(&OPER);
121+
buf[22..28].copy_from_slice(&SRC_MAC);
122+
buf[28..32].copy_from_slice(&SENDER_IP);
123+
124+
buf[32..38].copy_from_slice(&TARGET_MAC);
125+
buf[38..42].copy_from_slice(&TARGET_IP);
126+
});
127+
128+
match r {
129+
Ok(()) => {
130+
hprintln!("ARP sent").unwrap();
131+
}
132+
Err(TxError::WouldBlock) => hprintln!("ARP failed").unwrap(),
133+
}
134+
} else {
135+
hprintln!("Down").unwrap();
136+
}
137+
138+
cortex_m::interrupt::free(|cs| {
139+
let mut eth_pending = ETH_PENDING.borrow(cs).borrow_mut();
140+
*eth_pending = false;
141+
142+
if !*eth_pending {
143+
asm::wfi();
144+
}
145+
});
146+
}
147+
}
148+
149+
fn setup_systick(syst: &mut SYST) {
150+
syst.set_reload(100 * SYST::get_ticks_per_10ms());
151+
syst.enable_counter();
152+
syst.enable_interrupt();
153+
}
154+
155+
#[exception]
156+
fn SysTick() {
157+
cortex_m::interrupt::free(|cs| {
158+
let mut time = TIME.borrow(cs).borrow_mut();
159+
*time += 1;
160+
})
161+
}
162+
163+
#[interrupt]
164+
fn ETH() {
165+
cortex_m::interrupt::free(|cs| {
166+
let mut eth_pending = ETH_PENDING.borrow(cs).borrow_mut();
167+
*eth_pending = true;
168+
});
169+
170+
// Clear interrupt flags
171+
let p = unsafe { Peripherals::steal() };
172+
stm32_eth::eth_interrupt_handler(&p.ETHERNET_DMA);
173+
}

0 commit comments

Comments
 (0)