Skip to content

Commit 1179d0c

Browse files
bors[bot]hargoniXrichardeoin
authored
Merge #121
121: Ethernet merge r=richardeoin a=hargoniX This PR adds stm32h7-ethernet into the HAL behind the ethernet feature flag, trying to introduce as little diff as possible in the process of doing so. Closes: #102 Co-authored-by: Henrik Böving <[email protected]> Co-authored-by: Richard Meadows <[email protected]>
2 parents 6f8e6d3 + 4f8949b commit 1179d0c

File tree

11 files changed

+1797
-4
lines changed

11 files changed

+1797
-4
lines changed

Cargo.toml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ sdio-host = { version = "0.4", optional = true }
3636
version = "0.2.5"
3737
features = ["const-fn"]
3838

39+
[dependencies.smoltcp]
40+
version = "0.6.0"
41+
default-features = false
42+
features = ["ethernet", "proto-ipv4", "proto-dhcpv4", "socket-tcp", "socket-raw"]
43+
optional = true
44+
3945
[dev-dependencies]
4046
cortex-m-rtic = "0.5.3"
4147
log = "0.4.11"
@@ -49,6 +55,11 @@ panic-itm = { version = "~0.4.1" }
4955
panic-semihosting = { version = "0.5.3" }
5056
cortex-m-semihosting = { version = "0.3.5" }
5157

58+
[dev-dependencies.smoltcp]
59+
version = "0.6.0"
60+
default-features = false
61+
features = ["ethernet", "proto-ipv4", "proto-ipv6", "socket-raw"]
62+
5263
[features]
5364
default = ["unproven"]
5465
unproven = ["embedded-hal/unproven"]
@@ -61,6 +72,9 @@ cm4 = []
6172
cm7 = []
6273
quadspi = []
6374
sdmmc = ["sdio-host"]
75+
ethernet = ["smoltcp"]
76+
phy_ksz8081r = []
77+
phy_lan8742a = []
6478
rt = ["stm32h7/rt"]
6579
stm32h742 = ["stm32h7/stm32h743", "device-selected", "singlecore"]
6680
stm32h743 = ["stm32h7/stm32h743", "device-selected", "singlecore"]
@@ -75,7 +89,6 @@ log-itm = []
7589
log-rtt = []
7690
log-semihost = []
7791

78-
7992
[profile.dev]
8093
codegen-units = 1 # better optimizations
8194
debug = true # symbols are nice and they don't increase the size in flash
@@ -106,3 +119,15 @@ required-features = ["quadspi"]
106119
[[example]]
107120
name = "sdmmc"
108121
required-features = ["sdmmc"]
122+
123+
[[example]]
124+
name = "ethernet-stm32h747i-disco"
125+
required-features = ["phy_lan8742a", "rt", "stm32h747cm7", "ethernet"]
126+
127+
[[example]]
128+
name = "ethernet-rtic-stm32h747i-disco"
129+
required-features = ["phy_lan8742a", "rt", "stm32h747cm7", "ethernet"]
130+
131+
[[example]]
132+
name = "ethernet-nucleo-h743zi2"
133+
required-features = ["phy_lan8742a", "rt", "revision_v", "stm32h743v", "ethernet"]

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ other core functionality. An incomplete list of additional peripheral
114114
support crates is given here:
115115

116116
- [stm32h7-fmc](https://crates.io/crates/stm32h7-fmc)
117-
- [stm32h7-ethernet](https://crates.io/crates/stm32h7-ethernet)
118117
- _[Search crates.io...](https://crates.io/search?q=stm32h7)_
119118

120119
Changelog

examples/ethernet-nucleo-h743zi2.rs

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
extern crate cortex_m_rt as rt;
5+
use core::sync::atomic::{AtomicU32, Ordering};
6+
use rt::{entry, exception};
7+
8+
extern crate cortex_m;
9+
10+
#[path = "utilities/logger.rs"]
11+
mod logger;
12+
use log::info;
13+
14+
use stm32h7xx_hal::ethernet;
15+
use stm32h7xx_hal::gpio::Speed;
16+
use stm32h7xx_hal::hal::digital::v2::OutputPin;
17+
use stm32h7xx_hal::rcc::CoreClocks;
18+
use stm32h7xx_hal::{prelude::*, stm32, stm32::interrupt};
19+
use Speed::*;
20+
21+
/// Configure SYSTICK for 1ms timebase
22+
fn systick_init(syst: &mut stm32::SYST, clocks: CoreClocks) {
23+
let c_ck_mhz = clocks.c_ck().0 / 1_000_000;
24+
25+
let syst_calib = 0x3E8;
26+
27+
syst.set_clock_source(cortex_m::peripheral::syst::SystClkSource::Core);
28+
syst.set_reload((syst_calib * c_ck_mhz) - 1);
29+
syst.enable_interrupt();
30+
syst.enable_counter();
31+
}
32+
33+
/// ======================================================================
34+
/// Entry point
35+
/// ======================================================================
36+
37+
/// TIME is an atomic u32 that counts milliseconds. Although not used
38+
/// here, it is very useful to have for network protocols
39+
static TIME: AtomicU32 = AtomicU32::new(0);
40+
41+
/// Locally administered MAC address
42+
const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
43+
44+
/// Ethernet descriptor rings are a global singleton
45+
#[link_section = ".sram3.eth"]
46+
static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new();
47+
48+
// the program entry point
49+
#[entry]
50+
fn main() -> ! {
51+
logger::init();
52+
let dp = stm32::Peripherals::take().unwrap();
53+
let mut cp = stm32::CorePeripherals::take().unwrap();
54+
55+
// Initialise power...
56+
info!("Setup PWR... ");
57+
let pwr = dp.PWR.constrain();
58+
let vos = pwr.freeze();
59+
60+
// Initialise SRAM3
61+
info!("Setup RCC... ");
62+
dp.RCC.ahb2enr.modify(|_, w| w.sram3en().set_bit());
63+
64+
// Initialise clocks...
65+
let rcc = dp.RCC.constrain();
66+
let ccdr = rcc
67+
.sys_ck(200.mhz())
68+
.hclk(200.mhz())
69+
.pll1_r_ck(100.mhz()) // for TRACECK
70+
.freeze(vos, &dp.SYSCFG);
71+
72+
// Get the delay provider.
73+
let delay = cp.SYST.delay(ccdr.clocks);
74+
75+
// Initialise system...
76+
cp.SCB.invalidate_icache();
77+
cp.SCB.enable_icache();
78+
// TODO: ETH DMA coherence issues
79+
// cp.SCB.enable_dcache(&mut cp.CPUID);
80+
cp.DWT.enable_cycle_counter();
81+
82+
// Initialise IO...
83+
let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
84+
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
85+
let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);
86+
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
87+
let mut link_led = gpiob.pb0.into_push_pull_output(); // LED1, green
88+
link_led.set_high().ok();
89+
90+
let _rmii_ref_clk = gpioa.pa1.into_alternate_af11().set_speed(VeryHigh);
91+
let _rmii_mdio = gpioa.pa2.into_alternate_af11().set_speed(VeryHigh);
92+
let _rmii_mdc = gpioc.pc1.into_alternate_af11().set_speed(VeryHigh);
93+
let _rmii_crs_dv = gpioa.pa7.into_alternate_af11().set_speed(VeryHigh);
94+
let _rmii_rxd0 = gpioc.pc4.into_alternate_af11().set_speed(VeryHigh);
95+
let _rmii_rxd1 = gpioc.pc5.into_alternate_af11().set_speed(VeryHigh);
96+
let _rmii_tx_en = gpiog.pg11.into_alternate_af11().set_speed(VeryHigh);
97+
let _rmii_txd0 = gpiog.pg13.into_alternate_af11().set_speed(VeryHigh);
98+
let _rmii_txd1 = gpiob.pb13.into_alternate_af11().set_speed(VeryHigh);
99+
100+
// Initialise ethernet...
101+
assert_eq!(ccdr.clocks.hclk().0, 200_000_000); // HCLK 200MHz
102+
assert_eq!(ccdr.clocks.pclk1().0, 100_000_000); // PCLK 100MHz
103+
assert_eq!(ccdr.clocks.pclk2().0, 100_000_000); // PCLK 100MHz
104+
assert_eq!(ccdr.clocks.pclk4().0, 100_000_000); // PCLK 100MHz
105+
106+
let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS);
107+
let (_eth_dma, mut eth_mac) = unsafe {
108+
ethernet::new_unchecked(
109+
dp.ETHERNET_MAC,
110+
dp.ETHERNET_MTL,
111+
dp.ETHERNET_DMA,
112+
&mut DES_RING,
113+
mac_addr.clone(),
114+
)
115+
};
116+
unsafe {
117+
ethernet::enable_interrupt();
118+
cp.NVIC.set_priority(stm32::Interrupt::ETH, 196); // Mid prio
119+
cortex_m::peripheral::NVIC::unmask(stm32::Interrupt::ETH);
120+
}
121+
122+
// ----------------------------------------------------------
123+
// Begin periodic tasks
124+
125+
systick_init(&mut delay.free(), ccdr.clocks);
126+
unsafe {
127+
cp.SCB.shpr[15 - 4].write(128);
128+
} // systick exception priority
129+
130+
// ----------------------------------------------------------
131+
// Main application loop
132+
133+
let mut eth_up = false;
134+
loop {
135+
let _time = TIME.load(Ordering::Relaxed);
136+
137+
// Ethernet
138+
let eth_last = eth_up;
139+
eth_up = eth_mac.phy_poll_link();
140+
match eth_up {
141+
true => link_led.set_low(),
142+
_ => link_led.set_high(),
143+
}
144+
.ok();
145+
146+
if eth_up != eth_last {
147+
// Interface state change
148+
match eth_up {
149+
true => info!("Ethernet UP"),
150+
_ => info!("Ethernet DOWN"),
151+
}
152+
}
153+
}
154+
}
155+
156+
#[interrupt]
157+
fn ETH() {
158+
unsafe { ethernet::interrupt_handler() }
159+
}
160+
161+
#[exception]
162+
fn SysTick() {
163+
TIME.fetch_add(1, Ordering::Relaxed);
164+
}
165+
166+
#[exception]
167+
fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! {
168+
panic!("HardFault at {:#?}", ef);
169+
}
170+
171+
#[exception]
172+
fn DefaultHandler(irqn: i16) {
173+
panic!("Unhandled exception (IRQn = {})", irqn);
174+
}

0 commit comments

Comments
 (0)