Compare commits
55 Commits
stm32-cs-s
...
comment-me
Author | SHA1 | Date | |
---|---|---|---|
c7803bb8f4 | |||
683d5c3066 | |||
a3574e519a | |||
3e3317e8bd | |||
e7aeb9b29f | |||
7fd868ade9 | |||
6e6df22979 | |||
f7980885a5 | |||
5a1393aa0b | |||
40e4ca4751 | |||
1d810baa18 | |||
213b4c9dca | |||
889d482d2d | |||
ea0e83a7f9 | |||
f0497039ed | |||
aff77d2b65 | |||
a7c6999670 | |||
18e96898ea | |||
870dcc5970 | |||
5c5e681819 | |||
f54753beaa | |||
b24520579a | |||
31d4516516 | |||
66e62e9994 | |||
eeedaf2e76 | |||
1fc35c753b | |||
cd92bc3145 | |||
4a156df7a1 | |||
c46e758e2c | |||
8a10948ce9 | |||
7045c53170 | |||
0621e957a0 | |||
a818f33658 | |||
3bfbf2697f | |||
7559f9e583 | |||
c8fdbe19f9 | |||
2e50bf667a | |||
ba62037642 | |||
824556c9c8 | |||
f7c0ec66d2 | |||
69bb455c60 | |||
575db17264 | |||
0aa99e66f7 | |||
3264941c1b | |||
a57d383b1d | |||
9a7fda87b0 | |||
adc810d24b | |||
75baf186f3 | |||
a6bbb130c5 | |||
d1ac6d2824 | |||
636958ff70 | |||
7f6fe93f55 | |||
e9b1904db8 | |||
02d2c06b23 | |||
debda2f52c |
@ -62,9 +62,9 @@ async fn blink(pin: AnyPin) {
|
||||
loop {
|
||||
// Timekeeping is globally available, no need to mess with hardware timers.
|
||||
led.set_high();
|
||||
Timer::after(Duration::from_millis(150)).await;
|
||||
Timer::after_millis(150).await;
|
||||
led.set_low();
|
||||
Timer::after(Duration::from_millis(150)).await;
|
||||
Timer::after_millis(150).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,10 +11,10 @@ log = ["dep:log"]
|
||||
firmware-logs = []
|
||||
|
||||
[dependencies]
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time"}
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time"}
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync"}
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"}
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.17", optional = true }
|
||||
|
@ -1,5 +1,5 @@
|
||||
use embassy_futures::yield_now;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
use embedded_hal_1::digital::OutputPin;
|
||||
use futures::FutureExt;
|
||||
|
||||
@ -51,9 +51,9 @@ where
|
||||
pub async fn init(&mut self) {
|
||||
// Reset
|
||||
self.pwr.set_low().unwrap();
|
||||
Timer::after(Duration::from_millis(20)).await;
|
||||
Timer::after_millis(20).await;
|
||||
self.pwr.set_high().unwrap();
|
||||
Timer::after(Duration::from_millis(250)).await;
|
||||
Timer::after_millis(250).await;
|
||||
|
||||
while self
|
||||
.read32_swapped(REG_BUS_TEST_RO)
|
||||
|
@ -2,7 +2,7 @@ use core::cmp::{max, min};
|
||||
|
||||
use ch::driver::LinkState;
|
||||
use embassy_net_driver_channel as ch;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
|
||||
pub use crate::bus::SpiBusCyw43;
|
||||
use crate::consts::*;
|
||||
@ -87,22 +87,22 @@ impl<'a> Control<'a> {
|
||||
self.set_iovar("country", &country_info.to_bytes()).await;
|
||||
|
||||
// set country takes some time, next ioctls fail if we don't wait.
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
// Set antenna to chip antenna
|
||||
self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
|
||||
|
||||
self.set_iovar_u32("bus:txglom", 0).await;
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
//self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
|
||||
//Timer::after(Duration::from_millis(100)).await;
|
||||
//Timer::after_millis(100).await;
|
||||
self.set_iovar_u32("ampdu_ba_wsize", 8).await;
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
self.set_iovar_u32("ampdu_mpdu", 4).await;
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
//self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
|
||||
|
||||
//Timer::after(Duration::from_millis(100)).await;
|
||||
//Timer::after_millis(100).await;
|
||||
|
||||
// evts
|
||||
let mut evts = EventMask {
|
||||
@ -121,17 +121,17 @@ impl<'a> Control<'a> {
|
||||
|
||||
self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
// set wifi up
|
||||
self.up().await;
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
|
||||
self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
self.state_ch.set_ethernet_address(mac_addr);
|
||||
|
||||
@ -185,7 +185,7 @@ impl<'a> Control<'a> {
|
||||
self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
|
||||
self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
let mut pfi = PassphraseInfo {
|
||||
len: passphrase.len() as _,
|
||||
@ -297,7 +297,7 @@ impl<'a> Control<'a> {
|
||||
if security != Security::OPEN {
|
||||
self.set_iovar_u32x2("bsscfg:wpa_auth", 0, 0x0084).await; // wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
// Set passphrase
|
||||
let mut pfi = PassphraseInfo {
|
||||
|
@ -555,14 +555,14 @@ where
|
||||
|
||||
self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
|
||||
|
||||
Timer::after(Duration::from_millis(1)).await;
|
||||
Timer::after_millis(1).await;
|
||||
|
||||
self.bus
|
||||
.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
|
||||
.await;
|
||||
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||
|
||||
Timer::after(Duration::from_millis(1)).await;
|
||||
Timer::after_millis(1).await;
|
||||
}
|
||||
|
||||
async fn core_is_up(&mut self, core: Core) -> bool {
|
||||
|
@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-executor = { version = "0.3.0", path = "../../../../../embassy-executor", features = ["defmt", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
||||
embassy-time = { version = "0.1.0", path = "../../../../../embassy-time", features = ["defmt", "nightly"] }
|
||||
embassy-time = { version = "0.1.4", path = "../../../../../embassy-time", features = ["defmt", "nightly"] }
|
||||
embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] }
|
||||
|
||||
defmt = "0.3"
|
||||
|
@ -6,7 +6,7 @@ The Embassy executor is an async/await executor designed for embedded usage alon
|
||||
|
||||
* No `alloc`, no heap needed. Task are statically allocated.
|
||||
* No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
|
||||
* Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
|
||||
* Integrated timer queue: sleeping is easy, just do `Timer::after_secs(1).await;`.
|
||||
* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
|
||||
* Efficient polling: a wake will only poll the woken task, not all of them.
|
||||
* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
|
||||
|
@ -21,7 +21,7 @@ default = ["time"]
|
||||
[dependencies]
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
|
||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
|
||||
"unproven",
|
||||
] }
|
||||
|
@ -76,9 +76,7 @@ where
|
||||
#[cfg(not(feature = "time"))]
|
||||
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
|
||||
#[cfg(feature = "time")]
|
||||
Operation::DelayUs(us) => {
|
||||
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
|
||||
}
|
||||
Operation::DelayUs(us) => embassy_time::Timer::after_micros(*us as _).await,
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -143,9 +141,7 @@ where
|
||||
#[cfg(not(feature = "time"))]
|
||||
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
|
||||
#[cfg(feature = "time")]
|
||||
Operation::DelayUs(us) => {
|
||||
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
|
||||
}
|
||||
Operation::DelayUs(us) => embassy_time::Timer::after_micros(*us as _).await,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ rtos-trace = { version = "0.1.2", optional = true }
|
||||
|
||||
futures-util = { version = "0.3.17", default-features = false }
|
||||
embassy-macros = { version = "0.2.1", path = "../embassy-macros" }
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true}
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true}
|
||||
atomic-polyfill = "1.0.1"
|
||||
critical-section = "1.1"
|
||||
static_cell = "1.1"
|
||||
|
@ -4,7 +4,7 @@ An async/await executor designed for embedded usage.
|
||||
|
||||
- No `alloc`, no heap needed. Task futures are statically allocated.
|
||||
- No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
|
||||
- Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
|
||||
- Integrated timer queue: sleeping is easy, just do `Timer::after_secs(1).await;`.
|
||||
- No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
|
||||
- Efficient polling: a wake will only poll the woken task, not all of them.
|
||||
- Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# embassy-macros
|
||||
# embassy-hal-internal
|
||||
|
||||
An [Embassy](https://embassy.dev) project.
|
||||
|
||||
|
@ -10,7 +10,6 @@ pub mod drop;
|
||||
mod macros;
|
||||
mod peripheral;
|
||||
pub mod ratio;
|
||||
pub mod ring_buffer;
|
||||
pub use peripheral::{Peripheral, PeripheralRef};
|
||||
|
||||
#[cfg(feature = "cortex-m")]
|
||||
|
@ -1,136 +0,0 @@
|
||||
pub struct RingBuffer<'a> {
|
||||
buf: &'a mut [u8],
|
||||
start: usize,
|
||||
end: usize,
|
||||
empty: bool,
|
||||
}
|
||||
|
||||
impl<'a> RingBuffer<'a> {
|
||||
pub fn new(buf: &'a mut [u8]) -> Self {
|
||||
Self {
|
||||
buf,
|
||||
start: 0,
|
||||
end: 0,
|
||||
empty: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_buf(&mut self) -> &mut [u8] {
|
||||
if self.start == self.end && !self.empty {
|
||||
trace!(" ringbuf: push_buf empty");
|
||||
return &mut self.buf[..0];
|
||||
}
|
||||
|
||||
let n = if self.start <= self.end {
|
||||
self.buf.len() - self.end
|
||||
} else {
|
||||
self.start - self.end
|
||||
};
|
||||
|
||||
trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
|
||||
&mut self.buf[self.end..self.end + n]
|
||||
}
|
||||
|
||||
pub fn push(&mut self, n: usize) {
|
||||
trace!(" ringbuf: push {:?}", n);
|
||||
if n == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.end = self.wrap(self.end + n);
|
||||
self.empty = false;
|
||||
}
|
||||
|
||||
pub fn pop_buf(&mut self) -> &mut [u8] {
|
||||
if self.empty {
|
||||
trace!(" ringbuf: pop_buf empty");
|
||||
return &mut self.buf[..0];
|
||||
}
|
||||
|
||||
let n = if self.end <= self.start {
|
||||
self.buf.len() - self.start
|
||||
} else {
|
||||
self.end - self.start
|
||||
};
|
||||
|
||||
trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
|
||||
&mut self.buf[self.start..self.start + n]
|
||||
}
|
||||
|
||||
pub fn pop(&mut self, n: usize) {
|
||||
trace!(" ringbuf: pop {:?}", n);
|
||||
if n == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.start = self.wrap(self.start + n);
|
||||
self.empty = self.start == self.end;
|
||||
}
|
||||
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.start == self.end && !self.empty
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.empty
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.start = 0;
|
||||
self.end = 0;
|
||||
self.empty = true;
|
||||
}
|
||||
|
||||
fn wrap(&self, n: usize) -> usize {
|
||||
assert!(n <= self.buf.len());
|
||||
if n == self.buf.len() {
|
||||
0
|
||||
} else {
|
||||
n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn push_pop() {
|
||||
let mut b = [0; 4];
|
||||
let mut rb = RingBuffer::new(&mut b);
|
||||
let buf = rb.push_buf();
|
||||
assert_eq!(4, buf.len());
|
||||
buf[0] = 1;
|
||||
buf[1] = 2;
|
||||
buf[2] = 3;
|
||||
buf[3] = 4;
|
||||
rb.push(4);
|
||||
|
||||
let buf = rb.pop_buf();
|
||||
assert_eq!(4, buf.len());
|
||||
assert_eq!(1, buf[0]);
|
||||
rb.pop(1);
|
||||
|
||||
let buf = rb.pop_buf();
|
||||
assert_eq!(3, buf.len());
|
||||
assert_eq!(2, buf[0]);
|
||||
rb.pop(1);
|
||||
|
||||
let buf = rb.pop_buf();
|
||||
assert_eq!(2, buf.len());
|
||||
assert_eq!(3, buf[0]);
|
||||
rb.pop(1);
|
||||
|
||||
let buf = rb.pop_buf();
|
||||
assert_eq!(1, buf.len());
|
||||
assert_eq!(4, buf[0]);
|
||||
rb.pop(1);
|
||||
|
||||
let buf = rb.pop_buf();
|
||||
assert_eq!(0, buf.len());
|
||||
|
||||
let buf = rb.push_buf();
|
||||
assert_eq!(4, buf.len());
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ defmt = ["dep:defmt", "lorawan-device/defmt"]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
|
||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||
|
@ -34,6 +34,6 @@ impl lorawan_device::async_device::radio::Timer for LoraTimer {
|
||||
}
|
||||
|
||||
async fn delay_ms(&mut self, millis: u64) {
|
||||
Timer::after(Duration::from_millis(millis)).await
|
||||
Timer::after_millis(millis).await
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ log = { version = "0.4", default-features = false, optional = true }
|
||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
|
||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||
embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] }
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-time = { version = "0.1.3" }
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
bitfield = "0.14.0"
|
||||
|
||||
|
@ -20,7 +20,7 @@ pub use crc32::ETH_FCS;
|
||||
use crc8::crc8;
|
||||
use embassy_futures::select::{select, Either};
|
||||
use embassy_net_driver_channel as ch;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
use embedded_hal_1::digital::OutputPin;
|
||||
use embedded_hal_async::digital::Wait;
|
||||
use embedded_hal_async::spi::{Error, Operation, SpiDevice};
|
||||
@ -609,12 +609,12 @@ pub async fn new<const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait
|
||||
reset.set_low().unwrap();
|
||||
|
||||
// Wait t1: 20-43mS
|
||||
Timer::after(Duration::from_millis(30)).await;
|
||||
Timer::after_millis(30).await;
|
||||
|
||||
reset.set_high().unwrap();
|
||||
|
||||
// Wait t3: 50mS
|
||||
Timer::after(Duration::from_millis(50)).await;
|
||||
Timer::after_millis(50).await;
|
||||
|
||||
// Create device
|
||||
let mut mac = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx);
|
||||
|
18
embassy-net-driver-channel/CHANGELOG.md
Normal file
18
embassy-net-driver-channel/CHANGELOG.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0 - 2023-10-15
|
||||
|
||||
- Update embassy-net-driver
|
||||
- `Runner::new` now takes an `embassy_net_driver::HardwareAddress` parameter
|
||||
- Added `Runner::set_ieee802154_address`, `Runner::ieee802154_address`
|
||||
|
||||
## 0.1.0 - 2023-06-29
|
||||
|
||||
- First release
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-net-driver-channel"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack."
|
||||
@ -26,4 +26,4 @@ log = { version = "0.4.14", optional = true }
|
||||
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||
|
17
embassy-net-driver/CHANGELOG.md
Normal file
17
embassy-net-driver/CHANGELOG.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0 - 2023-10-15
|
||||
|
||||
- Added `Driver::ieee802154_address`
|
||||
- Added `Medium::Ieee802154`
|
||||
|
||||
## 0.1.0 - 2023-06-29
|
||||
|
||||
- First release
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-net-driver"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Driver trait for the `embassy-net` async TCP/IP network stack."
|
||||
|
@ -10,8 +10,8 @@ edition = "2021"
|
||||
[dependencies]
|
||||
embedded-hal = { version = "1.0.0-rc.1" }
|
||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
@ -7,10 +7,10 @@ edition = "2021"
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync"}
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"}
|
||||
|
||||
embedded-hal = { version = "1.0.0-rc.1" }
|
||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||
|
@ -169,9 +169,9 @@ where
|
||||
pub async fn run(mut self) -> ! {
|
||||
debug!("resetting...");
|
||||
self.reset.set_low().unwrap();
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
self.reset.set_high().unwrap();
|
||||
Timer::after(Duration::from_millis(1000)).await;
|
||||
Timer::after_millis(1000).await;
|
||||
|
||||
let mut tx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
|
||||
let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
|
||||
|
@ -16,7 +16,7 @@ defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embedded-io-async = { version = "0.6.0" }
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
ppproto = { version = "0.1.2"}
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||
async-io = "1.6.0"
|
||||
log = "0.4.14"
|
||||
libc = "0.2.101"
|
||||
|
@ -10,8 +10,8 @@ edition = "2021"
|
||||
[dependencies]
|
||||
embedded-hal = { version = "1.0.0-rc.1" }
|
||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
||||
|
@ -8,7 +8,7 @@ mod device;
|
||||
use embassy_futures::select::{select, Either};
|
||||
use embassy_net_driver_channel as ch;
|
||||
use embassy_net_driver_channel::driver::LinkState;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use embedded_hal_async::digital::Wait;
|
||||
use embedded_hal_async::spi::SpiDevice;
|
||||
@ -95,12 +95,12 @@ pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevi
|
||||
// Reset the chip.
|
||||
reset.set_low().ok();
|
||||
// Ensure the reset is registered.
|
||||
Timer::after(Duration::from_millis(1)).await;
|
||||
Timer::after_millis(1).await;
|
||||
reset.set_high().ok();
|
||||
|
||||
// Wait for PLL lock. Some chips are slower than others.
|
||||
// Slowest is w5100s which is 100ms, so let's just wait that.
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap();
|
||||
|
||||
|
31
embassy-net/CHANGELOG.md
Normal file
31
embassy-net/CHANGELOG.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0 - 2023-10-15
|
||||
|
||||
- Re-export `smoltcp::wire::IpEndpoint`
|
||||
- Add poll functions on UdpSocket
|
||||
- Make dual-stack work in embassy-net
|
||||
- Fix multicast support
|
||||
- Allow ethernet and 802.15.4 to coexist
|
||||
- Add IEEE802.15.4 address to embassy net Stack
|
||||
- Use HardwareAddress in Driver
|
||||
- Add async versions of smoltcp's `send` and `recv` closure based API
|
||||
- add error translation to tcp errors
|
||||
- Forward TCP/UDP socket capacity impls
|
||||
- allow changing IP config at runtime
|
||||
- allow non-'static drivers
|
||||
- Remove impl_trait_projections
|
||||
- update embedded-io, embedded-nal-async
|
||||
- add support for dhcp hostname option
|
||||
- Wake stack's task after queueing a DNS query
|
||||
|
||||
## 0.1.0 - 2023-06-29
|
||||
|
||||
- First release
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-net"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Async TCP/IP network stack for embedded systems"
|
||||
@ -51,8 +51,8 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
|
||||
"async",
|
||||
] }
|
||||
|
||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
embedded-io-async = { version = "0.6.0", optional = true }
|
||||
|
||||
|
@ -509,7 +509,10 @@ impl<D: Driver> Stack<D> {
|
||||
self.with_mut(|s, i| {
|
||||
let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
|
||||
match socket.start_query(s.iface.context(), name, qtype) {
|
||||
Ok(handle) => Poll::Ready(Ok(handle)),
|
||||
Ok(handle) => {
|
||||
s.waker.wake();
|
||||
Poll::Ready(Ok(handle))
|
||||
}
|
||||
Err(dns::StartQueryError::NoFreeSlot) => {
|
||||
i.dns_waker.register(cx.waker());
|
||||
Poll::Pending
|
||||
|
@ -94,7 +94,7 @@ _gpio-p1 = []
|
||||
_nrf52832_anomaly_109 = []
|
||||
|
||||
[dependencies]
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
|
||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
|
@ -6,10 +6,13 @@ pub mod pac {
|
||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||
|
||||
pub use nrf5340_app_pac::NVIC_PRIO_BITS;
|
||||
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
interrupt,
|
||||
Interrupt,
|
||||
Peripherals,
|
||||
|
||||
@ -60,156 +63,167 @@ pub mod pac {
|
||||
wdt0_ns as wdt0,
|
||||
};
|
||||
|
||||
#[cfg(feature = "nrf5340-app-ns")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
COMP_NS as COMP,
|
||||
CTRLAP_NS as CTRLAP,
|
||||
DCNF_NS as DCNF,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
EGU1_NS as EGU1,
|
||||
EGU2_NS as EGU2,
|
||||
EGU3_NS as EGU3,
|
||||
EGU4_NS as EGU4,
|
||||
EGU5_NS as EGU5,
|
||||
FPU_NS as FPU,
|
||||
GPIOTE1_NS as GPIOTE1,
|
||||
I2S0_NS as I2S0,
|
||||
IPC_NS as IPC,
|
||||
KMU_NS as KMU,
|
||||
LPCOMP_NS as LPCOMP,
|
||||
MUTEX_NS as MUTEX,
|
||||
NFCT_NS as NFCT,
|
||||
NVMC_NS as NVMC,
|
||||
OSCILLATORS_NS as OSCILLATORS,
|
||||
P0_NS as P0,
|
||||
P1_NS as P1,
|
||||
PDM0_NS as PDM0,
|
||||
POWER_NS as POWER,
|
||||
PWM0_NS as PWM0,
|
||||
PWM1_NS as PWM1,
|
||||
PWM2_NS as PWM2,
|
||||
PWM3_NS as PWM3,
|
||||
QDEC0_NS as QDEC0,
|
||||
QDEC1_NS as QDEC1,
|
||||
QSPI_NS as QSPI,
|
||||
REGULATORS_NS as REGULATORS,
|
||||
RESET_NS as RESET,
|
||||
RTC0_NS as RTC0,
|
||||
RTC1_NS as RTC1,
|
||||
SAADC_NS as SAADC,
|
||||
SPIM0_NS as SPIM0,
|
||||
SPIM1_NS as SPIM1,
|
||||
SPIM2_NS as SPIM2,
|
||||
SPIM3_NS as SPIM3,
|
||||
SPIM4_NS as SPIM4,
|
||||
SPIS0_NS as SPIS0,
|
||||
SPIS1_NS as SPIS1,
|
||||
SPIS2_NS as SPIS2,
|
||||
SPIS3_NS as SPIS3,
|
||||
TIMER0_NS as TIMER0,
|
||||
TIMER1_NS as TIMER1,
|
||||
TIMER2_NS as TIMER2,
|
||||
TWIM0_NS as TWIM0,
|
||||
TWIM1_NS as TWIM1,
|
||||
TWIM2_NS as TWIM2,
|
||||
TWIM3_NS as TWIM3,
|
||||
TWIS0_NS as TWIS0,
|
||||
TWIS1_NS as TWIS1,
|
||||
TWIS2_NS as TWIS2,
|
||||
TWIS3_NS as TWIS3,
|
||||
UARTE0_NS as UARTE0,
|
||||
UARTE1_NS as UARTE1,
|
||||
UARTE2_NS as UARTE2,
|
||||
UARTE3_NS as UARTE3,
|
||||
USBD_NS as USBD,
|
||||
USBREGULATOR_NS as USBREGULATOR,
|
||||
VMC_NS as VMC,
|
||||
WDT0_NS as WDT0,
|
||||
WDT1_NS as WDT1,
|
||||
};
|
||||
/// Non-Secure mode (NS) peripherals
|
||||
pub mod ns {
|
||||
#[cfg(feature = "nrf5340-app-ns")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
COMP_NS as COMP,
|
||||
CTRLAP_NS as CTRLAP,
|
||||
DCNF_NS as DCNF,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
EGU1_NS as EGU1,
|
||||
EGU2_NS as EGU2,
|
||||
EGU3_NS as EGU3,
|
||||
EGU4_NS as EGU4,
|
||||
EGU5_NS as EGU5,
|
||||
FPU_NS as FPU,
|
||||
GPIOTE1_NS as GPIOTE1,
|
||||
I2S0_NS as I2S0,
|
||||
IPC_NS as IPC,
|
||||
KMU_NS as KMU,
|
||||
LPCOMP_NS as LPCOMP,
|
||||
MUTEX_NS as MUTEX,
|
||||
NFCT_NS as NFCT,
|
||||
NVMC_NS as NVMC,
|
||||
OSCILLATORS_NS as OSCILLATORS,
|
||||
P0_NS as P0,
|
||||
P1_NS as P1,
|
||||
PDM0_NS as PDM0,
|
||||
POWER_NS as POWER,
|
||||
PWM0_NS as PWM0,
|
||||
PWM1_NS as PWM1,
|
||||
PWM2_NS as PWM2,
|
||||
PWM3_NS as PWM3,
|
||||
QDEC0_NS as QDEC0,
|
||||
QDEC1_NS as QDEC1,
|
||||
QSPI_NS as QSPI,
|
||||
REGULATORS_NS as REGULATORS,
|
||||
RESET_NS as RESET,
|
||||
RTC0_NS as RTC0,
|
||||
RTC1_NS as RTC1,
|
||||
SAADC_NS as SAADC,
|
||||
SPIM0_NS as SPIM0,
|
||||
SPIM1_NS as SPIM1,
|
||||
SPIM2_NS as SPIM2,
|
||||
SPIM3_NS as SPIM3,
|
||||
SPIM4_NS as SPIM4,
|
||||
SPIS0_NS as SPIS0,
|
||||
SPIS1_NS as SPIS1,
|
||||
SPIS2_NS as SPIS2,
|
||||
SPIS3_NS as SPIS3,
|
||||
TIMER0_NS as TIMER0,
|
||||
TIMER1_NS as TIMER1,
|
||||
TIMER2_NS as TIMER2,
|
||||
TWIM0_NS as TWIM0,
|
||||
TWIM1_NS as TWIM1,
|
||||
TWIM2_NS as TWIM2,
|
||||
TWIM3_NS as TWIM3,
|
||||
TWIS0_NS as TWIS0,
|
||||
TWIS1_NS as TWIS1,
|
||||
TWIS2_NS as TWIS2,
|
||||
TWIS3_NS as TWIS3,
|
||||
UARTE0_NS as UARTE0,
|
||||
UARTE1_NS as UARTE1,
|
||||
UARTE2_NS as UARTE2,
|
||||
UARTE3_NS as UARTE3,
|
||||
USBD_NS as USBD,
|
||||
USBREGULATOR_NS as USBREGULATOR,
|
||||
VMC_NS as VMC,
|
||||
WDT0_NS as WDT0,
|
||||
WDT1_NS as WDT1,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "nrf5340-app-s")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
CACHEDATA_S as CACHEDATA,
|
||||
CACHEINFO_S as CACHEINFO,
|
||||
CACHE_S as CACHE,
|
||||
CLOCK_S as CLOCK,
|
||||
COMP_S as COMP,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
CTI_S as CTI,
|
||||
CTRLAP_S as CTRLAP,
|
||||
DCNF_S as DCNF,
|
||||
DPPIC_S as DPPIC,
|
||||
EGU0_S as EGU0,
|
||||
EGU1_S as EGU1,
|
||||
EGU2_S as EGU2,
|
||||
EGU3_S as EGU3,
|
||||
EGU4_S as EGU4,
|
||||
EGU5_S as EGU5,
|
||||
FICR_S as FICR,
|
||||
FPU_S as FPU,
|
||||
GPIOTE0_S as GPIOTE0,
|
||||
I2S0_S as I2S0,
|
||||
IPC_S as IPC,
|
||||
KMU_S as KMU,
|
||||
LPCOMP_S as LPCOMP,
|
||||
MUTEX_S as MUTEX,
|
||||
NFCT_S as NFCT,
|
||||
NVMC_S as NVMC,
|
||||
OSCILLATORS_S as OSCILLATORS,
|
||||
P0_S as P0,
|
||||
P1_S as P1,
|
||||
PDM0_S as PDM0,
|
||||
POWER_S as POWER,
|
||||
PWM0_S as PWM0,
|
||||
PWM1_S as PWM1,
|
||||
PWM2_S as PWM2,
|
||||
PWM3_S as PWM3,
|
||||
QDEC0_S as QDEC0,
|
||||
QDEC1_S as QDEC1,
|
||||
QSPI_S as QSPI,
|
||||
REGULATORS_S as REGULATORS,
|
||||
RESET_S as RESET,
|
||||
RTC0_S as RTC0,
|
||||
RTC1_S as RTC1,
|
||||
SAADC_S as SAADC,
|
||||
SPIM0_S as SPIM0,
|
||||
SPIM1_S as SPIM1,
|
||||
SPIM2_S as SPIM2,
|
||||
SPIM3_S as SPIM3,
|
||||
SPIM4_S as SPIM4,
|
||||
SPIS0_S as SPIS0,
|
||||
SPIS1_S as SPIS1,
|
||||
SPIS2_S as SPIS2,
|
||||
SPIS3_S as SPIS3,
|
||||
SPU_S as SPU,
|
||||
TAD_S as TAD,
|
||||
TIMER0_S as TIMER0,
|
||||
TIMER1_S as TIMER1,
|
||||
TIMER2_S as TIMER2,
|
||||
TWIM0_S as TWIM0,
|
||||
TWIM1_S as TWIM1,
|
||||
TWIM2_S as TWIM2,
|
||||
TWIM3_S as TWIM3,
|
||||
TWIS0_S as TWIS0,
|
||||
TWIS1_S as TWIS1,
|
||||
TWIS2_S as TWIS2,
|
||||
TWIS3_S as TWIS3,
|
||||
UARTE0_S as UARTE0,
|
||||
UARTE1_S as UARTE1,
|
||||
UARTE2_S as UARTE2,
|
||||
UARTE3_S as UARTE3,
|
||||
UICR_S as UICR,
|
||||
USBD_S as USBD,
|
||||
USBREGULATOR_S as USBREGULATOR,
|
||||
VMC_S as VMC,
|
||||
WDT0_S as WDT0,
|
||||
WDT1_S as WDT1,
|
||||
};
|
||||
/// Secure mode (S) peripherals
|
||||
pub mod s {
|
||||
#[cfg(feature = "nrf5340-app-s")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
CACHEDATA_S as CACHEDATA,
|
||||
CACHEINFO_S as CACHEINFO,
|
||||
CACHE_S as CACHE,
|
||||
CLOCK_S as CLOCK,
|
||||
COMP_S as COMP,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
CTI_S as CTI,
|
||||
CTRLAP_S as CTRLAP,
|
||||
DCNF_S as DCNF,
|
||||
DPPIC_S as DPPIC,
|
||||
EGU0_S as EGU0,
|
||||
EGU1_S as EGU1,
|
||||
EGU2_S as EGU2,
|
||||
EGU3_S as EGU3,
|
||||
EGU4_S as EGU4,
|
||||
EGU5_S as EGU5,
|
||||
FICR_S as FICR,
|
||||
FPU_S as FPU,
|
||||
GPIOTE0_S as GPIOTE0,
|
||||
I2S0_S as I2S0,
|
||||
IPC_S as IPC,
|
||||
KMU_S as KMU,
|
||||
LPCOMP_S as LPCOMP,
|
||||
MUTEX_S as MUTEX,
|
||||
NFCT_S as NFCT,
|
||||
NVMC_S as NVMC,
|
||||
OSCILLATORS_S as OSCILLATORS,
|
||||
P0_S as P0,
|
||||
P1_S as P1,
|
||||
PDM0_S as PDM0,
|
||||
POWER_S as POWER,
|
||||
PWM0_S as PWM0,
|
||||
PWM1_S as PWM1,
|
||||
PWM2_S as PWM2,
|
||||
PWM3_S as PWM3,
|
||||
QDEC0_S as QDEC0,
|
||||
QDEC1_S as QDEC1,
|
||||
QSPI_S as QSPI,
|
||||
REGULATORS_S as REGULATORS,
|
||||
RESET_S as RESET,
|
||||
RTC0_S as RTC0,
|
||||
RTC1_S as RTC1,
|
||||
SAADC_S as SAADC,
|
||||
SPIM0_S as SPIM0,
|
||||
SPIM1_S as SPIM1,
|
||||
SPIM2_S as SPIM2,
|
||||
SPIM3_S as SPIM3,
|
||||
SPIM4_S as SPIM4,
|
||||
SPIS0_S as SPIS0,
|
||||
SPIS1_S as SPIS1,
|
||||
SPIS2_S as SPIS2,
|
||||
SPIS3_S as SPIS3,
|
||||
SPU_S as SPU,
|
||||
TAD_S as TAD,
|
||||
TIMER0_S as TIMER0,
|
||||
TIMER1_S as TIMER1,
|
||||
TIMER2_S as TIMER2,
|
||||
TWIM0_S as TWIM0,
|
||||
TWIM1_S as TWIM1,
|
||||
TWIM2_S as TWIM2,
|
||||
TWIM3_S as TWIM3,
|
||||
TWIS0_S as TWIS0,
|
||||
TWIS1_S as TWIS1,
|
||||
TWIS2_S as TWIS2,
|
||||
TWIS3_S as TWIS3,
|
||||
UARTE0_S as UARTE0,
|
||||
UARTE1_S as UARTE1,
|
||||
UARTE2_S as UARTE2,
|
||||
UARTE3_S as UARTE3,
|
||||
UICR_S as UICR,
|
||||
USBD_S as USBD,
|
||||
USBREGULATOR_S as USBREGULATOR,
|
||||
VMC_S as VMC,
|
||||
WDT0_S as WDT0,
|
||||
WDT1_S as WDT1,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "_ns")]
|
||||
pub use ns::*;
|
||||
#[cfg(feature = "_s")]
|
||||
pub use s::*;
|
||||
}
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
|
@ -7,9 +7,12 @@ pub mod pac {
|
||||
|
||||
pub use nrf5340_net_pac::NVIC_PRIO_BITS;
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_net_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_net_pac::{
|
||||
interrupt,
|
||||
Interrupt,
|
||||
Peripherals,
|
||||
|
||||
|
@ -7,9 +7,12 @@ pub mod pac {
|
||||
|
||||
pub use nrf9160_pac::NVIC_PRIO_BITS;
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
interrupt,
|
||||
Interrupt,
|
||||
|
||||
cc_host_rgf_s as cc_host_rgf,
|
||||
@ -45,122 +48,131 @@ pub mod pac {
|
||||
wdt_ns as wdt,
|
||||
};
|
||||
|
||||
#[cfg(feature = "nrf9160-ns")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
EGU1_NS as EGU1,
|
||||
EGU2_NS as EGU2,
|
||||
EGU3_NS as EGU3,
|
||||
EGU4_NS as EGU4,
|
||||
EGU5_NS as EGU5,
|
||||
FPU_NS as FPU,
|
||||
GPIOTE1_NS as GPIOTE1,
|
||||
I2S_NS as I2S,
|
||||
IPC_NS as IPC,
|
||||
KMU_NS as KMU,
|
||||
NVMC_NS as NVMC,
|
||||
P0_NS as P0,
|
||||
PDM_NS as PDM,
|
||||
POWER_NS as POWER,
|
||||
PWM0_NS as PWM0,
|
||||
PWM1_NS as PWM1,
|
||||
PWM2_NS as PWM2,
|
||||
PWM3_NS as PWM3,
|
||||
REGULATORS_NS as REGULATORS,
|
||||
RTC0_NS as RTC0,
|
||||
RTC1_NS as RTC1,
|
||||
SAADC_NS as SAADC,
|
||||
SPIM0_NS as SPIM0,
|
||||
SPIM1_NS as SPIM1,
|
||||
SPIM2_NS as SPIM2,
|
||||
SPIM3_NS as SPIM3,
|
||||
SPIS0_NS as SPIS0,
|
||||
SPIS1_NS as SPIS1,
|
||||
SPIS2_NS as SPIS2,
|
||||
SPIS3_NS as SPIS3,
|
||||
TIMER0_NS as TIMER0,
|
||||
TIMER1_NS as TIMER1,
|
||||
TIMER2_NS as TIMER2,
|
||||
TWIM0_NS as TWIM0,
|
||||
TWIM1_NS as TWIM1,
|
||||
TWIM2_NS as TWIM2,
|
||||
TWIM3_NS as TWIM3,
|
||||
TWIS0_NS as TWIS0,
|
||||
TWIS1_NS as TWIS1,
|
||||
TWIS2_NS as TWIS2,
|
||||
TWIS3_NS as TWIS3,
|
||||
UARTE0_NS as UARTE0,
|
||||
UARTE1_NS as UARTE1,
|
||||
UARTE2_NS as UARTE2,
|
||||
UARTE3_NS as UARTE3,
|
||||
VMC_NS as VMC,
|
||||
WDT_NS as WDT,
|
||||
};
|
||||
/// Non-Secure mode (NS) peripherals
|
||||
pub mod ns {
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
EGU1_NS as EGU1,
|
||||
EGU2_NS as EGU2,
|
||||
EGU3_NS as EGU3,
|
||||
EGU4_NS as EGU4,
|
||||
EGU5_NS as EGU5,
|
||||
FPU_NS as FPU,
|
||||
GPIOTE1_NS as GPIOTE1,
|
||||
I2S_NS as I2S,
|
||||
IPC_NS as IPC,
|
||||
KMU_NS as KMU,
|
||||
NVMC_NS as NVMC,
|
||||
P0_NS as P0,
|
||||
PDM_NS as PDM,
|
||||
POWER_NS as POWER,
|
||||
PWM0_NS as PWM0,
|
||||
PWM1_NS as PWM1,
|
||||
PWM2_NS as PWM2,
|
||||
PWM3_NS as PWM3,
|
||||
REGULATORS_NS as REGULATORS,
|
||||
RTC0_NS as RTC0,
|
||||
RTC1_NS as RTC1,
|
||||
SAADC_NS as SAADC,
|
||||
SPIM0_NS as SPIM0,
|
||||
SPIM1_NS as SPIM1,
|
||||
SPIM2_NS as SPIM2,
|
||||
SPIM3_NS as SPIM3,
|
||||
SPIS0_NS as SPIS0,
|
||||
SPIS1_NS as SPIS1,
|
||||
SPIS2_NS as SPIS2,
|
||||
SPIS3_NS as SPIS3,
|
||||
TIMER0_NS as TIMER0,
|
||||
TIMER1_NS as TIMER1,
|
||||
TIMER2_NS as TIMER2,
|
||||
TWIM0_NS as TWIM0,
|
||||
TWIM1_NS as TWIM1,
|
||||
TWIM2_NS as TWIM2,
|
||||
TWIM3_NS as TWIM3,
|
||||
TWIS0_NS as TWIS0,
|
||||
TWIS1_NS as TWIS1,
|
||||
TWIS2_NS as TWIS2,
|
||||
TWIS3_NS as TWIS3,
|
||||
UARTE0_NS as UARTE0,
|
||||
UARTE1_NS as UARTE1,
|
||||
UARTE2_NS as UARTE2,
|
||||
UARTE3_NS as UARTE3,
|
||||
VMC_NS as VMC,
|
||||
WDT_NS as WDT,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "nrf9160-s")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
CC_HOST_RGF_S as CC_HOST_RGF,
|
||||
CLOCK_S as CLOCK,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
CTRL_AP_PERI_S as CTRL_AP_PERI,
|
||||
DPPIC_S as DPPIC,
|
||||
EGU0_S as EGU0,
|
||||
EGU1_S as EGU1,
|
||||
EGU2_S as EGU2,
|
||||
EGU3_S as EGU3,
|
||||
EGU4_S as EGU4,
|
||||
EGU5_S as EGU5,
|
||||
FICR_S as FICR,
|
||||
FPU_S as FPU,
|
||||
GPIOTE0_S as GPIOTE0,
|
||||
I2S_S as I2S,
|
||||
IPC_S as IPC,
|
||||
KMU_S as KMU,
|
||||
NVMC_S as NVMC,
|
||||
P0_S as P0,
|
||||
PDM_S as PDM,
|
||||
POWER_S as POWER,
|
||||
PWM0_S as PWM0,
|
||||
PWM1_S as PWM1,
|
||||
PWM2_S as PWM2,
|
||||
PWM3_S as PWM3,
|
||||
REGULATORS_S as REGULATORS,
|
||||
RTC0_S as RTC0,
|
||||
RTC1_S as RTC1,
|
||||
SAADC_S as SAADC,
|
||||
SPIM0_S as SPIM0,
|
||||
SPIM1_S as SPIM1,
|
||||
SPIM2_S as SPIM2,
|
||||
SPIM3_S as SPIM3,
|
||||
SPIS0_S as SPIS0,
|
||||
SPIS1_S as SPIS1,
|
||||
SPIS2_S as SPIS2,
|
||||
SPIS3_S as SPIS3,
|
||||
SPU_S as SPU,
|
||||
TAD_S as TAD,
|
||||
TIMER0_S as TIMER0,
|
||||
TIMER1_S as TIMER1,
|
||||
TIMER2_S as TIMER2,
|
||||
TWIM0_S as TWIM0,
|
||||
TWIM1_S as TWIM1,
|
||||
TWIM2_S as TWIM2,
|
||||
TWIM3_S as TWIM3,
|
||||
TWIS0_S as TWIS0,
|
||||
TWIS1_S as TWIS1,
|
||||
TWIS2_S as TWIS2,
|
||||
TWIS3_S as TWIS3,
|
||||
UARTE0_S as UARTE0,
|
||||
UARTE1_S as UARTE1,
|
||||
UARTE2_S as UARTE2,
|
||||
UARTE3_S as UARTE3,
|
||||
UICR_S as UICR,
|
||||
VMC_S as VMC,
|
||||
WDT_S as WDT,
|
||||
};
|
||||
/// Secure mode (S) peripherals
|
||||
pub mod s {
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
CC_HOST_RGF_S as CC_HOST_RGF,
|
||||
CLOCK_S as CLOCK,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
CTRL_AP_PERI_S as CTRL_AP_PERI,
|
||||
DPPIC_S as DPPIC,
|
||||
EGU0_S as EGU0,
|
||||
EGU1_S as EGU1,
|
||||
EGU2_S as EGU2,
|
||||
EGU3_S as EGU3,
|
||||
EGU4_S as EGU4,
|
||||
EGU5_S as EGU5,
|
||||
FICR_S as FICR,
|
||||
FPU_S as FPU,
|
||||
GPIOTE0_S as GPIOTE0,
|
||||
I2S_S as I2S,
|
||||
IPC_S as IPC,
|
||||
KMU_S as KMU,
|
||||
NVMC_S as NVMC,
|
||||
P0_S as P0,
|
||||
PDM_S as PDM,
|
||||
POWER_S as POWER,
|
||||
PWM0_S as PWM0,
|
||||
PWM1_S as PWM1,
|
||||
PWM2_S as PWM2,
|
||||
PWM3_S as PWM3,
|
||||
REGULATORS_S as REGULATORS,
|
||||
RTC0_S as RTC0,
|
||||
RTC1_S as RTC1,
|
||||
SAADC_S as SAADC,
|
||||
SPIM0_S as SPIM0,
|
||||
SPIM1_S as SPIM1,
|
||||
SPIM2_S as SPIM2,
|
||||
SPIM3_S as SPIM3,
|
||||
SPIS0_S as SPIS0,
|
||||
SPIS1_S as SPIS1,
|
||||
SPIS2_S as SPIS2,
|
||||
SPIS3_S as SPIS3,
|
||||
SPU_S as SPU,
|
||||
TAD_S as TAD,
|
||||
TIMER0_S as TIMER0,
|
||||
TIMER1_S as TIMER1,
|
||||
TIMER2_S as TIMER2,
|
||||
TWIM0_S as TWIM0,
|
||||
TWIM1_S as TWIM1,
|
||||
TWIM2_S as TWIM2,
|
||||
TWIM3_S as TWIM3,
|
||||
TWIS0_S as TWIS0,
|
||||
TWIS1_S as TWIS1,
|
||||
TWIS2_S as TWIS2,
|
||||
TWIS3_S as TWIS3,
|
||||
UARTE0_S as UARTE0,
|
||||
UARTE1_S as UARTE1,
|
||||
UARTE2_S as UARTE2,
|
||||
UARTE3_S as UARTE3,
|
||||
UICR_S as UICR,
|
||||
VMC_S as VMC,
|
||||
WDT_S as WDT,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "_ns")]
|
||||
pub use ns::*;
|
||||
#[cfg(feature = "_s")]
|
||||
pub use s::*;
|
||||
}
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
|
@ -60,7 +60,7 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
|
||||
|
||||
[dependencies]
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
|
||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
|
@ -5,7 +5,7 @@ use core::task::Poll;
|
||||
use atomic_polyfill::{AtomicU8, Ordering};
|
||||
use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
|
||||
use super::*;
|
||||
use crate::clocks::clk_peri_freq;
|
||||
@ -435,7 +435,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
Self::flush().await.unwrap();
|
||||
while self.busy() {}
|
||||
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
||||
Timer::after(Duration::from_micros(wait_usecs)).await;
|
||||
Timer::after_micros(wait_usecs).await;
|
||||
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use atomic_polyfill::{AtomicU16, Ordering};
|
||||
use embassy_futures::select::{select, Either};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
use pac::uart::regs::Uartris;
|
||||
|
||||
use crate::clocks::clk_peri_freq;
|
||||
@ -187,7 +187,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
||||
self.blocking_flush().unwrap();
|
||||
while self.busy() {}
|
||||
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
||||
Timer::after(Duration::from_micros(wait_usecs)).await;
|
||||
Timer::after_micros(wait_usecs).await;
|
||||
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
|
||||
}
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ features = ["stm32wb55rg"]
|
||||
[dependencies]
|
||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" }
|
||||
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver", optional=true }
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
cortex-m = "0.7.6"
|
||||
|
@ -33,11 +33,11 @@ flavors = [
|
||||
|
||||
[dependencies]
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
|
||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
|
||||
embassy-executor = { version = "0.3.0", path = "../embassy-executor", optional = true }
|
||||
|
||||
@ -58,7 +58,7 @@ rand_core = "0.6.3"
|
||||
sdio-host = "0.5.0"
|
||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||
critical-section = "1.1"
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6bfa5a0dcec6a9bd42cea94ba11eeae1a17a7f2c" }
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c20cbde88fdfaef4645361d09df0cb63a4dc6462" }
|
||||
vcell = "0.1.3"
|
||||
bxcan = "0.7.0"
|
||||
nb = "1.0.0"
|
||||
@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
||||
[build-dependencies]
|
||||
proc-macro2 = "1.0.36"
|
||||
quote = "1.0.15"
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6bfa5a0dcec6a9bd42cea94ba11eeae1a17a7f2c", default-features = false, features = ["metadata"]}
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c20cbde88fdfaef4645361d09df0cb63a4dc6462", default-features = false, features = ["metadata"]}
|
||||
|
||||
|
||||
[features]
|
||||
|
@ -5,7 +5,7 @@ use std::{env, fs};
|
||||
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use stm32_metapac::metadata::ir::{BlockItemInner, Enum};
|
||||
use stm32_metapac::metadata::ir::{BlockItemInner, Enum, FieldSet};
|
||||
use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, METADATA};
|
||||
|
||||
fn main() {
|
||||
@ -388,41 +388,37 @@ fn main() {
|
||||
});
|
||||
}
|
||||
|
||||
// ========
|
||||
// Extract the rcc registers
|
||||
let rcc_registers = METADATA
|
||||
.peripherals
|
||||
.iter()
|
||||
.filter_map(|p| p.registers.as_ref())
|
||||
.find(|r| r.kind == "rcc")
|
||||
.unwrap();
|
||||
|
||||
// ========
|
||||
// Generate rcc fieldset and enum maps
|
||||
let rcc_enum_map: HashMap<&str, HashMap<&str, &Enum>> = {
|
||||
let rcc_registers = METADATA
|
||||
.peripherals
|
||||
.iter()
|
||||
.filter_map(|p| p.registers.as_ref())
|
||||
.find(|r| r.kind == "rcc")
|
||||
.unwrap()
|
||||
.ir;
|
||||
let rcc_blocks = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap().items;
|
||||
let rcc_fieldsets: HashMap<&str, &FieldSet> = rcc_registers.ir.fieldsets.iter().map(|f| (f.name, f)).collect();
|
||||
let rcc_enums: HashMap<&str, &Enum> = rcc_registers.ir.enums.iter().map(|e| (e.name, e)).collect();
|
||||
|
||||
let rcc_blocks = rcc_registers.blocks.iter().find(|b| b.name == "Rcc").unwrap().items;
|
||||
|
||||
let rcc_block_item_map: HashMap<&str, &str> = rcc_blocks
|
||||
rcc_blocks
|
||||
.iter()
|
||||
.filter_map(|b| match &b.inner {
|
||||
BlockItemInner::Register(register) => register.fieldset.map(|f| (f, b.name)),
|
||||
BlockItemInner::Register(register) => register.fieldset.map(|f| (b.name, f)),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let rcc_enum_map: HashMap<&str, &Enum> = rcc_registers.enums.iter().map(|e| (e.name, e)).collect();
|
||||
|
||||
rcc_registers
|
||||
.fieldsets
|
||||
.iter()
|
||||
.filter_map(|f| {
|
||||
rcc_block_item_map.get(f.name).map(|b| {
|
||||
.filter_map(|(b, f)| {
|
||||
rcc_fieldsets.get(f).map(|f| {
|
||||
(
|
||||
*b,
|
||||
b,
|
||||
f.fields
|
||||
.iter()
|
||||
.filter_map(|f| {
|
||||
let enumm = f.enumm?;
|
||||
let enumm = rcc_enum_map.get(enumm)?;
|
||||
let enumm = rcc_enums.get(enumm)?;
|
||||
|
||||
Some((f.name, *enumm))
|
||||
})
|
||||
@ -470,9 +466,9 @@ fn main() {
|
||||
|
||||
let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
|
||||
let pname = format_ident!("{}", p.name);
|
||||
let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase());
|
||||
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
|
||||
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
|
||||
let clk = format_ident!("{}", rcc.clock);
|
||||
let en_reg = format_ident!("{}", en.register);
|
||||
let set_en_field = format_ident!("set_{}", en.field);
|
||||
|
||||
let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) {
|
||||
let refcount_static =
|
||||
@ -498,9 +494,11 @@ fn main() {
|
||||
(TokenStream::new(), TokenStream::new())
|
||||
};
|
||||
|
||||
let mux_supported = HashSet::from(["c0", "h5", "h50", "h7", "h7ab", "h7rm0433", "g4", "l4"])
|
||||
.contains(rcc_registers.version);
|
||||
let mux_for = |mux: Option<&'static PeripheralRccRegister>| {
|
||||
// temporary hack to restrict the scope of the implementation to h5
|
||||
if !&chip_name.starts_with("stm32h5") {
|
||||
// restrict mux implementation to supported versions
|
||||
if !mux_supported {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -523,12 +521,16 @@ fn main() {
|
||||
.filter(|v| v.name != "DISABLE")
|
||||
.map(|v| {
|
||||
let variant_name = format_ident!("{}", v.name);
|
||||
let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
|
||||
|
||||
// temporary hack to restrict the scope of the implementation until clock names can be stabilized
|
||||
let clock_name = format_ident!("mux_{}", v.name.to_ascii_lowercase());
|
||||
|
||||
quote! {
|
||||
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
|
||||
if v.name.starts_with("HCLK") || v.name.starts_with("PCLK") || v.name == "SYS" {
|
||||
quote! {
|
||||
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name },
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@ -1012,15 +1014,7 @@ fn main() {
|
||||
|
||||
// ========
|
||||
// Generate Div/Mul impls for RCC prescalers/dividers/multipliers.
|
||||
let rcc_registers = METADATA
|
||||
.peripherals
|
||||
.iter()
|
||||
.filter_map(|p| p.registers.as_ref())
|
||||
.find(|r| r.kind == "rcc")
|
||||
.unwrap()
|
||||
.ir;
|
||||
|
||||
for e in rcc_registers.enums {
|
||||
for e in rcc_registers.ir.enums {
|
||||
fn is_rcc_name(e: &str) -> bool {
|
||||
match e {
|
||||
"Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true,
|
||||
|
@ -564,7 +564,7 @@ foreach_peripheral!(
|
||||
#[cfg(any(rcc_h7, rcc_h7rm0433))]
|
||||
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
|
||||
critical_section::with(|_| unsafe { crate::rcc::get_freqs().pclk1 })
|
||||
}
|
||||
|
||||
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
|
||||
|
@ -191,7 +191,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
||||
// TODO MTU size setting not found for v1 ethernet, check if correct
|
||||
|
||||
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
|
||||
let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
|
||||
let hclk = unsafe { crate::rcc::get_freqs() }.hclk1;
|
||||
let hclk_mhz = hclk.0 / 1_000_000;
|
||||
|
||||
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
|
||||
|
@ -164,7 +164,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
||||
});
|
||||
|
||||
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
|
||||
let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
|
||||
let hclk = unsafe { crate::rcc::get_freqs() }.hclk1;
|
||||
let hclk_mhz = hclk.0 / 1_000_000;
|
||||
|
||||
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
|
||||
|
@ -170,7 +170,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
||||
let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
|
||||
|
||||
#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
let pclk = unsafe { get_freqs() }.plli2s.unwrap();
|
||||
let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
|
||||
|
||||
#[cfg(stm32f410)]
|
||||
let pclk = T::frequency();
|
||||
|
@ -106,7 +106,7 @@ impl LsConfig {
|
||||
|
||||
pub const fn off() -> Self {
|
||||
Self {
|
||||
rtc: RtcClockSource::NOCLOCK,
|
||||
rtc: RtcClockSource::DISABLE,
|
||||
lsi: false,
|
||||
lse: None,
|
||||
}
|
||||
@ -133,7 +133,7 @@ impl LsConfig {
|
||||
Some(LSI_FREQ)
|
||||
}
|
||||
RtcClockSource::LSE => Some(self.lse.as_ref().unwrap().frequency),
|
||||
RtcClockSource::NOCLOCK => None,
|
||||
RtcClockSource::DISABLE => None,
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
@ -180,7 +180,7 @@ impl LsConfig {
|
||||
ok &= reg.rtcsel() == self.rtc;
|
||||
#[cfg(not(rcc_wba))]
|
||||
{
|
||||
ok &= reg.rtcen() == (self.rtc != RtcClockSource::NOCLOCK);
|
||||
ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE);
|
||||
}
|
||||
ok &= reg.lseon() == lse_en;
|
||||
ok &= reg.lsebyp() == lse_byp;
|
||||
@ -225,7 +225,7 @@ impl LsConfig {
|
||||
while !bdcr().read().lserdy() {}
|
||||
}
|
||||
|
||||
if self.rtc != RtcClockSource::NOCLOCK {
|
||||
if self.rtc != RtcClockSource::DISABLE {
|
||||
bdcr().modify(|w| {
|
||||
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
|
||||
assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
|
||||
|
@ -134,10 +134,12 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
};
|
||||
|
||||
set_freqs(Clocks {
|
||||
hsi: None,
|
||||
lse: None,
|
||||
sys: sys_clk,
|
||||
ahb1: ahb_freq,
|
||||
apb1: apb_freq,
|
||||
apb1_tim: apb_tim_freq,
|
||||
hclk1: ahb_freq,
|
||||
pclk1: apb_freq,
|
||||
pclk1_tim: apb_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
@ -162,11 +162,11 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: Hertz(real_sysclk),
|
||||
apb1: Hertz(pclk),
|
||||
apb2: Hertz(pclk),
|
||||
apb1_tim: Hertz(pclk * timer_mul),
|
||||
apb2_tim: Hertz(pclk * timer_mul),
|
||||
ahb1: Hertz(hclk),
|
||||
pclk1: Hertz(pclk),
|
||||
pclk2: Hertz(pclk),
|
||||
pclk1_tim: Hertz(pclk * timer_mul),
|
||||
pclk2_tim: Hertz(pclk * timer_mul),
|
||||
hclk1: Hertz(hclk),
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
@ -102,7 +102,6 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
assert!(pclk2 <= 72_000_000);
|
||||
|
||||
// Only needed for stm32f103?
|
||||
FLASH.acr().write(|w| {
|
||||
w.set_latency(if real_sysclk <= 24_000_000 {
|
||||
Latency::WS0
|
||||
@ -111,6 +110,8 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
} else {
|
||||
Latency::WS2
|
||||
});
|
||||
// the prefetch buffer is enabled by default, let's keep it enabled
|
||||
w.set_prftbe(true);
|
||||
});
|
||||
|
||||
// the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
|
||||
@ -180,11 +181,11 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: Hertz(real_sysclk),
|
||||
apb1: Hertz(pclk1),
|
||||
apb2: Hertz(pclk2),
|
||||
apb1_tim: Hertz(pclk1 * timer_mul1),
|
||||
apb2_tim: Hertz(pclk2 * timer_mul2),
|
||||
ahb1: Hertz(hclk),
|
||||
pclk1: Hertz(pclk1),
|
||||
pclk2: Hertz(pclk2),
|
||||
pclk1_tim: Hertz(pclk1 * timer_mul1),
|
||||
pclk2_tim: Hertz(pclk2 * timer_mul2),
|
||||
hclk1: Hertz(hclk),
|
||||
adc: Some(Hertz(adcclk)),
|
||||
rtc,
|
||||
});
|
||||
|
@ -307,14 +307,14 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
ahb1: ahb_freq,
|
||||
ahb2: ahb_freq,
|
||||
ahb3: ahb_freq,
|
||||
apb1: apb1_freq,
|
||||
apb1_tim: apb1_tim_freq,
|
||||
apb2: apb2_freq,
|
||||
apb2_tim: apb2_tim_freq,
|
||||
pll48: Some(pll_clocks.pll48_freq),
|
||||
hclk1: ahb_freq,
|
||||
hclk2: ahb_freq,
|
||||
hclk3: ahb_freq,
|
||||
pclk1: apb1_freq,
|
||||
pclk1_tim: apb1_tim_freq,
|
||||
pclk2: apb2_freq,
|
||||
pclk2_tim: apb2_tim_freq,
|
||||
pll1_q: Some(pll_clocks.pll48_freq),
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
@ -281,11 +281,11 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sysclk,
|
||||
apb1: pclk1,
|
||||
apb2: pclk2,
|
||||
apb1_tim: pclk1 * timer_mul1,
|
||||
apb2_tim: pclk2 * timer_mul2,
|
||||
ahb1: hclk,
|
||||
pclk1: pclk1,
|
||||
pclk2: pclk2,
|
||||
pclk1_tim: pclk1 * timer_mul1,
|
||||
pclk2_tim: pclk2 * timer_mul2,
|
||||
hclk1: hclk,
|
||||
#[cfg(rcc_f3)]
|
||||
adc: adc,
|
||||
#[cfg(all(rcc_f3, adc3_common))]
|
||||
|
@ -340,23 +340,27 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: Hertz(sysclk),
|
||||
apb1: Hertz(pclk1),
|
||||
apb2: Hertz(pclk2),
|
||||
pclk1: Hertz(pclk1),
|
||||
pclk2: Hertz(pclk2),
|
||||
|
||||
apb1_tim: Hertz(pclk1 * timer_mul1),
|
||||
apb2_tim: Hertz(pclk2 * timer_mul2),
|
||||
pclk1_tim: Hertz(pclk1 * timer_mul1),
|
||||
pclk2_tim: Hertz(pclk2 * timer_mul2),
|
||||
|
||||
ahb1: Hertz(hclk),
|
||||
ahb2: Hertz(hclk),
|
||||
ahb3: Hertz(hclk),
|
||||
hclk1: Hertz(hclk),
|
||||
hclk2: Hertz(hclk),
|
||||
hclk3: Hertz(hclk),
|
||||
|
||||
pll48: plls.pll48clk.map(Hertz),
|
||||
pll1_q: plls.pll48clk.map(Hertz),
|
||||
|
||||
#[cfg(not(stm32f410))]
|
||||
plli2s: plls.plli2sclk.map(Hertz),
|
||||
plli2s1_q: plls.plli2sclk.map(Hertz),
|
||||
#[cfg(not(stm32f410))]
|
||||
plli2s1_r: None,
|
||||
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pllsai: plls.pllsaiclk.map(Hertz),
|
||||
pllsai1_q: plls.pllsaiclk.map(Hertz),
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pllsai1_r: None,
|
||||
|
||||
rtc,
|
||||
});
|
||||
|
@ -259,17 +259,17 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: Hertz(sysclk),
|
||||
apb1: Hertz(pclk1),
|
||||
apb2: Hertz(pclk2),
|
||||
pclk1: Hertz(pclk1),
|
||||
pclk2: Hertz(pclk2),
|
||||
|
||||
apb1_tim: Hertz(pclk1 * timer_mul1),
|
||||
apb2_tim: Hertz(pclk2 * timer_mul2),
|
||||
pclk1_tim: Hertz(pclk1 * timer_mul1),
|
||||
pclk2_tim: Hertz(pclk2 * timer_mul2),
|
||||
|
||||
ahb1: Hertz(hclk),
|
||||
ahb2: Hertz(hclk),
|
||||
ahb3: Hertz(hclk),
|
||||
hclk1: Hertz(hclk),
|
||||
hclk2: Hertz(hclk),
|
||||
hclk3: Hertz(hclk),
|
||||
|
||||
pll48: plls.pll48clk.map(Hertz),
|
||||
pll1_q: plls.pll48clk.map(Hertz),
|
||||
|
||||
rtc,
|
||||
});
|
||||
|
@ -89,7 +89,7 @@ impl Default for Config {
|
||||
impl PllConfig {
|
||||
pub(crate) fn init(self) -> Hertz {
|
||||
let (src, input_freq) = match self.source {
|
||||
PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ),
|
||||
PllSrc::HSI16 => (vals::Pllsrc::HSI, HSI_FREQ),
|
||||
PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq),
|
||||
};
|
||||
|
||||
@ -186,7 +186,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
}
|
||||
ClockSrc::PLL(pll) => {
|
||||
let freq = pll.init();
|
||||
(freq, Sw::PLLRCLK)
|
||||
(freq, Sw::PLL1_R)
|
||||
}
|
||||
ClockSrc::LSI => {
|
||||
// Enable LSI
|
||||
@ -275,9 +275,9 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
ahb1: ahb_freq,
|
||||
apb1: apb_freq,
|
||||
apb1_tim: apb_tim_freq,
|
||||
hclk1: ahb_freq,
|
||||
pclk1: apb_freq,
|
||||
pclk1_tim: apb_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ impl Into<Pllsrc> for PllSrc {
|
||||
fn into(self) -> Pllsrc {
|
||||
match self {
|
||||
PllSrc::HSE(..) => Pllsrc::HSE,
|
||||
PllSrc::HSI16 => Pllsrc::HSI16,
|
||||
PllSrc::HSI16 => Pllsrc::HSI,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,9 +118,9 @@ impl Default for Config {
|
||||
apb2_pre: APBPrescaler::DIV1,
|
||||
low_power_run: false,
|
||||
pll: None,
|
||||
clock_48mhz_src: None,
|
||||
adc12_clock_source: Adcsel::NOCLK,
|
||||
adc345_clock_source: Adcsel::NOCLK,
|
||||
clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(None)),
|
||||
adc12_clock_source: Adcsel::DISABLE,
|
||||
adc345_clock_source: Adcsel::DISABLE,
|
||||
ls: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -201,7 +201,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
RCC.cr().write(|w| w.set_hsion(true));
|
||||
while !RCC.cr().read().hsirdy() {}
|
||||
|
||||
(HSI_FREQ, Sw::HSI16)
|
||||
(HSI_FREQ, Sw::HSI)
|
||||
}
|
||||
ClockSrc::HSE(freq) => {
|
||||
// Enable HSE
|
||||
@ -249,7 +249,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
}
|
||||
}
|
||||
|
||||
(Hertz(freq), Sw::PLLRCLK)
|
||||
(Hertz(freq), Sw::PLL1_R)
|
||||
}
|
||||
};
|
||||
|
||||
@ -286,7 +286,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q);
|
||||
assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000);
|
||||
|
||||
crate::pac::rcc::vals::Clk48sel::PLLQCLK
|
||||
crate::pac::rcc::vals::Clk48sel::PLL1_Q
|
||||
}
|
||||
Clock48MhzSrc::Hsi48(crs_config) => {
|
||||
// Enable HSI48
|
||||
@ -326,16 +326,16 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
|
||||
|
||||
let adc12_ck = match config.adc12_clock_source {
|
||||
AdcClockSource::NOCLK => None,
|
||||
AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p,
|
||||
AdcClockSource::SYSCLK => Some(sys_clk),
|
||||
AdcClockSource::DISABLE => None,
|
||||
AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
|
||||
AdcClockSource::SYS => Some(sys_clk),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let adc345_ck = match config.adc345_clock_source {
|
||||
AdcClockSource::NOCLK => None,
|
||||
AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p,
|
||||
AdcClockSource::SYSCLK => Some(sys_clk),
|
||||
AdcClockSource::DISABLE => None,
|
||||
AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
|
||||
AdcClockSource::SYS => Some(sys_clk),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
@ -348,14 +348,15 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
ahb1: ahb_freq,
|
||||
ahb2: ahb_freq,
|
||||
apb1: apb1_freq,
|
||||
apb1_tim: apb1_tim_freq,
|
||||
apb2: apb2_freq,
|
||||
apb2_tim: apb2_tim_freq,
|
||||
hclk1: ahb_freq,
|
||||
hclk2: ahb_freq,
|
||||
pclk1: apb1_freq,
|
||||
pclk1_tim: apb1_tim_freq,
|
||||
pclk2: apb2_freq,
|
||||
pclk2_tim: apb2_tim_freq,
|
||||
adc: adc12_ck,
|
||||
adc34: adc345_ck,
|
||||
pll1_p: None,
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
@ -163,10 +163,6 @@ impl From<TimerPrescaler> for Timpre {
|
||||
pub struct Config {
|
||||
pub hsi: Option<Hsi>,
|
||||
pub hse: Option<Hse>,
|
||||
#[cfg(stm32h7)]
|
||||
pub lse: Option<Lse>,
|
||||
#[cfg(stm32h7)]
|
||||
pub lsi: bool,
|
||||
pub csi: bool,
|
||||
pub hsi48: bool,
|
||||
pub sys: Sysclk,
|
||||
@ -199,10 +195,6 @@ impl Default for Config {
|
||||
Self {
|
||||
hsi: Some(Hsi::Mhz64),
|
||||
hse: None,
|
||||
#[cfg(stm32h7)]
|
||||
lse: None,
|
||||
#[cfg(stm32h7)]
|
||||
lsi: false,
|
||||
csi: false,
|
||||
hsi48: false,
|
||||
sys: Sysclk::HSI,
|
||||
@ -395,7 +387,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
|
||||
Sysclk::HSE => (unwrap!(hse), Sw::HSE),
|
||||
Sysclk::CSI => (unwrap!(csi), Sw::CSI),
|
||||
Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
|
||||
Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1_P),
|
||||
};
|
||||
|
||||
// Check limits.
|
||||
@ -453,12 +445,12 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
};
|
||||
#[cfg(stm32h5)]
|
||||
let adc = match config.adc_clock_source {
|
||||
AdcClockSource::HCLK => Some(hclk),
|
||||
AdcClockSource::SYSCLK => Some(sys),
|
||||
AdcClockSource::HCLK1 => Some(hclk),
|
||||
AdcClockSource::SYS => Some(sys),
|
||||
AdcClockSource::PLL2_R => pll2.r,
|
||||
AdcClockSource::HSE => hse,
|
||||
AdcClockSource::HSI_KER => hsi,
|
||||
AdcClockSource::CSI_KER => csi,
|
||||
AdcClockSource::HSI => hsi,
|
||||
AdcClockSource::CSI => csi,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
@ -532,66 +524,65 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys,
|
||||
ahb1: hclk,
|
||||
ahb2: hclk,
|
||||
ahb3: hclk,
|
||||
ahb4: hclk,
|
||||
apb1,
|
||||
apb2,
|
||||
apb3,
|
||||
hclk1: hclk,
|
||||
hclk2: hclk,
|
||||
hclk3: hclk,
|
||||
hclk4: hclk,
|
||||
pclk1: apb1,
|
||||
pclk2: apb2,
|
||||
pclk3: apb3,
|
||||
#[cfg(stm32h7)]
|
||||
apb4,
|
||||
apb1_tim,
|
||||
apb2_tim,
|
||||
pclk4: apb4,
|
||||
#[cfg(stm32h5)]
|
||||
pclk4: Hertz(1),
|
||||
pclk1_tim: apb1_tim,
|
||||
pclk2_tim: apb2_tim,
|
||||
adc,
|
||||
rtc,
|
||||
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
hsi: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_rcc_pclk1: Some(apb1),
|
||||
hsi48: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_pll2_q: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_pll3_q: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_hsi_ker: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_csi_ker: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_lse: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_pll1_q: pll1.q,
|
||||
#[cfg(stm32h5)]
|
||||
mux_pll2_p: pll2.p,
|
||||
#[cfg(rcc_h5)]
|
||||
mux_pll3_p: pll3.p,
|
||||
#[cfg(stm32h5)]
|
||||
mux_audioclk: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_per: None,
|
||||
lsi: None,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
csi: None,
|
||||
|
||||
#[cfg(rcc_h5)]
|
||||
mux_pll3_r: pll3.r,
|
||||
#[cfg(all(not(rcc_h5), stm32h5))]
|
||||
mux_pll3_r: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_rcc_pclk3: Some(apb3),
|
||||
#[cfg(stm32h5)]
|
||||
mux_pll3_1: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_hsi48_ker: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_lsi_ker: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_pll2_r: pll2.r,
|
||||
#[cfg(stm32h5)]
|
||||
mux_rcc_pclk2: Some(apb2),
|
||||
#[cfg(stm32h5)]
|
||||
mux_rcc_pclk4: None,
|
||||
#[cfg(stm32h5)]
|
||||
mux_hse: hse,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
lse: None,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
hse: None,
|
||||
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pll1_q: pll1.q,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pll2_p: pll2.p,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pll2_q: pll2.q,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pll2_r: pll2.r,
|
||||
#[cfg(any(rcc_h5, stm32h7))]
|
||||
pll3_p: pll3.p,
|
||||
#[cfg(any(rcc_h5, stm32h7))]
|
||||
pll3_q: pll3.q,
|
||||
#[cfg(any(rcc_h5, stm32h7))]
|
||||
pll3_r: pll3.r,
|
||||
|
||||
#[cfg(rcc_h50)]
|
||||
pll3_p: None,
|
||||
#[cfg(rcc_h50)]
|
||||
pll3_q: None,
|
||||
#[cfg(rcc_h50)]
|
||||
pll3_r: None,
|
||||
|
||||
#[cfg(stm32h5)]
|
||||
mux_hsi48: None,
|
||||
audioclk: None,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
per: None,
|
||||
|
||||
#[cfg(stm32h7)]
|
||||
rcc_pclk_d3: None,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ pub enum PLLSource {
|
||||
impl From<PLLSource> for Pllsrc {
|
||||
fn from(val: PLLSource) -> Pllsrc {
|
||||
match val {
|
||||
PLLSource::HSI16 => Pllsrc::HSI16,
|
||||
PLLSource::HSI16 => Pllsrc::HSI,
|
||||
PLLSource::HSE(_) => Pllsrc::HSE,
|
||||
}
|
||||
}
|
||||
@ -88,7 +88,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
RCC.cr().write(|w| w.set_hsi16on(true));
|
||||
while !RCC.cr().read().hsi16rdy() {}
|
||||
|
||||
(HSI_FREQ, Sw::HSI16)
|
||||
(HSI_FREQ, Sw::HSI)
|
||||
}
|
||||
ClockSrc::HSE(freq) => {
|
||||
// Enable HSE
|
||||
@ -209,11 +209,11 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
ahb1: ahb_freq,
|
||||
apb1: apb1_freq,
|
||||
apb2: apb2_freq,
|
||||
apb1_tim: apb1_tim_freq,
|
||||
apb2_tim: apb2_tim_freq,
|
||||
hclk1: ahb_freq,
|
||||
pclk1: apb1_freq,
|
||||
pclk2: apb2_freq,
|
||||
pclk1_tim: apb1_tim_freq,
|
||||
pclk2_tim: apb2_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
@ -1,296 +0,0 @@
|
||||
use crate::pac::rcc::regs::Cfgr;
|
||||
pub use crate::pac::rcc::vals::{
|
||||
Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv,
|
||||
Pllr as PllRDiv, Ppre as APBPrescaler,
|
||||
};
|
||||
use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
||||
|
||||
/// System clock mux source
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ClockSrc {
|
||||
MSI(MSIRange),
|
||||
PLL(PLLSource, PllRDiv, PllPreDiv, PllMul, Option<PllQDiv>),
|
||||
HSE(Hertz),
|
||||
HSI16,
|
||||
}
|
||||
|
||||
/// PLL clock input source
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PLLSource {
|
||||
HSI16,
|
||||
HSE(Hertz),
|
||||
MSI(MSIRange),
|
||||
}
|
||||
|
||||
impl From<PLLSource> for Pllsrc {
|
||||
fn from(val: PLLSource) -> Pllsrc {
|
||||
match val {
|
||||
PLLSource::HSI16 => Pllsrc::HSI16,
|
||||
PLLSource::HSE(_) => Pllsrc::HSE,
|
||||
PLLSource::MSI(_) => Pllsrc::MSI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clocks configutation
|
||||
pub struct Config {
|
||||
pub mux: ClockSrc,
|
||||
pub ahb_pre: AHBPrescaler,
|
||||
pub apb1_pre: APBPrescaler,
|
||||
pub apb2_pre: APBPrescaler,
|
||||
pub pllsai1: Option<(PllMul, PllPreDiv, Option<PllRDiv>, Option<PllQDiv>, Option<PllPDiv>)>,
|
||||
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
||||
pub hsi48: bool,
|
||||
pub ls: super::LsConfig,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
#[inline]
|
||||
fn default() -> Config {
|
||||
Config {
|
||||
mux: ClockSrc::MSI(MSIRange::RANGE4M),
|
||||
ahb_pre: AHBPrescaler::DIV1,
|
||||
apb1_pre: APBPrescaler::DIV1,
|
||||
apb2_pre: APBPrescaler::DIV1,
|
||||
pllsai1: None,
|
||||
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
||||
hsi48: false,
|
||||
ls: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn init(config: Config) {
|
||||
// Switch to MSI to prevent problems with PLL configuration.
|
||||
if !RCC.cr().read().msion() {
|
||||
// Turn on MSI and configure it to 4MHz.
|
||||
RCC.cr().modify(|w| {
|
||||
w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0].
|
||||
w.set_msirange(MSIRange::RANGE4M);
|
||||
w.set_msipllen(false);
|
||||
w.set_msion(true)
|
||||
});
|
||||
|
||||
// Wait until MSI is running
|
||||
while !RCC.cr().read().msirdy() {}
|
||||
}
|
||||
if RCC.cfgr().read().sws() != Sw::MSI {
|
||||
// Set MSI as a clock source, reset prescalers.
|
||||
RCC.cfgr().write_value(Cfgr::default());
|
||||
// Wait for clock switch status bits to change.
|
||||
while RCC.cfgr().read().sws() != Sw::MSI {}
|
||||
}
|
||||
|
||||
let rtc = config.ls.init();
|
||||
|
||||
let (sys_clk, sw) = match config.mux {
|
||||
ClockSrc::MSI(range) => {
|
||||
// Enable MSI
|
||||
RCC.cr().write(|w| {
|
||||
w.set_msirange(range);
|
||||
w.set_msirgsel(true);
|
||||
w.set_msion(true);
|
||||
|
||||
// If LSE is enabled, enable calibration of MSI
|
||||
w.set_msipllen(config.ls.lse.is_some());
|
||||
});
|
||||
while !RCC.cr().read().msirdy() {}
|
||||
|
||||
// Enable as clock source for USB, RNG if running at 48 MHz
|
||||
if range == MSIRange::RANGE48M {
|
||||
RCC.ccipr().modify(|w| {
|
||||
w.set_clk48sel(0b11);
|
||||
});
|
||||
}
|
||||
(msirange_to_hertz(range), Sw::MSI)
|
||||
}
|
||||
ClockSrc::HSI16 => {
|
||||
// Enable HSI16
|
||||
RCC.cr().write(|w| w.set_hsion(true));
|
||||
while !RCC.cr().read().hsirdy() {}
|
||||
|
||||
(HSI_FREQ, Sw::HSI16)
|
||||
}
|
||||
ClockSrc::HSE(freq) => {
|
||||
// Enable HSE
|
||||
RCC.cr().write(|w| w.set_hseon(true));
|
||||
while !RCC.cr().read().hserdy() {}
|
||||
|
||||
(freq, Sw::HSE)
|
||||
}
|
||||
ClockSrc::PLL(src, divr, prediv, mul, divq) => {
|
||||
let src_freq = match src {
|
||||
PLLSource::HSE(freq) => {
|
||||
// Enable HSE
|
||||
RCC.cr().write(|w| w.set_hseon(true));
|
||||
while !RCC.cr().read().hserdy() {}
|
||||
freq
|
||||
}
|
||||
PLLSource::HSI16 => {
|
||||
// Enable HSI
|
||||
RCC.cr().write(|w| w.set_hsion(true));
|
||||
while !RCC.cr().read().hsirdy() {}
|
||||
HSI_FREQ
|
||||
}
|
||||
PLLSource::MSI(range) => {
|
||||
// Enable MSI
|
||||
RCC.cr().write(|w| {
|
||||
w.set_msirange(range);
|
||||
w.set_msipllen(false); // should be turned on if LSE is started
|
||||
w.set_msirgsel(true);
|
||||
w.set_msion(true);
|
||||
});
|
||||
while !RCC.cr().read().msirdy() {}
|
||||
|
||||
msirange_to_hertz(range)
|
||||
}
|
||||
};
|
||||
|
||||
// Disable PLL
|
||||
RCC.cr().modify(|w| w.set_pllon(false));
|
||||
while RCC.cr().read().pllrdy() {}
|
||||
|
||||
let freq = src_freq / prediv * mul / divr;
|
||||
|
||||
#[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))]
|
||||
assert!(freq.0 <= 120_000_000);
|
||||
#[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))]
|
||||
assert!(freq.0 <= 80_000_000);
|
||||
|
||||
RCC.pllcfgr().write(move |w| {
|
||||
w.set_plln(mul);
|
||||
w.set_pllm(prediv);
|
||||
w.set_pllr(divr);
|
||||
if let Some(divq) = divq {
|
||||
w.set_pllq(divq);
|
||||
w.set_pllqen(true);
|
||||
}
|
||||
w.set_pllsrc(src.into());
|
||||
});
|
||||
|
||||
// Enable as clock source for USB, RNG if PLL48 divisor is provided
|
||||
if let Some(divq) = divq {
|
||||
let freq = src_freq / prediv * mul / divq;
|
||||
assert!(freq.0 == 48_000_000);
|
||||
RCC.ccipr().modify(|w| {
|
||||
w.set_clk48sel(0b10);
|
||||
});
|
||||
}
|
||||
|
||||
if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 {
|
||||
RCC.pllsai1cfgr().write(move |w| {
|
||||
w.set_plln(mul);
|
||||
w.set_pllm(prediv);
|
||||
if let Some(r_div) = r_div {
|
||||
w.set_pllr(r_div);
|
||||
w.set_pllren(true);
|
||||
}
|
||||
if let Some(q_div) = q_div {
|
||||
w.set_pllq(q_div);
|
||||
w.set_pllqen(true);
|
||||
let freq = src_freq / prediv * mul / q_div;
|
||||
if freq.0 == 48_000_000 {
|
||||
RCC.ccipr().modify(|w| {
|
||||
w.set_clk48sel(0b1);
|
||||
});
|
||||
}
|
||||
}
|
||||
if let Some(p_div) = p_div {
|
||||
w.set_pllp(p_div);
|
||||
w.set_pllpen(true);
|
||||
}
|
||||
});
|
||||
|
||||
RCC.cr().modify(|w| w.set_pllsai1on(true));
|
||||
}
|
||||
|
||||
// Enable PLL
|
||||
RCC.cr().modify(|w| w.set_pllon(true));
|
||||
while !RCC.cr().read().pllrdy() {}
|
||||
RCC.pllcfgr().modify(|w| w.set_pllren(true));
|
||||
|
||||
(freq, Sw::PLL)
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
||||
if config.hsi48 {
|
||||
RCC.crrcr().modify(|w| w.set_hsi48on(true));
|
||||
while !RCC.crrcr().read().hsi48rdy() {}
|
||||
|
||||
// Enable as clock source for USB, RNG and SDMMC
|
||||
RCC.ccipr().modify(|w| w.set_clk48sel(0));
|
||||
}
|
||||
|
||||
// Set flash wait states
|
||||
FLASH.acr().modify(|w| {
|
||||
w.set_latency(match sys_clk.0 {
|
||||
0..=16_000_000 => 0,
|
||||
0..=32_000_000 => 1,
|
||||
0..=48_000_000 => 2,
|
||||
0..=64_000_000 => 3,
|
||||
_ => 4,
|
||||
})
|
||||
});
|
||||
|
||||
RCC.cfgr().modify(|w| {
|
||||
w.set_sw(sw);
|
||||
w.set_hpre(config.ahb_pre);
|
||||
w.set_ppre1(config.apb1_pre);
|
||||
w.set_ppre2(config.apb2_pre);
|
||||
});
|
||||
|
||||
let ahb_freq = sys_clk / config.ahb_pre;
|
||||
|
||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||
pre => {
|
||||
let freq = ahb_freq / pre;
|
||||
(freq, freq * 2u32)
|
||||
}
|
||||
};
|
||||
|
||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||
pre => {
|
||||
let freq = ahb_freq / pre;
|
||||
(freq, freq * 2u32)
|
||||
}
|
||||
};
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
ahb1: ahb_freq,
|
||||
ahb2: ahb_freq,
|
||||
ahb3: ahb_freq,
|
||||
apb1: apb1_freq,
|
||||
apb2: apb2_freq,
|
||||
apb1_tim: apb1_tim_freq,
|
||||
apb2_tim: apb2_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
||||
fn msirange_to_hertz(range: Msirange) -> Hertz {
|
||||
match range {
|
||||
MSIRange::RANGE100K => Hertz(100_000),
|
||||
MSIRange::RANGE200K => Hertz(200_000),
|
||||
MSIRange::RANGE400K => Hertz(400_000),
|
||||
MSIRange::RANGE800K => Hertz(800_000),
|
||||
MSIRange::RANGE1M => Hertz(1_000_000),
|
||||
MSIRange::RANGE2M => Hertz(2_000_000),
|
||||
MSIRange::RANGE4M => Hertz(4_000_000),
|
||||
MSIRange::RANGE8M => Hertz(8_000_000),
|
||||
MSIRange::RANGE16M => Hertz(16_000_000),
|
||||
MSIRange::RANGE24M => Hertz(24_000_000),
|
||||
MSIRange::RANGE32M => Hertz(32_000_000),
|
||||
MSIRange::RANGE48M => Hertz(48_000_000),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
446
embassy-stm32/src/rcc/l4l5.rs
Normal file
446
embassy-stm32/src/rcc/l4l5.rs
Normal file
@ -0,0 +1,446 @@
|
||||
use crate::pac::rcc::regs::Cfgr;
|
||||
use crate::pac::rcc::vals::Msirgsel;
|
||||
pub use crate::pac::rcc::vals::{
|
||||
Clk48sel as Clk48Src, Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul,
|
||||
Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PLLSource, Ppre as APBPrescaler, Sw as ClockSrc,
|
||||
};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Pll {
|
||||
/// PLL source
|
||||
pub source: PLLSource,
|
||||
|
||||
/// PLL pre-divider (DIVM).
|
||||
pub prediv: PllPreDiv,
|
||||
|
||||
/// PLL multiplication factor.
|
||||
pub mul: PllMul,
|
||||
|
||||
/// PLL P division factor. If None, PLL P output is disabled.
|
||||
pub divp: Option<PllPDiv>,
|
||||
/// PLL Q division factor. If None, PLL Q output is disabled.
|
||||
pub divq: Option<PllQDiv>,
|
||||
/// PLL R division factor. If None, PLL R output is disabled.
|
||||
pub divr: Option<PllRDiv>,
|
||||
}
|
||||
|
||||
/// Clocks configutation
|
||||
pub struct Config {
|
||||
// base clock sources
|
||||
pub msi: Option<MSIRange>,
|
||||
pub hsi16: bool,
|
||||
pub hse: Option<Hertz>,
|
||||
#[cfg(not(any(stm32l47x, stm32l48x)))]
|
||||
pub hsi48: bool,
|
||||
|
||||
// pll
|
||||
pub pll: Option<Pll>,
|
||||
pub pllsai1: Option<Pll>,
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
pub pllsai2: Option<Pll>,
|
||||
|
||||
// sysclk, buses.
|
||||
pub mux: ClockSrc,
|
||||
pub ahb_pre: AHBPrescaler,
|
||||
pub apb1_pre: APBPrescaler,
|
||||
pub apb2_pre: APBPrescaler,
|
||||
|
||||
// muxes
|
||||
pub clk48_src: Clk48Src,
|
||||
|
||||
// low speed LSI/LSE/RTC
|
||||
pub ls: super::LsConfig,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
#[inline]
|
||||
fn default() -> Config {
|
||||
Config {
|
||||
hse: None,
|
||||
hsi16: false,
|
||||
msi: Some(MSIRange::RANGE4M),
|
||||
mux: ClockSrc::MSI,
|
||||
ahb_pre: AHBPrescaler::DIV1,
|
||||
apb1_pre: APBPrescaler::DIV1,
|
||||
apb2_pre: APBPrescaler::DIV1,
|
||||
pll: None,
|
||||
pllsai1: None,
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
pllsai2: None,
|
||||
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
||||
hsi48: true,
|
||||
clk48_src: Clk48Src::HSI48,
|
||||
ls: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn init(config: Config) {
|
||||
// Switch to MSI to prevent problems with PLL configuration.
|
||||
if !RCC.cr().read().msion() {
|
||||
// Turn on MSI and configure it to 4MHz.
|
||||
RCC.cr().modify(|w| {
|
||||
w.set_msirgsel(Msirgsel::CR);
|
||||
w.set_msirange(MSIRange::RANGE4M);
|
||||
w.set_msipllen(false);
|
||||
w.set_msion(true)
|
||||
});
|
||||
|
||||
// Wait until MSI is running
|
||||
while !RCC.cr().read().msirdy() {}
|
||||
}
|
||||
if RCC.cfgr().read().sws() != ClockSrc::MSI {
|
||||
// Set MSI as a clock source, reset prescalers.
|
||||
RCC.cfgr().write_value(Cfgr::default());
|
||||
// Wait for clock switch status bits to change.
|
||||
while RCC.cfgr().read().sws() != ClockSrc::MSI {}
|
||||
}
|
||||
|
||||
#[cfg(stm32l5)]
|
||||
crate::pac::PWR.cr1().modify(|w| {
|
||||
w.set_vos(crate::pac::pwr::vals::Vos::RANGE0);
|
||||
});
|
||||
|
||||
let rtc = config.ls.init();
|
||||
|
||||
let msi = config.msi.map(|range| {
|
||||
// Enable MSI
|
||||
RCC.cr().write(|w| {
|
||||
w.set_msirange(range);
|
||||
w.set_msirgsel(Msirgsel::CR);
|
||||
w.set_msion(true);
|
||||
|
||||
// If LSE is enabled, enable calibration of MSI
|
||||
w.set_msipllen(config.ls.lse.is_some());
|
||||
});
|
||||
while !RCC.cr().read().msirdy() {}
|
||||
|
||||
// Enable as clock source for USB, RNG if running at 48 MHz
|
||||
if range == MSIRange::RANGE48M {}
|
||||
|
||||
msirange_to_hertz(range)
|
||||
});
|
||||
|
||||
let hsi16 = config.hsi16.then(|| {
|
||||
RCC.cr().write(|w| w.set_hsion(true));
|
||||
while !RCC.cr().read().hsirdy() {}
|
||||
|
||||
HSI_FREQ
|
||||
});
|
||||
|
||||
let hse = config.hse.map(|freq| {
|
||||
RCC.cr().write(|w| w.set_hseon(true));
|
||||
while !RCC.cr().read().hserdy() {}
|
||||
|
||||
freq
|
||||
});
|
||||
|
||||
#[cfg(not(any(stm32l47x, stm32l48x)))]
|
||||
let hsi48 = config.hsi48.then(|| {
|
||||
RCC.crrcr().modify(|w| w.set_hsi48on(true));
|
||||
while !RCC.crrcr().read().hsi48rdy() {}
|
||||
|
||||
Hertz(48_000_000)
|
||||
});
|
||||
#[cfg(any(stm32l47x, stm32l48x))]
|
||||
let hsi48 = None;
|
||||
|
||||
let _plls = [
|
||||
&config.pll,
|
||||
&config.pllsai1,
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
&config.pllsai2,
|
||||
];
|
||||
|
||||
// L4 has shared PLLSRC, PLLM, check it's equal in all PLLs.
|
||||
#[cfg(all(stm32l4, not(rcc_l4plus)))]
|
||||
match get_equal(_plls.into_iter().flatten().map(|p| (p.source, p.prediv))) {
|
||||
Err(()) => panic!("Source must be equal across all enabled PLLs."),
|
||||
Ok(None) => {}
|
||||
Ok(Some((source, prediv))) => RCC.pllcfgr().write(|w| {
|
||||
w.set_pllm(prediv);
|
||||
w.set_pllsrc(source);
|
||||
}),
|
||||
};
|
||||
|
||||
// L4+ has shared PLLSRC, check it's equal in all PLLs.
|
||||
#[cfg(any(rcc_l4plus))]
|
||||
match get_equal(_plls.into_iter().flatten().map(|p| p.source)) {
|
||||
Err(()) => panic!("Source must be equal across all enabled PLLs."),
|
||||
Ok(None) => {}
|
||||
Ok(Some(source)) => RCC.pllcfgr().write(|w| {
|
||||
w.set_pllsrc(source);
|
||||
}),
|
||||
};
|
||||
|
||||
let pll_input = PllInput { hse, hsi16, msi };
|
||||
let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
|
||||
let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input);
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
let _pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input);
|
||||
|
||||
let sys_clk = match config.mux {
|
||||
ClockSrc::HSE => hse.unwrap(),
|
||||
#[cfg(rcc_l5)]
|
||||
ClockSrc::HSI16 => hsi16.unwrap(),
|
||||
#[cfg(not(rcc_l5))]
|
||||
ClockSrc::HSI => hsi16.unwrap(),
|
||||
ClockSrc::MSI => msi.unwrap(),
|
||||
ClockSrc::PLL => pll._r.unwrap(),
|
||||
};
|
||||
|
||||
#[cfg(stm32l4)]
|
||||
RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src));
|
||||
#[cfg(stm32l5)]
|
||||
RCC.ccipr1().modify(|w| w.set_clk48sel(config.clk48_src));
|
||||
let _clk48 = match config.clk48_src {
|
||||
Clk48Src::HSI48 => hsi48,
|
||||
Clk48Src::MSI => msi,
|
||||
Clk48Src::PLLSAI1_Q => pllsai1._q,
|
||||
#[cfg(rcc_l5)]
|
||||
Clk48Src::PLL_Q => pll._q,
|
||||
#[cfg(not(rcc_l5))]
|
||||
Clk48Src::PLL1_Q => pll._q,
|
||||
};
|
||||
|
||||
#[cfg(rcc_l4plus)]
|
||||
assert!(sys_clk.0 <= 120_000_000);
|
||||
#[cfg(all(stm32l4, not(rcc_l4plus)))]
|
||||
assert!(sys_clk.0 <= 80_000_000);
|
||||
|
||||
// Set flash wait states
|
||||
#[cfg(stm32l4)]
|
||||
FLASH.acr().modify(|w| {
|
||||
w.set_latency(match sys_clk.0 {
|
||||
0..=16_000_000 => 0,
|
||||
0..=32_000_000 => 1,
|
||||
0..=48_000_000 => 2,
|
||||
0..=64_000_000 => 3,
|
||||
_ => 4,
|
||||
})
|
||||
});
|
||||
// VCORE Range 0 (performance), others TODO
|
||||
#[cfg(stm32l5)]
|
||||
FLASH.acr().modify(|w| {
|
||||
w.set_latency(match sys_clk.0 {
|
||||
0..=20_000_000 => 0,
|
||||
0..=40_000_000 => 1,
|
||||
0..=60_000_000 => 2,
|
||||
0..=80_000_000 => 3,
|
||||
0..=100_000_000 => 4,
|
||||
_ => 5,
|
||||
})
|
||||
});
|
||||
|
||||
RCC.cfgr().modify(|w| {
|
||||
w.set_sw(config.mux);
|
||||
w.set_hpre(config.ahb_pre);
|
||||
w.set_ppre1(config.apb1_pre);
|
||||
w.set_ppre2(config.apb2_pre);
|
||||
});
|
||||
|
||||
let ahb_freq = sys_clk / config.ahb_pre;
|
||||
|
||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||
pre => {
|
||||
let freq = ahb_freq / pre;
|
||||
(freq, freq * 2u32)
|
||||
}
|
||||
};
|
||||
|
||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||
pre => {
|
||||
let freq = ahb_freq / pre;
|
||||
(freq, freq * 2u32)
|
||||
}
|
||||
};
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
hclk1: ahb_freq,
|
||||
hclk2: ahb_freq,
|
||||
hclk3: ahb_freq,
|
||||
pclk1: apb1_freq,
|
||||
pclk2: apb2_freq,
|
||||
pclk1_tim: apb1_tim_freq,
|
||||
pclk2_tim: apb2_tim_freq,
|
||||
#[cfg(rcc_l4)]
|
||||
hsi: None,
|
||||
#[cfg(rcc_l4)]
|
||||
lse: None,
|
||||
#[cfg(rcc_l4)]
|
||||
pllsai1_p: None,
|
||||
#[cfg(rcc_l4)]
|
||||
pllsai2_p: None,
|
||||
#[cfg(rcc_l4)]
|
||||
pll1_p: None,
|
||||
#[cfg(rcc_l4)]
|
||||
pll1_q: None,
|
||||
#[cfg(rcc_l4)]
|
||||
sai1_extclk: None,
|
||||
#[cfg(rcc_l4)]
|
||||
sai2_extclk: None,
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
||||
fn msirange_to_hertz(range: MSIRange) -> Hertz {
|
||||
match range {
|
||||
MSIRange::RANGE100K => Hertz(100_000),
|
||||
MSIRange::RANGE200K => Hertz(200_000),
|
||||
MSIRange::RANGE400K => Hertz(400_000),
|
||||
MSIRange::RANGE800K => Hertz(800_000),
|
||||
MSIRange::RANGE1M => Hertz(1_000_000),
|
||||
MSIRange::RANGE2M => Hertz(2_000_000),
|
||||
MSIRange::RANGE4M => Hertz(4_000_000),
|
||||
MSIRange::RANGE8M => Hertz(8_000_000),
|
||||
MSIRange::RANGE16M => Hertz(16_000_000),
|
||||
MSIRange::RANGE24M => Hertz(24_000_000),
|
||||
MSIRange::RANGE32M => Hertz(32_000_000),
|
||||
MSIRange::RANGE48M => Hertz(48_000_000),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn get_equal<T: Eq>(mut iter: impl Iterator<Item = T>) -> Result<Option<T>, ()> {
|
||||
let Some(x) = iter.next() else { return Ok(None) };
|
||||
if !iter.all(|y| y == x) {
|
||||
return Err(());
|
||||
}
|
||||
return Ok(Some(x));
|
||||
}
|
||||
|
||||
struct PllInput {
|
||||
hsi16: Option<Hertz>,
|
||||
hse: Option<Hertz>,
|
||||
msi: Option<Hertz>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct PllOutput {
|
||||
_p: Option<Hertz>,
|
||||
_q: Option<Hertz>,
|
||||
_r: Option<Hertz>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
enum PllInstance {
|
||||
Pll,
|
||||
Pllsai1,
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
Pllsai2,
|
||||
}
|
||||
|
||||
fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
||||
// Disable PLL
|
||||
match instance {
|
||||
PllInstance::Pll => {
|
||||
RCC.cr().modify(|w| w.set_pllon(false));
|
||||
while RCC.cr().read().pllrdy() {}
|
||||
}
|
||||
PllInstance::Pllsai1 => {
|
||||
RCC.cr().modify(|w| w.set_pllsai1on(false));
|
||||
while RCC.cr().read().pllsai1rdy() {}
|
||||
}
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
PllInstance::Pllsai2 => {
|
||||
RCC.cr().modify(|w| w.set_pllsai2on(false));
|
||||
while RCC.cr().read().pllsai2rdy() {}
|
||||
}
|
||||
}
|
||||
|
||||
let Some(pll) = config else { return PllOutput::default() };
|
||||
|
||||
let pll_src = match pll.source {
|
||||
PLLSource::NONE => panic!("must not select PLL source as NONE"),
|
||||
PLLSource::HSE => input.hse,
|
||||
#[cfg(rcc_l5)]
|
||||
PLLSource::HSI16 => input.hsi16,
|
||||
#[cfg(not(rcc_l5))]
|
||||
PLLSource::HSI => input.hsi16,
|
||||
PLLSource::MSI => input.msi,
|
||||
};
|
||||
|
||||
let pll_src = pll_src.unwrap();
|
||||
|
||||
let vco_freq = pll_src / pll.prediv * pll.mul;
|
||||
|
||||
let p = pll.divp.map(|div| vco_freq / div);
|
||||
let q = pll.divq.map(|div| vco_freq / div);
|
||||
let r = pll.divr.map(|div| vco_freq / div);
|
||||
|
||||
#[cfg(stm32l5)]
|
||||
if instance == PllInstance::Pllsai2 {
|
||||
assert!(q.is_none(), "PLLSAI2_Q is not available on L5");
|
||||
assert!(r.is_none(), "PLLSAI2_R is not available on L5");
|
||||
}
|
||||
|
||||
macro_rules! write_fields {
|
||||
($w:ident) => {
|
||||
$w.set_plln(pll.mul);
|
||||
if let Some(divp) = pll.divp {
|
||||
$w.set_pllp(divp);
|
||||
$w.set_pllpen(true);
|
||||
}
|
||||
if let Some(divq) = pll.divq {
|
||||
$w.set_pllq(divq);
|
||||
$w.set_pllqen(true);
|
||||
}
|
||||
if let Some(divr) = pll.divr {
|
||||
$w.set_pllr(divr);
|
||||
$w.set_pllren(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
match instance {
|
||||
PllInstance::Pll => RCC.pllcfgr().write(|w| {
|
||||
w.set_pllm(pll.prediv);
|
||||
w.set_pllsrc(pll.source);
|
||||
write_fields!(w);
|
||||
}),
|
||||
PllInstance::Pllsai1 => RCC.pllsai1cfgr().write(|w| {
|
||||
#[cfg(any(rcc_l4plus, stm32l5))]
|
||||
w.set_pllm(pll.prediv);
|
||||
#[cfg(stm32l5)]
|
||||
w.set_pllsrc(pll.source);
|
||||
write_fields!(w);
|
||||
}),
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
PllInstance::Pllsai2 => RCC.pllsai2cfgr().write(|w| {
|
||||
#[cfg(any(rcc_l4plus, stm32l5))]
|
||||
w.set_pllm(pll.prediv);
|
||||
#[cfg(stm32l5)]
|
||||
w.set_pllsrc(pll.source);
|
||||
write_fields!(w);
|
||||
}),
|
||||
}
|
||||
|
||||
// Enable PLL
|
||||
match instance {
|
||||
PllInstance::Pll => {
|
||||
RCC.cr().modify(|w| w.set_pllon(true));
|
||||
while !RCC.cr().read().pllrdy() {}
|
||||
}
|
||||
PllInstance::Pllsai1 => {
|
||||
RCC.cr().modify(|w| w.set_pllsai1on(true));
|
||||
while !RCC.cr().read().pllsai1rdy() {}
|
||||
}
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
PllInstance::Pllsai2 => {
|
||||
RCC.cr().modify(|w| w.set_pllsai2on(true));
|
||||
while !RCC.cr().read().pllsai2rdy() {}
|
||||
}
|
||||
}
|
||||
|
||||
PllOutput { _p: p, _q: q, _r: r }
|
||||
}
|
@ -1,291 +0,0 @@
|
||||
use crate::pac::rcc::regs::Cfgr;
|
||||
pub use crate::pac::rcc::vals::{
|
||||
Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv,
|
||||
Pllr as PllRDiv, Ppre as APBPrescaler,
|
||||
};
|
||||
use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw};
|
||||
use crate::pac::{FLASH, PWR, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
||||
|
||||
/// System clock mux source
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ClockSrc {
|
||||
MSI(MSIRange),
|
||||
PLL(PLLSource, PllRDiv, PllPreDiv, PllMul, Option<PllQDiv>),
|
||||
HSE(Hertz),
|
||||
HSI16,
|
||||
}
|
||||
|
||||
/// PLL clock input source
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PLLSource {
|
||||
HSI16,
|
||||
HSE(Hertz),
|
||||
MSI(MSIRange),
|
||||
}
|
||||
|
||||
impl From<PLLSource> for Pllsrc {
|
||||
fn from(val: PLLSource) -> Pllsrc {
|
||||
match val {
|
||||
PLLSource::HSI16 => Pllsrc::HSI16,
|
||||
PLLSource::HSE(_) => Pllsrc::HSE,
|
||||
PLLSource::MSI(_) => Pllsrc::MSI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clocks configutation
|
||||
pub struct Config {
|
||||
pub mux: ClockSrc,
|
||||
pub ahb_pre: AHBPrescaler,
|
||||
pub apb1_pre: APBPrescaler,
|
||||
pub apb2_pre: APBPrescaler,
|
||||
pub pllsai1: Option<(PllMul, PllPreDiv, Option<PllRDiv>, Option<PllQDiv>, Option<PllPDiv>)>,
|
||||
pub hsi48: bool,
|
||||
pub ls: super::LsConfig,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
#[inline]
|
||||
fn default() -> Config {
|
||||
Config {
|
||||
mux: ClockSrc::MSI(MSIRange::RANGE4M),
|
||||
ahb_pre: AHBPrescaler::DIV1,
|
||||
apb1_pre: APBPrescaler::DIV1,
|
||||
apb2_pre: APBPrescaler::DIV1,
|
||||
pllsai1: None,
|
||||
hsi48: false,
|
||||
ls: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn init(config: Config) {
|
||||
// Switch to MSI to prevent problems with PLL configuration.
|
||||
if !RCC.cr().read().msion() {
|
||||
// Turn on MSI and configure it to 4MHz.
|
||||
RCC.cr().modify(|w| {
|
||||
w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0].
|
||||
w.set_msirange(MSIRange::RANGE4M);
|
||||
w.set_msipllen(false);
|
||||
w.set_msion(true)
|
||||
});
|
||||
|
||||
// Wait until MSI is running
|
||||
while !RCC.cr().read().msirdy() {}
|
||||
}
|
||||
if RCC.cfgr().read().sws() != Sw::MSI {
|
||||
// Set MSI as a clock source, reset prescalers.
|
||||
RCC.cfgr().write_value(Cfgr::default());
|
||||
// Wait for clock switch status bits to change.
|
||||
while RCC.cfgr().read().sws() != Sw::MSI {}
|
||||
}
|
||||
|
||||
let rtc = config.ls.init();
|
||||
|
||||
PWR.cr1().modify(|w| w.set_vos(stm32_metapac::pwr::vals::Vos::RANGE0));
|
||||
let (sys_clk, sw) = match config.mux {
|
||||
ClockSrc::MSI(range) => {
|
||||
// Enable MSI
|
||||
RCC.cr().write(|w| {
|
||||
w.set_msirange(range);
|
||||
w.set_msirgsel(true);
|
||||
w.set_msion(true);
|
||||
|
||||
// If LSE is enabled, enable calibration of MSI
|
||||
w.set_msipllen(config.ls.lse.is_some());
|
||||
});
|
||||
while !RCC.cr().read().msirdy() {}
|
||||
|
||||
// Enable as clock source for USB, RNG if running at 48 MHz
|
||||
if range == MSIRange::RANGE48M {
|
||||
RCC.ccipr1().modify(|w| {
|
||||
w.set_clk48msel(0b11);
|
||||
});
|
||||
}
|
||||
(msirange_to_hertz(range), Sw::MSI)
|
||||
}
|
||||
ClockSrc::HSI16 => {
|
||||
// Enable HSI16
|
||||
RCC.cr().write(|w| w.set_hsion(true));
|
||||
while !RCC.cr().read().hsirdy() {}
|
||||
|
||||
(HSI_FREQ, Sw::HSI16)
|
||||
}
|
||||
ClockSrc::HSE(freq) => {
|
||||
// Enable HSE
|
||||
RCC.cr().write(|w| w.set_hseon(true));
|
||||
while !RCC.cr().read().hserdy() {}
|
||||
|
||||
(freq, Sw::HSE)
|
||||
}
|
||||
ClockSrc::PLL(src, divr, prediv, mul, divq) => {
|
||||
let src_freq = match src {
|
||||
PLLSource::HSE(freq) => {
|
||||
// Enable HSE
|
||||
RCC.cr().write(|w| w.set_hseon(true));
|
||||
while !RCC.cr().read().hserdy() {}
|
||||
freq
|
||||
}
|
||||
PLLSource::HSI16 => {
|
||||
// Enable HSI
|
||||
RCC.cr().write(|w| w.set_hsion(true));
|
||||
while !RCC.cr().read().hsirdy() {}
|
||||
HSI_FREQ
|
||||
}
|
||||
PLLSource::MSI(range) => {
|
||||
// Enable MSI
|
||||
RCC.cr().write(|w| {
|
||||
w.set_msirange(range);
|
||||
w.set_msipllen(false); // should be turned on if LSE is started
|
||||
w.set_msirgsel(true);
|
||||
w.set_msion(true);
|
||||
});
|
||||
while !RCC.cr().read().msirdy() {}
|
||||
|
||||
msirange_to_hertz(range)
|
||||
}
|
||||
};
|
||||
|
||||
// Disable PLL
|
||||
RCC.cr().modify(|w| w.set_pllon(false));
|
||||
while RCC.cr().read().pllrdy() {}
|
||||
|
||||
let freq = src_freq / prediv * mul / divr;
|
||||
|
||||
RCC.pllcfgr().write(move |w| {
|
||||
w.set_plln(mul);
|
||||
w.set_pllm(prediv);
|
||||
w.set_pllr(divr);
|
||||
if let Some(divq) = divq {
|
||||
w.set_pllq(divq);
|
||||
w.set_pllqen(true);
|
||||
}
|
||||
w.set_pllsrc(src.into());
|
||||
});
|
||||
|
||||
// Enable as clock source for USB, RNG if PLL48 divisor is provided
|
||||
if let Some(divq) = divq {
|
||||
let freq = src_freq / prediv * mul / divq;
|
||||
assert!(freq.0 == 48_000_000);
|
||||
RCC.ccipr1().modify(|w| {
|
||||
w.set_clk48msel(0b10);
|
||||
});
|
||||
}
|
||||
|
||||
if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 {
|
||||
RCC.pllsai1cfgr().write(move |w| {
|
||||
w.set_plln(mul);
|
||||
w.set_pllm(prediv);
|
||||
if let Some(r_div) = r_div {
|
||||
w.set_pllr(r_div);
|
||||
w.set_pllren(true);
|
||||
}
|
||||
if let Some(q_div) = q_div {
|
||||
w.set_pllq(q_div);
|
||||
w.set_pllqen(true);
|
||||
let freq = src_freq / prediv * mul / q_div;
|
||||
if freq.0 == 48_000_000 {
|
||||
RCC.ccipr1().modify(|w| {
|
||||
w.set_clk48msel(0b1);
|
||||
});
|
||||
}
|
||||
}
|
||||
if let Some(p_div) = p_div {
|
||||
w.set_pllp(p_div);
|
||||
w.set_pllpen(true);
|
||||
}
|
||||
});
|
||||
|
||||
RCC.cr().modify(|w| w.set_pllsai1on(true));
|
||||
}
|
||||
|
||||
// Enable PLL
|
||||
RCC.cr().modify(|w| w.set_pllon(true));
|
||||
while !RCC.cr().read().pllrdy() {}
|
||||
RCC.pllcfgr().modify(|w| w.set_pllren(true));
|
||||
|
||||
(freq, Sw::PLL)
|
||||
}
|
||||
};
|
||||
|
||||
if config.hsi48 {
|
||||
RCC.crrcr().modify(|w| w.set_hsi48on(true));
|
||||
while !RCC.crrcr().read().hsi48rdy() {}
|
||||
|
||||
// Enable as clock source for USB, RNG and SDMMC
|
||||
RCC.ccipr1().modify(|w| w.set_clk48msel(0));
|
||||
}
|
||||
|
||||
// Set flash wait states
|
||||
// VCORE Range 0 (performance), others TODO
|
||||
FLASH.acr().modify(|w| {
|
||||
w.set_latency(match sys_clk.0 {
|
||||
0..=20_000_000 => 0,
|
||||
0..=40_000_000 => 1,
|
||||
0..=60_000_000 => 2,
|
||||
0..=80_000_000 => 3,
|
||||
0..=100_000_000 => 4,
|
||||
_ => 5,
|
||||
})
|
||||
});
|
||||
|
||||
RCC.cfgr().modify(|w| {
|
||||
w.set_sw(sw);
|
||||
w.set_hpre(config.ahb_pre);
|
||||
w.set_ppre1(config.apb1_pre);
|
||||
w.set_ppre2(config.apb2_pre);
|
||||
});
|
||||
|
||||
let ahb_freq = sys_clk / config.ahb_pre;
|
||||
|
||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||
pre => {
|
||||
let freq = ahb_freq / pre;
|
||||
(freq, freq * 2u32)
|
||||
}
|
||||
};
|
||||
|
||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||
pre => {
|
||||
let freq = ahb_freq / pre;
|
||||
(freq, freq * 2u32)
|
||||
}
|
||||
};
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
ahb1: ahb_freq,
|
||||
ahb2: ahb_freq,
|
||||
ahb3: ahb_freq,
|
||||
apb1: apb1_freq,
|
||||
apb2: apb2_freq,
|
||||
apb1_tim: apb1_tim_freq,
|
||||
apb2_tim: apb2_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
||||
fn msirange_to_hertz(range: Msirange) -> Hertz {
|
||||
match range {
|
||||
MSIRange::RANGE100K => Hertz(100_000),
|
||||
MSIRange::RANGE200K => Hertz(200_000),
|
||||
MSIRange::RANGE400K => Hertz(400_000),
|
||||
MSIRange::RANGE800K => Hertz(800_000),
|
||||
MSIRange::RANGE1M => Hertz(1_000_000),
|
||||
MSIRange::RANGE2M => Hertz(2_000_000),
|
||||
MSIRange::RANGE4M => Hertz(4_000_000),
|
||||
MSIRange::RANGE8M => Hertz(8_000_000),
|
||||
MSIRange::RANGE16M => Hertz(16_000_000),
|
||||
MSIRange::RANGE24M => Hertz(24_000_000),
|
||||
MSIRange::RANGE32M => Hertz(32_000_000),
|
||||
MSIRange::RANGE48M => Hertz(48_000_000),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
@ -20,8 +20,7 @@ pub use mco::*;
|
||||
#[cfg_attr(rcc_g4, path = "g4.rs")]
|
||||
#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")]
|
||||
#[cfg_attr(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")]
|
||||
#[cfg_attr(rcc_l4, path = "l4.rs")]
|
||||
#[cfg_attr(rcc_l5, path = "l5.rs")]
|
||||
#[cfg_attr(any(rcc_l4, rcc_l4plus, rcc_l5), path = "l4l5.rs")]
|
||||
#[cfg_attr(rcc_u5, path = "u5.rs")]
|
||||
#[cfg_attr(rcc_wb, path = "wb.rs")]
|
||||
#[cfg_attr(rcc_wba, path = "wba.rs")]
|
||||
@ -48,23 +47,24 @@ pub struct Clocks {
|
||||
pub sys: Hertz,
|
||||
|
||||
// APB
|
||||
pub apb1: Hertz,
|
||||
pub apb1_tim: Hertz,
|
||||
pub pclk1: Hertz,
|
||||
pub pclk1_tim: Hertz,
|
||||
#[cfg(not(any(rcc_c0, rcc_g0)))]
|
||||
pub apb2: Hertz,
|
||||
pub pclk2: Hertz,
|
||||
#[cfg(not(any(rcc_c0, rcc_g0)))]
|
||||
pub apb2_tim: Hertz,
|
||||
pub pclk2_tim: Hertz,
|
||||
#[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_u5))]
|
||||
pub apb3: Hertz,
|
||||
#[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab))]
|
||||
pub apb4: Hertz,
|
||||
pub pclk3: Hertz,
|
||||
#[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab, stm32h5))]
|
||||
pub pclk4: Hertz,
|
||||
#[cfg(any(rcc_wba))]
|
||||
pub apb7: Hertz,
|
||||
pub pclk7: Hertz,
|
||||
|
||||
// AHB
|
||||
pub ahb1: Hertz,
|
||||
pub hclk1: Hertz,
|
||||
#[cfg(any(
|
||||
rcc_l4,
|
||||
rcc_l4plus,
|
||||
rcc_l5,
|
||||
rcc_f2,
|
||||
rcc_f4,
|
||||
@ -82,9 +82,10 @@ pub struct Clocks {
|
||||
rcc_wl5,
|
||||
rcc_wle
|
||||
))]
|
||||
pub ahb2: Hertz,
|
||||
pub hclk2: Hertz,
|
||||
#[cfg(any(
|
||||
rcc_l4,
|
||||
rcc_l4plus,
|
||||
rcc_l5,
|
||||
rcc_f2,
|
||||
rcc_f4,
|
||||
@ -100,18 +101,40 @@ pub struct Clocks {
|
||||
rcc_wl5,
|
||||
rcc_wle
|
||||
))]
|
||||
pub ahb3: Hertz,
|
||||
pub hclk3: Hertz,
|
||||
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))]
|
||||
pub ahb4: Hertz,
|
||||
|
||||
#[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))]
|
||||
pub pll48: Option<Hertz>,
|
||||
pub hclk4: Hertz,
|
||||
|
||||
#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
pub plli2s: Option<Hertz>,
|
||||
pub plli2s1_q: Option<Hertz>,
|
||||
#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
pub plli2s1_r: Option<Hertz>,
|
||||
|
||||
#[cfg(rcc_l4)]
|
||||
pub pllsai1_p: Option<Hertz>,
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pub pllsai: Option<Hertz>,
|
||||
pub pllsai1_q: Option<Hertz>,
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pub pllsai1_r: Option<Hertz>,
|
||||
#[cfg(rcc_l4)]
|
||||
pub pllsai2_p: Option<Hertz>,
|
||||
|
||||
#[cfg(any(stm32g4, rcc_l4))]
|
||||
pub pll1_p: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_l4))]
|
||||
pub pll1_q: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll2_p: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll2_q: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll2_r: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll3_p: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll3_q: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll3_r: Option<Hertz>,
|
||||
|
||||
#[cfg(any(
|
||||
rcc_f1,
|
||||
@ -135,51 +158,31 @@ pub struct Clocks {
|
||||
|
||||
pub rtc: Option<Hertz>,
|
||||
|
||||
#[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))]
|
||||
pub hsi: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_rcc_pclk1: Option<Hertz>,
|
||||
pub hsi48: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_pll2_q: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_pll3_q: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_hsi_ker: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_csi_ker: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_lse: Option<Hertz>,
|
||||
pub lsi: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub csi: Option<Hertz>,
|
||||
|
||||
#[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))]
|
||||
pub lse: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub hse: Option<Hertz>,
|
||||
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_pll1_q: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_pll2_p: Option<Hertz>,
|
||||
#[cfg(rcc_h5)]
|
||||
pub mux_pll3_p: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_audioclk: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_per: Option<Hertz>,
|
||||
pub audioclk: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub per: Option<Hertz>,
|
||||
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_pll3_r: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_rcc_pclk3: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_pll3_1: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_hsi48_ker: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_lsi_ker: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_pll2_r: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_rcc_pclk2: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_rcc_pclk4: Option<Hertz>,
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_hse: Option<Hertz>,
|
||||
|
||||
#[cfg(stm32h5)]
|
||||
pub mux_hsi48: Option<Hertz>,
|
||||
#[cfg(stm32h7)]
|
||||
pub rcc_pclk_d3: Option<Hertz>,
|
||||
#[cfg(rcc_l4)]
|
||||
pub sai1_extclk: Option<Hertz>,
|
||||
#[cfg(rcc_l4)]
|
||||
pub sai2_extclk: Option<Hertz>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
|
@ -188,7 +188,7 @@ impl Default for Config {
|
||||
apb1_pre: APBPrescaler::DIV1,
|
||||
apb2_pre: APBPrescaler::DIV1,
|
||||
apb3_pre: APBPrescaler::DIV1,
|
||||
hsi48: false,
|
||||
hsi48: true,
|
||||
voltage_range: VoltageScale::RANGE3,
|
||||
ls: Default::default(),
|
||||
}
|
||||
@ -436,14 +436,14 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
ahb1: ahb_freq,
|
||||
ahb2: ahb_freq,
|
||||
ahb3: ahb_freq,
|
||||
apb1: apb1_freq,
|
||||
apb2: apb2_freq,
|
||||
apb3: apb3_freq,
|
||||
apb1_tim: apb1_tim_freq,
|
||||
apb2_tim: apb2_tim_freq,
|
||||
hclk1: ahb_freq,
|
||||
hclk2: ahb_freq,
|
||||
hclk3: ahb_freq,
|
||||
pclk1: apb1_freq,
|
||||
pclk2: apb2_freq,
|
||||
pclk3: apb3_freq,
|
||||
pclk1_tim: apb1_tim_freq,
|
||||
pclk2_tim: apb2_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ pub struct Config {
|
||||
pub hse: Option<Hse>,
|
||||
pub sys: Sysclk,
|
||||
pub mux: Option<PllMux>,
|
||||
pub hsi48: bool,
|
||||
|
||||
pub pll: Option<Pll>,
|
||||
pub pllsai: Option<Pll>,
|
||||
@ -63,6 +64,7 @@ pub const WPAN_DEFAULT: Config = Config {
|
||||
source: PllSource::HSE,
|
||||
prediv: Pllm::DIV2,
|
||||
}),
|
||||
hsi48: true,
|
||||
|
||||
ls: super::LsConfig::default_lse(),
|
||||
|
||||
@ -90,6 +92,7 @@ impl Default for Config {
|
||||
mux: None,
|
||||
pll: None,
|
||||
pllsai: None,
|
||||
hsi48: true,
|
||||
|
||||
ls: Default::default(),
|
||||
|
||||
@ -222,6 +225,13 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let _hsi48 = config.hsi48.then(|| {
|
||||
rcc.crrcr().modify(|w| w.set_hsi48on(true));
|
||||
while !rcc.crrcr().read().hsi48rdy() {}
|
||||
|
||||
Hertz(48_000_000)
|
||||
});
|
||||
|
||||
rcc.cfgr().modify(|w| {
|
||||
w.set_sw(config.sys.into());
|
||||
w.set_hpre(config.ahb1_pre);
|
||||
@ -236,13 +246,13 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
ahb1: ahb1_clk,
|
||||
ahb2: ahb2_clk,
|
||||
ahb3: ahb3_clk,
|
||||
apb1: apb1_clk,
|
||||
apb2: apb2_clk,
|
||||
apb1_tim: apb1_tim_clk,
|
||||
apb2_tim: apb2_tim_clk,
|
||||
hclk1: ahb1_clk,
|
||||
hclk2: ahb2_clk,
|
||||
hclk3: ahb3_clk,
|
||||
pclk1: apb1_clk,
|
||||
pclk2: apb2_clk,
|
||||
pclk1_tim: apb1_tim_clk,
|
||||
pclk2_tim: apb2_tim_clk,
|
||||
rtc,
|
||||
})
|
||||
}
|
||||
|
@ -142,14 +142,14 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
ahb1: ahb_freq,
|
||||
ahb2: ahb_freq,
|
||||
ahb4: ahb_freq,
|
||||
apb1: apb1_freq,
|
||||
apb2: apb2_freq,
|
||||
apb7: apb7_freq,
|
||||
apb1_tim: apb1_tim_freq,
|
||||
apb2_tim: apb2_tim_freq,
|
||||
hclk1: ahb_freq,
|
||||
hclk2: ahb_freq,
|
||||
hclk4: ahb_freq,
|
||||
pclk1: apb1_freq,
|
||||
pclk2: apb2_freq,
|
||||
pclk7: apb7_freq,
|
||||
pclk1_tim: apb1_tim_freq,
|
||||
pclk2_tim: apb2_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
@ -145,14 +145,14 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
ahb1: ahb_freq,
|
||||
ahb2: ahb_freq,
|
||||
ahb3: shd_ahb_freq,
|
||||
apb1: apb1_freq,
|
||||
apb2: apb2_freq,
|
||||
apb3: shd_ahb_freq,
|
||||
apb1_tim: apb1_tim_freq,
|
||||
apb2_tim: apb2_tim_freq,
|
||||
hclk1: ahb_freq,
|
||||
hclk2: ahb_freq,
|
||||
hclk3: shd_ahb_freq,
|
||||
pclk1: apb1_freq,
|
||||
pclk2: apb2_freq,
|
||||
pclk3: shd_ahb_freq,
|
||||
pclk1_tim: apb1_tim_freq,
|
||||
pclk2_tim: apb2_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ impl<'d, T: Instance> Rng<'d, T> {
|
||||
reg.set_ie(false);
|
||||
reg.set_rngen(true);
|
||||
});
|
||||
T::regs().cr().write(|reg| {
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_ced(false);
|
||||
});
|
||||
// wait for CONDRST to be set
|
||||
|
@ -1457,7 +1457,7 @@ cfg_if::cfg_if! {
|
||||
macro_rules! kernel_clk {
|
||||
($inst:ident) => {
|
||||
critical_section::with(|_| unsafe {
|
||||
crate::rcc::get_freqs().pll48
|
||||
crate::rcc::get_freqs().pll1_q
|
||||
}).expect("PLL48 is required for SDIO")
|
||||
}
|
||||
}
|
||||
@ -1469,7 +1469,7 @@ cfg_if::cfg_if! {
|
||||
if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYSCLK {
|
||||
crate::rcc::get_freqs().sys
|
||||
} else {
|
||||
crate::rcc::get_freqs().pll48.expect("PLL48 is required for SDMMC")
|
||||
crate::rcc::get_freqs().pll1_q.expect("PLL48 is required for SDMMC")
|
||||
}
|
||||
})
|
||||
};
|
||||
@ -1479,7 +1479,7 @@ cfg_if::cfg_if! {
|
||||
if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYSCLK {
|
||||
crate::rcc::get_freqs().sys
|
||||
} else {
|
||||
crate::rcc::get_freqs().pll48.expect("PLL48 is required for SDMMC")
|
||||
crate::rcc::get_freqs().pll1_q.expect("PLL48 is required for SDMMC")
|
||||
}
|
||||
})
|
||||
};
|
||||
|
@ -322,7 +322,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
}
|
||||
|
||||
/// Reconfigures it with the supplied config.
|
||||
fn set_config(&mut self, config: Config) {
|
||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ()> {
|
||||
let cpha = config.raw_phase();
|
||||
let cpol = config.raw_polarity();
|
||||
|
||||
@ -351,6 +351,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
w.set_mbr(br);
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_current_config(&self) -> Config {
|
||||
@ -1062,8 +1063,6 @@ impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> {
|
||||
type Config = Config;
|
||||
type ConfigError = ();
|
||||
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
|
||||
self.set_config(*config);
|
||||
|
||||
Ok(())
|
||||
self.set_config(config)
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
|
||||
this.inner.set_frequency(freq);
|
||||
this.inner.start();
|
||||
|
||||
this.inner.enable_outputs(true);
|
||||
this.inner.enable_outputs();
|
||||
|
||||
this.inner
|
||||
.set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
|
||||
|
@ -173,7 +173,7 @@ pub(crate) mod sealed {
|
||||
}
|
||||
});
|
||||
}
|
||||
fn enable_outputs(&mut self, _enable: bool) {}
|
||||
fn enable_outputs(&mut self);
|
||||
|
||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
|
||||
let r = Self::regs_gp16();
|
||||
@ -401,7 +401,9 @@ macro_rules! impl_32bit_timer {
|
||||
#[allow(unused)]
|
||||
macro_rules! impl_compare_capable_16bit {
|
||||
($inst:ident) => {
|
||||
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn enable_outputs(&mut self) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -450,7 +452,13 @@ foreach_interrupt! {
|
||||
impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl AdvancedControlInstance for crate::peripherals::$inst {}
|
||||
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn enable_outputs(&mut self) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
let r = Self::regs_advanced();
|
||||
r.bdtr().modify(|w| w.set_moe(true));
|
||||
}
|
||||
}
|
||||
impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||
fn regs_gp16() -> crate::pac::timer::TimGp16 {
|
||||
|
@ -70,7 +70,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
||||
this.inner.set_frequency(freq);
|
||||
this.inner.start();
|
||||
|
||||
this.inner.enable_outputs(true);
|
||||
this.inner.enable_outputs();
|
||||
|
||||
this.inner
|
||||
.set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
|
||||
|
@ -253,7 +253,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
||||
(self.tx, self.rx)
|
||||
}
|
||||
|
||||
fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
reconfigure::<T>(config)
|
||||
}
|
||||
}
|
||||
@ -333,7 +333,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
reconfigure::<T>(config)
|
||||
}
|
||||
}
|
||||
@ -407,7 +407,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
reconfigure::<T>(config)
|
||||
}
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
|
||||
})
|
||||
}
|
||||
|
||||
fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
reconfigure::<T>(config)
|
||||
}
|
||||
|
||||
@ -373,7 +373,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
||||
})
|
||||
}
|
||||
|
||||
fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
reconfigure::<T>(config)
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
|
||||
Err(err)
|
||||
}
|
||||
|
||||
fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
self.teardown_uart();
|
||||
reconfigure::<T>(config)
|
||||
}
|
||||
|
@ -5,7 +5,14 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.1.4 - ???
|
||||
## 0.1.5 - 2023-10-16
|
||||
|
||||
- Added `links` key to Cargo.toml, to prevent multiple copies of this crate in the same binary.
|
||||
Needed because different copies might get different tick rates, causing
|
||||
wrong delays if the time driver is using one copy and user code is using another.
|
||||
This is especially common when mixing crates from crates.io and git.
|
||||
|
||||
## 0.1.4 - 2023-10-12
|
||||
|
||||
- Added more tick rates
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-time"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
edition = "2021"
|
||||
description = "Instant and Duration for embedded no-std systems, with async timer support"
|
||||
repository = "https://github.com/embassy-rs/embassy"
|
||||
@ -13,6 +13,12 @@ categories = [
|
||||
"asynchronous",
|
||||
]
|
||||
|
||||
# Prevent multiple copies of this crate in the same binary.
|
||||
# Needed because different copies might get different tick rates, causing
|
||||
# wrong delays if the time driver is using one copy and user code is using another.
|
||||
# This is especially common when mixing crates from crates.io and git.
|
||||
links = "embassy-time"
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-v$VERSION/embassy-time/src/"
|
||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time/src/"
|
||||
|
3
embassy-time/build.rs
Normal file
3
embassy-time/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
// empty, needed to be able to use `links` in Cargo.toml.
|
||||
|
||||
fn main() {}
|
@ -36,11 +36,11 @@ mod eha {
|
||||
|
||||
impl embedded_hal_async::delay::DelayUs for Delay {
|
||||
async fn delay_us(&mut self, micros: u32) {
|
||||
Timer::after(Duration::from_micros(micros as _)).await
|
||||
Timer::after_micros(micros as _).await
|
||||
}
|
||||
|
||||
async fn delay_ms(&mut self, millis: u32) {
|
||||
Timer::after(Duration::from_millis(millis as _)).await
|
||||
Timer::after_millis(millis as _).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,42 @@ impl Timer {
|
||||
yielded_once: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Expire after the specified number of ticks.
|
||||
///
|
||||
/// This method is a convenience wrapper for calling `Timer::after(Duration::from_ticks())`.
|
||||
/// For more details, refer to [`Timer::after()`] and [`Duration::from_ticks()`].
|
||||
#[inline]
|
||||
pub fn after_ticks(ticks: u64) -> Self {
|
||||
Self::after(Duration::from_ticks(ticks))
|
||||
}
|
||||
|
||||
/// Expire after the specified number of microseconds.
|
||||
///
|
||||
/// This method is a convenience wrapper for calling `Timer::after(Duration::from_micros())`.
|
||||
/// For more details, refer to [`Timer::after()`] and [`Duration::from_micros()`].
|
||||
#[inline]
|
||||
pub fn after_micros(micros: u64) -> Self {
|
||||
Self::after(Duration::from_micros(micros))
|
||||
}
|
||||
|
||||
/// Expire after the specified number of milliseconds.
|
||||
///
|
||||
/// This method is a convenience wrapper for calling `Timer::after(Duration::from_millis())`.
|
||||
/// For more details, refer to [`Timer::after`] and [`Duration::from_millis()`].
|
||||
#[inline]
|
||||
pub fn after_millis(millis: u64) -> Self {
|
||||
Self::after(Duration::from_millis(millis))
|
||||
}
|
||||
|
||||
/// Expire after the specified number of seconds.
|
||||
///
|
||||
/// This method is a convenience wrapper for calling `Timer::after(Duration::from_secs())`.
|
||||
/// For more details, refer to [`Timer::after`] and [`Duration::from_secs()`].
|
||||
#[inline]
|
||||
pub fn after_secs(secs: u64) -> Self {
|
||||
Self::after(Duration::from_secs(secs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Unpin for Timer {}
|
||||
|
@ -42,7 +42,7 @@ max-handler-count-8 = []
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
@ -70,9 +70,11 @@ fn main() {
|
||||
|
||||
// envvars take priority.
|
||||
if !cfg.seen_env {
|
||||
if cfg.seen_feature {
|
||||
panic!("multiple values set for feature {}: {} and {}", name, cfg.value, value);
|
||||
}
|
||||
assert!(
|
||||
!cfg.seen_feature,
|
||||
"multiple values set for feature {}: {} and {}",
|
||||
name, cfg.value, value
|
||||
);
|
||||
|
||||
cfg.value = value;
|
||||
cfg.seen_feature = true;
|
||||
|
@ -1,17 +1,17 @@
|
||||
use heapless::Vec;
|
||||
|
||||
use crate::config::*;
|
||||
use crate::config::MAX_HANDLER_COUNT;
|
||||
use crate::descriptor::{BosWriter, DescriptorWriter};
|
||||
use crate::driver::{Driver, Endpoint, EndpointType};
|
||||
#[cfg(feature = "msos-descriptor")]
|
||||
use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter};
|
||||
use crate::types::*;
|
||||
use crate::types::{InterfaceNumber, StringIndex};
|
||||
use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[non_exhaustive]
|
||||
/// Configuration used when creating [UsbDevice].
|
||||
/// Configuration used when creating [`UsbDevice`].
|
||||
pub struct Config<'a> {
|
||||
pub(crate) vendor_id: u16,
|
||||
pub(crate) product_id: u16,
|
||||
@ -99,7 +99,7 @@ pub struct Config<'a> {
|
||||
|
||||
impl<'a> Config<'a> {
|
||||
/// Create default configuration with the provided vid and pid values.
|
||||
pub fn new(vid: u16, pid: u16) -> Self {
|
||||
pub const fn new(vid: u16, pid: u16) -> Self {
|
||||
Self {
|
||||
device_class: 0x00,
|
||||
device_sub_class: 0x00,
|
||||
@ -159,9 +159,10 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
|
||||
panic!("if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01");
|
||||
}
|
||||
|
||||
if config.max_power > 500 {
|
||||
panic!("The maximum allowed value for `max_power` is 500mA");
|
||||
}
|
||||
assert!(
|
||||
config.max_power <= 500,
|
||||
"The maximum allowed value for `max_power` is 500mA"
|
||||
);
|
||||
|
||||
match config.max_packet_size_0 {
|
||||
8 | 16 | 32 | 64 => {}
|
||||
@ -260,12 +261,11 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
|
||||
/// The Handler is called on some USB bus events, and to handle all control requests not already
|
||||
/// handled by the USB stack.
|
||||
pub fn handler(&mut self, handler: &'d mut dyn Handler) {
|
||||
if self.handlers.push(handler).is_err() {
|
||||
panic!(
|
||||
"embassy-usb: handler list full. Increase the `max_handler_count` compile-time setting. Current value: {}",
|
||||
MAX_HANDLER_COUNT
|
||||
)
|
||||
}
|
||||
assert!(
|
||||
self.handlers.push(handler).is_ok(),
|
||||
"embassy-usb: handler list full. Increase the `max_handler_count` compile-time setting. Current value: {}",
|
||||
MAX_HANDLER_COUNT
|
||||
);
|
||||
}
|
||||
|
||||
/// Allocates a new string index.
|
||||
@ -332,12 +332,10 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
|
||||
num_alt_settings: 0,
|
||||
};
|
||||
|
||||
if self.builder.interfaces.push(iface).is_err() {
|
||||
panic!(
|
||||
"embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}",
|
||||
MAX_INTERFACE_COUNT
|
||||
)
|
||||
}
|
||||
assert!(self.builder.interfaces.push(iface).is_ok(),
|
||||
"embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}",
|
||||
MAX_INTERFACE_COUNT
|
||||
);
|
||||
|
||||
InterfaceBuilder {
|
||||
builder: self.builder,
|
||||
@ -371,7 +369,7 @@ pub struct InterfaceBuilder<'a, 'd, D: Driver<'d>> {
|
||||
|
||||
impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
|
||||
/// Get the interface number.
|
||||
pub fn interface_number(&self) -> InterfaceNumber {
|
||||
pub const fn interface_number(&self) -> InterfaceNumber {
|
||||
self.interface_number
|
||||
}
|
||||
|
||||
@ -422,12 +420,12 @@ pub struct InterfaceAltBuilder<'a, 'd, D: Driver<'d>> {
|
||||
|
||||
impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
||||
/// Get the interface number.
|
||||
pub fn interface_number(&self) -> InterfaceNumber {
|
||||
pub const fn interface_number(&self) -> InterfaceNumber {
|
||||
self.interface_number
|
||||
}
|
||||
|
||||
/// Get the alternate setting number.
|
||||
pub fn alt_setting_number(&self) -> u8 {
|
||||
pub const fn alt_setting_number(&self) -> u8 {
|
||||
self.alt_setting_number
|
||||
}
|
||||
|
||||
@ -436,7 +434,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
||||
/// Descriptors are written in the order builder functions are called. Note that some
|
||||
/// classes care about the order.
|
||||
pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) {
|
||||
self.builder.config_descriptor.write(descriptor_type, descriptor)
|
||||
self.builder.config_descriptor.write(descriptor_type, descriptor);
|
||||
}
|
||||
|
||||
fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {
|
||||
|
@ -11,7 +11,7 @@ use embassy_sync::waitqueue::WakerRegistration;
|
||||
|
||||
use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
|
||||
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
||||
use crate::types::*;
|
||||
use crate::types::InterfaceNumber;
|
||||
use crate::{Builder, Handler};
|
||||
|
||||
/// This should be used as `device_class` when building the `UsbDevice`.
|
||||
@ -39,12 +39,18 @@ pub struct State<'a> {
|
||||
shared: ControlShared,
|
||||
}
|
||||
|
||||
impl<'a> Default for State<'a> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> State<'a> {
|
||||
/// Create a new `State`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
control: MaybeUninit::uninit(),
|
||||
shared: Default::default(),
|
||||
shared: ControlShared::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,9 +61,9 @@ impl<'a> State<'a> {
|
||||
/// writing USB packets with no intermediate buffers, but it will not act like a stream-like serial
|
||||
/// port. The following constraints must be followed if you use this class directly:
|
||||
///
|
||||
/// - `read_packet` must be called with a buffer large enough to hold max_packet_size bytes.
|
||||
/// - `write_packet` must not be called with a buffer larger than max_packet_size bytes.
|
||||
/// - If you write a packet that is exactly max_packet_size bytes long, it won't be processed by the
|
||||
/// - `read_packet` must be called with a buffer large enough to hold `max_packet_size` bytes.
|
||||
/// - `write_packet` must not be called with a buffer larger than `max_packet_size` bytes.
|
||||
/// - If you write a packet that is exactly `max_packet_size` bytes long, it won't be processed by the
|
||||
/// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP)
|
||||
/// can be sent if there is no other data to send. This is because USB bulk transactions must be
|
||||
/// terminated with a short packet, even if the bulk endpoint is used for stream-like data.
|
||||
@ -103,17 +109,16 @@ impl Default for ControlShared {
|
||||
|
||||
impl ControlShared {
|
||||
async fn changed(&self) {
|
||||
poll_fn(|cx| match self.changed.load(Ordering::Relaxed) {
|
||||
true => {
|
||||
poll_fn(|cx| {
|
||||
if self.changed.load(Ordering::Relaxed) {
|
||||
self.changed.store(false, Ordering::Relaxed);
|
||||
Poll::Ready(())
|
||||
}
|
||||
false => {
|
||||
} else {
|
||||
self.waker.borrow_mut().register(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,7 +197,7 @@ impl<'d> Handler for Control<'d> {
|
||||
// REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
|
||||
REQ_GET_LINE_CODING if req.length == 7 => {
|
||||
debug!("Sending line coding");
|
||||
let coding = self.shared().line_coding.lock(|x| x.get());
|
||||
let coding = self.shared().line_coding.lock(Cell::get);
|
||||
assert!(buf.len() >= 7);
|
||||
buf[0..4].copy_from_slice(&coding.data_rate.to_le_bytes());
|
||||
buf[4] = coding.stop_bits as u8;
|
||||
@ -206,8 +211,8 @@ impl<'d> Handler for Control<'d> {
|
||||
}
|
||||
|
||||
impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
||||
/// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For
|
||||
/// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
|
||||
/// Creates a new CdcAcmClass with the provided UsbBus and `max_packet_size` in bytes. For
|
||||
/// full-speed devices, `max_packet_size` has to be one of 8, 16, 32 or 64.
|
||||
pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, max_packet_size: u16) -> Self {
|
||||
assert!(builder.control_buf_len() >= 7);
|
||||
|
||||
@ -242,7 +247,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
||||
&[
|
||||
CDC_TYPE_UNION, // bDescriptorSubtype
|
||||
comm_if.into(), // bControlInterface
|
||||
data_if.into(), // bSubordinateInterface
|
||||
data_if, // bSubordinateInterface
|
||||
],
|
||||
);
|
||||
|
||||
@ -283,7 +288,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
||||
/// Gets the current line coding. The line coding contains information that's mainly relevant
|
||||
/// for USB to UART serial port emulators, and can be ignored if not relevant.
|
||||
pub fn line_coding(&self) -> LineCoding {
|
||||
self.control.line_coding.lock(|x| x.get())
|
||||
self.control.line_coding.lock(Cell::get)
|
||||
}
|
||||
|
||||
/// Gets the DTR (data terminal ready) state
|
||||
@ -308,7 +313,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
||||
|
||||
/// Waits for the USB host to enable this interface
|
||||
pub async fn wait_connection(&mut self) {
|
||||
self.read_ep.wait_enabled().await
|
||||
self.read_ep.wait_enabled().await;
|
||||
}
|
||||
|
||||
/// Split the class into a sender and receiver.
|
||||
@ -356,7 +361,7 @@ pub struct ControlChanged<'d> {
|
||||
impl<'d> ControlChanged<'d> {
|
||||
/// Return a future for when the control settings change
|
||||
pub async fn control_changed(&self) {
|
||||
self.control.changed().await
|
||||
self.control.changed().await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,7 +383,7 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
|
||||
/// Gets the current line coding. The line coding contains information that's mainly relevant
|
||||
/// for USB to UART serial port emulators, and can be ignored if not relevant.
|
||||
pub fn line_coding(&self) -> LineCoding {
|
||||
self.control.line_coding.lock(|x| x.get())
|
||||
self.control.line_coding.lock(Cell::get)
|
||||
}
|
||||
|
||||
/// Gets the DTR (data terminal ready) state
|
||||
@ -398,7 +403,7 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
|
||||
|
||||
/// Waits for the USB host to enable this interface
|
||||
pub async fn wait_connection(&mut self) {
|
||||
self.write_ep.wait_enabled().await
|
||||
self.write_ep.wait_enabled().await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,7 +425,7 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
|
||||
/// Gets the current line coding. The line coding contains information that's mainly relevant
|
||||
/// for USB to UART serial port emulators, and can be ignored if not relevant.
|
||||
pub fn line_coding(&self) -> LineCoding {
|
||||
self.control.line_coding.lock(|x| x.get())
|
||||
self.control.line_coding.lock(Cell::get)
|
||||
}
|
||||
|
||||
/// Gets the DTR (data terminal ready) state
|
||||
@ -440,7 +445,7 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
|
||||
|
||||
/// Waits for the USB host to enable this interface
|
||||
pub async fn wait_connection(&mut self) {
|
||||
self.read_ep.wait_enabled().await
|
||||
self.read_ep.wait_enabled().await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,17 +519,17 @@ impl LineCoding {
|
||||
}
|
||||
|
||||
/// Gets the number of data bits for UART communication.
|
||||
pub fn data_bits(&self) -> u8 {
|
||||
pub const fn data_bits(&self) -> u8 {
|
||||
self.data_bits
|
||||
}
|
||||
|
||||
/// Gets the parity type for UART communication.
|
||||
pub fn parity_type(&self) -> ParityType {
|
||||
pub const fn parity_type(&self) -> ParityType {
|
||||
self.parity_type
|
||||
}
|
||||
|
||||
/// Gets the data rate in bits per second for UART communication.
|
||||
pub fn data_rate(&self) -> u32 {
|
||||
pub const fn data_rate(&self) -> u32 {
|
||||
self.data_rate
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,11 @@
|
||||
|
||||
use core::intrinsics::copy_nonoverlapping;
|
||||
use core::mem::{size_of, MaybeUninit};
|
||||
use core::ptr::addr_of;
|
||||
|
||||
use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
|
||||
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
||||
use crate::types::*;
|
||||
use crate::types::{InterfaceNumber, StringIndex};
|
||||
use crate::{Builder, Handler};
|
||||
|
||||
pub mod embassy_net;
|
||||
@ -62,9 +63,9 @@ const REQ_SET_NTB_INPUT_SIZE: u8 = 0x86;
|
||||
//const NOTIF_POLL_INTERVAL: u8 = 20;
|
||||
|
||||
const NTB_MAX_SIZE: usize = 2048;
|
||||
const SIG_NTH: u32 = 0x484d434e;
|
||||
const SIG_NDP_NO_FCS: u32 = 0x304d434e;
|
||||
const SIG_NDP_WITH_FCS: u32 = 0x314d434e;
|
||||
const SIG_NTH: u32 = 0x484d_434e;
|
||||
const SIG_NDP_NO_FCS: u32 = 0x304d_434e;
|
||||
const SIG_NDP_WITH_FCS: u32 = 0x314d_434e;
|
||||
|
||||
const ALTERNATE_SETTING_DISABLED: u8 = 0x00;
|
||||
const ALTERNATE_SETTING_ENABLED: u8 = 0x01;
|
||||
@ -111,7 +112,7 @@ struct NtbParametersDir {
|
||||
|
||||
fn byteify<T>(buf: &mut [u8], data: T) -> &[u8] {
|
||||
let len = size_of::<T>();
|
||||
unsafe { copy_nonoverlapping(&data as *const _ as *const u8, buf.as_mut_ptr(), len) }
|
||||
unsafe { copy_nonoverlapping(addr_of!(data).cast(), buf.as_mut_ptr(), len) }
|
||||
&buf[..len]
|
||||
}
|
||||
|
||||
@ -121,27 +122,28 @@ pub struct State<'a> {
|
||||
shared: ControlShared,
|
||||
}
|
||||
|
||||
impl<'a> Default for State<'a> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> State<'a> {
|
||||
/// Create a new `State`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
control: MaybeUninit::uninit(),
|
||||
shared: Default::default(),
|
||||
shared: ControlShared::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared data between Control and CdcAcmClass
|
||||
/// Shared data between Control and `CdcAcmClass`
|
||||
#[derive(Default)]
|
||||
struct ControlShared {
|
||||
mac_addr: [u8; 6],
|
||||
}
|
||||
|
||||
impl Default for ControlShared {
|
||||
fn default() -> Self {
|
||||
ControlShared { mac_addr: [0; 6] }
|
||||
}
|
||||
}
|
||||
|
||||
struct Control<'a> {
|
||||
mac_addr_string: StringIndex,
|
||||
shared: &'a ControlShared,
|
||||
@ -377,12 +379,12 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
|
||||
///
|
||||
/// This waits until the packet is successfully stored in the CDC-NCM endpoint buffers.
|
||||
pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
|
||||
let seq = self.seq;
|
||||
self.seq = self.seq.wrapping_add(1);
|
||||
|
||||
const OUT_HEADER_LEN: usize = 28;
|
||||
const ABS_MAX_PACKET_SIZE: usize = 512;
|
||||
|
||||
let seq = self.seq;
|
||||
self.seq = self.seq.wrapping_add(1);
|
||||
|
||||
let header = NtbOutHeader {
|
||||
nth_sig: SIG_NTH,
|
||||
nth_len: 0x0c,
|
||||
@ -416,7 +418,7 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
|
||||
self.write_ep.write(&buf[..self.max_packet_size]).await?;
|
||||
|
||||
for chunk in d2.chunks(self.max_packet_size) {
|
||||
self.write_ep.write(&chunk).await?;
|
||||
self.write_ep.write(chunk).await?;
|
||||
}
|
||||
|
||||
// Send ZLP if needed.
|
||||
@ -459,12 +461,9 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
|
||||
let ntb = &ntb[..pos];
|
||||
|
||||
// Process NTB header (NTH)
|
||||
let nth = match ntb.get(..12) {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
warn!("Received too short NTB");
|
||||
continue;
|
||||
}
|
||||
let Some(nth) = ntb.get(..12) else {
|
||||
warn!("Received too short NTB");
|
||||
continue;
|
||||
};
|
||||
let sig = u32::from_le_bytes(nth[0..4].try_into().unwrap());
|
||||
if sig != SIG_NTH {
|
||||
@ -474,12 +473,9 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
|
||||
let ndp_idx = u16::from_le_bytes(nth[10..12].try_into().unwrap()) as usize;
|
||||
|
||||
// Process NTB Datagram Pointer (NDP)
|
||||
let ndp = match ntb.get(ndp_idx..ndp_idx + 12) {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
warn!("NTH has an NDP pointer out of range.");
|
||||
continue;
|
||||
}
|
||||
let Some(ndp) = ntb.get(ndp_idx..ndp_idx + 12) else {
|
||||
warn!("NTH has an NDP pointer out of range.");
|
||||
continue;
|
||||
};
|
||||
let sig = u32::from_le_bytes(ndp[0..4].try_into().unwrap());
|
||||
if sig != SIG_NDP_NO_FCS && sig != SIG_NDP_WITH_FCS {
|
||||
@ -495,12 +491,9 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
|
||||
}
|
||||
|
||||
// Process actual datagram, finally.
|
||||
let datagram = match ntb.get(datagram_index..datagram_index + datagram_len) {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
warn!("NDP has a datagram pointer out of range.");
|
||||
continue;
|
||||
}
|
||||
let Some(datagram) = ntb.get(datagram_index..datagram_index + datagram_len) else {
|
||||
warn!("NDP has a datagram pointer out of range.");
|
||||
continue;
|
||||
};
|
||||
buf[..datagram_len].copy_from_slice(datagram);
|
||||
|
||||
|
@ -63,7 +63,7 @@ pub enum ReportId {
|
||||
}
|
||||
|
||||
impl ReportId {
|
||||
fn try_from(value: u16) -> Result<Self, ()> {
|
||||
const fn try_from(value: u16) -> Result<Self, ()> {
|
||||
match value >> 8 {
|
||||
1 => Ok(ReportId::In(value as u8)),
|
||||
2 => Ok(ReportId::Out(value as u8)),
|
||||
@ -79,9 +79,15 @@ pub struct State<'d> {
|
||||
out_report_offset: AtomicUsize,
|
||||
}
|
||||
|
||||
impl<'d> Default for State<'d> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> State<'d> {
|
||||
/// Create a new `State`.
|
||||
pub fn new() -> Self {
|
||||
pub const fn new() -> Self {
|
||||
State {
|
||||
control: MaybeUninit::uninit(),
|
||||
out_report_offset: AtomicUsize::new(0),
|
||||
@ -148,7 +154,7 @@ fn build<'d, D: Driver<'d>>(
|
||||
}
|
||||
|
||||
impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> HidReaderWriter<'d, D, READ_N, WRITE_N> {
|
||||
/// Creates a new HidReaderWriter.
|
||||
/// Creates a new `HidReaderWriter`.
|
||||
///
|
||||
/// This will allocate one IN and one OUT endpoints. If you only need writing (sending)
|
||||
/// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only.
|
||||
@ -171,7 +177,7 @@ impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> HidReaderWrit
|
||||
}
|
||||
|
||||
/// Waits for both IN and OUT endpoints to be enabled.
|
||||
pub async fn ready(&mut self) -> () {
|
||||
pub async fn ready(&mut self) {
|
||||
self.reader.ready().await;
|
||||
self.writer.ready().await;
|
||||
}
|
||||
@ -224,7 +230,7 @@ pub enum ReadError {
|
||||
|
||||
impl From<EndpointError> for ReadError {
|
||||
fn from(val: EndpointError) -> Self {
|
||||
use EndpointError::*;
|
||||
use EndpointError::{BufferOverflow, Disabled};
|
||||
match val {
|
||||
BufferOverflow => ReadError::BufferOverflow,
|
||||
Disabled => ReadError::Disabled,
|
||||
@ -251,17 +257,16 @@ impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> {
|
||||
}
|
||||
|
||||
/// Waits for the interrupt in endpoint to be enabled.
|
||||
pub async fn ready(&mut self) -> () {
|
||||
self.ep_in.wait_enabled().await
|
||||
pub async fn ready(&mut self) {
|
||||
self.ep_in.wait_enabled().await;
|
||||
}
|
||||
|
||||
/// Writes an input report by serializing the given report structure.
|
||||
#[cfg(feature = "usbd-hid")]
|
||||
pub async fn write_serialize<IR: AsInputReport>(&mut self, r: &IR) -> Result<(), EndpointError> {
|
||||
let mut buf: [u8; N] = [0; N];
|
||||
let size = match serialize(&mut buf, r) {
|
||||
Ok(size) => size,
|
||||
Err(_) => return Err(EndpointError::BufferOverflow),
|
||||
let Ok(size) = serialize(&mut buf, r) else {
|
||||
return Err(EndpointError::BufferOverflow);
|
||||
};
|
||||
self.write(&buf[0..size]).await
|
||||
}
|
||||
@ -286,8 +291,8 @@ impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> {
|
||||
|
||||
impl<'d, D: Driver<'d>, const N: usize> HidReader<'d, D, N> {
|
||||
/// Waits for the interrupt out endpoint to be enabled.
|
||||
pub async fn ready(&mut self) -> () {
|
||||
self.ep_out.wait_enabled().await
|
||||
pub async fn ready(&mut self) {
|
||||
self.ep_out.wait_enabled().await;
|
||||
}
|
||||
|
||||
/// Delivers output reports from the Interrupt Out pipe to `handler`.
|
||||
@ -344,9 +349,8 @@ impl<'d, D: Driver<'d>, const N: usize> HidReader<'d, D, N> {
|
||||
if size < max_packet_size || total == N {
|
||||
self.offset.store(0, Ordering::Release);
|
||||
break;
|
||||
} else {
|
||||
self.offset.store(total, Ordering::Release);
|
||||
}
|
||||
self.offset.store(total, Ordering::Release);
|
||||
}
|
||||
Err(err) => {
|
||||
self.offset.store(0, Ordering::Release);
|
||||
@ -466,7 +470,7 @@ impl<'d> Handler for Control<'d> {
|
||||
HID_REQ_SET_IDLE => {
|
||||
if let Some(handler) = self.request_handler {
|
||||
let id = req.value as u8;
|
||||
let id = (id != 0).then(|| ReportId::In(id));
|
||||
let id = (id != 0).then_some(ReportId::In(id));
|
||||
let dur = u32::from(req.value >> 8);
|
||||
let dur = if dur == 0 { u32::MAX } else { 4 * dur };
|
||||
handler.set_idle_ms(id, dur);
|
||||
@ -522,7 +526,7 @@ impl<'d> Handler for Control<'d> {
|
||||
HID_REQ_GET_IDLE => {
|
||||
if let Some(handler) = self.request_handler {
|
||||
let id = req.value as u8;
|
||||
let id = (id != 0).then(|| ReportId::In(id));
|
||||
let id = (id != 0).then_some(ReportId::In(id));
|
||||
if let Some(dur) = handler.get_idle_ms(id) {
|
||||
let dur = u8::try_from(dur / 4).unwrap_or(0);
|
||||
buf[0] = dur;
|
||||
|
227
embassy-usb/src/class/midi.rs
Normal file
227
embassy-usb/src/class/midi.rs
Normal file
@ -0,0 +1,227 @@
|
||||
//! MIDI class implementation.
|
||||
|
||||
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
||||
use crate::Builder;
|
||||
|
||||
/// This should be used as `device_class` when building the `UsbDevice`.
|
||||
pub const USB_AUDIO_CLASS: u8 = 0x01;
|
||||
|
||||
const USB_AUDIOCONTROL_SUBCLASS: u8 = 0x01;
|
||||
const USB_MIDISTREAMING_SUBCLASS: u8 = 0x03;
|
||||
const MIDI_IN_JACK_SUBTYPE: u8 = 0x02;
|
||||
const MIDI_OUT_JACK_SUBTYPE: u8 = 0x03;
|
||||
const EMBEDDED: u8 = 0x01;
|
||||
const EXTERNAL: u8 = 0x02;
|
||||
const CS_INTERFACE: u8 = 0x24;
|
||||
const CS_ENDPOINT: u8 = 0x25;
|
||||
const HEADER_SUBTYPE: u8 = 0x01;
|
||||
const MS_HEADER_SUBTYPE: u8 = 0x01;
|
||||
const MS_GENERAL: u8 = 0x01;
|
||||
const PROTOCOL_NONE: u8 = 0x00;
|
||||
const MIDI_IN_SIZE: u8 = 0x06;
|
||||
const MIDI_OUT_SIZE: u8 = 0x09;
|
||||
|
||||
/// Packet level implementation of a USB MIDI device.
|
||||
///
|
||||
/// This class can be used directly and it has the least overhead due to directly reading and
|
||||
/// writing USB packets with no intermediate buffers, but it will not act like a stream-like port.
|
||||
/// The following constraints must be followed if you use this class directly:
|
||||
///
|
||||
/// - `read_packet` must be called with a buffer large enough to hold `max_packet_size` bytes.
|
||||
/// - `write_packet` must not be called with a buffer larger than `max_packet_size` bytes.
|
||||
/// - If you write a packet that is exactly `max_packet_size` bytes long, it won't be processed by the
|
||||
/// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP)
|
||||
/// can be sent if there is no other data to send. This is because USB bulk transactions must be
|
||||
/// terminated with a short packet, even if the bulk endpoint is used for stream-like data.
|
||||
pub struct MidiClass<'d, D: Driver<'d>> {
|
||||
read_ep: D::EndpointOut,
|
||||
write_ep: D::EndpointIn,
|
||||
}
|
||||
|
||||
impl<'d, D: Driver<'d>> MidiClass<'d, D> {
|
||||
/// Creates a new `MidiClass` with the provided UsbBus, number of input and output jacks and `max_packet_size` in bytes.
|
||||
/// For full-speed devices, `max_packet_size` has to be one of 8, 16, 32 or 64.
|
||||
pub fn new(builder: &mut Builder<'d, D>, n_in_jacks: u8, n_out_jacks: u8, max_packet_size: u16) -> Self {
|
||||
let mut func = builder.function(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE);
|
||||
|
||||
// Audio control interface
|
||||
let mut iface = func.interface();
|
||||
let audio_if = iface.interface_number();
|
||||
let midi_if = u8::from(audio_if) + 1;
|
||||
let mut alt = iface.alt_setting(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE, None);
|
||||
alt.descriptor(CS_INTERFACE, &[HEADER_SUBTYPE, 0x00, 0x01, 0x09, 0x00, 0x01, midi_if]);
|
||||
|
||||
// MIDIStreaming interface
|
||||
let mut iface = func.interface();
|
||||
let _midi_if = iface.interface_number();
|
||||
let mut alt = iface.alt_setting(USB_AUDIO_CLASS, USB_MIDISTREAMING_SUBCLASS, PROTOCOL_NONE, None);
|
||||
|
||||
let midi_streaming_total_length = 7
|
||||
+ (n_in_jacks + n_out_jacks) as usize * (MIDI_IN_SIZE + MIDI_OUT_SIZE) as usize
|
||||
+ 7
|
||||
+ (4 + n_out_jacks as usize)
|
||||
+ 7
|
||||
+ (4 + n_in_jacks as usize);
|
||||
|
||||
alt.descriptor(
|
||||
CS_INTERFACE,
|
||||
&[
|
||||
MS_HEADER_SUBTYPE,
|
||||
0x00,
|
||||
0x01,
|
||||
(midi_streaming_total_length & 0xFF) as u8,
|
||||
((midi_streaming_total_length >> 8) & 0xFF) as u8,
|
||||
],
|
||||
);
|
||||
|
||||
// Calculates the index'th external midi in jack id
|
||||
let in_jack_id_ext = |index| 2 * index + 1;
|
||||
// Calculates the index'th embedded midi out jack id
|
||||
let out_jack_id_emb = |index| 2 * index + 2;
|
||||
// Calculates the index'th external midi out jack id
|
||||
let out_jack_id_ext = |index| 2 * n_in_jacks + 2 * index + 1;
|
||||
// Calculates the index'th embedded midi in jack id
|
||||
let in_jack_id_emb = |index| 2 * n_in_jacks + 2 * index + 2;
|
||||
|
||||
for i in 0..n_in_jacks {
|
||||
alt.descriptor(CS_INTERFACE, &[MIDI_IN_JACK_SUBTYPE, EXTERNAL, in_jack_id_ext(i), 0x00]);
|
||||
}
|
||||
|
||||
for i in 0..n_out_jacks {
|
||||
alt.descriptor(CS_INTERFACE, &[MIDI_IN_JACK_SUBTYPE, EMBEDDED, in_jack_id_emb(i), 0x00]);
|
||||
}
|
||||
|
||||
for i in 0..n_out_jacks {
|
||||
alt.descriptor(
|
||||
CS_INTERFACE,
|
||||
&[
|
||||
MIDI_OUT_JACK_SUBTYPE,
|
||||
EXTERNAL,
|
||||
out_jack_id_ext(i),
|
||||
0x01,
|
||||
in_jack_id_emb(i),
|
||||
0x01,
|
||||
0x00,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
for i in 0..n_in_jacks {
|
||||
alt.descriptor(
|
||||
CS_INTERFACE,
|
||||
&[
|
||||
MIDI_OUT_JACK_SUBTYPE,
|
||||
EMBEDDED,
|
||||
out_jack_id_emb(i),
|
||||
0x01,
|
||||
in_jack_id_ext(i),
|
||||
0x01,
|
||||
0x00,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
let mut endpoint_data = [
|
||||
MS_GENERAL, 0, // Number of jacks
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Jack mappings
|
||||
];
|
||||
endpoint_data[1] = n_out_jacks;
|
||||
for i in 0..n_out_jacks {
|
||||
endpoint_data[2 + i as usize] = in_jack_id_emb(i);
|
||||
}
|
||||
let read_ep = alt.endpoint_bulk_out(max_packet_size);
|
||||
alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_out_jacks as usize]);
|
||||
|
||||
endpoint_data[1] = n_in_jacks;
|
||||
for i in 0..n_in_jacks {
|
||||
endpoint_data[2 + i as usize] = out_jack_id_emb(i);
|
||||
}
|
||||
let write_ep = alt.endpoint_bulk_in(max_packet_size);
|
||||
alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_in_jacks as usize]);
|
||||
|
||||
MidiClass { read_ep, write_ep }
|
||||
}
|
||||
|
||||
/// Gets the maximum packet size in bytes.
|
||||
pub fn max_packet_size(&self) -> u16 {
|
||||
// The size is the same for both endpoints.
|
||||
self.read_ep.info().max_packet_size
|
||||
}
|
||||
|
||||
/// Writes a single packet into the IN endpoint.
|
||||
pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
|
||||
self.write_ep.write(data).await
|
||||
}
|
||||
|
||||
/// Reads a single packet from the OUT endpoint.
|
||||
pub async fn read_packet(&mut self, data: &mut [u8]) -> Result<usize, EndpointError> {
|
||||
self.read_ep.read(data).await
|
||||
}
|
||||
|
||||
/// Waits for the USB host to enable this interface
|
||||
pub async fn wait_connection(&mut self) {
|
||||
self.read_ep.wait_enabled().await;
|
||||
}
|
||||
|
||||
/// Split the class into a sender and receiver.
|
||||
///
|
||||
/// This allows concurrently sending and receiving packets from separate tasks.
|
||||
pub fn split(self) -> (Sender<'d, D>, Receiver<'d, D>) {
|
||||
(
|
||||
Sender {
|
||||
write_ep: self.write_ep,
|
||||
},
|
||||
Receiver { read_ep: self.read_ep },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Midi class packet sender.
|
||||
///
|
||||
/// You can obtain a `Sender` with [`MidiClass::split`]
|
||||
pub struct Sender<'d, D: Driver<'d>> {
|
||||
write_ep: D::EndpointIn,
|
||||
}
|
||||
|
||||
impl<'d, D: Driver<'d>> Sender<'d, D> {
|
||||
/// Gets the maximum packet size in bytes.
|
||||
pub fn max_packet_size(&self) -> u16 {
|
||||
// The size is the same for both endpoints.
|
||||
self.write_ep.info().max_packet_size
|
||||
}
|
||||
|
||||
/// Writes a single packet.
|
||||
pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
|
||||
self.write_ep.write(data).await
|
||||
}
|
||||
|
||||
/// Waits for the USB host to enable this interface
|
||||
pub async fn wait_connection(&mut self) {
|
||||
self.write_ep.wait_enabled().await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Midi class packet receiver.
|
||||
///
|
||||
/// You can obtain a `Receiver` with [`MidiClass::split`]
|
||||
pub struct Receiver<'d, D: Driver<'d>> {
|
||||
read_ep: D::EndpointOut,
|
||||
}
|
||||
|
||||
impl<'d, D: Driver<'d>> Receiver<'d, D> {
|
||||
/// Gets the maximum packet size in bytes.
|
||||
pub fn max_packet_size(&self) -> u16 {
|
||||
// The size is the same for both endpoints.
|
||||
self.read_ep.info().max_packet_size
|
||||
}
|
||||
|
||||
/// Reads a single packet.
|
||||
pub async fn read_packet(&mut self, data: &mut [u8]) -> Result<usize, EndpointError> {
|
||||
self.read_ep.read(data).await
|
||||
}
|
||||
|
||||
/// Waits for the USB host to enable this interface
|
||||
pub async fn wait_connection(&mut self) {
|
||||
self.read_ep.wait_enabled().await;
|
||||
}
|
||||
}
|
@ -2,3 +2,4 @@
|
||||
pub mod cdc_acm;
|
||||
pub mod cdc_ncm;
|
||||
pub mod hid;
|
||||
pub mod midi;
|
||||
|
@ -120,7 +120,7 @@ impl Request {
|
||||
}
|
||||
|
||||
/// Gets the descriptor type and index from the value field of a GET_DESCRIPTOR request.
|
||||
pub fn descriptor_type_index(&self) -> (u8, u8) {
|
||||
pub const fn descriptor_type_index(&self) -> (u8, u8) {
|
||||
((self.value >> 8) as u8, self.value as u8)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::builder::Config;
|
||||
use crate::driver::EndpointInfo;
|
||||
use crate::types::*;
|
||||
use crate::types::{InterfaceNumber, StringIndex};
|
||||
use crate::CONFIGURATION_VALUE;
|
||||
|
||||
/// Standard descriptor types
|
||||
@ -59,7 +59,7 @@ impl<'a> DescriptorWriter<'a> {
|
||||
}
|
||||
|
||||
/// Gets the current position in the buffer, i.e. the number of bytes written so far.
|
||||
pub fn position(&self) -> usize {
|
||||
pub const fn position(&self) -> usize {
|
||||
self.position
|
||||
}
|
||||
|
||||
@ -67,9 +67,10 @@ impl<'a> DescriptorWriter<'a> {
|
||||
pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) {
|
||||
let length = descriptor.len();
|
||||
|
||||
if (self.position + 2 + length) > self.buf.len() || (length + 2) > 255 {
|
||||
panic!("Descriptor buffer full");
|
||||
}
|
||||
assert!(
|
||||
(self.position + 2 + length) <= self.buf.len() && (length + 2) <= 255,
|
||||
"Descriptor buffer full"
|
||||
);
|
||||
|
||||
self.buf[self.position] = (length + 2) as u8;
|
||||
self.buf[self.position + 1] = descriptor_type;
|
||||
@ -102,7 +103,7 @@ impl<'a> DescriptorWriter<'a> {
|
||||
config.serial_number.map_or(0, |_| 3), // iSerialNumber
|
||||
1, // bNumConfigurations
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn configuration(&mut self, config: &Config) {
|
||||
@ -120,7 +121,7 @@ impl<'a> DescriptorWriter<'a> {
|
||||
| if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes
|
||||
(config.max_power / 2) as u8, // bMaxPower
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
@ -248,9 +249,7 @@ impl<'a> DescriptorWriter<'a> {
|
||||
pub(crate) fn string(&mut self, string: &str) {
|
||||
let mut pos = self.position;
|
||||
|
||||
if pos + 2 > self.buf.len() {
|
||||
panic!("Descriptor buffer full");
|
||||
}
|
||||
assert!(pos + 2 <= self.buf.len(), "Descriptor buffer full");
|
||||
|
||||
self.buf[pos] = 0; // length placeholder
|
||||
self.buf[pos + 1] = descriptor_type::STRING;
|
||||
@ -258,9 +257,7 @@ impl<'a> DescriptorWriter<'a> {
|
||||
pos += 2;
|
||||
|
||||
for c in string.encode_utf16() {
|
||||
if pos >= self.buf.len() {
|
||||
panic!("Descriptor buffer full");
|
||||
}
|
||||
assert!(pos < self.buf.len(), "Descriptor buffer full");
|
||||
|
||||
self.buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes());
|
||||
pos += 2;
|
||||
@ -279,9 +276,9 @@ pub struct BosWriter<'a> {
|
||||
}
|
||||
|
||||
impl<'a> BosWriter<'a> {
|
||||
pub(crate) fn new(writer: DescriptorWriter<'a>) -> Self {
|
||||
pub(crate) const fn new(writer: DescriptorWriter<'a>) -> Self {
|
||||
Self {
|
||||
writer: writer,
|
||||
writer,
|
||||
num_caps_mark: None,
|
||||
}
|
||||
}
|
||||
@ -314,9 +311,10 @@ impl<'a> BosWriter<'a> {
|
||||
let mut start = self.writer.position;
|
||||
let blen = data.len();
|
||||
|
||||
if (start + blen + 3) > self.writer.buf.len() || (blen + 3) > 255 {
|
||||
panic!("Descriptor buffer full");
|
||||
}
|
||||
assert!(
|
||||
(start + blen + 3) <= self.writer.buf.len() && (blen + 3) <= 255,
|
||||
"Descriptor buffer full"
|
||||
);
|
||||
|
||||
self.writer.buf[start] = (blen + 3) as u8;
|
||||
self.writer.buf[start + 1] = descriptor_type::CAPABILITY;
|
||||
|
@ -11,11 +11,11 @@ pub struct Reader<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Reader<'a> {
|
||||
pub fn new(data: &'a [u8]) -> Self {
|
||||
pub const fn new(data: &'a [u8]) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
|
||||
pub fn eof(&self) -> bool {
|
||||
pub const fn eof(&self) -> bool {
|
||||
self.data.is_empty()
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ pub fn foreach_endpoint(data: &[u8], mut f: impl FnMut(EndpointInfo)) -> Result<
|
||||
}
|
||||
descriptor_type::ENDPOINT => {
|
||||
ep.ep_address = EndpointAddress::from(r.read_u8()?);
|
||||
f(ep)
|
||||
f(ep);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -24,12 +24,12 @@ use embassy_futures::select::{select, Either};
|
||||
use heapless::Vec;
|
||||
|
||||
pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder};
|
||||
use crate::config::*;
|
||||
use crate::control::*;
|
||||
use crate::descriptor::*;
|
||||
use crate::config::{MAX_HANDLER_COUNT, MAX_INTERFACE_COUNT};
|
||||
use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType};
|
||||
use crate::descriptor::{descriptor_type, lang_id};
|
||||
use crate::descriptor_reader::foreach_endpoint;
|
||||
use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event};
|
||||
use crate::types::*;
|
||||
use crate::types::{InterfaceNumber, StringIndex};
|
||||
|
||||
/// The global state of the USB device.
|
||||
///
|
||||
@ -294,7 +294,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
||||
/// After dropping the future, [`UsbDevice::disable()`] should be called
|
||||
/// before calling any other `UsbDevice` methods to fully reset the
|
||||
/// peripheral.
|
||||
pub async fn run_until_suspend(&mut self) -> () {
|
||||
pub async fn run_until_suspend(&mut self) {
|
||||
while !self.inner.suspended {
|
||||
let control_fut = self.control.setup();
|
||||
let bus_fut = self.inner.bus.poll();
|
||||
@ -364,6 +364,8 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
||||
}
|
||||
|
||||
async fn handle_control_in(&mut self, req: Request) {
|
||||
const DEVICE_DESCRIPTOR_LEN: usize = 18;
|
||||
|
||||
let mut resp_length = req.length as usize;
|
||||
let max_packet_size = self.control.max_packet_size();
|
||||
|
||||
@ -371,19 +373,15 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
||||
// The host doesn't know our EP0 max packet size yet, and might assume
|
||||
// a full-length packet is a short packet, thinking we're done sending data.
|
||||
// See https://github.com/hathach/tinyusb/issues/184
|
||||
const DEVICE_DESCRIPTOR_LEN: usize = 18;
|
||||
if self.inner.address == 0
|
||||
&& max_packet_size < DEVICE_DESCRIPTOR_LEN
|
||||
&& (max_packet_size as usize) < resp_length
|
||||
{
|
||||
if self.inner.address == 0 && max_packet_size < DEVICE_DESCRIPTOR_LEN && max_packet_size < resp_length {
|
||||
trace!("received control req while not addressed: capping response to 1 packet.");
|
||||
resp_length = max_packet_size;
|
||||
}
|
||||
|
||||
match self.inner.handle_control_in(req, &mut self.control_buf) {
|
||||
match self.inner.handle_control_in(req, self.control_buf) {
|
||||
InResponse::Accepted(data) => {
|
||||
let len = data.len().min(resp_length);
|
||||
let need_zlp = len != resp_length && (len % usize::from(max_packet_size)) == 0;
|
||||
let need_zlp = len != resp_length && (len % max_packet_size) == 0;
|
||||
|
||||
let chunks = data[0..len]
|
||||
.chunks(max_packet_size)
|
||||
@ -435,7 +433,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
||||
self.control.accept_set_address(self.inner.address).await;
|
||||
self.inner.set_address_pending = false;
|
||||
} else {
|
||||
self.control.accept().await
|
||||
self.control.accept().await;
|
||||
}
|
||||
}
|
||||
OutResponse::Rejected => self.control.reject().await,
|
||||
@ -548,9 +546,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
|
||||
|
||||
OutResponse::Accepted
|
||||
}
|
||||
(Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => match self.device_state {
|
||||
UsbDeviceState::Default => OutResponse::Accepted,
|
||||
_ => {
|
||||
(Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => {
|
||||
if self.device_state != UsbDeviceState::Default {
|
||||
debug!("SET_CONFIGURATION: unconfigured");
|
||||
self.device_state = UsbDeviceState::Addressed;
|
||||
|
||||
@ -564,17 +561,15 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
|
||||
for h in &mut self.handlers {
|
||||
h.configured(false);
|
||||
}
|
||||
|
||||
OutResponse::Accepted
|
||||
}
|
||||
},
|
||||
OutResponse::Accepted
|
||||
}
|
||||
_ => OutResponse::Rejected,
|
||||
},
|
||||
(RequestType::Standard, Recipient::Interface) => {
|
||||
let iface_num = InterfaceNumber::new(req.index as _);
|
||||
let iface = match self.interfaces.get_mut(iface_num.0 as usize) {
|
||||
Some(iface) => iface,
|
||||
None => return OutResponse::Rejected,
|
||||
let Some(iface) = self.interfaces.get_mut(iface_num.0 as usize) else {
|
||||
return OutResponse::Rejected;
|
||||
};
|
||||
|
||||
match req.request {
|
||||
@ -650,9 +645,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
|
||||
_ => InResponse::Rejected,
|
||||
},
|
||||
(RequestType::Standard, Recipient::Interface) => {
|
||||
let iface = match self.interfaces.get_mut(req.index as usize) {
|
||||
Some(iface) => iface,
|
||||
None => return InResponse::Rejected,
|
||||
let Some(iface) = self.interfaces.get_mut(req.index as usize) else {
|
||||
return InResponse::Rejected;
|
||||
};
|
||||
|
||||
match req.request {
|
||||
@ -706,7 +700,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
|
||||
}
|
||||
|
||||
fn handle_control_in_delegated<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
|
||||
unsafe fn extend_lifetime<'x, 'y>(r: InResponse<'x>) -> InResponse<'y> {
|
||||
unsafe fn extend_lifetime<'y>(r: InResponse<'_>) -> InResponse<'y> {
|
||||
core::mem::transmute(r)
|
||||
}
|
||||
|
||||
@ -756,16 +750,12 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
|
||||
};
|
||||
|
||||
if let Some(s) = s {
|
||||
if buf.len() < 2 {
|
||||
panic!("control buffer too small");
|
||||
}
|
||||
assert!(buf.len() >= 2, "control buffer too small");
|
||||
|
||||
buf[1] = descriptor_type::STRING;
|
||||
let mut pos = 2;
|
||||
for c in s.encode_utf16() {
|
||||
if pos + 2 >= buf.len() {
|
||||
panic!("control buffer too small");
|
||||
}
|
||||
assert!(pos + 2 < buf.len(), "control buffer too small");
|
||||
|
||||
buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes());
|
||||
pos += 2;
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
use core::mem::size_of;
|
||||
|
||||
use super::{capability_type, BosWriter};
|
||||
use crate::descriptor::{capability_type, BosWriter};
|
||||
use crate::types::InterfaceNumber;
|
||||
|
||||
/// A serialized Microsoft OS 2.0 Descriptor set.
|
||||
|
@ -7,7 +7,7 @@
|
||||
pub struct InterfaceNumber(pub u8);
|
||||
|
||||
impl InterfaceNumber {
|
||||
pub(crate) fn new(index: u8) -> InterfaceNumber {
|
||||
pub(crate) const fn new(index: u8) -> InterfaceNumber {
|
||||
InterfaceNumber(index)
|
||||
}
|
||||
}
|
||||
@ -25,7 +25,7 @@ impl From<InterfaceNumber> for u8 {
|
||||
pub struct StringIndex(pub u8);
|
||||
|
||||
impl StringIndex {
|
||||
pub(crate) fn new(index: u8) -> StringIndex {
|
||||
pub(crate) const fn new(index: u8) -> StringIndex {
|
||||
StringIndex(index)
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
|
||||
[dependencies]
|
||||
embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
|
||||
embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
||||
embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly"] }
|
||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly"] }
|
||||
embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] }
|
||||
embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] }
|
||||
embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = ["nightly"] }
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::gpio::{Level, Output, OutputDrive};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
use panic_reset as _;
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -19,8 +19,8 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
loop {
|
||||
led.set_high();
|
||||
Timer::after(Duration::from_millis(300)).await;
|
||||
Timer::after_millis(300).await;
|
||||
led.set_low();
|
||||
Timer::after(Duration::from_millis(300)).await;
|
||||
Timer::after_millis(300).await;
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
|
||||
[dependencies]
|
||||
embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
|
||||
embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
||||
embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly"] }
|
||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly"] }
|
||||
embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] }
|
||||
embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = ["nightly"] }
|
||||
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
|
||||
|
@ -41,7 +41,7 @@ async fn main(_s: Spawner) {
|
||||
let mut aligned = AlignedBuffer([0; 1]);
|
||||
let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0);
|
||||
|
||||
Timer::after(Duration::from_secs(5)).await;
|
||||
Timer::after_secs(5).await;
|
||||
watchdog.feed();
|
||||
led.set_high();
|
||||
let mut offset = 0;
|
||||
@ -61,7 +61,7 @@ async fn main(_s: Spawner) {
|
||||
watchdog.feed();
|
||||
defmt::info!("firmware written, marking update");
|
||||
updater.mark_updated().unwrap();
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
Timer::after_secs(2).await;
|
||||
led.set_low();
|
||||
defmt::info!("update marked, resetting");
|
||||
cortex_m::peripheral::SCB::sys_reset();
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::gpio;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
use gpio::{Level, Output};
|
||||
use {defmt_rtt as _, panic_reset as _};
|
||||
|
||||
@ -15,9 +15,9 @@ async fn main(_s: Spawner) {
|
||||
|
||||
loop {
|
||||
led.set_high();
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
led.set_low();
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
|
||||
[dependencies]
|
||||
embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" }
|
||||
embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
||||
embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
||||
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] }
|
||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
||||
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user