Compare commits

...

55 Commits

Author SHA1 Message Date
c7803bb8f4 docs: add linker script comments
Existing comment were outdated. Provide an example configuration
for using the softdevice with the nRF52 examples.
2023-10-19 09:29:20 +02:00
683d5c3066 Merge pull request #2077 from xoviat/rcc
stm32: update metapac
2023-10-17 01:05:18 +00:00
a3574e519a stm32: update metapac 2023-10-16 20:04:10 -05:00
3e3317e8bd Merge pull request #2078 from GrantM11235/prefetch
stm32f1: Keep flash prefetch enabled
2023-10-17 00:29:30 +00:00
e7aeb9b29f stm32f1: Keep flash prefetch enabled 2023-10-16 19:23:01 -05:00
7fd868ade9 Merge pull request #2068 from barafael/const_usb_config_builder_new
Constify UsbDevice Config::new (and clippy fixes) in embassy-usb
2023-10-16 23:23:10 +00:00
6e6df22979 Merge pull request #2075 from CBJamo/rosc_example
Add example to show useage of rp2040 rosc
2023-10-16 23:22:06 +00:00
f7980885a5 Merge pull request #2066 from bugadani/net
Prepare embassy-net 0.2.0
2023-10-16 21:19:29 +00:00
5a1393aa0b Add example to show useage of rp2040 rosc 2023-10-16 16:17:07 -04:00
40e4ca4751 Prepare embassy-net(/-driver,/-driver-channel) 0.2.0 2023-10-16 20:59:06 +02:00
1d810baa18 Merge pull request #2074 from embassy-rs/rcc-no-spaghetti
time: add `links` key, release v0.1.5.
2023-10-16 18:19:59 +00:00
213b4c9dca time: add links key, release v0.1.5. 2023-10-16 20:11:35 +02:00
889d482d2d Merge pull request #2073 from embassy-rs/rcc-no-spaghetti
nrf/pac: reeport s and ns peripherals always independently of the current mode.
2023-10-16 17:43:13 +00:00
ea0e83a7f9 nrf/pac: reeport s and ns peripherals always independently of the current mode.
You sometimes need this, for example for using nrf91 modem from S mode
you need to acces IPC_NS.
2023-10-16 19:38:53 +02:00
f0497039ed Merge pull request #2071 from embassy-rs/rcc-no-spaghetti
stm32/rng: add test.
2023-10-16 03:37:18 +00:00
aff77d2b65 stm32/rng: add test. 2023-10-16 05:35:29 +02:00
a7c6999670 Merge pull request #2070 from embassy-rs/rcc-no-spaghetti
stm32/rcc: unify L4 and L5.
2023-10-16 02:10:37 +00:00
18e96898ea stm32/rcc: unify L4 and L5. 2023-10-16 04:00:51 +02:00
870dcc5970 Merge pull request #2069 from embassy-rs/rcc-no-spaghetti
stm32/rcc: add better support for L4/L4+ differences.
2023-10-16 01:41:40 +00:00
5c5e681819 stm32/rcc: add better support for L4/L4+ differences. 2023-10-16 03:23:43 +02:00
f54753beaa Merge pull request #2067 from xoviat/rcc
rcc: update pll clock naming
2023-10-16 00:52:47 +00:00
b24520579a rcc: ahb/apb -> hclk/pclk 2023-10-15 19:51:35 -05:00
31d4516516 Apply Pedantic Clippy Lints 2023-10-15 23:52:44 +02:00
66e62e9994 Fix clippy 2023-10-15 22:25:35 +02:00
eeedaf2e76 Constify Config::new 2023-10-15 22:11:30 +02:00
1fc35c753b rcc: update pll clock naming 2023-10-15 15:10:42 -05:00
cd92bc3145 Merge pull request #2060 from xoviat/rcc
stm32: expand rcc mux to g4 and h7
2023-10-15 04:37:36 +00:00
4a156df7a1 stm32: expand rcc mux to g4 and h7 2023-10-14 23:33:57 -05:00
c46e758e2c Merge pull request #2063 from embassy-rs/rcc-no-spaghetti
stm32/rcc: port L4 to the "flattened" API like h5/h7.
2023-10-15 01:12:46 +00:00
8a10948ce9 stm32/rcc: port L4 to the "flattened" API like h5/h7. 2023-10-15 03:08:49 +02:00
7045c53170 Merge pull request #2061 from adamgreig/timer-helpers
Add convenience methods for Timer::after_secs/millis/micros/ticks
2023-10-15 00:34:59 +00:00
0621e957a0 time: Update examples, tests, and other code to use new Timer::after_x convenience methods 2023-10-15 01:30:12 +01:00
a818f33658 Merge pull request #2062 from embassy-rs/rcc-no-spaghetti
stm32/rcc: remove unused lse/lsi fields in h7
2023-10-15 01:49:01 +02:00
3bfbf2697f stm32/rcc: remove unused lse/lsi fields in h7 2023-10-15 01:48:27 +02:00
7559f9e583 time: Update documentation to use new after_x convenience methods 2023-10-15 00:47:56 +01:00
c8fdbe19f9 time: Add convenience methods for Timer::after_secs/millis/micros/ticks 2023-10-15 00:47:55 +01:00
2e50bf667a Merge pull request #2055 from kalkyl/usb-midi
embassy-usb: Add MIDI class
2023-10-14 23:10:25 +00:00
ba62037642 Merge pull request #2058 from xoviat/rcc
rcc: remove mux_prefix from clocks
2023-10-14 17:57:44 +00:00
824556c9c8 rcc: remove mux_prefix from clocks 2023-10-14 12:51:45 -05:00
f7c0ec66d2 Merge pull request #2057 from bugadani/dns
Wake Stack's polling task after queueing a DNS query
2023-10-14 14:17:54 +00:00
69bb455c60 Wake stack's task after queueing a DNS query 2023-10-14 13:35:53 +02:00
575db17264 Merge pull request #2053 from jr-oss/fix_stm32_advanced_timer_enable_output
STM32: Fix regression in advanced timer to enable output of PWM signa…
2023-10-14 04:09:57 +00:00
0aa99e66f7 Merge pull request #2054 from xoviat/rcc-mux
rcc mux: update metapac
2023-10-14 04:07:38 +00:00
3264941c1b rcc mux: update metapac 2023-10-13 23:06:32 -05:00
a57d383b1d embassy-usb: Add MIDI class 2023-10-14 04:20:59 +02:00
9a7fda87b0 STM32: timer enable_output does not take bool, but just enables the output 2023-10-13 18:52:10 +02:00
adc810d24b STM32: Fix regression in advanced timer to enable output of PWM signal by partly reverting commit 74eb519 2023-10-13 17:38:40 +02:00
75baf186f3 Merge pull request #2051 from MabezDev/stm32/set_config-concrete
make set_config concrete methods public again
2023-10-12 22:06:29 +00:00
a6bbb130c5 make set_config concrete methods public again 2023-10-12 23:03:33 +01:00
d1ac6d2824 Merge pull request #2050 from embassy-rs/remove-unused-rb
Remove unused ringbuffer
2023-10-12 19:13:12 +00:00
636958ff70 fix: correct name in readme 2023-10-12 20:54:38 +02:00
7f6fe93f55 fix: remove unused ringbuffer code 2023-10-12 20:54:26 +02:00
e9b1904db8 Merge pull request #2049 from bugadani/time
(Please) Release embassy-time 0.1.4
2023-10-12 16:40:40 +00:00
02d2c06b23 Release embassy-time 0.1.4 2023-10-12 18:14:33 +02:00
debda2f52c Merge pull request #2045 from embassy-rs/stm32-cs-spam
Avoid creating many tiny critical sections in embassy-stm32::init
2023-10-12 14:29:23 +00:00
309 changed files with 2488 additions and 2130 deletions

View File

@ -62,9 +62,9 @@ async fn blink(pin: AnyPin) {
loop { loop {
// Timekeeping is globally available, no need to mess with hardware timers. // Timekeeping is globally available, no need to mess with hardware timers.
led.set_high(); led.set_high();
Timer::after(Duration::from_millis(150)).await; Timer::after_millis(150).await;
led.set_low(); led.set_low();
Timer::after(Duration::from_millis(150)).await; Timer::after_millis(150).await;
} }
} }

View File

@ -11,10 +11,10 @@ log = ["dep:log"]
firmware-logs = [] firmware-logs = []
[dependencies] [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-sync = { version = "0.3.0", path = "../embassy-sync"}
embassy-futures = { version = "0.1.0", path = "../embassy-futures"} 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 } defmt = { version = "0.3", optional = true }
log = { version = "0.4.17", optional = true } log = { version = "0.4.17", optional = true }

View File

@ -1,5 +1,5 @@
use embassy_futures::yield_now; use embassy_futures::yield_now;
use embassy_time::{Duration, Timer}; use embassy_time::Timer;
use embedded_hal_1::digital::OutputPin; use embedded_hal_1::digital::OutputPin;
use futures::FutureExt; use futures::FutureExt;
@ -51,9 +51,9 @@ where
pub async fn init(&mut self) { pub async fn init(&mut self) {
// Reset // Reset
self.pwr.set_low().unwrap(); self.pwr.set_low().unwrap();
Timer::after(Duration::from_millis(20)).await; Timer::after_millis(20).await;
self.pwr.set_high().unwrap(); self.pwr.set_high().unwrap();
Timer::after(Duration::from_millis(250)).await; Timer::after_millis(250).await;
while self while self
.read32_swapped(REG_BUS_TEST_RO) .read32_swapped(REG_BUS_TEST_RO)

View File

@ -2,7 +2,7 @@ use core::cmp::{max, min};
use ch::driver::LinkState; use ch::driver::LinkState;
use embassy_net_driver_channel as ch; use embassy_net_driver_channel as ch;
use embassy_time::{Duration, Timer}; use embassy_time::Timer;
pub use crate::bus::SpiBusCyw43; pub use crate::bus::SpiBusCyw43;
use crate::consts::*; use crate::consts::*;
@ -87,22 +87,22 @@ impl<'a> Control<'a> {
self.set_iovar("country", &country_info.to_bytes()).await; self.set_iovar("country", &country_info.to_bytes()).await;
// set country takes some time, next ioctls fail if we don't wait. // 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 // Set antenna to chip antenna
self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await; self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
self.set_iovar_u32("bus:txglom", 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...?? //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; 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; 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 //self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
//Timer::after(Duration::from_millis(100)).await; //Timer::after_millis(100).await;
// evts // evts
let mut evts = EventMask { let mut evts = EventMask {
@ -121,17 +121,17 @@ impl<'a> Control<'a> {
self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await; 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 // set wifi up
self.up().await; 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(110, 0, 1).await; // SET_GMODE = auto
self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any 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); 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_wpa2_eapver", 0, 0xFFFF_FFFF).await;
self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).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 { let mut pfi = PassphraseInfo {
len: passphrase.len() as _, len: passphrase.len() as _,
@ -297,7 +297,7 @@ impl<'a> Control<'a> {
if security != Security::OPEN { if security != Security::OPEN {
self.set_iovar_u32x2("bsscfg:wpa_auth", 0, 0x0084).await; // wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK 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 // Set passphrase
let mut pfi = PassphraseInfo { let mut pfi = PassphraseInfo {

View File

@ -555,14 +555,14 @@ where
self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await; self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
Timer::after(Duration::from_millis(1)).await; Timer::after_millis(1).await;
self.bus self.bus
.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN) .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
.await; .await;
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).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 { async fn core_is_up(&mut self, core: Core) -> bool {

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-executor = { version = "0.3.0", path = "../../../../../embassy-executor", features = ["defmt", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } 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"] } embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] }
defmt = "0.3" defmt = "0.3"

View File

@ -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 `alloc`, no heap needed. Task are statically allocated.
* No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning. * 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`. * 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. * 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. * 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.

View File

@ -21,7 +21,7 @@ default = ["time"]
[dependencies] [dependencies]
embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } 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 = [ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
"unproven", "unproven",
] } ] }

View File

@ -76,9 +76,7 @@ where
#[cfg(not(feature = "time"))] #[cfg(not(feature = "time"))]
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported), Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
#[cfg(feature = "time")] #[cfg(feature = "time")]
Operation::DelayUs(us) => { Operation::DelayUs(us) => embassy_time::Timer::after_micros(*us as _).await,
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
}
} }
} }
}; };
@ -143,9 +141,7 @@ where
#[cfg(not(feature = "time"))] #[cfg(not(feature = "time"))]
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported), Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
#[cfg(feature = "time")] #[cfg(feature = "time")]
Operation::DelayUs(us) => { Operation::DelayUs(us) => embassy_time::Timer::after_micros(*us as _).await,
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
}
} }
} }
}; };

View File

@ -59,7 +59,7 @@ rtos-trace = { version = "0.1.2", optional = true }
futures-util = { version = "0.3.17", default-features = false } futures-util = { version = "0.3.17", default-features = false }
embassy-macros = { version = "0.2.1", path = "../embassy-macros" } 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" atomic-polyfill = "1.0.1"
critical-section = "1.1" critical-section = "1.1"
static_cell = "1.1" static_cell = "1.1"

View File

@ -4,7 +4,7 @@ An async/await executor designed for embedded usage.
- No `alloc`, no heap needed. Task futures are statically allocated. - 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. - 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`. - 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. - 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. - 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.

View File

@ -1,4 +1,4 @@
# embassy-macros # embassy-hal-internal
An [Embassy](https://embassy.dev) project. An [Embassy](https://embassy.dev) project.

View File

@ -10,7 +10,6 @@ pub mod drop;
mod macros; mod macros;
mod peripheral; mod peripheral;
pub mod ratio; pub mod ratio;
pub mod ring_buffer;
pub use peripheral::{Peripheral, PeripheralRef}; pub use peripheral::{Peripheral, PeripheralRef};
#[cfg(feature = "cortex-m")] #[cfg(feature = "cortex-m")]

View File

@ -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());
}
}

View File

@ -20,7 +20,7 @@ defmt = ["dep:defmt", "lorawan-device/defmt"]
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", 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-sync = { version = "0.3.0", path = "../embassy-sync" }
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
embedded-hal-async = { version = "=1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" }

View File

@ -34,6 +34,6 @@ impl lorawan_device::async_device::radio::Timer for LoraTimer {
} }
async fn delay_ms(&mut self, millis: u64) { async fn delay_ms(&mut self, millis: u64) {
Timer::after(Duration::from_millis(millis)).await Timer::after_millis(millis).await
} }
} }

View File

@ -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-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
embedded-hal-async = { 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"] } 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-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
embassy-time = { version = "0.1.3" } embassy-time = { version = "0.1.5", path = "../embassy-time" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
bitfield = "0.14.0" bitfield = "0.14.0"

View File

@ -20,7 +20,7 @@ pub use crc32::ETH_FCS;
use crc8::crc8; use crc8::crc8;
use embassy_futures::select::{select, Either}; use embassy_futures::select::{select, Either};
use embassy_net_driver_channel as ch; 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_1::digital::OutputPin;
use embedded_hal_async::digital::Wait; use embedded_hal_async::digital::Wait;
use embedded_hal_async::spi::{Error, Operation, SpiDevice}; 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(); reset.set_low().unwrap();
// Wait t1: 20-43mS // Wait t1: 20-43mS
Timer::after(Duration::from_millis(30)).await; Timer::after_millis(30).await;
reset.set_high().unwrap(); reset.set_high().unwrap();
// Wait t3: 50mS // Wait t3: 50mS
Timer::after(Duration::from_millis(50)).await; Timer::after_millis(50).await;
// Create device // Create device
let mut mac = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx); let mut mac = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx);

View 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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "embassy-net-driver-channel" name = "embassy-net-driver-channel"
version = "0.1.0" version = "0.2.0"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack." 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-sync = { version = "0.3.0", path = "../embassy-sync" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 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" }

View 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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "embassy-net-driver" name = "embassy-net-driver"
version = "0.1.0" version = "0.2.0"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
description = "Driver trait for the `embassy-net` async TCP/IP network stack." description = "Driver trait for the `embassy-net` async TCP/IP network stack."

View File

@ -10,8 +10,8 @@ edition = "2021"
[dependencies] [dependencies]
embedded-hal = { version = "1.0.0-rc.1" } embedded-hal = { version = "1.0.0-rc.1" }
embedded-hal-async = { 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-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
embassy-time = { version = "0.1.3", path = "../embassy-time" } embassy-time = { version = "0.1.5", path = "../embassy-time" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }

View File

@ -7,10 +7,10 @@ edition = "2021"
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", 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-sync = { version = "0.3.0", path = "../embassy-sync"}
embassy-futures = { version = "0.1.0", path = "../embassy-futures"} 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 = { version = "1.0.0-rc.1" }
embedded-hal-async = { version = "=1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" }

View File

@ -169,9 +169,9 @@ where
pub async fn run(mut self) -> ! { pub async fn run(mut self) -> ! {
debug!("resetting..."); debug!("resetting...");
self.reset.set_low().unwrap(); self.reset.set_low().unwrap();
Timer::after(Duration::from_millis(100)).await; Timer::after_millis(100).await;
self.reset.set_high().unwrap(); 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 tx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE]; let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE];

View File

@ -16,7 +16,7 @@ defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true } log = { version = "0.4.14", optional = true }
embedded-io-async = { version = "0.6.0" } 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" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
ppproto = { version = "0.1.2"} ppproto = { version = "0.1.2"}
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
edition = "2021" edition = "2021"
[dependencies] [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" async-io = "1.6.0"
log = "0.4.14" log = "0.4.14"
libc = "0.2.101" libc = "0.2.101"

View File

@ -10,8 +10,8 @@ edition = "2021"
[dependencies] [dependencies]
embedded-hal = { version = "1.0.0-rc.1" } embedded-hal = { version = "1.0.0-rc.1" }
embedded-hal-async = { 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-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
embassy-time = { version = "0.1.3", path = "../embassy-time" } embassy-time = { version = "0.1.5", path = "../embassy-time" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }

View File

@ -8,7 +8,7 @@ mod device;
use embassy_futures::select::{select, Either}; use embassy_futures::select::{select, Either};
use embassy_net_driver_channel as ch; use embassy_net_driver_channel as ch;
use embassy_net_driver_channel::driver::LinkState; use embassy_net_driver_channel::driver::LinkState;
use embassy_time::{Duration, Timer}; use embassy_time::Timer;
use embedded_hal::digital::OutputPin; use embedded_hal::digital::OutputPin;
use embedded_hal_async::digital::Wait; use embedded_hal_async::digital::Wait;
use embedded_hal_async::spi::SpiDevice; 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 the chip.
reset.set_low().ok(); reset.set_low().ok();
// Ensure the reset is registered. // Ensure the reset is registered.
Timer::after(Duration::from_millis(1)).await; Timer::after_millis(1).await;
reset.set_high().ok(); reset.set_high().ok();
// Wait for PLL lock. Some chips are slower than others. // Wait for PLL lock. Some chips are slower than others.
// Slowest is w5100s which is 100ms, so let's just wait that. // 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(); let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap();

31
embassy-net/CHANGELOG.md Normal file
View 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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "embassy-net" name = "embassy-net"
version = "0.1.0" version = "0.2.0"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
description = "Async TCP/IP network stack for embedded systems" description = "Async TCP/IP network stack for embedded systems"
@ -51,8 +51,8 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
"async", "async",
] } ] }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
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-sync = { version = "0.3.0", path = "../embassy-sync" }
embedded-io-async = { version = "0.6.0", optional = true } embedded-io-async = { version = "0.6.0", optional = true }

View File

@ -509,7 +509,10 @@ impl<D: Driver> Stack<D> {
self.with_mut(|s, i| { self.with_mut(|s, i| {
let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket); let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
match socket.start_query(s.iface.context(), name, qtype) { 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) => { Err(dns::StartQueryError::NoFreeSlot) => {
i.dns_waker.register(cx.waker()); i.dns_waker.register(cx.waker());
Poll::Pending Poll::Pending

View File

@ -94,7 +94,7 @@ _gpio-p1 = []
_nrf52832_anomaly_109 = [] _nrf52832_anomaly_109 = []
[dependencies] [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-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-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" } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }

View File

@ -6,10 +6,13 @@ pub mod pac {
// To avoid cfg spam, we remove _ns or _s suffixes here. // To avoid cfg spam, we remove _ns or _s suffixes here.
pub use nrf5340_app_pac::NVIC_PRIO_BITS; pub use nrf5340_app_pac::NVIC_PRIO_BITS;
#[cfg(feature="rt")]
#[doc(no_inline)]
pub use nrf5340_app_pac::interrupt;
#[doc(no_inline)] #[doc(no_inline)]
pub use nrf5340_app_pac::{ pub use nrf5340_app_pac::{
interrupt,
Interrupt, Interrupt,
Peripherals, Peripherals,
@ -60,156 +63,167 @@ pub mod pac {
wdt0_ns as wdt0, wdt0_ns as wdt0,
}; };
#[cfg(feature = "nrf5340-app-ns")] /// Non-Secure mode (NS) peripherals
#[doc(no_inline)] pub mod ns {
pub use nrf5340_app_pac::{ #[cfg(feature = "nrf5340-app-ns")]
CLOCK_NS as CLOCK, #[doc(no_inline)]
COMP_NS as COMP, pub use nrf5340_app_pac::{
CTRLAP_NS as CTRLAP, CLOCK_NS as CLOCK,
DCNF_NS as DCNF, COMP_NS as COMP,
DPPIC_NS as DPPIC, CTRLAP_NS as CTRLAP,
EGU0_NS as EGU0, DCNF_NS as DCNF,
EGU1_NS as EGU1, DPPIC_NS as DPPIC,
EGU2_NS as EGU2, EGU0_NS as EGU0,
EGU3_NS as EGU3, EGU1_NS as EGU1,
EGU4_NS as EGU4, EGU2_NS as EGU2,
EGU5_NS as EGU5, EGU3_NS as EGU3,
FPU_NS as FPU, EGU4_NS as EGU4,
GPIOTE1_NS as GPIOTE1, EGU5_NS as EGU5,
I2S0_NS as I2S0, FPU_NS as FPU,
IPC_NS as IPC, GPIOTE1_NS as GPIOTE1,
KMU_NS as KMU, I2S0_NS as I2S0,
LPCOMP_NS as LPCOMP, IPC_NS as IPC,
MUTEX_NS as MUTEX, KMU_NS as KMU,
NFCT_NS as NFCT, LPCOMP_NS as LPCOMP,
NVMC_NS as NVMC, MUTEX_NS as MUTEX,
OSCILLATORS_NS as OSCILLATORS, NFCT_NS as NFCT,
P0_NS as P0, NVMC_NS as NVMC,
P1_NS as P1, OSCILLATORS_NS as OSCILLATORS,
PDM0_NS as PDM0, P0_NS as P0,
POWER_NS as POWER, P1_NS as P1,
PWM0_NS as PWM0, PDM0_NS as PDM0,
PWM1_NS as PWM1, POWER_NS as POWER,
PWM2_NS as PWM2, PWM0_NS as PWM0,
PWM3_NS as PWM3, PWM1_NS as PWM1,
QDEC0_NS as QDEC0, PWM2_NS as PWM2,
QDEC1_NS as QDEC1, PWM3_NS as PWM3,
QSPI_NS as QSPI, QDEC0_NS as QDEC0,
REGULATORS_NS as REGULATORS, QDEC1_NS as QDEC1,
RESET_NS as RESET, QSPI_NS as QSPI,
RTC0_NS as RTC0, REGULATORS_NS as REGULATORS,
RTC1_NS as RTC1, RESET_NS as RESET,
SAADC_NS as SAADC, RTC0_NS as RTC0,
SPIM0_NS as SPIM0, RTC1_NS as RTC1,
SPIM1_NS as SPIM1, SAADC_NS as SAADC,
SPIM2_NS as SPIM2, SPIM0_NS as SPIM0,
SPIM3_NS as SPIM3, SPIM1_NS as SPIM1,
SPIM4_NS as SPIM4, SPIM2_NS as SPIM2,
SPIS0_NS as SPIS0, SPIM3_NS as SPIM3,
SPIS1_NS as SPIS1, SPIM4_NS as SPIM4,
SPIS2_NS as SPIS2, SPIS0_NS as SPIS0,
SPIS3_NS as SPIS3, SPIS1_NS as SPIS1,
TIMER0_NS as TIMER0, SPIS2_NS as SPIS2,
TIMER1_NS as TIMER1, SPIS3_NS as SPIS3,
TIMER2_NS as TIMER2, TIMER0_NS as TIMER0,
TWIM0_NS as TWIM0, TIMER1_NS as TIMER1,
TWIM1_NS as TWIM1, TIMER2_NS as TIMER2,
TWIM2_NS as TWIM2, TWIM0_NS as TWIM0,
TWIM3_NS as TWIM3, TWIM1_NS as TWIM1,
TWIS0_NS as TWIS0, TWIM2_NS as TWIM2,
TWIS1_NS as TWIS1, TWIM3_NS as TWIM3,
TWIS2_NS as TWIS2, TWIS0_NS as TWIS0,
TWIS3_NS as TWIS3, TWIS1_NS as TWIS1,
UARTE0_NS as UARTE0, TWIS2_NS as TWIS2,
UARTE1_NS as UARTE1, TWIS3_NS as TWIS3,
UARTE2_NS as UARTE2, UARTE0_NS as UARTE0,
UARTE3_NS as UARTE3, UARTE1_NS as UARTE1,
USBD_NS as USBD, UARTE2_NS as UARTE2,
USBREGULATOR_NS as USBREGULATOR, UARTE3_NS as UARTE3,
VMC_NS as VMC, USBD_NS as USBD,
WDT0_NS as WDT0, USBREGULATOR_NS as USBREGULATOR,
WDT1_NS as WDT1, VMC_NS as VMC,
}; WDT0_NS as WDT0,
WDT1_NS as WDT1,
};
}
#[cfg(feature = "nrf5340-app-s")] /// Secure mode (S) peripherals
#[doc(no_inline)] pub mod s {
pub use nrf5340_app_pac::{ #[cfg(feature = "nrf5340-app-s")]
CACHEDATA_S as CACHEDATA, #[doc(no_inline)]
CACHEINFO_S as CACHEINFO, pub use nrf5340_app_pac::{
CACHE_S as CACHE, CACHEDATA_S as CACHEDATA,
CLOCK_S as CLOCK, CACHEINFO_S as CACHEINFO,
COMP_S as COMP, CACHE_S as CACHE,
CRYPTOCELL_S as CRYPTOCELL, CLOCK_S as CLOCK,
CTI_S as CTI, COMP_S as COMP,
CTRLAP_S as CTRLAP, CRYPTOCELL_S as CRYPTOCELL,
DCNF_S as DCNF, CTI_S as CTI,
DPPIC_S as DPPIC, CTRLAP_S as CTRLAP,
EGU0_S as EGU0, DCNF_S as DCNF,
EGU1_S as EGU1, DPPIC_S as DPPIC,
EGU2_S as EGU2, EGU0_S as EGU0,
EGU3_S as EGU3, EGU1_S as EGU1,
EGU4_S as EGU4, EGU2_S as EGU2,
EGU5_S as EGU5, EGU3_S as EGU3,
FICR_S as FICR, EGU4_S as EGU4,
FPU_S as FPU, EGU5_S as EGU5,
GPIOTE0_S as GPIOTE0, FICR_S as FICR,
I2S0_S as I2S0, FPU_S as FPU,
IPC_S as IPC, GPIOTE0_S as GPIOTE0,
KMU_S as KMU, I2S0_S as I2S0,
LPCOMP_S as LPCOMP, IPC_S as IPC,
MUTEX_S as MUTEX, KMU_S as KMU,
NFCT_S as NFCT, LPCOMP_S as LPCOMP,
NVMC_S as NVMC, MUTEX_S as MUTEX,
OSCILLATORS_S as OSCILLATORS, NFCT_S as NFCT,
P0_S as P0, NVMC_S as NVMC,
P1_S as P1, OSCILLATORS_S as OSCILLATORS,
PDM0_S as PDM0, P0_S as P0,
POWER_S as POWER, P1_S as P1,
PWM0_S as PWM0, PDM0_S as PDM0,
PWM1_S as PWM1, POWER_S as POWER,
PWM2_S as PWM2, PWM0_S as PWM0,
PWM3_S as PWM3, PWM1_S as PWM1,
QDEC0_S as QDEC0, PWM2_S as PWM2,
QDEC1_S as QDEC1, PWM3_S as PWM3,
QSPI_S as QSPI, QDEC0_S as QDEC0,
REGULATORS_S as REGULATORS, QDEC1_S as QDEC1,
RESET_S as RESET, QSPI_S as QSPI,
RTC0_S as RTC0, REGULATORS_S as REGULATORS,
RTC1_S as RTC1, RESET_S as RESET,
SAADC_S as SAADC, RTC0_S as RTC0,
SPIM0_S as SPIM0, RTC1_S as RTC1,
SPIM1_S as SPIM1, SAADC_S as SAADC,
SPIM2_S as SPIM2, SPIM0_S as SPIM0,
SPIM3_S as SPIM3, SPIM1_S as SPIM1,
SPIM4_S as SPIM4, SPIM2_S as SPIM2,
SPIS0_S as SPIS0, SPIM3_S as SPIM3,
SPIS1_S as SPIS1, SPIM4_S as SPIM4,
SPIS2_S as SPIS2, SPIS0_S as SPIS0,
SPIS3_S as SPIS3, SPIS1_S as SPIS1,
SPU_S as SPU, SPIS2_S as SPIS2,
TAD_S as TAD, SPIS3_S as SPIS3,
TIMER0_S as TIMER0, SPU_S as SPU,
TIMER1_S as TIMER1, TAD_S as TAD,
TIMER2_S as TIMER2, TIMER0_S as TIMER0,
TWIM0_S as TWIM0, TIMER1_S as TIMER1,
TWIM1_S as TWIM1, TIMER2_S as TIMER2,
TWIM2_S as TWIM2, TWIM0_S as TWIM0,
TWIM3_S as TWIM3, TWIM1_S as TWIM1,
TWIS0_S as TWIS0, TWIM2_S as TWIM2,
TWIS1_S as TWIS1, TWIM3_S as TWIM3,
TWIS2_S as TWIS2, TWIS0_S as TWIS0,
TWIS3_S as TWIS3, TWIS1_S as TWIS1,
UARTE0_S as UARTE0, TWIS2_S as TWIS2,
UARTE1_S as UARTE1, TWIS3_S as TWIS3,
UARTE2_S as UARTE2, UARTE0_S as UARTE0,
UARTE3_S as UARTE3, UARTE1_S as UARTE1,
UICR_S as UICR, UARTE2_S as UARTE2,
USBD_S as USBD, UARTE3_S as UARTE3,
USBREGULATOR_S as USBREGULATOR, UICR_S as UICR,
VMC_S as VMC, USBD_S as USBD,
WDT0_S as WDT0, USBREGULATOR_S as USBREGULATOR,
WDT1_S as WDT1, 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. /// The maximum buffer size that the EasyDMA can send/recv in one operation.

View File

@ -7,9 +7,12 @@ pub mod pac {
pub use nrf5340_net_pac::NVIC_PRIO_BITS; pub use nrf5340_net_pac::NVIC_PRIO_BITS;
#[cfg(feature="rt")]
#[doc(no_inline)]
pub use nrf5340_net_pac::interrupt;
#[doc(no_inline)] #[doc(no_inline)]
pub use nrf5340_net_pac::{ pub use nrf5340_net_pac::{
interrupt,
Interrupt, Interrupt,
Peripherals, Peripherals,

View File

@ -7,9 +7,12 @@ pub mod pac {
pub use nrf9160_pac::NVIC_PRIO_BITS; pub use nrf9160_pac::NVIC_PRIO_BITS;
#[cfg(feature="rt")]
#[doc(no_inline)]
pub use nrf9160_pac::interrupt;
#[doc(no_inline)] #[doc(no_inline)]
pub use nrf9160_pac::{ pub use nrf9160_pac::{
interrupt,
Interrupt, Interrupt,
cc_host_rgf_s as cc_host_rgf, cc_host_rgf_s as cc_host_rgf,
@ -45,122 +48,131 @@ pub mod pac {
wdt_ns as wdt, wdt_ns as wdt,
}; };
#[cfg(feature = "nrf9160-ns")] /// Non-Secure mode (NS) peripherals
#[doc(no_inline)] pub mod ns {
pub use nrf9160_pac::{ #[doc(no_inline)]
CLOCK_NS as CLOCK, pub use nrf9160_pac::{
DPPIC_NS as DPPIC, CLOCK_NS as CLOCK,
EGU0_NS as EGU0, DPPIC_NS as DPPIC,
EGU1_NS as EGU1, EGU0_NS as EGU0,
EGU2_NS as EGU2, EGU1_NS as EGU1,
EGU3_NS as EGU3, EGU2_NS as EGU2,
EGU4_NS as EGU4, EGU3_NS as EGU3,
EGU5_NS as EGU5, EGU4_NS as EGU4,
FPU_NS as FPU, EGU5_NS as EGU5,
GPIOTE1_NS as GPIOTE1, FPU_NS as FPU,
I2S_NS as I2S, GPIOTE1_NS as GPIOTE1,
IPC_NS as IPC, I2S_NS as I2S,
KMU_NS as KMU, IPC_NS as IPC,
NVMC_NS as NVMC, KMU_NS as KMU,
P0_NS as P0, NVMC_NS as NVMC,
PDM_NS as PDM, P0_NS as P0,
POWER_NS as POWER, PDM_NS as PDM,
PWM0_NS as PWM0, POWER_NS as POWER,
PWM1_NS as PWM1, PWM0_NS as PWM0,
PWM2_NS as PWM2, PWM1_NS as PWM1,
PWM3_NS as PWM3, PWM2_NS as PWM2,
REGULATORS_NS as REGULATORS, PWM3_NS as PWM3,
RTC0_NS as RTC0, REGULATORS_NS as REGULATORS,
RTC1_NS as RTC1, RTC0_NS as RTC0,
SAADC_NS as SAADC, RTC1_NS as RTC1,
SPIM0_NS as SPIM0, SAADC_NS as SAADC,
SPIM1_NS as SPIM1, SPIM0_NS as SPIM0,
SPIM2_NS as SPIM2, SPIM1_NS as SPIM1,
SPIM3_NS as SPIM3, SPIM2_NS as SPIM2,
SPIS0_NS as SPIS0, SPIM3_NS as SPIM3,
SPIS1_NS as SPIS1, SPIS0_NS as SPIS0,
SPIS2_NS as SPIS2, SPIS1_NS as SPIS1,
SPIS3_NS as SPIS3, SPIS2_NS as SPIS2,
TIMER0_NS as TIMER0, SPIS3_NS as SPIS3,
TIMER1_NS as TIMER1, TIMER0_NS as TIMER0,
TIMER2_NS as TIMER2, TIMER1_NS as TIMER1,
TWIM0_NS as TWIM0, TIMER2_NS as TIMER2,
TWIM1_NS as TWIM1, TWIM0_NS as TWIM0,
TWIM2_NS as TWIM2, TWIM1_NS as TWIM1,
TWIM3_NS as TWIM3, TWIM2_NS as TWIM2,
TWIS0_NS as TWIS0, TWIM3_NS as TWIM3,
TWIS1_NS as TWIS1, TWIS0_NS as TWIS0,
TWIS2_NS as TWIS2, TWIS1_NS as TWIS1,
TWIS3_NS as TWIS3, TWIS2_NS as TWIS2,
UARTE0_NS as UARTE0, TWIS3_NS as TWIS3,
UARTE1_NS as UARTE1, UARTE0_NS as UARTE0,
UARTE2_NS as UARTE2, UARTE1_NS as UARTE1,
UARTE3_NS as UARTE3, UARTE2_NS as UARTE2,
VMC_NS as VMC, UARTE3_NS as UARTE3,
WDT_NS as WDT, VMC_NS as VMC,
}; WDT_NS as WDT,
};
}
#[cfg(feature = "nrf9160-s")] /// Secure mode (S) peripherals
#[doc(no_inline)] pub mod s {
pub use nrf9160_pac::{ #[doc(no_inline)]
CC_HOST_RGF_S as CC_HOST_RGF, pub use nrf9160_pac::{
CLOCK_S as CLOCK, CC_HOST_RGF_S as CC_HOST_RGF,
CRYPTOCELL_S as CRYPTOCELL, CLOCK_S as CLOCK,
CTRL_AP_PERI_S as CTRL_AP_PERI, CRYPTOCELL_S as CRYPTOCELL,
DPPIC_S as DPPIC, CTRL_AP_PERI_S as CTRL_AP_PERI,
EGU0_S as EGU0, DPPIC_S as DPPIC,
EGU1_S as EGU1, EGU0_S as EGU0,
EGU2_S as EGU2, EGU1_S as EGU1,
EGU3_S as EGU3, EGU2_S as EGU2,
EGU4_S as EGU4, EGU3_S as EGU3,
EGU5_S as EGU5, EGU4_S as EGU4,
FICR_S as FICR, EGU5_S as EGU5,
FPU_S as FPU, FICR_S as FICR,
GPIOTE0_S as GPIOTE0, FPU_S as FPU,
I2S_S as I2S, GPIOTE0_S as GPIOTE0,
IPC_S as IPC, I2S_S as I2S,
KMU_S as KMU, IPC_S as IPC,
NVMC_S as NVMC, KMU_S as KMU,
P0_S as P0, NVMC_S as NVMC,
PDM_S as PDM, P0_S as P0,
POWER_S as POWER, PDM_S as PDM,
PWM0_S as PWM0, POWER_S as POWER,
PWM1_S as PWM1, PWM0_S as PWM0,
PWM2_S as PWM2, PWM1_S as PWM1,
PWM3_S as PWM3, PWM2_S as PWM2,
REGULATORS_S as REGULATORS, PWM3_S as PWM3,
RTC0_S as RTC0, REGULATORS_S as REGULATORS,
RTC1_S as RTC1, RTC0_S as RTC0,
SAADC_S as SAADC, RTC1_S as RTC1,
SPIM0_S as SPIM0, SAADC_S as SAADC,
SPIM1_S as SPIM1, SPIM0_S as SPIM0,
SPIM2_S as SPIM2, SPIM1_S as SPIM1,
SPIM3_S as SPIM3, SPIM2_S as SPIM2,
SPIS0_S as SPIS0, SPIM3_S as SPIM3,
SPIS1_S as SPIS1, SPIS0_S as SPIS0,
SPIS2_S as SPIS2, SPIS1_S as SPIS1,
SPIS3_S as SPIS3, SPIS2_S as SPIS2,
SPU_S as SPU, SPIS3_S as SPIS3,
TAD_S as TAD, SPU_S as SPU,
TIMER0_S as TIMER0, TAD_S as TAD,
TIMER1_S as TIMER1, TIMER0_S as TIMER0,
TIMER2_S as TIMER2, TIMER1_S as TIMER1,
TWIM0_S as TWIM0, TIMER2_S as TIMER2,
TWIM1_S as TWIM1, TWIM0_S as TWIM0,
TWIM2_S as TWIM2, TWIM1_S as TWIM1,
TWIM3_S as TWIM3, TWIM2_S as TWIM2,
TWIS0_S as TWIS0, TWIM3_S as TWIM3,
TWIS1_S as TWIS1, TWIS0_S as TWIS0,
TWIS2_S as TWIS2, TWIS1_S as TWIS1,
TWIS3_S as TWIS3, TWIS2_S as TWIS2,
UARTE0_S as UARTE0, TWIS3_S as TWIS3,
UARTE1_S as UARTE1, UARTE0_S as UARTE0,
UARTE2_S as UARTE2, UARTE1_S as UARTE1,
UARTE3_S as UARTE3, UARTE2_S as UARTE2,
UICR_S as UICR, UARTE3_S as UARTE3,
VMC_S as VMC, UICR_S as UICR,
WDT_S as WDT, 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. /// The maximum buffer size that the EasyDMA can send/recv in one operation.

View File

@ -60,7 +60,7 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
[dependencies] [dependencies]
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } 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-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-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" } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }

View File

@ -5,7 +5,7 @@ use core::task::Poll;
use atomic_polyfill::{AtomicU8, Ordering}; use atomic_polyfill::{AtomicU8, Ordering};
use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use embassy_time::{Duration, Timer}; use embassy_time::Timer;
use super::*; use super::*;
use crate::clocks::clk_peri_freq; use crate::clocks::clk_peri_freq;
@ -435,7 +435,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
Self::flush().await.unwrap(); Self::flush().await.unwrap();
while self.busy() {} while self.busy() {}
regs.uartlcr_h().write_set(|w| w.set_brk(true)); 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)); regs.uartlcr_h().write_clear(|w| w.set_brk(true));
} }
} }

View File

@ -6,7 +6,7 @@ use atomic_polyfill::{AtomicU16, Ordering};
use embassy_futures::select::{select, Either}; use embassy_futures::select::{select, Either};
use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_hal_internal::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use embassy_time::{Duration, Timer}; use embassy_time::Timer;
use pac::uart::regs::Uartris; use pac::uart::regs::Uartris;
use crate::clocks::clk_peri_freq; use crate::clocks::clk_peri_freq;
@ -187,7 +187,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
self.blocking_flush().unwrap(); self.blocking_flush().unwrap();
while self.busy() {} while self.busy() {}
regs.uartlcr_h().write_set(|w| w.set_brk(true)); 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)); regs.uartlcr_h().write_clear(|w| w.set_brk(true));
} }
} }

View File

@ -13,11 +13,11 @@ features = ["stm32wb55rg"]
[dependencies] [dependencies]
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } 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-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" } embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" }
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } 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 } defmt = { version = "0.3", optional = true }
cortex-m = "0.7.6" cortex-m = "0.7.6"

View File

@ -33,11 +33,11 @@ flavors = [
[dependencies] [dependencies]
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } 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-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-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-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-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
embassy-executor = { version = "0.3.0", path = "../embassy-executor", 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" sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1" 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" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies] [build-dependencies]
proc-macro2 = "1.0.36" proc-macro2 = "1.0.36"
quote = "1.0.15" 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] [features]

View File

@ -5,7 +5,7 @@ use std::{env, fs};
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; 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}; use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, METADATA};
fn main() { 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 // Generate rcc fieldset and enum maps
let rcc_enum_map: HashMap<&str, HashMap<&str, &Enum>> = { let rcc_enum_map: HashMap<&str, HashMap<&str, &Enum>> = {
let rcc_registers = METADATA let rcc_blocks = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap().items;
.peripherals let rcc_fieldsets: HashMap<&str, &FieldSet> = rcc_registers.ir.fieldsets.iter().map(|f| (f.name, f)).collect();
.iter() let rcc_enums: HashMap<&str, &Enum> = rcc_registers.ir.enums.iter().map(|e| (e.name, e)).collect();
.filter_map(|p| p.registers.as_ref())
.find(|r| r.kind == "rcc")
.unwrap()
.ir;
let rcc_blocks = rcc_registers.blocks.iter().find(|b| b.name == "Rcc").unwrap().items; rcc_blocks
let rcc_block_item_map: HashMap<&str, &str> = rcc_blocks
.iter() .iter()
.filter_map(|b| match &b.inner { .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, _ => None,
}) })
.collect(); .filter_map(|(b, f)| {
rcc_fieldsets.get(f).map(|f| {
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| {
( (
*b, b,
f.fields f.fields
.iter() .iter()
.filter_map(|f| { .filter_map(|f| {
let enumm = f.enumm?; let enumm = f.enumm?;
let enumm = rcc_enum_map.get(enumm)?; let enumm = rcc_enums.get(enumm)?;
Some((f.name, *enumm)) Some((f.name, *enumm))
}) })
@ -470,9 +466,9 @@ fn main() {
let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
let pname = format_ident!("{}", p.name); let pname = format_ident!("{}", p.name);
let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); let clk = format_ident!("{}", rcc.clock);
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); let en_reg = format_ident!("{}", en.register);
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); let set_en_field = format_ident!("set_{}", en.field);
let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) { let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) {
let refcount_static = let refcount_static =
@ -498,9 +494,11 @@ fn main() {
(TokenStream::new(), TokenStream::new()) (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>| { let mux_for = |mux: Option<&'static PeripheralRccRegister>| {
// temporary hack to restrict the scope of the implementation to h5 // restrict mux implementation to supported versions
if !&chip_name.starts_with("stm32h5") { if !mux_supported {
return None; return None;
} }
@ -523,12 +521,16 @@ fn main() {
.filter(|v| v.name != "DISABLE") .filter(|v| v.name != "DISABLE")
.map(|v| { .map(|v| {
let variant_name = format_ident!("{}", v.name); 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 if v.name.starts_with("HCLK") || v.name.starts_with("PCLK") || v.name == "SYS" {
let clock_name = format_ident!("mux_{}", v.name.to_ascii_lowercase()); quote! {
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name },
quote! { }
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }, } else {
quote! {
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
}
} }
}) })
.collect(); .collect();
@ -1012,15 +1014,7 @@ fn main() {
// ======== // ========
// Generate Div/Mul impls for RCC prescalers/dividers/multipliers. // Generate Div/Mul impls for RCC prescalers/dividers/multipliers.
let rcc_registers = METADATA for e in rcc_registers.ir.enums {
.peripherals
.iter()
.filter_map(|p| p.registers.as_ref())
.find(|r| r.kind == "rcc")
.unwrap()
.ir;
for e in rcc_registers.enums {
fn is_rcc_name(e: &str) -> bool { fn is_rcc_name(e: &str) -> bool {
match e { match e {
"Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true, "Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true,

View File

@ -564,7 +564,7 @@ foreach_peripheral!(
#[cfg(any(rcc_h7, rcc_h7rm0433))] #[cfg(any(rcc_h7, rcc_h7rm0433))]
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
fn frequency() -> crate::time::Hertz { 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) { fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {

View File

@ -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 // 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 // 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; let hclk_mhz = hclk.0 / 1_000_000;
// Set the MDC clock frequency in the range 1MHz - 2.5MHz // Set the MDC clock frequency in the range 1MHz - 2.5MHz

View File

@ -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 // 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; let hclk_mhz = hclk.0 / 1_000_000;
// Set the MDC clock frequency in the range 1MHz - 2.5MHz // Set the MDC clock frequency in the range 1MHz - 2.5MHz

View File

@ -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); let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
#[cfg(all(rcc_f4, not(stm32f410)))] #[cfg(all(rcc_f4, not(stm32f410)))]
let pclk = unsafe { get_freqs() }.plli2s.unwrap(); let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
#[cfg(stm32f410)] #[cfg(stm32f410)]
let pclk = T::frequency(); let pclk = T::frequency();

View File

@ -106,7 +106,7 @@ impl LsConfig {
pub const fn off() -> Self { pub const fn off() -> Self {
Self { Self {
rtc: RtcClockSource::NOCLOCK, rtc: RtcClockSource::DISABLE,
lsi: false, lsi: false,
lse: None, lse: None,
} }
@ -133,7 +133,7 @@ impl LsConfig {
Some(LSI_FREQ) Some(LSI_FREQ)
} }
RtcClockSource::LSE => Some(self.lse.as_ref().unwrap().frequency), RtcClockSource::LSE => Some(self.lse.as_ref().unwrap().frequency),
RtcClockSource::NOCLOCK => None, RtcClockSource::DISABLE => None,
_ => todo!(), _ => todo!(),
}; };
@ -180,7 +180,7 @@ impl LsConfig {
ok &= reg.rtcsel() == self.rtc; ok &= reg.rtcsel() == self.rtc;
#[cfg(not(rcc_wba))] #[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.lseon() == lse_en;
ok &= reg.lsebyp() == lse_byp; ok &= reg.lsebyp() == lse_byp;
@ -225,7 +225,7 @@ impl LsConfig {
while !bdcr().read().lserdy() {} while !bdcr().read().lserdy() {}
} }
if self.rtc != RtcClockSource::NOCLOCK { if self.rtc != RtcClockSource::DISABLE {
bdcr().modify(|w| { bdcr().modify(|w| {
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");

View File

@ -134,10 +134,12 @@ pub(crate) unsafe fn init(config: Config) {
}; };
set_freqs(Clocks { set_freqs(Clocks {
hsi: None,
lse: None,
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, hclk1: ahb_freq,
apb1: apb_freq, pclk1: apb_freq,
apb1_tim: apb_tim_freq, pclk1_tim: apb_tim_freq,
rtc, rtc,
}); });
} }

View File

@ -162,11 +162,11 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(real_sysclk), sys: Hertz(real_sysclk),
apb1: Hertz(pclk), pclk1: Hertz(pclk),
apb2: Hertz(pclk), pclk2: Hertz(pclk),
apb1_tim: Hertz(pclk * timer_mul), pclk1_tim: Hertz(pclk * timer_mul),
apb2_tim: Hertz(pclk * timer_mul), pclk2_tim: Hertz(pclk * timer_mul),
ahb1: Hertz(hclk), hclk1: Hertz(hclk),
rtc, rtc,
}); });
} }

View File

@ -102,7 +102,6 @@ pub(crate) unsafe fn init(config: Config) {
assert!(pclk2 <= 72_000_000); assert!(pclk2 <= 72_000_000);
// Only needed for stm32f103?
FLASH.acr().write(|w| { FLASH.acr().write(|w| {
w.set_latency(if real_sysclk <= 24_000_000 { w.set_latency(if real_sysclk <= 24_000_000 {
Latency::WS0 Latency::WS0
@ -111,6 +110,8 @@ pub(crate) unsafe fn init(config: Config) {
} else { } else {
Latency::WS2 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 // 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 { set_freqs(Clocks {
sys: Hertz(real_sysclk), sys: Hertz(real_sysclk),
apb1: Hertz(pclk1), pclk1: Hertz(pclk1),
apb2: Hertz(pclk2), pclk2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1), pclk1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2), pclk2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk), hclk1: Hertz(hclk),
adc: Some(Hertz(adcclk)), adc: Some(Hertz(adcclk)),
rtc, rtc,
}); });

View File

@ -307,14 +307,14 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, hclk1: ahb_freq,
ahb2: ahb_freq, hclk2: ahb_freq,
ahb3: ahb_freq, hclk3: ahb_freq,
apb1: apb1_freq, pclk1: apb1_freq,
apb1_tim: apb1_tim_freq, pclk1_tim: apb1_tim_freq,
apb2: apb2_freq, pclk2: apb2_freq,
apb2_tim: apb2_tim_freq, pclk2_tim: apb2_tim_freq,
pll48: Some(pll_clocks.pll48_freq), pll1_q: Some(pll_clocks.pll48_freq),
rtc, rtc,
}); });
} }

View File

@ -281,11 +281,11 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: sysclk, sys: sysclk,
apb1: pclk1, pclk1: pclk1,
apb2: pclk2, pclk2: pclk2,
apb1_tim: pclk1 * timer_mul1, pclk1_tim: pclk1 * timer_mul1,
apb2_tim: pclk2 * timer_mul2, pclk2_tim: pclk2 * timer_mul2,
ahb1: hclk, hclk1: hclk,
#[cfg(rcc_f3)] #[cfg(rcc_f3)]
adc: adc, adc: adc,
#[cfg(all(rcc_f3, adc3_common))] #[cfg(all(rcc_f3, adc3_common))]

View File

@ -340,23 +340,27 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sysclk), sys: Hertz(sysclk),
apb1: Hertz(pclk1), pclk1: Hertz(pclk1),
apb2: Hertz(pclk2), pclk2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1), pclk1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2), pclk2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk), hclk1: Hertz(hclk),
ahb2: Hertz(hclk), hclk2: Hertz(hclk),
ahb3: Hertz(hclk), hclk3: Hertz(hclk),
pll48: plls.pll48clk.map(Hertz), pll1_q: plls.pll48clk.map(Hertz),
#[cfg(not(stm32f410))] #[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))] #[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, rtc,
}); });

View File

@ -259,17 +259,17 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sysclk), sys: Hertz(sysclk),
apb1: Hertz(pclk1), pclk1: Hertz(pclk1),
apb2: Hertz(pclk2), pclk2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1), pclk1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2), pclk2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk), hclk1: Hertz(hclk),
ahb2: Hertz(hclk), hclk2: Hertz(hclk),
ahb3: Hertz(hclk), hclk3: Hertz(hclk),
pll48: plls.pll48clk.map(Hertz), pll1_q: plls.pll48clk.map(Hertz),
rtc, rtc,
}); });

View File

@ -89,7 +89,7 @@ impl Default for Config {
impl PllConfig { impl PllConfig {
pub(crate) fn init(self) -> Hertz { pub(crate) fn init(self) -> Hertz {
let (src, input_freq) = match self.source { 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), PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq),
}; };
@ -186,7 +186,7 @@ pub(crate) unsafe fn init(config: Config) {
} }
ClockSrc::PLL(pll) => { ClockSrc::PLL(pll) => {
let freq = pll.init(); let freq = pll.init();
(freq, Sw::PLLRCLK) (freq, Sw::PLL1_R)
} }
ClockSrc::LSI => { ClockSrc::LSI => {
// Enable LSI // Enable LSI
@ -275,9 +275,9 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, hclk1: ahb_freq,
apb1: apb_freq, pclk1: apb_freq,
apb1_tim: apb_tim_freq, pclk1_tim: apb_tim_freq,
rtc, rtc,
}); });
} }

View File

@ -33,7 +33,7 @@ impl Into<Pllsrc> for PllSrc {
fn into(self) -> Pllsrc { fn into(self) -> Pllsrc {
match self { match self {
PllSrc::HSE(..) => Pllsrc::HSE, PllSrc::HSE(..) => Pllsrc::HSE,
PllSrc::HSI16 => Pllsrc::HSI16, PllSrc::HSI16 => Pllsrc::HSI,
} }
} }
} }
@ -118,9 +118,9 @@ impl Default for Config {
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
low_power_run: false, low_power_run: false,
pll: None, pll: None,
clock_48mhz_src: None, clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(None)),
adc12_clock_source: Adcsel::NOCLK, adc12_clock_source: Adcsel::DISABLE,
adc345_clock_source: Adcsel::NOCLK, adc345_clock_source: Adcsel::DISABLE,
ls: Default::default(), ls: Default::default(),
} }
} }
@ -201,7 +201,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ, Sw::HSI16) (HSI_FREQ, Sw::HSI)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // 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); 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); 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) => { Clock48MhzSrc::Hsi48(crs_config) => {
// Enable HSI48 // Enable HSI48
@ -326,16 +326,16 @@ pub(crate) unsafe fn init(config: Config) {
RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
let adc12_ck = match config.adc12_clock_source { let adc12_ck = match config.adc12_clock_source {
AdcClockSource::NOCLK => None, AdcClockSource::DISABLE => None,
AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p, AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
AdcClockSource::SYSCLK => Some(sys_clk), AdcClockSource::SYS => Some(sys_clk),
_ => unreachable!(), _ => unreachable!(),
}; };
let adc345_ck = match config.adc345_clock_source { let adc345_ck = match config.adc345_clock_source {
AdcClockSource::NOCLK => None, AdcClockSource::DISABLE => None,
AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p, AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
AdcClockSource::SYSCLK => Some(sys_clk), AdcClockSource::SYS => Some(sys_clk),
_ => unreachable!(), _ => unreachable!(),
}; };
@ -348,14 +348,15 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, hclk1: ahb_freq,
ahb2: ahb_freq, hclk2: ahb_freq,
apb1: apb1_freq, pclk1: apb1_freq,
apb1_tim: apb1_tim_freq, pclk1_tim: apb1_tim_freq,
apb2: apb2_freq, pclk2: apb2_freq,
apb2_tim: apb2_tim_freq, pclk2_tim: apb2_tim_freq,
adc: adc12_ck, adc: adc12_ck,
adc34: adc345_ck, adc34: adc345_ck,
pll1_p: None,
rtc, rtc,
}); });
} }

View File

@ -163,10 +163,6 @@ impl From<TimerPrescaler> for Timpre {
pub struct Config { pub struct Config {
pub hsi: Option<Hsi>, pub hsi: Option<Hsi>,
pub hse: Option<Hse>, pub hse: Option<Hse>,
#[cfg(stm32h7)]
pub lse: Option<Lse>,
#[cfg(stm32h7)]
pub lsi: bool,
pub csi: bool, pub csi: bool,
pub hsi48: bool, pub hsi48: bool,
pub sys: Sysclk, pub sys: Sysclk,
@ -199,10 +195,6 @@ impl Default for Config {
Self { Self {
hsi: Some(Hsi::Mhz64), hsi: Some(Hsi::Mhz64),
hse: None, hse: None,
#[cfg(stm32h7)]
lse: None,
#[cfg(stm32h7)]
lsi: false,
csi: false, csi: false,
hsi48: false, hsi48: false,
sys: Sysclk::HSI, sys: Sysclk::HSI,
@ -395,7 +387,7 @@ pub(crate) unsafe fn init(config: Config) {
Sysclk::HSI => (unwrap!(hsi), Sw::HSI), Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
Sysclk::HSE => (unwrap!(hse), Sw::HSE), Sysclk::HSE => (unwrap!(hse), Sw::HSE),
Sysclk::CSI => (unwrap!(csi), Sw::CSI), Sysclk::CSI => (unwrap!(csi), Sw::CSI),
Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1), Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1_P),
}; };
// Check limits. // Check limits.
@ -453,12 +445,12 @@ pub(crate) unsafe fn init(config: Config) {
}; };
#[cfg(stm32h5)] #[cfg(stm32h5)]
let adc = match config.adc_clock_source { let adc = match config.adc_clock_source {
AdcClockSource::HCLK => Some(hclk), AdcClockSource::HCLK1 => Some(hclk),
AdcClockSource::SYSCLK => Some(sys), AdcClockSource::SYS => Some(sys),
AdcClockSource::PLL2_R => pll2.r, AdcClockSource::PLL2_R => pll2.r,
AdcClockSource::HSE => hse, AdcClockSource::HSE => hse,
AdcClockSource::HSI_KER => hsi, AdcClockSource::HSI => hsi,
AdcClockSource::CSI_KER => csi, AdcClockSource::CSI => csi,
_ => unreachable!(), _ => unreachable!(),
}; };
@ -532,66 +524,65 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys, sys,
ahb1: hclk, hclk1: hclk,
ahb2: hclk, hclk2: hclk,
ahb3: hclk, hclk3: hclk,
ahb4: hclk, hclk4: hclk,
apb1, pclk1: apb1,
apb2, pclk2: apb2,
apb3, pclk3: apb3,
#[cfg(stm32h7)] #[cfg(stm32h7)]
apb4, pclk4: apb4,
apb1_tim, #[cfg(stm32h5)]
apb2_tim, pclk4: Hertz(1),
pclk1_tim: apb1_tim,
pclk2_tim: apb2_tim,
adc, adc,
rtc, rtc,
#[cfg(any(stm32h5, stm32h7))]
hsi: None,
#[cfg(stm32h5)] #[cfg(stm32h5)]
mux_rcc_pclk1: Some(apb1), hsi48: None,
#[cfg(stm32h5)] #[cfg(stm32h5)]
mux_pll2_q: None, lsi: None,
#[cfg(stm32h5)] #[cfg(any(stm32h5, stm32h7))]
mux_pll3_q: None, csi: 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,
#[cfg(rcc_h5)] #[cfg(any(stm32h5, stm32h7))]
mux_pll3_r: pll3.r, lse: None,
#[cfg(all(not(rcc_h5), stm32h5))] #[cfg(any(stm32h5, stm32h7))]
mux_pll3_r: None, hse: None,
#[cfg(stm32h5)]
mux_rcc_pclk3: Some(apb3), #[cfg(any(stm32h5, stm32h7))]
#[cfg(stm32h5)] pll1_q: pll1.q,
mux_pll3_1: None, #[cfg(any(stm32h5, stm32h7))]
#[cfg(stm32h5)] pll2_p: pll2.p,
mux_hsi48_ker: None, #[cfg(any(stm32h5, stm32h7))]
#[cfg(stm32h5)] pll2_q: pll2.q,
mux_lsi_ker: None, #[cfg(any(stm32h5, stm32h7))]
#[cfg(stm32h5)] pll2_r: pll2.r,
mux_pll2_r: pll2.r, #[cfg(any(rcc_h5, stm32h7))]
#[cfg(stm32h5)] pll3_p: pll3.p,
mux_rcc_pclk2: Some(apb2), #[cfg(any(rcc_h5, stm32h7))]
#[cfg(stm32h5)] pll3_q: pll3.q,
mux_rcc_pclk4: None, #[cfg(any(rcc_h5, stm32h7))]
#[cfg(stm32h5)] pll3_r: pll3.r,
mux_hse: hse,
#[cfg(rcc_h50)]
pll3_p: None,
#[cfg(rcc_h50)]
pll3_q: None,
#[cfg(rcc_h50)]
pll3_r: None,
#[cfg(stm32h5)] #[cfg(stm32h5)]
mux_hsi48: None, audioclk: None,
#[cfg(any(stm32h5, stm32h7))]
per: None,
#[cfg(stm32h7)]
rcc_pclk_d3: None,
}); });
} }

View File

@ -31,7 +31,7 @@ pub enum PLLSource {
impl From<PLLSource> for Pllsrc { impl From<PLLSource> for Pllsrc {
fn from(val: PLLSource) -> Pllsrc { fn from(val: PLLSource) -> Pllsrc {
match val { match val {
PLLSource::HSI16 => Pllsrc::HSI16, PLLSource::HSI16 => Pllsrc::HSI,
PLLSource::HSE(_) => Pllsrc::HSE, PLLSource::HSE(_) => Pllsrc::HSE,
} }
} }
@ -88,7 +88,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsi16on(true)); RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdy() {} while !RCC.cr().read().hsi16rdy() {}
(HSI_FREQ, Sw::HSI16) (HSI_FREQ, Sw::HSI)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
@ -209,11 +209,11 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, hclk1: ahb_freq,
apb1: apb1_freq, pclk1: apb1_freq,
apb2: apb2_freq, pclk2: apb2_freq,
apb1_tim: apb1_tim_freq, pclk1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq, pclk2_tim: apb2_tim_freq,
rtc, rtc,
}); });
} }

View File

@ -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!(),
}
}

View 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 }
}

View File

@ -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!(),
}
}

View File

@ -20,8 +20,7 @@ pub use mco::*;
#[cfg_attr(rcc_g4, path = "g4.rs")] #[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_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(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")]
#[cfg_attr(rcc_l4, path = "l4.rs")] #[cfg_attr(any(rcc_l4, rcc_l4plus, rcc_l5), path = "l4l5.rs")]
#[cfg_attr(rcc_l5, path = "l5.rs")]
#[cfg_attr(rcc_u5, path = "u5.rs")] #[cfg_attr(rcc_u5, path = "u5.rs")]
#[cfg_attr(rcc_wb, path = "wb.rs")] #[cfg_attr(rcc_wb, path = "wb.rs")]
#[cfg_attr(rcc_wba, path = "wba.rs")] #[cfg_attr(rcc_wba, path = "wba.rs")]
@ -48,23 +47,24 @@ pub struct Clocks {
pub sys: Hertz, pub sys: Hertz,
// APB // APB
pub apb1: Hertz, pub pclk1: Hertz,
pub apb1_tim: Hertz, pub pclk1_tim: Hertz,
#[cfg(not(any(rcc_c0, rcc_g0)))] #[cfg(not(any(rcc_c0, rcc_g0)))]
pub apb2: Hertz, pub pclk2: Hertz,
#[cfg(not(any(rcc_c0, rcc_g0)))] #[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))] #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_u5))]
pub apb3: Hertz, pub pclk3: Hertz,
#[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab))] #[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab, stm32h5))]
pub apb4: Hertz, pub pclk4: Hertz,
#[cfg(any(rcc_wba))] #[cfg(any(rcc_wba))]
pub apb7: Hertz, pub pclk7: Hertz,
// AHB // AHB
pub ahb1: Hertz, pub hclk1: Hertz,
#[cfg(any( #[cfg(any(
rcc_l4, rcc_l4,
rcc_l4plus,
rcc_l5, rcc_l5,
rcc_f2, rcc_f2,
rcc_f4, rcc_f4,
@ -82,9 +82,10 @@ pub struct Clocks {
rcc_wl5, rcc_wl5,
rcc_wle rcc_wle
))] ))]
pub ahb2: Hertz, pub hclk2: Hertz,
#[cfg(any( #[cfg(any(
rcc_l4, rcc_l4,
rcc_l4plus,
rcc_l5, rcc_l5,
rcc_f2, rcc_f2,
rcc_f4, rcc_f4,
@ -100,18 +101,40 @@ pub struct Clocks {
rcc_wl5, rcc_wl5,
rcc_wle rcc_wle
))] ))]
pub ahb3: Hertz, pub hclk3: Hertz,
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))] #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))]
pub ahb4: Hertz, pub hclk4: Hertz,
#[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))]
pub pll48: Option<Hertz>,
#[cfg(all(rcc_f4, not(stm32f410)))] #[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))] #[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( #[cfg(any(
rcc_f1, rcc_f1,
@ -135,51 +158,31 @@ pub struct Clocks {
pub rtc: Option<Hertz>, pub rtc: Option<Hertz>,
#[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))]
pub hsi: Option<Hertz>,
#[cfg(stm32h5)] #[cfg(stm32h5)]
pub mux_rcc_pclk1: Option<Hertz>, pub hsi48: Option<Hertz>,
#[cfg(stm32h5)] #[cfg(stm32h5)]
pub mux_pll2_q: Option<Hertz>, pub lsi: Option<Hertz>,
#[cfg(stm32h5)] #[cfg(any(stm32h5, stm32h7))]
pub mux_pll3_q: Option<Hertz>, pub csi: Option<Hertz>,
#[cfg(stm32h5)]
pub mux_hsi_ker: Option<Hertz>, #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))]
#[cfg(stm32h5)] pub lse: Option<Hertz>,
pub mux_csi_ker: Option<Hertz>, #[cfg(any(stm32h5, stm32h7))]
#[cfg(stm32h5)] pub hse: Option<Hertz>,
pub mux_lse: Option<Hertz>,
#[cfg(stm32h5)] #[cfg(stm32h5)]
pub mux_pll1_q: Option<Hertz>, pub audioclk: Option<Hertz>,
#[cfg(stm32h5)] #[cfg(any(stm32h5, stm32h7))]
pub mux_pll2_p: Option<Hertz>, pub per: 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>,
#[cfg(stm32h5)] #[cfg(stm32h7)]
pub mux_pll3_r: Option<Hertz>, pub rcc_pclk_d3: Option<Hertz>,
#[cfg(stm32h5)] #[cfg(rcc_l4)]
pub mux_rcc_pclk3: Option<Hertz>, pub sai1_extclk: Option<Hertz>,
#[cfg(stm32h5)] #[cfg(rcc_l4)]
pub mux_pll3_1: Option<Hertz>, pub sai2_extclk: 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(feature = "low-power")] #[cfg(feature = "low-power")]

View File

@ -188,7 +188,7 @@ impl Default for Config {
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
apb3_pre: APBPrescaler::DIV1, apb3_pre: APBPrescaler::DIV1,
hsi48: false, hsi48: true,
voltage_range: VoltageScale::RANGE3, voltage_range: VoltageScale::RANGE3,
ls: Default::default(), ls: Default::default(),
} }
@ -436,14 +436,14 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, hclk1: ahb_freq,
ahb2: ahb_freq, hclk2: ahb_freq,
ahb3: ahb_freq, hclk3: ahb_freq,
apb1: apb1_freq, pclk1: apb1_freq,
apb2: apb2_freq, pclk2: apb2_freq,
apb3: apb3_freq, pclk3: apb3_freq,
apb1_tim: apb1_tim_freq, pclk1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq, pclk2_tim: apb2_tim_freq,
rtc, rtc,
}); });
} }

View File

@ -40,6 +40,7 @@ pub struct Config {
pub hse: Option<Hse>, pub hse: Option<Hse>,
pub sys: Sysclk, pub sys: Sysclk,
pub mux: Option<PllMux>, pub mux: Option<PllMux>,
pub hsi48: bool,
pub pll: Option<Pll>, pub pll: Option<Pll>,
pub pllsai: Option<Pll>, pub pllsai: Option<Pll>,
@ -63,6 +64,7 @@ pub const WPAN_DEFAULT: Config = Config {
source: PllSource::HSE, source: PllSource::HSE,
prediv: Pllm::DIV2, prediv: Pllm::DIV2,
}), }),
hsi48: true,
ls: super::LsConfig::default_lse(), ls: super::LsConfig::default_lse(),
@ -90,6 +92,7 @@ impl Default for Config {
mux: None, mux: None,
pll: None, pll: None,
pllsai: None, pllsai: None,
hsi48: true,
ls: Default::default(), 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| { rcc.cfgr().modify(|w| {
w.set_sw(config.sys.into()); w.set_sw(config.sys.into());
w.set_hpre(config.ahb1_pre); w.set_hpre(config.ahb1_pre);
@ -236,13 +246,13 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb1_clk, hclk1: ahb1_clk,
ahb2: ahb2_clk, hclk2: ahb2_clk,
ahb3: ahb3_clk, hclk3: ahb3_clk,
apb1: apb1_clk, pclk1: apb1_clk,
apb2: apb2_clk, pclk2: apb2_clk,
apb1_tim: apb1_tim_clk, pclk1_tim: apb1_tim_clk,
apb2_tim: apb2_tim_clk, pclk2_tim: apb2_tim_clk,
rtc, rtc,
}) })
} }

View File

@ -142,14 +142,14 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, hclk1: ahb_freq,
ahb2: ahb_freq, hclk2: ahb_freq,
ahb4: ahb_freq, hclk4: ahb_freq,
apb1: apb1_freq, pclk1: apb1_freq,
apb2: apb2_freq, pclk2: apb2_freq,
apb7: apb7_freq, pclk7: apb7_freq,
apb1_tim: apb1_tim_freq, pclk1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq, pclk2_tim: apb2_tim_freq,
rtc, rtc,
}); });
} }

View File

@ -145,14 +145,14 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, hclk1: ahb_freq,
ahb2: ahb_freq, hclk2: ahb_freq,
ahb3: shd_ahb_freq, hclk3: shd_ahb_freq,
apb1: apb1_freq, pclk1: apb1_freq,
apb2: apb2_freq, pclk2: apb2_freq,
apb3: shd_ahb_freq, pclk3: shd_ahb_freq,
apb1_tim: apb1_tim_freq, pclk1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq, pclk2_tim: apb2_tim_freq,
rtc, rtc,
}); });
} }

View File

@ -85,7 +85,7 @@ impl<'d, T: Instance> Rng<'d, T> {
reg.set_ie(false); reg.set_ie(false);
reg.set_rngen(true); reg.set_rngen(true);
}); });
T::regs().cr().write(|reg| { T::regs().cr().modify(|reg| {
reg.set_ced(false); reg.set_ced(false);
}); });
// wait for CONDRST to be set // wait for CONDRST to be set

View File

@ -1457,7 +1457,7 @@ cfg_if::cfg_if! {
macro_rules! kernel_clk { macro_rules! kernel_clk {
($inst:ident) => { ($inst:ident) => {
critical_section::with(|_| unsafe { critical_section::with(|_| unsafe {
crate::rcc::get_freqs().pll48 crate::rcc::get_freqs().pll1_q
}).expect("PLL48 is required for SDIO") }).expect("PLL48 is required for SDIO")
} }
} }
@ -1469,7 +1469,7 @@ cfg_if::cfg_if! {
if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYSCLK { if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYSCLK {
crate::rcc::get_freqs().sys crate::rcc::get_freqs().sys
} else { } 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 { if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYSCLK {
crate::rcc::get_freqs().sys crate::rcc::get_freqs().sys
} else { } else {
crate::rcc::get_freqs().pll48.expect("PLL48 is required for SDMMC") crate::rcc::get_freqs().pll1_q.expect("PLL48 is required for SDMMC")
} }
}) })
}; };

View File

@ -322,7 +322,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
} }
/// Reconfigures it with the supplied config. /// 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 cpha = config.raw_phase();
let cpol = config.raw_polarity(); let cpol = config.raw_polarity();
@ -351,6 +351,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
w.set_mbr(br); w.set_mbr(br);
}); });
} }
Ok(())
} }
pub fn get_current_config(&self) -> Config { 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 Config = Config;
type ConfigError = (); type ConfigError = ();
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
self.set_config(*config); self.set_config(config)
Ok(())
} }
} }

View File

@ -71,7 +71,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
this.inner.set_frequency(freq); this.inner.set_frequency(freq);
this.inner.start(); this.inner.start();
this.inner.enable_outputs(true); this.inner.enable_outputs();
this.inner this.inner
.set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);

View File

@ -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) { fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
let r = Self::regs_gp16(); let r = Self::regs_gp16();
@ -401,7 +401,9 @@ macro_rules! impl_32bit_timer {
#[allow(unused)] #[allow(unused)]
macro_rules! impl_compare_capable_16bit { macro_rules! impl_compare_capable_16bit {
($inst:ident) => { ($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 CaptureCompare16bitInstance for crate::peripherals::$inst {}
impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
impl AdvancedControlInstance 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::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
fn regs_gp16() -> crate::pac::timer::TimGp16 { fn regs_gp16() -> crate::pac::timer::TimGp16 {

View File

@ -70,7 +70,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
this.inner.set_frequency(freq); this.inner.set_frequency(freq);
this.inner.start(); this.inner.start();
this.inner.enable_outputs(true); this.inner.enable_outputs();
this.inner this.inner
.set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);

View File

@ -253,7 +253,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
(self.tx, self.rx) (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) 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) 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) reconfigure::<T>(config)
} }
} }

View File

@ -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) 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) reconfigure::<T>(config)
} }

View File

@ -64,7 +64,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
Err(err) Err(err)
} }
fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.teardown_uart(); self.teardown_uart();
reconfigure::<T>(config) reconfigure::<T>(config)
} }

View File

@ -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/), 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). 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 - Added more tick rates

View File

@ -1,6 +1,6 @@
[package] [package]
name = "embassy-time" name = "embassy-time"
version = "0.1.4" version = "0.1.5"
edition = "2021" edition = "2021"
description = "Instant and Duration for embedded no-std systems, with async timer support" description = "Instant and Duration for embedded no-std systems, with async timer support"
repository = "https://github.com/embassy-rs/embassy" repository = "https://github.com/embassy-rs/embassy"
@ -13,6 +13,12 @@ categories = [
"asynchronous", "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] [package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-v$VERSION/embassy-time/src/" 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/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time/src/"

3
embassy-time/build.rs Normal file
View File

@ -0,0 +1,3 @@
// empty, needed to be able to use `links` in Cargo.toml.
fn main() {}

View File

@ -36,11 +36,11 @@ mod eha {
impl embedded_hal_async::delay::DelayUs for Delay { impl embedded_hal_async::delay::DelayUs for Delay {
async fn delay_us(&mut self, micros: u32) { 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) { async fn delay_ms(&mut self, millis: u32) {
Timer::after(Duration::from_millis(millis as _)).await Timer::after_millis(millis as _).await
} }
} }
} }

View File

@ -64,6 +64,42 @@ impl Timer {
yielded_once: false, 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 {} impl Unpin for Timer {}

View File

@ -42,7 +42,7 @@ max-handler-count-8 = []
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } 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 } defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true } log = { version = "0.4.14", optional = true }

View File

@ -70,9 +70,11 @@ fn main() {
// envvars take priority. // envvars take priority.
if !cfg.seen_env { if !cfg.seen_env {
if cfg.seen_feature { assert!(
panic!("multiple values set for feature {}: {} and {}", name, cfg.value, value); !cfg.seen_feature,
} "multiple values set for feature {}: {} and {}",
name, cfg.value, value
);
cfg.value = value; cfg.value = value;
cfg.seen_feature = true; cfg.seen_feature = true;

View File

@ -1,17 +1,17 @@
use heapless::Vec; use heapless::Vec;
use crate::config::*; use crate::config::MAX_HANDLER_COUNT;
use crate::descriptor::{BosWriter, DescriptorWriter}; use crate::descriptor::{BosWriter, DescriptorWriter};
use crate::driver::{Driver, Endpoint, EndpointType}; use crate::driver::{Driver, Endpoint, EndpointType};
#[cfg(feature = "msos-descriptor")] #[cfg(feature = "msos-descriptor")]
use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; 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}; use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
/// Configuration used when creating [UsbDevice]. /// Configuration used when creating [`UsbDevice`].
pub struct Config<'a> { pub struct Config<'a> {
pub(crate) vendor_id: u16, pub(crate) vendor_id: u16,
pub(crate) product_id: u16, pub(crate) product_id: u16,
@ -99,7 +99,7 @@ pub struct Config<'a> {
impl<'a> Config<'a> { impl<'a> Config<'a> {
/// Create default configuration with the provided vid and pid values. /// 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 { Self {
device_class: 0x00, device_class: 0x00,
device_sub_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"); 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 { assert!(
panic!("The maximum allowed value for `max_power` is 500mA"); config.max_power <= 500,
} "The maximum allowed value for `max_power` is 500mA"
);
match config.max_packet_size_0 { match config.max_packet_size_0 {
8 | 16 | 32 | 64 => {} 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 /// The Handler is called on some USB bus events, and to handle all control requests not already
/// handled by the USB stack. /// handled by the USB stack.
pub fn handler(&mut self, handler: &'d mut dyn Handler) { pub fn handler(&mut self, handler: &'d mut dyn Handler) {
if self.handlers.push(handler).is_err() { assert!(
panic!( self.handlers.push(handler).is_ok(),
"embassy-usb: handler list full. Increase the `max_handler_count` compile-time setting. Current value: {}", "embassy-usb: handler list full. Increase the `max_handler_count` compile-time setting. Current value: {}",
MAX_HANDLER_COUNT MAX_HANDLER_COUNT
) );
}
} }
/// Allocates a new string index. /// Allocates a new string index.
@ -332,12 +332,10 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
num_alt_settings: 0, num_alt_settings: 0,
}; };
if self.builder.interfaces.push(iface).is_err() { assert!(self.builder.interfaces.push(iface).is_ok(),
panic!( "embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}",
"embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}", MAX_INTERFACE_COUNT
MAX_INTERFACE_COUNT );
)
}
InterfaceBuilder { InterfaceBuilder {
builder: self.builder, 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> { impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
/// Get the interface number. /// Get the interface number.
pub fn interface_number(&self) -> InterfaceNumber { pub const fn interface_number(&self) -> InterfaceNumber {
self.interface_number 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> { impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
/// Get the interface number. /// Get the interface number.
pub fn interface_number(&self) -> InterfaceNumber { pub const fn interface_number(&self) -> InterfaceNumber {
self.interface_number self.interface_number
} }
/// Get the alternate setting 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 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 /// Descriptors are written in the order builder functions are called. Note that some
/// classes care about the order. /// classes care about the order.
pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) { 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 { fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {

View File

@ -11,7 +11,7 @@ use embassy_sync::waitqueue::WakerRegistration;
use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
use crate::types::*; use crate::types::InterfaceNumber;
use crate::{Builder, Handler}; use crate::{Builder, Handler};
/// This should be used as `device_class` when building the `UsbDevice`. /// This should be used as `device_class` when building the `UsbDevice`.
@ -39,12 +39,18 @@ pub struct State<'a> {
shared: ControlShared, shared: ControlShared,
} }
impl<'a> Default for State<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> State<'a> { impl<'a> State<'a> {
/// Create a new `State`. /// Create a new `State`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
control: MaybeUninit::uninit(), 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 /// 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: /// 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. /// - `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. /// - `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 /// - 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) /// 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 /// 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. /// 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 { impl ControlShared {
async fn changed(&self) { async fn changed(&self) {
poll_fn(|cx| match self.changed.load(Ordering::Relaxed) { poll_fn(|cx| {
true => { if self.changed.load(Ordering::Relaxed) {
self.changed.store(false, Ordering::Relaxed); self.changed.store(false, Ordering::Relaxed);
Poll::Ready(()) Poll::Ready(())
} } else {
false => {
self.waker.borrow_mut().register(cx.waker()); self.waker.borrow_mut().register(cx.waker());
Poll::Pending 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_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
REQ_GET_LINE_CODING if req.length == 7 => { REQ_GET_LINE_CODING if req.length == 7 => {
debug!("Sending line coding"); 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); assert!(buf.len() >= 7);
buf[0..4].copy_from_slice(&coding.data_rate.to_le_bytes()); buf[0..4].copy_from_slice(&coding.data_rate.to_le_bytes());
buf[4] = coding.stop_bits as u8; 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> { impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
/// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For /// 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. /// 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 { pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, max_packet_size: u16) -> Self {
assert!(builder.control_buf_len() >= 7); assert!(builder.control_buf_len() >= 7);
@ -242,7 +247,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
&[ &[
CDC_TYPE_UNION, // bDescriptorSubtype CDC_TYPE_UNION, // bDescriptorSubtype
comm_if.into(), // bControlInterface 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 /// 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. /// for USB to UART serial port emulators, and can be ignored if not relevant.
pub fn line_coding(&self) -> LineCoding { 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 /// 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 /// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) { 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. /// Split the class into a sender and receiver.
@ -356,7 +361,7 @@ pub struct ControlChanged<'d> {
impl<'d> ControlChanged<'d> { impl<'d> ControlChanged<'d> {
/// Return a future for when the control settings change /// Return a future for when the control settings change
pub async fn control_changed(&self) { 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 /// 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. /// for USB to UART serial port emulators, and can be ignored if not relevant.
pub fn line_coding(&self) -> LineCoding { 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 /// 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 /// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) { 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 /// 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. /// for USB to UART serial port emulators, and can be ignored if not relevant.
pub fn line_coding(&self) -> LineCoding { 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 /// 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 /// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) { 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. /// 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 self.data_bits
} }
/// Gets the parity type for UART communication. /// Gets the parity type for UART communication.
pub fn parity_type(&self) -> ParityType { pub const fn parity_type(&self) -> ParityType {
self.parity_type self.parity_type
} }
/// Gets the data rate in bits per second for UART communication. /// 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 self.data_rate
} }
} }

View File

@ -16,10 +16,11 @@
use core::intrinsics::copy_nonoverlapping; use core::intrinsics::copy_nonoverlapping;
use core::mem::{size_of, MaybeUninit}; use core::mem::{size_of, MaybeUninit};
use core::ptr::addr_of;
use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
use crate::types::*; use crate::types::{InterfaceNumber, StringIndex};
use crate::{Builder, Handler}; use crate::{Builder, Handler};
pub mod embassy_net; pub mod embassy_net;
@ -62,9 +63,9 @@ const REQ_SET_NTB_INPUT_SIZE: u8 = 0x86;
//const NOTIF_POLL_INTERVAL: u8 = 20; //const NOTIF_POLL_INTERVAL: u8 = 20;
const NTB_MAX_SIZE: usize = 2048; const NTB_MAX_SIZE: usize = 2048;
const SIG_NTH: u32 = 0x484d434e; const SIG_NTH: u32 = 0x484d_434e;
const SIG_NDP_NO_FCS: u32 = 0x304d434e; const SIG_NDP_NO_FCS: u32 = 0x304d_434e;
const SIG_NDP_WITH_FCS: u32 = 0x314d434e; const SIG_NDP_WITH_FCS: u32 = 0x314d_434e;
const ALTERNATE_SETTING_DISABLED: u8 = 0x00; const ALTERNATE_SETTING_DISABLED: u8 = 0x00;
const ALTERNATE_SETTING_ENABLED: u8 = 0x01; const ALTERNATE_SETTING_ENABLED: u8 = 0x01;
@ -111,7 +112,7 @@ struct NtbParametersDir {
fn byteify<T>(buf: &mut [u8], data: T) -> &[u8] { fn byteify<T>(buf: &mut [u8], data: T) -> &[u8] {
let len = size_of::<T>(); 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] &buf[..len]
} }
@ -121,27 +122,28 @@ pub struct State<'a> {
shared: ControlShared, shared: ControlShared,
} }
impl<'a> Default for State<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> State<'a> { impl<'a> State<'a> {
/// Create a new `State`. /// Create a new `State`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
control: MaybeUninit::uninit(), 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 { struct ControlShared {
mac_addr: [u8; 6], mac_addr: [u8; 6],
} }
impl Default for ControlShared {
fn default() -> Self {
ControlShared { mac_addr: [0; 6] }
}
}
struct Control<'a> { struct Control<'a> {
mac_addr_string: StringIndex, mac_addr_string: StringIndex,
shared: &'a ControlShared, 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. /// 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> { 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 OUT_HEADER_LEN: usize = 28;
const ABS_MAX_PACKET_SIZE: usize = 512; const ABS_MAX_PACKET_SIZE: usize = 512;
let seq = self.seq;
self.seq = self.seq.wrapping_add(1);
let header = NtbOutHeader { let header = NtbOutHeader {
nth_sig: SIG_NTH, nth_sig: SIG_NTH,
nth_len: 0x0c, 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?; self.write_ep.write(&buf[..self.max_packet_size]).await?;
for chunk in d2.chunks(self.max_packet_size) { 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. // Send ZLP if needed.
@ -459,12 +461,9 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
let ntb = &ntb[..pos]; let ntb = &ntb[..pos];
// Process NTB header (NTH) // Process NTB header (NTH)
let nth = match ntb.get(..12) { let Some(nth) = ntb.get(..12) else {
Some(x) => x, warn!("Received too short NTB");
None => { continue;
warn!("Received too short NTB");
continue;
}
}; };
let sig = u32::from_le_bytes(nth[0..4].try_into().unwrap()); let sig = u32::from_le_bytes(nth[0..4].try_into().unwrap());
if sig != SIG_NTH { 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; let ndp_idx = u16::from_le_bytes(nth[10..12].try_into().unwrap()) as usize;
// Process NTB Datagram Pointer (NDP) // Process NTB Datagram Pointer (NDP)
let ndp = match ntb.get(ndp_idx..ndp_idx + 12) { let Some(ndp) = ntb.get(ndp_idx..ndp_idx + 12) else {
Some(x) => x, warn!("NTH has an NDP pointer out of range.");
None => { continue;
warn!("NTH has an NDP pointer out of range.");
continue;
}
}; };
let sig = u32::from_le_bytes(ndp[0..4].try_into().unwrap()); let sig = u32::from_le_bytes(ndp[0..4].try_into().unwrap());
if sig != SIG_NDP_NO_FCS && sig != SIG_NDP_WITH_FCS { 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. // Process actual datagram, finally.
let datagram = match ntb.get(datagram_index..datagram_index + datagram_len) { let Some(datagram) = ntb.get(datagram_index..datagram_index + datagram_len) else {
Some(x) => x, warn!("NDP has a datagram pointer out of range.");
None => { continue;
warn!("NDP has a datagram pointer out of range.");
continue;
}
}; };
buf[..datagram_len].copy_from_slice(datagram); buf[..datagram_len].copy_from_slice(datagram);

View File

@ -63,7 +63,7 @@ pub enum ReportId {
} }
impl ReportId { impl ReportId {
fn try_from(value: u16) -> Result<Self, ()> { const fn try_from(value: u16) -> Result<Self, ()> {
match value >> 8 { match value >> 8 {
1 => Ok(ReportId::In(value as u8)), 1 => Ok(ReportId::In(value as u8)),
2 => Ok(ReportId::Out(value as u8)), 2 => Ok(ReportId::Out(value as u8)),
@ -79,9 +79,15 @@ pub struct State<'d> {
out_report_offset: AtomicUsize, out_report_offset: AtomicUsize,
} }
impl<'d> Default for State<'d> {
fn default() -> Self {
Self::new()
}
}
impl<'d> State<'d> { impl<'d> State<'d> {
/// Create a new `State`. /// Create a new `State`.
pub fn new() -> Self { pub const fn new() -> Self {
State { State {
control: MaybeUninit::uninit(), control: MaybeUninit::uninit(),
out_report_offset: AtomicUsize::new(0), 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> { 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) /// 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. /// 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. /// 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.reader.ready().await;
self.writer.ready().await; self.writer.ready().await;
} }
@ -224,7 +230,7 @@ pub enum ReadError {
impl From<EndpointError> for ReadError { impl From<EndpointError> for ReadError {
fn from(val: EndpointError) -> Self { fn from(val: EndpointError) -> Self {
use EndpointError::*; use EndpointError::{BufferOverflow, Disabled};
match val { match val {
BufferOverflow => ReadError::BufferOverflow, BufferOverflow => ReadError::BufferOverflow,
Disabled => ReadError::Disabled, 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. /// Waits for the interrupt in endpoint to be enabled.
pub async fn ready(&mut self) -> () { pub async fn ready(&mut self) {
self.ep_in.wait_enabled().await self.ep_in.wait_enabled().await;
} }
/// Writes an input report by serializing the given report structure. /// Writes an input report by serializing the given report structure.
#[cfg(feature = "usbd-hid")] #[cfg(feature = "usbd-hid")]
pub async fn write_serialize<IR: AsInputReport>(&mut self, r: &IR) -> Result<(), EndpointError> { pub async fn write_serialize<IR: AsInputReport>(&mut self, r: &IR) -> Result<(), EndpointError> {
let mut buf: [u8; N] = [0; N]; let mut buf: [u8; N] = [0; N];
let size = match serialize(&mut buf, r) { let Ok(size) = serialize(&mut buf, r) else {
Ok(size) => size, return Err(EndpointError::BufferOverflow);
Err(_) => return Err(EndpointError::BufferOverflow),
}; };
self.write(&buf[0..size]).await 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> { impl<'d, D: Driver<'d>, const N: usize> HidReader<'d, D, N> {
/// Waits for the interrupt out endpoint to be enabled. /// Waits for the interrupt out endpoint to be enabled.
pub async fn ready(&mut self) -> () { pub async fn ready(&mut self) {
self.ep_out.wait_enabled().await self.ep_out.wait_enabled().await;
} }
/// Delivers output reports from the Interrupt Out pipe to `handler`. /// 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 { if size < max_packet_size || total == N {
self.offset.store(0, Ordering::Release); self.offset.store(0, Ordering::Release);
break; break;
} else {
self.offset.store(total, Ordering::Release);
} }
self.offset.store(total, Ordering::Release);
} }
Err(err) => { Err(err) => {
self.offset.store(0, Ordering::Release); self.offset.store(0, Ordering::Release);
@ -466,7 +470,7 @@ impl<'d> Handler for Control<'d> {
HID_REQ_SET_IDLE => { HID_REQ_SET_IDLE => {
if let Some(handler) = self.request_handler { if let Some(handler) = self.request_handler {
let id = req.value as u8; 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 = u32::from(req.value >> 8);
let dur = if dur == 0 { u32::MAX } else { 4 * dur }; let dur = if dur == 0 { u32::MAX } else { 4 * dur };
handler.set_idle_ms(id, dur); handler.set_idle_ms(id, dur);
@ -522,7 +526,7 @@ impl<'d> Handler for Control<'d> {
HID_REQ_GET_IDLE => { HID_REQ_GET_IDLE => {
if let Some(handler) = self.request_handler { if let Some(handler) = self.request_handler {
let id = req.value as u8; 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) { if let Some(dur) = handler.get_idle_ms(id) {
let dur = u8::try_from(dur / 4).unwrap_or(0); let dur = u8::try_from(dur / 4).unwrap_or(0);
buf[0] = dur; buf[0] = dur;

View 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;
}
}

View File

@ -2,3 +2,4 @@
pub mod cdc_acm; pub mod cdc_acm;
pub mod cdc_ncm; pub mod cdc_ncm;
pub mod hid; pub mod hid;
pub mod midi;

View File

@ -120,7 +120,7 @@ impl Request {
} }
/// Gets the descriptor type and index from the value field of a GET_DESCRIPTOR 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) ((self.value >> 8) as u8, self.value as u8)
} }
} }

View File

@ -2,7 +2,7 @@
use crate::builder::Config; use crate::builder::Config;
use crate::driver::EndpointInfo; use crate::driver::EndpointInfo;
use crate::types::*; use crate::types::{InterfaceNumber, StringIndex};
use crate::CONFIGURATION_VALUE; use crate::CONFIGURATION_VALUE;
/// Standard descriptor types /// 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. /// 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 self.position
} }
@ -67,9 +67,10 @@ impl<'a> DescriptorWriter<'a> {
pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) { pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) {
let length = descriptor.len(); let length = descriptor.len();
if (self.position + 2 + length) > self.buf.len() || (length + 2) > 255 { assert!(
panic!("Descriptor buffer full"); (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] = (length + 2) as u8;
self.buf[self.position + 1] = descriptor_type; self.buf[self.position + 1] = descriptor_type;
@ -102,7 +103,7 @@ impl<'a> DescriptorWriter<'a> {
config.serial_number.map_or(0, |_| 3), // iSerialNumber config.serial_number.map_or(0, |_| 3), // iSerialNumber
1, // bNumConfigurations 1, // bNumConfigurations
], ],
) );
} }
pub(crate) fn configuration(&mut self, config: &Config) { 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 | if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes
(config.max_power / 2) as u8, // bMaxPower (config.max_power / 2) as u8, // bMaxPower
], ],
) );
} }
#[allow(unused)] #[allow(unused)]
@ -248,9 +249,7 @@ impl<'a> DescriptorWriter<'a> {
pub(crate) fn string(&mut self, string: &str) { pub(crate) fn string(&mut self, string: &str) {
let mut pos = self.position; let mut pos = self.position;
if pos + 2 > self.buf.len() { assert!(pos + 2 <= self.buf.len(), "Descriptor buffer full");
panic!("Descriptor buffer full");
}
self.buf[pos] = 0; // length placeholder self.buf[pos] = 0; // length placeholder
self.buf[pos + 1] = descriptor_type::STRING; self.buf[pos + 1] = descriptor_type::STRING;
@ -258,9 +257,7 @@ impl<'a> DescriptorWriter<'a> {
pos += 2; pos += 2;
for c in string.encode_utf16() { for c in string.encode_utf16() {
if pos >= self.buf.len() { assert!(pos < self.buf.len(), "Descriptor buffer full");
panic!("Descriptor buffer full");
}
self.buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes()); self.buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes());
pos += 2; pos += 2;
@ -279,9 +276,9 @@ pub struct BosWriter<'a> {
} }
impl<'a> BosWriter<'a> { impl<'a> BosWriter<'a> {
pub(crate) fn new(writer: DescriptorWriter<'a>) -> Self { pub(crate) const fn new(writer: DescriptorWriter<'a>) -> Self {
Self { Self {
writer: writer, writer,
num_caps_mark: None, num_caps_mark: None,
} }
} }
@ -314,9 +311,10 @@ impl<'a> BosWriter<'a> {
let mut start = self.writer.position; let mut start = self.writer.position;
let blen = data.len(); let blen = data.len();
if (start + blen + 3) > self.writer.buf.len() || (blen + 3) > 255 { assert!(
panic!("Descriptor buffer full"); (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] = (blen + 3) as u8;
self.writer.buf[start + 1] = descriptor_type::CAPABILITY; self.writer.buf[start + 1] = descriptor_type::CAPABILITY;

View File

@ -11,11 +11,11 @@ pub struct Reader<'a> {
} }
impl<'a> Reader<'a> { impl<'a> Reader<'a> {
pub fn new(data: &'a [u8]) -> Self { pub const fn new(data: &'a [u8]) -> Self {
Self { data } Self { data }
} }
pub fn eof(&self) -> bool { pub const fn eof(&self) -> bool {
self.data.is_empty() self.data.is_empty()
} }
@ -102,7 +102,7 @@ pub fn foreach_endpoint(data: &[u8], mut f: impl FnMut(EndpointInfo)) -> Result<
} }
descriptor_type::ENDPOINT => { descriptor_type::ENDPOINT => {
ep.ep_address = EndpointAddress::from(r.read_u8()?); ep.ep_address = EndpointAddress::from(r.read_u8()?);
f(ep) f(ep);
} }
_ => {} _ => {}
} }

View File

@ -24,12 +24,12 @@ use embassy_futures::select::{select, Either};
use heapless::Vec; use heapless::Vec;
pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder}; pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder};
use crate::config::*; use crate::config::{MAX_HANDLER_COUNT, MAX_INTERFACE_COUNT};
use crate::control::*; use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType};
use crate::descriptor::*; use crate::descriptor::{descriptor_type, lang_id};
use crate::descriptor_reader::foreach_endpoint; use crate::descriptor_reader::foreach_endpoint;
use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event}; use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event};
use crate::types::*; use crate::types::{InterfaceNumber, StringIndex};
/// The global state of the USB device. /// 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 /// After dropping the future, [`UsbDevice::disable()`] should be called
/// before calling any other `UsbDevice` methods to fully reset the /// before calling any other `UsbDevice` methods to fully reset the
/// peripheral. /// peripheral.
pub async fn run_until_suspend(&mut self) -> () { pub async fn run_until_suspend(&mut self) {
while !self.inner.suspended { while !self.inner.suspended {
let control_fut = self.control.setup(); let control_fut = self.control.setup();
let bus_fut = self.inner.bus.poll(); 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) { async fn handle_control_in(&mut self, req: Request) {
const DEVICE_DESCRIPTOR_LEN: usize = 18;
let mut resp_length = req.length as usize; let mut resp_length = req.length as usize;
let max_packet_size = self.control.max_packet_size(); 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 // 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. // a full-length packet is a short packet, thinking we're done sending data.
// See https://github.com/hathach/tinyusb/issues/184 // 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 < resp_length {
if self.inner.address == 0
&& max_packet_size < DEVICE_DESCRIPTOR_LEN
&& (max_packet_size as usize) < resp_length
{
trace!("received control req while not addressed: capping response to 1 packet."); trace!("received control req while not addressed: capping response to 1 packet.");
resp_length = max_packet_size; 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) => { InResponse::Accepted(data) => {
let len = data.len().min(resp_length); 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] let chunks = data[0..len]
.chunks(max_packet_size) .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.control.accept_set_address(self.inner.address).await;
self.inner.set_address_pending = false; self.inner.set_address_pending = false;
} else { } else {
self.control.accept().await self.control.accept().await;
} }
} }
OutResponse::Rejected => self.control.reject().await, OutResponse::Rejected => self.control.reject().await,
@ -548,9 +546,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
OutResponse::Accepted OutResponse::Accepted
} }
(Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => match self.device_state { (Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => {
UsbDeviceState::Default => OutResponse::Accepted, if self.device_state != UsbDeviceState::Default {
_ => {
debug!("SET_CONFIGURATION: unconfigured"); debug!("SET_CONFIGURATION: unconfigured");
self.device_state = UsbDeviceState::Addressed; self.device_state = UsbDeviceState::Addressed;
@ -564,17 +561,15 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
for h in &mut self.handlers { for h in &mut self.handlers {
h.configured(false); h.configured(false);
} }
OutResponse::Accepted
} }
}, OutResponse::Accepted
}
_ => OutResponse::Rejected, _ => OutResponse::Rejected,
}, },
(RequestType::Standard, Recipient::Interface) => { (RequestType::Standard, Recipient::Interface) => {
let iface_num = InterfaceNumber::new(req.index as _); let iface_num = InterfaceNumber::new(req.index as _);
let iface = match self.interfaces.get_mut(iface_num.0 as usize) { let Some(iface) = self.interfaces.get_mut(iface_num.0 as usize) else {
Some(iface) => iface, return OutResponse::Rejected;
None => return OutResponse::Rejected,
}; };
match req.request { match req.request {
@ -650,9 +645,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
_ => InResponse::Rejected, _ => InResponse::Rejected,
}, },
(RequestType::Standard, Recipient::Interface) => { (RequestType::Standard, Recipient::Interface) => {
let iface = match self.interfaces.get_mut(req.index as usize) { let Some(iface) = self.interfaces.get_mut(req.index as usize) else {
Some(iface) => iface, return InResponse::Rejected;
None => return InResponse::Rejected,
}; };
match req.request { 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> { 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) core::mem::transmute(r)
} }
@ -756,16 +750,12 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
}; };
if let Some(s) = s { if let Some(s) = s {
if buf.len() < 2 { assert!(buf.len() >= 2, "control buffer too small");
panic!("control buffer too small");
}
buf[1] = descriptor_type::STRING; buf[1] = descriptor_type::STRING;
let mut pos = 2; let mut pos = 2;
for c in s.encode_utf16() { for c in s.encode_utf16() {
if pos + 2 >= buf.len() { assert!(pos + 2 < buf.len(), "control buffer too small");
panic!("control buffer too small");
}
buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes()); buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes());
pos += 2; pos += 2;

View File

@ -6,7 +6,7 @@
use core::mem::size_of; use core::mem::size_of;
use super::{capability_type, BosWriter}; use crate::descriptor::{capability_type, BosWriter};
use crate::types::InterfaceNumber; use crate::types::InterfaceNumber;
/// A serialized Microsoft OS 2.0 Descriptor set. /// A serialized Microsoft OS 2.0 Descriptor set.

View File

@ -7,7 +7,7 @@
pub struct InterfaceNumber(pub u8); pub struct InterfaceNumber(pub u8);
impl InterfaceNumber { impl InterfaceNumber {
pub(crate) fn new(index: u8) -> InterfaceNumber { pub(crate) const fn new(index: u8) -> InterfaceNumber {
InterfaceNumber(index) InterfaceNumber(index)
} }
} }
@ -25,7 +25,7 @@ impl From<InterfaceNumber> for u8 {
pub struct StringIndex(pub u8); pub struct StringIndex(pub u8);
impl StringIndex { impl StringIndex {
pub(crate) fn new(index: u8) -> StringIndex { pub(crate) const fn new(index: u8) -> StringIndex {
StringIndex(index) StringIndex(index)
} }
} }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } 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-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-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 = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] }
embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = ["nightly"] } embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = ["nightly"] }

View File

@ -5,7 +5,7 @@
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::gpio::{Level, Output, OutputDrive};
use embassy_time::{Duration, Timer}; use embassy_time::Timer;
use panic_reset as _; use panic_reset as _;
#[embassy_executor::main] #[embassy_executor::main]
@ -19,8 +19,8 @@ async fn main(_spawner: Spawner) {
loop { loop {
led.set_high(); led.set_high();
Timer::after(Duration::from_millis(300)).await; Timer::after_millis(300).await;
led.set_low(); led.set_low();
Timer::after(Duration::from_millis(300)).await; Timer::after_millis(300).await;
} }
} }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } 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-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-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-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }

View File

@ -41,7 +41,7 @@ async fn main(_s: Spawner) {
let mut aligned = AlignedBuffer([0; 1]); let mut aligned = AlignedBuffer([0; 1]);
let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0); let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0);
Timer::after(Duration::from_secs(5)).await; Timer::after_secs(5).await;
watchdog.feed(); watchdog.feed();
led.set_high(); led.set_high();
let mut offset = 0; let mut offset = 0;
@ -61,7 +61,7 @@ async fn main(_s: Spawner) {
watchdog.feed(); watchdog.feed();
defmt::info!("firmware written, marking update"); defmt::info!("firmware written, marking update");
updater.mark_updated().unwrap(); updater.mark_updated().unwrap();
Timer::after(Duration::from_secs(2)).await; Timer::after_secs(2).await;
led.set_low(); led.set_low();
defmt::info!("update marked, resetting"); defmt::info!("update marked, resetting");
cortex_m::peripheral::SCB::sys_reset(); cortex_m::peripheral::SCB::sys_reset();

View File

@ -4,7 +4,7 @@
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_rp::gpio; use embassy_rp::gpio;
use embassy_time::{Duration, Timer}; use embassy_time::Timer;
use gpio::{Level, Output}; use gpio::{Level, Output};
use {defmt_rtt as _, panic_reset as _}; use {defmt_rtt as _, panic_reset as _};
@ -15,9 +15,9 @@ async fn main(_s: Spawner) {
loop { loop {
led.set_high(); led.set_high();
Timer::after(Duration::from_millis(100)).await; Timer::after_millis(100).await;
led.set_low(); led.set_low();
Timer::after(Duration::from_millis(100)).await; Timer::after_millis(100).await;
} }
} }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } 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-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-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-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 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