forked from stm32-rs/stm32h7xx-hal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ethernet-stm32h747i-disco.rs
157 lines (134 loc) · 4.51 KB
/
ethernet-stm32h747i-disco.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Demo for STM32H747I-DISCO eval board
//!
//! STM32H747I-DISCO: RMII TXD1 is on PG12
//!
//! The ethernet ring buffers are placed in SRAM3, where they can be
//! accessed by both the core and the Ethernet DMA.
//!
//! This demo does not use smoltcp - see the ethernet-rtic-stm32h747i-disco demo
//! for an example of smoltcp
#![deny(warnings)]
#![no_main]
#![no_std]
use cortex_m_rt as rt;
use rt::{entry, exception};
#[macro_use]
#[allow(unused)]
mod utilities;
use log::info;
use stm32h7xx_hal::{ethernet, ethernet::PHY};
use stm32h7xx_hal::{prelude::*, stm32, stm32::interrupt};
/// Locally administered MAC address
const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
/// Ethernet descriptor rings are a global singleton
#[link_section = ".sram3.eth"]
static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new();
// the program entry point
#[entry]
fn main() -> ! {
utilities::logger::init();
let dp = stm32::Peripherals::take().unwrap();
let mut cp = stm32::CorePeripherals::take().unwrap();
// Initialise power...
info!("Setup PWR... ");
let pwr = dp.PWR.constrain();
let pwrcfg = pwr.smps().freeze();
// Link the SRAM3 power state to CPU1
info!("Setup RCC... ");
dp.RCC.ahb2enr.modify(|_, w| w.sram3en().set_bit());
// Initialise clocks...
let rcc = dp.RCC.constrain();
let ccdr = rcc
.sys_ck(200.MHz())
.hclk(200.MHz())
.freeze(pwrcfg, &dp.SYSCFG);
// Initialise system...
cp.SCB.enable_icache();
// TODO: ETH DMA coherence issues
// cp.SCB.enable_dcache(&mut cp.CPUID);
cp.DWT.enable_cycle_counter();
// Initialise IO...
let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
let gpioi = dp.GPIOI.split(ccdr.peripheral.GPIOI);
let mut link_led = gpioi.pi14.into_push_pull_output(); // LED3
link_led.set_high();
let rmii_ref_clk = gpioa.pa1.into_alternate();
let rmii_mdio = gpioa.pa2.into_alternate();
let rmii_mdc = gpioc.pc1.into_alternate();
let rmii_crs_dv = gpioa.pa7.into_alternate();
let rmii_rxd0 = gpioc.pc4.into_alternate();
let rmii_rxd1 = gpioc.pc5.into_alternate();
let rmii_tx_en = gpiog.pg11.into_alternate();
let rmii_txd0 = gpiog.pg13.into_alternate();
let rmii_txd1 = gpiog.pg12.into_alternate();
// Initialise ethernet...
assert_eq!(ccdr.clocks.hclk().raw(), 200_000_000); // HCLK 200MHz
assert_eq!(ccdr.clocks.pclk1().raw(), 100_000_000); // PCLK 100MHz
assert_eq!(ccdr.clocks.pclk2().raw(), 100_000_000); // PCLK 100MHz
assert_eq!(ccdr.clocks.pclk4().raw(), 100_000_000); // PCLK 100MHz
let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS);
let (_eth_dma, eth_mac) = unsafe {
ethernet::new(
dp.ETHERNET_MAC,
dp.ETHERNET_MTL,
dp.ETHERNET_DMA,
(
rmii_ref_clk,
rmii_mdio,
rmii_mdc,
rmii_crs_dv,
rmii_rxd0,
rmii_rxd1,
rmii_tx_en,
rmii_txd0,
rmii_txd1,
),
&mut DES_RING,
mac_addr,
ccdr.peripheral.ETH1MAC,
&ccdr.clocks,
)
};
// Initialise ethernet PHY...
let mut lan8742a = ethernet::phy::LAN8742A::new(eth_mac.set_phy_addr(0));
lan8742a.phy_reset();
lan8742a.phy_init();
unsafe {
ethernet::enable_interrupt();
cp.NVIC.set_priority(stm32::Interrupt::ETH, 196); // Mid prio
cortex_m::peripheral::NVIC::unmask(stm32::Interrupt::ETH);
}
// ----------------------------------------------------------
// Main application loop
let mut eth_up = false;
loop {
// Ethernet
let eth_last = eth_up;
eth_up = lan8742a.poll_link();
match eth_up {
true => link_led.set_low(),
_ => link_led.set_high(),
}
if eth_up != eth_last {
// Interface state change
match eth_up {
true => info!("Ethernet UP"),
_ => info!("Ethernet DOWN"),
}
}
}
}
#[interrupt]
fn ETH() {
unsafe { ethernet::interrupt_handler() }
}
#[exception]
unsafe fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! {
panic!("HardFault at {:#?}", ef);
}
#[exception]
unsafe fn DefaultHandler(irqn: i16) {
panic!("Unhandled exception (IRQn = {})", irqn);
}