Skip to content

Commit fe7943d

Browse files
authored
Merge branch 'stm32-rs:master' into embedded-iopin
2 parents b3cbeda + 69d3fe2 commit fe7943d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1210
-346
lines changed

.github/bors.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ status = [
99
"ci (1.51.0, stm32h747cm7)",
1010
"ci (1.51.0, stm32h7b3)",
1111
"ci (1.51.0, stm32h7b0)",
12+
"ci (1.51.0, stm32h735)",
1213
"ci (stable, stm32h743)",
1314
"ci (stable, stm32h753)",
1415
"ci (stable, stm32h743v)",
1516
"ci (stable, stm32h753v)",
1617
"ci (stable, stm32h747cm7)",
1718
"ci (stable, stm32h7b3)",
1819
"ci (stable, stm32h7b0)",
20+
"ci (stable, stm32h735)",
1921
]

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
- stm32h747cm7
2222
- stm32h7b3
2323
- stm32h7b0
24+
- stm32h735
2425
env: # Peripheral Feature flags
2526
FLAGS: rt,quadspi,sdmmc,fmc,usb_hs,rtc,ethernet,ltdc,crc
2627

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
* Rename the PeripheralREC object for BDMA2 on 7B3, 7B0, 7A3 parts from BDMA to BDMA2
1414
* pac: Upgrade to stm32-rs v0.14.0
1515

16+
* ethernet: `ethernet::DesRing` and `ethernet::EthernetDMA` require generic
17+
constants to specify how many transmit / receive buffers to include in
18+
`ethernet::DesRing`. To replicate the previous behaviour, use `DesRing<4, 4>`
19+
1620
## [v0.10.0] 2021-07-xx
1721

1822
* **Breaking**: Don't reset peripheral in DMA1/2 `StreamsTuple::new()` method #229

Cargo.toml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ targets = ["thumbv7em-none-eabihf"]
2828
embedded-hal = "0.2.4"
2929
embedded-dma = "0.1.2"
3030
cortex-m = "^0.7.1"
31-
cortex-m-rt = "^0.6.15"
3231
stm32h7 = "^0.14.0"
3332
void = { version = "1.0.2", default-features = false }
34-
cast = { version = "0.2.3", default-features = false }
33+
cast = { version = "0.3.0", default-features = false }
3534
nb = "1.0.0"
3635
paste = "1.0.1"
3736
bare-metal = "1.0.0"
38-
sdio-host = { version = "0.4", optional = true }
37+
sdio-host = { version = "0.5", optional = true }
38+
embedded-sdmmc = { version = "0.3", optional = true }
3939
stm32-fmc = { version = "0.2", optional = true }
4040
synopsys-usb-otg = { version = "^0.2.4", features = ["cortex-m"], optional = true }
4141
embedded-display-controller = { version = "^0.1.0", optional = true }
@@ -52,6 +52,7 @@ default-features = false
5252
optional = true
5353

5454
[dev-dependencies]
55+
cortex-m-rt = ">=0.6.15,<0.8"
5556
cortex-m-rtic = { version = "0.5.8", default-features = false, features = ["cortex-m-7"] }
5657
log = "0.4.11"
5758
panic-halt = "0.2.0"
@@ -79,6 +80,7 @@ revision_v = []
7980
rm0433 = [] # aka. "single core" devices
8081
rm0399 = [] # aka. "dual core" devices
8182
rm0455 = [] # aka. "high memory integration" devices
83+
rm0468 = [] # aka. "high speed" devices
8284
dsi = []
8385
cm4 = []
8486
cm7 = []
@@ -87,6 +89,7 @@ ltdc = ["embedded-display-controller"]
8789
quadspi = []
8890
fmc = ["stm32-fmc"]
8991
sdmmc = ["sdio-host"]
92+
sdmmc-fatfs = ["embedded-sdmmc", "sdmmc"]
9093
ethernet = ["smoltcp"]
9194
rtc = ["chrono"]
9295
crc = []
@@ -104,6 +107,7 @@ stm32h747cm7 = ["stm32h7/stm32h747cm7", "device-selected", "revision_v", "rm0399
104107
stm32h7b3 = ["stm32h7/stm32h7b3", "device-selected", "revision_v", "rm0455", "smps"]
105108
stm32h7b0 = ["stm32h7/stm32h7b3", "device-selected", "revision_v", "rm0455", "smps"]
106109
stm32h7a3 = ["stm32h7/stm32h7b3", "device-selected", "revision_v", "rm0455", "smps"]
110+
stm32h735 = ["stm32h7/stm32h735", "device-selected", "revision_v", "rm0468", "smps"]
107111
# Flags for examples
108112
log-itm = []
109113
log-rtt = []
@@ -129,15 +133,15 @@ required-features = ["rt"]
129133

130134
[[example]]
131135
name = "rtic_timers"
132-
required-features = ["rt"]
136+
required-features = ["rt", "rm0433"]
133137

134138
[[example]]
135139
name = "vos0"
136140
required-features = ["revision_v", "rm0433"]
137141

138142
[[example]]
139143
name = "fmc"
140-
required-features = ["fmc"]
144+
required-features = ["fmc", "rm0399"]
141145

142146
[[example]]
143147
name = "qspi"
@@ -151,6 +155,10 @@ required-features = ["quadspi", "rm0433"]
151155
name = "sdmmc"
152156
required-features = ["sdmmc", "rm0433"]
153157

158+
[[example]]
159+
name = "sdmmc_fat"
160+
required-features = ["sdmmc", "sdmmc-fatfs", "stm32h747cm7"]
161+
154162
[[example]]
155163
name = "ethernet-stm32h747i-disco"
156164
required-features = ["rt", "stm32h747cm7", "ethernet"]
@@ -159,6 +167,10 @@ required-features = ["rt", "stm32h747cm7", "ethernet"]
159167
name = "ethernet-rtic-stm32h747i-disco"
160168
required-features = ["rt", "stm32h747cm7", "ethernet"]
161169

170+
[[example]]
171+
name = "ethernet-rtic-stm32h735g-dk"
172+
required-features = ["rt", "stm32h735", "ethernet"]
173+
162174
[[example]]
163175
name = "ethernet-nucleo-h743zi2"
164176
required-features = ["rt", "revision_v", "stm32h743v", "ethernet"]

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Supported Configurations
3333
* __stm32h7b3__
3434
* __stm32h7b0__
3535
* __stm32h7a3__
36+
* __stm32h735__ (stm32h725, stm32h735)
3637

3738
#### Old revision STM32H742/743/750/753 parts
3839

examples/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Examples
55

66
For these parts, the program needs to know more about the power supply
77
scheme in order to successfully transition from Run* mode to Run mode. For
8-
en explaination of Run* mode, see RM0433 Rev 7 Section 6.6.1 "System/D3
8+
an explaination of Run* mode, see RM0433 Rev 7 Section 6.6.1 "System/D3
99
domain modes".
1010

1111
For your own code, see the

examples/ethernet-nucleo-h743zi2.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
4343

4444
/// Ethernet descriptor rings are a global singleton
4545
#[link_section = ".sram3.eth"]
46-
static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new();
46+
static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new();
4747

4848
// the program entry point
4949
#[entry]
@@ -171,11 +171,11 @@ fn SysTick() {
171171
}
172172

173173
#[exception]
174-
fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! {
174+
unsafe fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! {
175175
panic!("HardFault at {:#?}", ef);
176176
}
177177

178178
#[exception]
179-
fn DefaultHandler(irqn: i16) {
179+
unsafe fn DefaultHandler(irqn: i16) {
180180
panic!("Unhandled exception (IRQn = {})", irqn);
181181
}
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
//! Demo for STM32H735G-DK eval board using the Real Time for the Masses
2+
//! (RTIC) framework.
3+
//!
4+
//! This demo responds to pings on 192.168.1.99 (IP address hardcoded below)
5+
//!
6+
//! We use the SysTick timer to create a 1ms timebase for use with smoltcp.
7+
//!
8+
//! The ethernet ring buffers are placed in AXI SRAM, where they can be
9+
//! accessed by both the core and the Ethernet DMA.
10+
#![deny(warnings)]
11+
#![no_main]
12+
#![no_std]
13+
14+
use cortex_m;
15+
use rtic::app;
16+
17+
#[macro_use]
18+
#[allow(unused)]
19+
mod utilities;
20+
use log::info;
21+
22+
use smoltcp::iface::{
23+
EthernetInterface, EthernetInterfaceBuilder, Neighbor, NeighborCache,
24+
Route, Routes,
25+
};
26+
use smoltcp::socket::{SocketSet, SocketSetItem};
27+
use smoltcp::time::Instant;
28+
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv6Cidr};
29+
30+
use gpio::Speed::*;
31+
use stm32h7xx_hal::gpio;
32+
use stm32h7xx_hal::hal::digital::v2::OutputPin;
33+
use stm32h7xx_hal::rcc::CoreClocks;
34+
use stm32h7xx_hal::{ethernet, ethernet::PHY};
35+
use stm32h7xx_hal::{prelude::*, stm32};
36+
37+
use core::sync::atomic::{AtomicU32, Ordering};
38+
39+
/// Configure SYSTICK for 1ms timebase
40+
fn systick_init(mut syst: stm32::SYST, clocks: CoreClocks) {
41+
let c_ck_mhz = clocks.c_ck().0 / 1_000_000;
42+
43+
let syst_calib = 0x3E8;
44+
45+
syst.set_clock_source(cortex_m::peripheral::syst::SystClkSource::Core);
46+
syst.set_reload((syst_calib * c_ck_mhz) - 1);
47+
syst.enable_interrupt();
48+
syst.enable_counter();
49+
}
50+
51+
/// TIME is an atomic u32 that counts milliseconds.
52+
static TIME: AtomicU32 = AtomicU32::new(0);
53+
54+
/// Locally administered MAC address
55+
const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
56+
57+
/// Ethernet descriptor rings are a global singleton
58+
#[link_section = ".axisram.eth"]
59+
static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new();
60+
61+
/// Net storage with static initialisation - another global singleton
62+
pub struct NetStorageStatic<'a> {
63+
ip_addrs: [IpCidr; 1],
64+
socket_set_entries: [Option<SocketSetItem<'a>>; 8],
65+
neighbor_cache_storage: [Option<(IpAddress, Neighbor)>; 8],
66+
routes_storage: [Option<(IpCidr, Route)>; 1],
67+
}
68+
static mut STORE: NetStorageStatic = NetStorageStatic {
69+
// Garbage
70+
ip_addrs: [IpCidr::Ipv6(Ipv6Cidr::SOLICITED_NODE_PREFIX)],
71+
socket_set_entries: [None, None, None, None, None, None, None, None],
72+
neighbor_cache_storage: [None; 8],
73+
routes_storage: [None; 1],
74+
};
75+
76+
pub struct Net<'a> {
77+
iface: EthernetInterface<'a, ethernet::EthernetDMA<'a, 4, 4>>,
78+
sockets: SocketSet<'a>,
79+
}
80+
impl<'a> Net<'a> {
81+
pub fn new(
82+
store: &'static mut NetStorageStatic<'a>,
83+
ethdev: ethernet::EthernetDMA<'a, 4, 4>,
84+
ethernet_addr: EthernetAddress,
85+
) -> Self {
86+
// Set IP address
87+
store.ip_addrs =
88+
[IpCidr::new(IpAddress::v4(192, 168, 1, 99).into(), 0)];
89+
90+
let neighbor_cache =
91+
NeighborCache::new(&mut store.neighbor_cache_storage[..]);
92+
let routes = Routes::new(&mut store.routes_storage[..]);
93+
94+
let iface = EthernetInterfaceBuilder::new(ethdev)
95+
.ethernet_addr(ethernet_addr)
96+
.neighbor_cache(neighbor_cache)
97+
.ip_addrs(&mut store.ip_addrs[..])
98+
.routes(routes)
99+
.finalize();
100+
let sockets = SocketSet::new(&mut store.socket_set_entries[..]);
101+
102+
return Net { iface, sockets };
103+
}
104+
105+
/// Polls on the ethernet interface. You should refer to the smoltcp
106+
/// documentation for poll() to understand how to call poll efficiently
107+
pub fn poll(&mut self, now: i64) {
108+
let timestamp = Instant::from_millis(now);
109+
110+
self.iface
111+
.poll(&mut self.sockets, timestamp)
112+
.map(|_| ())
113+
.unwrap_or_else(|e| info!("Poll: {:?}", e));
114+
}
115+
}
116+
117+
#[app(device = stm32h7xx_hal::stm32, peripherals = true)]
118+
const APP: () = {
119+
struct Resources {
120+
net: Net<'static>,
121+
lan8742a: ethernet::phy::LAN8742A<ethernet::EthernetMAC>,
122+
link_led: gpio::gpioc::PC3<gpio::Output<gpio::PushPull>>,
123+
}
124+
125+
#[init]
126+
fn init(mut ctx: init::Context) -> init::LateResources {
127+
utilities::logger::init();
128+
// Initialise power...
129+
let pwr = ctx.device.PWR.constrain();
130+
let pwrcfg = pwr.smps().freeze();
131+
132+
// Initialise clocks...
133+
let rcc = ctx.device.RCC.constrain();
134+
let ccdr = rcc
135+
.sys_ck(200.mhz())
136+
.hclk(200.mhz())
137+
.freeze(pwrcfg, &ctx.device.SYSCFG);
138+
139+
// Initialise system...
140+
ctx.core.SCB.invalidate_icache();
141+
ctx.core.SCB.enable_icache();
142+
// TODO: ETH DMA coherence issues
143+
// ctx.core.SCB.enable_dcache(&mut ctx.core.CPUID);
144+
ctx.core.DWT.enable_cycle_counter();
145+
146+
// Initialise IO...
147+
let gpioa = ctx.device.GPIOA.split(ccdr.peripheral.GPIOA);
148+
let gpioc = ctx.device.GPIOC.split(ccdr.peripheral.GPIOC);
149+
let gpiob = ctx.device.GPIOB.split(ccdr.peripheral.GPIOB);
150+
let mut link_led = gpioc.pc3.into_push_pull_output(); // USR LED1
151+
link_led.set_high().ok();
152+
153+
let _rmii_ref_clk = gpioa.pa1.into_alternate_af11().set_speed(VeryHigh);
154+
let _rmii_mdio = gpioa.pa2.into_alternate_af11().set_speed(VeryHigh);
155+
let _rmii_mdc = gpioc.pc1.into_alternate_af11().set_speed(VeryHigh);
156+
let _rmii_crs_dv = gpioa.pa7.into_alternate_af11().set_speed(VeryHigh);
157+
let _rmii_rxd0 = gpioc.pc4.into_alternate_af11().set_speed(VeryHigh);
158+
let _rmii_rxd1 = gpioc.pc5.into_alternate_af11().set_speed(VeryHigh);
159+
let _rmii_tx_en = gpiob.pb11.into_alternate_af11().set_speed(VeryHigh);
160+
let _rmii_txd0 = gpiob.pb12.into_alternate_af11().set_speed(VeryHigh);
161+
let _rmii_txd1 = gpiob.pb13.into_alternate_af11().set_speed(VeryHigh);
162+
163+
// Initialise ethernet...
164+
assert_eq!(ccdr.clocks.hclk().0, 200_000_000); // HCLK 200MHz
165+
assert_eq!(ccdr.clocks.pclk1().0, 100_000_000); // PCLK 100MHz
166+
assert_eq!(ccdr.clocks.pclk2().0, 100_000_000); // PCLK 100MHz
167+
assert_eq!(ccdr.clocks.pclk4().0, 100_000_000); // PCLK 100MHz
168+
169+
let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS);
170+
let (eth_dma, eth_mac) = unsafe {
171+
ethernet::new_unchecked(
172+
ctx.device.ETHERNET_MAC,
173+
ctx.device.ETHERNET_MTL,
174+
ctx.device.ETHERNET_DMA,
175+
&mut DES_RING,
176+
mac_addr.clone(),
177+
ccdr.peripheral.ETH1MAC,
178+
&ccdr.clocks,
179+
)
180+
};
181+
182+
// Initialise ethernet PHY...
183+
let mut lan8742a = ethernet::phy::LAN8742A::new(eth_mac);
184+
lan8742a.phy_reset();
185+
lan8742a.phy_init();
186+
// The eth_dma should not be used until the PHY reports the link is up
187+
188+
unsafe {
189+
ethernet::enable_interrupt();
190+
}
191+
192+
// unsafe: mutable reference to static storage, we only do this once
193+
let store = unsafe { &mut STORE };
194+
let net = Net::new(store, eth_dma, mac_addr);
195+
196+
// 1ms tick
197+
systick_init(ctx.core.SYST, ccdr.clocks);
198+
199+
init::LateResources {
200+
net,
201+
lan8742a,
202+
link_led,
203+
}
204+
}
205+
206+
#[idle(resources = [lan8742a, link_led])]
207+
fn idle(ctx: idle::Context) -> ! {
208+
loop {
209+
// Ethernet
210+
match ctx.resources.lan8742a.poll_link() {
211+
true => ctx.resources.link_led.set_low(),
212+
_ => ctx.resources.link_led.set_high(),
213+
}
214+
.ok();
215+
}
216+
}
217+
218+
#[task(binds = ETH, resources = [net])]
219+
fn ethernet_event(ctx: ethernet_event::Context) {
220+
unsafe { ethernet::interrupt_handler() }
221+
222+
let time = TIME.load(Ordering::Relaxed);
223+
ctx.resources.net.poll(time as i64);
224+
}
225+
226+
#[task(binds = SysTick, priority=15)]
227+
fn systick_tick(_: systick_tick::Context) {
228+
TIME.fetch_add(1, Ordering::Relaxed);
229+
}
230+
};

0 commit comments

Comments
 (0)