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