Skip to content

Commit 41be631

Browse files
committed
Add target time configuration with atomic accesses to MACIMR register
1 parent bc217e7 commit 41be631

File tree

7 files changed

+233
-96
lines changed

7 files changed

+233
-96
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ stm32f7xx-hal = { version = "0.7.0", optional = true }
2525
stm32f4xx-hal = { version = "0.14", optional = true }
2626
stm32f4 = { version = "0.15", optional = true }
2727
stm32f1xx-hal = { version = "0.10", optional = true }
28-
ieee802_3_miim = "0.7"
28+
ieee802_3_miim = "0.8"
2929
cortex-m = "0.7"
3030
log = { version = "0.4", optional = true }
3131
defmt = { version = "0.3", optional = true }

examples/common.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,15 +312,19 @@ impl<M: Miim> EthernetPhy<M> {
312312
///
313313
/// Returns an error if the PHY does not support the extended register
314314
/// set, or if the PHY's identifier does not correspond to a known PHY.
315-
pub fn from_miim(miim: M, phy_addr: u8) -> Result<Self, ()> {
315+
pub fn from_miim(miim: M, phy_addr: u8) -> Result<Self, M> {
316316
let mut bare = BarePhy::new(miim, phy_addr, Pause::NoPause);
317-
let phy_ident = bare.phy_ident().ok_or(())?;
317+
let phy_ident = if let Some(id) = bare.phy_ident() {
318+
id.raw_u32()
319+
} else {
320+
return Err(bare.release());
321+
};
318322
let miim = bare.release();
319323
match phy_ident & 0xFFFFFFF0 {
320324
0x0007C0F0 => Ok(Self::LAN8720A(LAN8720A::new(miim, phy_addr))),
321325
0x0007C130 => Ok(Self::LAN8742A(LAN8742A::new(miim, phy_addr))),
322326
0x00221560 => Ok(Self::KSZ8081R(KSZ8081R::new(miim, phy_addr))),
323-
_ => Err(()),
327+
_ => Err(miim),
324328
}
325329
}
326330

@@ -352,4 +356,13 @@ impl<M: Miim> EthernetPhy<M> {
352356
EthernetPhy::KSZ8081R(phy) => phy.link_speed(),
353357
}
354358
}
359+
360+
#[allow(dead_code)]
361+
pub fn release(self) -> M {
362+
match self {
363+
EthernetPhy::LAN8720A(phy) => phy.release(),
364+
EthernetPhy::LAN8742A(phy) => phy.release(),
365+
EthernetPhy::KSZ8081R(phy) => phy.release(),
366+
}
367+
}
355368
}

examples/rtic-timestamp.rs

Lines changed: 113 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ mod app {
4545
use stm32_eth::{
4646
dma::{EthernetDMA, PacketId, RxRingEntry, TxRingEntry},
4747
mac::Speed,
48-
ptp::{EthernetPTP, Timestamp},
48+
ptp::{EthernetPTP, Subseconds, Timestamp},
4949
Parts,
5050
};
5151

@@ -57,6 +57,7 @@ mod app {
5757
dma: EthernetDMA<'static, 'static>,
5858
ptp: EthernetPTP,
5959
tx_id: Option<(u32, Timestamp)>,
60+
scheduled_time: Option<Timestamp>,
6061
}
6162

6263
#[monotonic(binds = SysTick, default = true)]
@@ -88,57 +89,74 @@ mod app {
8889
defmt::info!("Enabling interrupts");
8990
dma.enable_interrupt();
9091

91-
if let Ok(mut phy) = EthernetPhy::from_miim(mac, 0) {
92-
defmt::info!(
93-
"Resetting PHY as an extra step. Type: {}",
94-
phy.ident_string()
95-
);
92+
match EthernetPhy::from_miim(mac, 0) {
93+
Ok(mut phy) => {
94+
defmt::info!(
95+
"Resetting PHY as an extra step. Type: {}",
96+
phy.ident_string()
97+
);
9698

97-
phy.phy_init();
99+
phy.phy_init();
98100

99-
defmt::info!("Waiting for link up.");
101+
defmt::info!("Waiting for link up.");
100102

101-
while !phy.phy_link_up() {}
103+
while !phy.phy_link_up() {}
102104

103-
defmt::info!("Link up.");
105+
defmt::info!("Link up.");
104106

105-
if let Some(speed) = phy.speed().map(|s| match s {
106-
PhySpeed::HalfDuplexBase10T => Speed::HalfDuplexBase10T,
107-
PhySpeed::FullDuplexBase10T => Speed::FullDuplexBase10T,
108-
PhySpeed::HalfDuplexBase100Tx => Speed::HalfDuplexBase100Tx,
109-
PhySpeed::FullDuplexBase100Tx => Speed::FullDuplexBase100Tx,
110-
}) {
111-
phy.get_miim().set_speed(speed);
112-
defmt::info!("Detected link speed: {}", speed);
113-
} else {
114-
defmt::warn!("Failed to detect link speed.");
107+
if let Some(speed) = phy.speed().map(|s| match s {
108+
PhySpeed::HalfDuplexBase10T => Speed::HalfDuplexBase10T,
109+
PhySpeed::FullDuplexBase10T => Speed::FullDuplexBase10T,
110+
PhySpeed::HalfDuplexBase100Tx => Speed::HalfDuplexBase100Tx,
111+
PhySpeed::FullDuplexBase100Tx => Speed::FullDuplexBase100Tx,
112+
}) {
113+
phy.get_miim().set_speed(speed);
114+
defmt::info!("Detected link speed: {}", speed);
115+
} else {
116+
defmt::warn!("Failed to detect link speed.");
117+
}
118+
}
119+
Err(_) => {
120+
defmt::info!("Not resetting unsupported PHY. Cannot detect link speed.");
115121
}
116-
} else {
117-
defmt::info!("Not resetting unsupported PHY. Cannot detect link speed.");
118-
}
122+
};
119123

120124
sender::spawn().ok();
121125

122126
(
123127
Shared {
124128
dma,
125129
tx_id: None,
130+
scheduled_time: None,
126131
ptp,
127132
},
128133
Local {},
129134
init::Monotonics(mono),
130135
)
131136
}
132137

133-
#[task(shared = [dma, tx_id, ptp], local = [tx_id_ctr: u32 = 0x8000_0000])]
134-
fn sender(mut cx: sender::Context) {
138+
#[task(shared = [dma, tx_id, ptp, scheduled_time], local = [tx_id_ctr: u32 = 0x8000_0000])]
139+
fn sender(cx: sender::Context) {
135140
sender::spawn_after(1u64.secs()).ok();
136141

137142
const SIZE: usize = 42;
138143

139144
// Obtain the current time to use as the "TX time" of our frame. It is clearly
140145
// incorrect, but works well enough in low-activity systems (such as this example).
141-
let now = cx.shared.ptp.lock(|ptp| ptp.get_time());
146+
let now = (cx.shared.ptp, cx.shared.scheduled_time).lock(|ptp, sched_time| {
147+
let now = ptp.get_time();
148+
let in_half_sec = now
149+
+ Timestamp::new(
150+
false,
151+
0,
152+
Subseconds::new_from_nanos(500_000_000).unwrap().raw(),
153+
)
154+
.unwrap();
155+
ptp.configure_target_time_interrupt(in_half_sec);
156+
*sched_time = Some(now);
157+
158+
now
159+
});
142160

143161
const DST_MAC: [u8; 6] = [0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56];
144162
const SRC_MAC: [u8; 6] = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
@@ -162,77 +180,94 @@ mod app {
162180
});
163181
}
164182

165-
#[task(binds = ETH, shared = [dma, tx_id, ptp], priority = 2)]
183+
#[task(binds = ETH, shared = [dma, tx_id, ptp, scheduled_time], priority = 2)]
166184
fn eth_interrupt(cx: eth_interrupt::Context) {
167-
(cx.shared.dma, cx.shared.tx_id, cx.shared.ptp).lock(|dma, tx_id, ptp| {
168-
dma.interrupt_handler();
185+
(
186+
cx.shared.dma,
187+
cx.shared.tx_id,
188+
cx.shared.ptp,
189+
cx.shared.scheduled_time,
190+
)
191+
.lock(|dma, tx_id, ptp, sched_time| {
192+
dma.interrupt_handler();
193+
194+
if ptp.interrupt_handler() {
195+
if let Some(sched_time) = sched_time.take() {
196+
let now = ptp.get_time();
197+
defmt::info!(
198+
"Got a timestamp interrupt {} seconds after scheduling",
199+
now - sched_time
200+
);
201+
}
202+
}
169203

170-
let mut packet_id = 0;
204+
let mut packet_id = 0;
171205

172-
while let Ok(packet) = dma.recv_next(Some(packet_id.into())) {
173-
let mut dst_mac = [0u8; 6];
174-
dst_mac.copy_from_slice(&packet[..6]);
206+
while let Ok(packet) = dma.recv_next(Some(packet_id.into())) {
207+
let mut dst_mac = [0u8; 6];
208+
dst_mac.copy_from_slice(&packet[..6]);
175209

176-
// Note that, instead of grabbing the timestamp from the `RxPacket` directly, it
177-
// is also possible to retrieve a cached version of the timestamp using
178-
// `EthernetDMA::get_timestamp_for_id` (in the same way as for TX timestamps).
179-
let ts = if let Some(timestamp) = packet.timestamp() {
180-
timestamp
181-
} else {
182-
continue;
183-
};
210+
// Note that, instead of grabbing the timestamp from the `RxPacket` directly, it
211+
// is also possible to retrieve a cached version of the timestamp using
212+
// `EthernetDMA::get_timestamp_for_id` (in the same way as for TX timestamps).
213+
let ts = if let Some(timestamp) = packet.timestamp() {
214+
timestamp
215+
} else {
216+
continue;
217+
};
184218

185-
let timestamp = if dst_mac == [0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56] {
186-
let mut timestamp_data = [0u8; 8];
187-
timestamp_data.copy_from_slice(&packet[14..22]);
188-
let raw = i64::from_be_bytes(timestamp_data);
219+
defmt::debug!("RX timestamp: {}", ts);
189220

190-
let timestamp = Timestamp::new_raw(raw);
191-
timestamp
192-
} else {
193-
continue;
194-
};
221+
let timestamp = if dst_mac == [0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56] {
222+
let mut timestamp_data = [0u8; 8];
223+
timestamp_data.copy_from_slice(&packet[14..22]);
224+
let raw = i64::from_be_bytes(timestamp_data);
195225

196-
defmt::debug!("RX timestamp: {}", ts);
197-
defmt::debug!("Contained TX timestamp: {}", ts);
226+
let timestamp = Timestamp::new_raw(raw);
227+
timestamp
228+
} else {
229+
continue;
230+
};
231+
232+
defmt::debug!("Contained TX timestamp: {}", ts);
198233

199-
let diff = timestamp - ts;
234+
let diff = timestamp - ts;
200235

201-
defmt::info!("Difference between TX and RX time: {}", diff);
236+
defmt::info!("Difference between TX and RX time: {}", diff);
202237

203-
let addend = ptp.addend();
204-
let nanos = diff.nanos() as u64;
238+
let addend = ptp.addend();
239+
let nanos = diff.nanos() as u64;
205240

206-
if nanos <= 20_000 {
207-
let p1 = ((nanos * addend as u64) / 1_000_000_000) as u32;
241+
if nanos <= 20_000 {
242+
let p1 = ((nanos * addend as u64) / 1_000_000_000) as u32;
208243

209-
defmt::debug!("Addend correction value: {}", p1);
244+
defmt::debug!("Addend correction value: {}", p1);
210245

211-
if diff.is_negative() {
212-
ptp.set_addend(addend - p1 / 2);
246+
if diff.is_negative() {
247+
ptp.set_addend(addend - p1 / 2);
248+
} else {
249+
ptp.set_addend(addend + p1 / 2);
250+
};
213251
} else {
214-
ptp.set_addend(addend + p1 / 2);
215-
};
216-
} else {
217-
defmt::warn!("Updated time.");
218-
ptp.update_time(diff);
219-
}
252+
defmt::warn!("Updated time.");
253+
ptp.update_time(diff);
254+
}
220255

221-
packet_id += 1;
222-
packet_id &= !0x8000_0000;
223-
}
256+
packet_id += 1;
257+
packet_id &= !0x8000_0000;
258+
}
224259

225-
if let Some((tx_id, sent_time)) = tx_id.take() {
226-
if let Ok(ts) = dma.get_timestamp_for_id(PacketId(tx_id)) {
227-
defmt::info!("TX timestamp: {}", ts);
228-
defmt::debug!(
260+
if let Some((tx_id, sent_time)) = tx_id.take() {
261+
if let Ok(ts) = dma.get_timestamp_for_id(PacketId(tx_id)) {
262+
defmt::info!("TX timestamp: {}", ts);
263+
defmt::debug!(
229264
"Diff between TX timestamp and the time that was put into the packet: {}",
230265
ts - sent_time
231266
);
232-
} else {
233-
defmt::warn!("Failed to retrieve TX timestamp");
267+
} else {
268+
defmt::warn!("Failed to retrieve TX timestamp");
269+
}
234270
}
235-
}
236-
});
271+
});
237272
}
238273
}

src/lib.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,15 @@ where
101101

102102
let eth_mac = parts.mac.into();
103103

104-
// Configure the ethernet PTP
105-
#[cfg(feature = "ptp")]
106-
let ptp = EthernetPTP::new(&eth_mac, parts.ptp.into(), clocks);
107-
108104
// Congfigure and start up the ethernet DMA.
109105
let dma = EthernetDMA::new(parts.dma.into(), rx_buffer, tx_buffer);
110106

107+
// Configure the ethernet PTP
108+
#[cfg(feature = "ptp")]
109+
let ptp = EthernetPTP::new(&eth_mac, parts.ptp.into(), clocks, &dma);
110+
111111
// Configure the ethernet MAC
112-
let mac = EthernetMAC::new(eth_mac, parts.mmc, clocks, Speed::FullDuplexBase100Tx)?;
112+
let mac = EthernetMAC::new(eth_mac, parts.mmc, clocks, Speed::FullDuplexBase100Tx, &dma)?;
113113

114114
let parts = Parts {
115115
mac,
@@ -170,15 +170,15 @@ where
170170

171171
let eth_mac = parts.mac.into();
172172

173-
// Configure the ethernet PTP
174-
#[cfg(feature = "ptp")]
175-
let ptp = EthernetPTP::new(&eth_mac, parts.ptp.into(), clocks);
176-
177173
// Congfigure and start up the ethernet DMA.
178174
let dma = EthernetDMA::new(parts.dma.into(), rx_buffer, tx_buffer);
179175

176+
// Configure the ethernet PTP
177+
#[cfg(feature = "ptp")]
178+
let ptp = EthernetPTP::new(&eth_mac, parts.ptp.into(), clocks, &dma);
179+
180180
// Configure the ethernet MAC
181-
let mac = EthernetMAC::new(eth_mac, parts.mmc, clocks, Speed::FullDuplexBase100Tx)?
181+
let mac = EthernetMAC::new(eth_mac, parts.mmc, clocks, Speed::FullDuplexBase100Tx, &dma)?
182182
.with_mii(mdio, mdc);
183183

184184
let parts = Parts {

0 commit comments

Comments
 (0)