aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorklownfish <[email protected]>2024-09-24 20:46:04 +0200
committerklownfish <[email protected]>2024-09-24 20:46:04 +0200
commit60347976b2e56eb8484e10d4aec5fa12534457f7 (patch)
treefe1af22314ae008f2a93f34e1bb2b4129d4d85da
parentfe868fc1948472666b6d8386a3191a074468a34e (diff)
parent0ede8479dc4c6a58cfab0a5d4df41c0592405971 (diff)
Merge remote-tracking branch 'origin/main' into u5_adc
-rw-r--r--.gitignore1
-rw-r--r--docs/pages/bootloader.adoc3
-rw-r--r--embassy-boot/src/boot_loader.rs6
-rw-r--r--embassy-boot/src/firmware_updater/asynch.rs10
-rw-r--r--embassy-boot/src/firmware_updater/blocking.rs12
-rw-r--r--embassy-boot/src/lib.rs24
-rw-r--r--embassy-net-esp-hosted/src/control.rs2
-rw-r--r--embassy-net-esp-hosted/src/lib.rs5
-rw-r--r--embassy-net/src/lib.rs40
-rw-r--r--embassy-rp/src/clocks.rs12
-rw-r--r--embassy-rp/src/gpio.rs6
-rw-r--r--embassy-rp/src/lib.rs4
-rw-r--r--embassy-rp/src/pio/mod.rs61
-rw-r--r--embassy-rp/src/trng.rs405
-rw-r--r--embassy-stm32/Cargo.toml8
-rw-r--r--embassy-stm32/build.rs4
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs2
-rw-r--r--embassy-stm32/src/dma/dma_bdma.rs54
-rw-r--r--embassy-stm32/src/dma/gpdma.rs14
-rw-r--r--embassy-stm32/src/eth/mod.rs14
-rw-r--r--embassy-stm32/src/rcc/h.rs36
-rw-r--r--embassy-stm32/src/spi/mod.rs76
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs51
-rw-r--r--embassy-stm32/src/usb/mod.rs30
-rw-r--r--embassy-stm32/src/usb/otg.rs55
-rw-r--r--embassy-sync/src/pubsub/mod.rs56
-rw-r--r--embassy-usb-synopsys-otg/src/lib.rs23
-rw-r--r--embassy-usb-synopsys-otg/src/otg_v1.rs171
-rw-r--r--examples/boot/application/nrf/build.rs3
-rw-r--r--examples/boot/application/nrf/src/bin/a.rs11
-rw-r--r--examples/rp/src/bin/pio_onewire.rs155
-rw-r--r--examples/rp23/src/bin/trng.rs64
-rw-r--r--examples/stm32f4/src/bin/eth_compliance_test.rs77
-rw-r--r--examples/stm32h7rs/src/bin/usb_serial.rs140
-rw-r--r--tests/stm32/src/bin/spi.rs98
-rw-r--r--tests/stm32/src/bin/spi_dma.rs116
36 files changed, 1602 insertions, 247 deletions
diff --git a/.gitignore b/.gitignore
index 1c221e876..a0b5d6a70 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ Cargo.lock
5third_party 5third_party
6/Cargo.toml 6/Cargo.toml
7out/ 7out/
8.zed
diff --git a/docs/pages/bootloader.adoc b/docs/pages/bootloader.adoc
index d8d50040b..53f85d995 100644
--- a/docs/pages/bootloader.adoc
+++ b/docs/pages/bootloader.adoc
@@ -88,8 +88,7 @@ Then, to sign your firmware given a declaration of `FIRMWARE_DIR` and a firmware
88 88
89[source, bash] 89[source, bash]
90---- 90----
91shasum -a 512 -b $FIRMWARE_DIR/myfirmware > $SECRETS_DIR/message.txt 91shasum -a 512 -b $FIRMWARE_DIR/myfirmware | head -c128 | xxd -p -r > $SECRETS_DIR/message.txt
92cat $SECRETS_DIR/message.txt | dd ibs=128 count=1 | xxd -p -r > $SECRETS_DIR/message.txt
93signify -S -s $SECRETS_DIR/key.sec -m $SECRETS_DIR/message.txt -x $SECRETS_DIR/message.txt.sig 92signify -S -s $SECRETS_DIR/key.sec -m $SECRETS_DIR/message.txt -x $SECRETS_DIR/message.txt.sig
94cp $FIRMWARE_DIR/myfirmware $FIRMWARE_DIR/myfirmware+signed 93cp $FIRMWARE_DIR/myfirmware $FIRMWARE_DIR/myfirmware+signed
95tail -n1 $SECRETS_DIR/message.txt.sig | base64 -d -i - | dd ibs=10 skip=1 >> $FIRMWARE_DIR/myfirmware+signed 94tail -n1 $SECRETS_DIR/message.txt.sig | base64 -d -i - | dd ibs=10 skip=1 >> $FIRMWARE_DIR/myfirmware+signed
diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs
index 61d61b96e..5bffdc5ea 100644
--- a/embassy-boot/src/boot_loader.rs
+++ b/embassy-boot/src/boot_loader.rs
@@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
5use embassy_sync::blocking_mutex::Mutex; 5use embassy_sync::blocking_mutex::Mutex;
6use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; 6use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
7 7
8use crate::{State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; 8use crate::{State, DFU_DETACH_MAGIC, REVERT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
9 9
10/// Errors returned by bootloader 10/// Errors returned by bootloader
11#[derive(PartialEq, Eq, Debug)] 11#[derive(PartialEq, Eq, Debug)]
@@ -276,7 +276,7 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
276 self.state.erase(0, self.state.capacity() as u32)?; 276 self.state.erase(0, self.state.capacity() as u32)?;
277 277
278 // Set magic 278 // Set magic
279 state_word.fill(BOOT_MAGIC); 279 state_word.fill(REVERT_MAGIC);
280 self.state.write(0, state_word)?; 280 self.state.write(0, state_word)?;
281 } 281 }
282 } 282 }
@@ -411,6 +411,8 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
411 Ok(State::Swap) 411 Ok(State::Swap)
412 } else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) { 412 } else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) {
413 Ok(State::DfuDetach) 413 Ok(State::DfuDetach)
414 } else if !state_word.iter().any(|&b| b != REVERT_MAGIC) {
415 Ok(State::Revert)
414 } else { 416 } else {
415 Ok(State::Boot) 417 Ok(State::Boot)
416 } 418 }
diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs
index 86b441592..d9d15b004 100644
--- a/embassy-boot/src/firmware_updater/asynch.rs
+++ b/embassy-boot/src/firmware_updater/asynch.rs
@@ -289,7 +289,8 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
289 289
290 // Make sure we are running a booted firmware to avoid reverting to a bad state. 290 // Make sure we are running a booted firmware to avoid reverting to a bad state.
291 async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 291 async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
292 if self.get_state().await? == State::Boot { 292 let state = self.get_state().await?;
293 if state == State::Boot || state == State::DfuDetach || state == State::Revert {
293 Ok(()) 294 Ok(())
294 } else { 295 } else {
295 Err(FirmwareUpdaterError::BadState) 296 Err(FirmwareUpdaterError::BadState)
@@ -303,12 +304,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
303 /// `mark_booted`. 304 /// `mark_booted`.
304 pub async fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> { 305 pub async fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> {
305 self.state.read(0, &mut self.aligned).await?; 306 self.state.read(0, &mut self.aligned).await?;
306 307 Ok(State::from(&self.aligned))
307 if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) {
308 Ok(State::Swap)
309 } else {
310 Ok(State::Boot)
311 }
312 } 308 }
313 309
314 /// Mark to trigger firmware swap on next boot. 310 /// Mark to trigger firmware swap on next boot.
diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs
index d3c723456..08062b0d0 100644
--- a/embassy-boot/src/firmware_updater/blocking.rs
+++ b/embassy-boot/src/firmware_updater/blocking.rs
@@ -324,7 +324,8 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
324 324
325 // Make sure we are running a booted firmware to avoid reverting to a bad state. 325 // Make sure we are running a booted firmware to avoid reverting to a bad state.
326 fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 326 fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
327 if self.get_state()? == State::Boot || self.get_state()? == State::DfuDetach { 327 let state = self.get_state()?;
328 if state == State::Boot || state == State::DfuDetach || state == State::Revert {
328 Ok(()) 329 Ok(())
329 } else { 330 } else {
330 Err(FirmwareUpdaterError::BadState) 331 Err(FirmwareUpdaterError::BadState)
@@ -338,14 +339,7 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
338 /// `mark_booted`. 339 /// `mark_booted`.
339 pub fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> { 340 pub fn get_state(&mut self) -> Result<State, FirmwareUpdaterError> {
340 self.state.read(0, &mut self.aligned)?; 341 self.state.read(0, &mut self.aligned)?;
341 342 Ok(State::from(&self.aligned))
342 if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) {
343 Ok(State::Swap)
344 } else if !self.aligned.iter().any(|&b| b != DFU_DETACH_MAGIC) {
345 Ok(State::DfuDetach)
346 } else {
347 Ok(State::Boot)
348 }
349 } 343 }
350 344
351 /// Mark to trigger firmware swap on next boot. 345 /// Mark to trigger firmware swap on next boot.
diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs
index 8849055e8..e2c4cf771 100644
--- a/embassy-boot/src/lib.rs
+++ b/embassy-boot/src/lib.rs
@@ -25,6 +25,7 @@ pub use firmware_updater::{
25 FirmwareUpdaterError, 25 FirmwareUpdaterError,
26}; 26};
27 27
28pub(crate) const REVERT_MAGIC: u8 = 0xC0;
28pub(crate) const BOOT_MAGIC: u8 = 0xD0; 29pub(crate) const BOOT_MAGIC: u8 = 0xD0;
29pub(crate) const SWAP_MAGIC: u8 = 0xF0; 30pub(crate) const SWAP_MAGIC: u8 = 0xF0;
30pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0; 31pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0;
@@ -37,10 +38,30 @@ pub enum State {
37 Boot, 38 Boot,
38 /// Bootloader has swapped the active partition with the dfu partition and will attempt boot. 39 /// Bootloader has swapped the active partition with the dfu partition and will attempt boot.
39 Swap, 40 Swap,
41 /// Bootloader has reverted the active partition with the dfu partition and will attempt boot.
42 Revert,
40 /// Application has received a request to reboot into DFU mode to apply an update. 43 /// Application has received a request to reboot into DFU mode to apply an update.
41 DfuDetach, 44 DfuDetach,
42} 45}
43 46
47impl<T> From<T> for State
48where
49 T: AsRef<[u8]>,
50{
51 fn from(magic: T) -> State {
52 let magic = magic.as_ref();
53 if !magic.iter().any(|&b| b != SWAP_MAGIC) {
54 State::Swap
55 } else if !magic.iter().any(|&b| b != REVERT_MAGIC) {
56 State::Revert
57 } else if !magic.iter().any(|&b| b != DFU_DETACH_MAGIC) {
58 State::DfuDetach
59 } else {
60 State::Boot
61 }
62 }
63}
64
44/// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot. 65/// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot.
45#[repr(align(32))] 66#[repr(align(32))]
46pub struct AlignedBuffer<const N: usize>(pub [u8; N]); 67pub struct AlignedBuffer<const N: usize>(pub [u8; N]);
@@ -157,6 +178,9 @@ mod tests {
157 // Running again should cause a revert 178 // Running again should cause a revert
158 assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap()); 179 assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
159 180
181 // Next time we know it was reverted
182 assert_eq!(State::Revert, bootloader.prepare_boot(&mut page).unwrap());
183
160 let mut read_buf = [0; FIRMWARE_SIZE]; 184 let mut read_buf = [0; FIRMWARE_SIZE];
161 flash.active().read(0, &mut read_buf).unwrap(); 185 flash.active().read(0, &mut read_buf).unwrap();
162 assert_eq!(ORIGINAL, read_buf); 186 assert_eq!(ORIGINAL, read_buf);
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index c8cea8503..b1838a425 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -120,7 +120,7 @@ impl<'a> Control<'a> {
120 pwd: unwrap!(String::try_from(password)), 120 pwd: unwrap!(String::try_from(password)),
121 bssid: String::new(), 121 bssid: String::new(),
122 listen_interval: 3, 122 listen_interval: 3,
123 is_wpa3_supported: false, 123 is_wpa3_supported: true,
124 }; 124 };
125 ioctl!(self, ReqConnectAp, RespConnectAp, req, resp); 125 ioctl!(self, ReqConnectAp, RespConnectAp, req, resp);
126 self.state_ch.set_link_state(LinkState::Up); 126 self.state_ch.set_link_state(LinkState::Up);
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index c78578bf1..f05e2a70a 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -137,7 +137,7 @@ where
137 let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ethernet([0; 6])); 137 let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
138 let state_ch = ch_runner.state_runner(); 138 let state_ch = ch_runner.state_runner();
139 139
140 let mut runner = Runner { 140 let runner = Runner {
141 ch: ch_runner, 141 ch: ch_runner,
142 state_ch, 142 state_ch,
143 shared: &state.shared, 143 shared: &state.shared,
@@ -148,7 +148,6 @@ where
148 spi, 148 spi,
149 heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP, 149 heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP,
150 }; 150 };
151 runner.init().await;
152 151
153 (device, Control::new(state_ch, &state.shared), runner) 152 (device, Control::new(state_ch, &state.shared), runner)
154} 153}
@@ -174,8 +173,6 @@ where
174 IN: InputPin + Wait, 173 IN: InputPin + Wait,
175 OUT: OutputPin, 174 OUT: OutputPin,
176{ 175{
177 async fn init(&mut self) {}
178
179 /// Run the packet processing. 176 /// Run the packet processing.
180 pub async fn run(mut self) -> ! { 177 pub async fn run(mut self) -> ! {
181 debug!("resetting..."); 178 debug!("resetting...");
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index ef53fb905..a7b7efa87 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -260,7 +260,10 @@ pub struct Stack<'d> {
260pub(crate) struct Inner { 260pub(crate) struct Inner {
261 pub(crate) sockets: SocketSet<'static>, // Lifetime type-erased. 261 pub(crate) sockets: SocketSet<'static>, // Lifetime type-erased.
262 pub(crate) iface: Interface, 262 pub(crate) iface: Interface,
263 /// Waker used for triggering polls.
263 pub(crate) waker: WakerRegistration, 264 pub(crate) waker: WakerRegistration,
265 /// Waker used for waiting for link up or config up.
266 state_waker: WakerRegistration,
264 hardware_address: HardwareAddress, 267 hardware_address: HardwareAddress,
265 next_local_port: u16, 268 next_local_port: u16,
266 link_up: bool, 269 link_up: bool,
@@ -270,7 +273,6 @@ pub(crate) struct Inner {
270 static_v6: Option<StaticConfigV6>, 273 static_v6: Option<StaticConfigV6>,
271 #[cfg(feature = "dhcpv4")] 274 #[cfg(feature = "dhcpv4")]
272 dhcp_socket: Option<SocketHandle>, 275 dhcp_socket: Option<SocketHandle>,
273 config_waker: WakerRegistration,
274 #[cfg(feature = "dns")] 276 #[cfg(feature = "dns")]
275 dns_socket: SocketHandle, 277 dns_socket: SocketHandle,
276 #[cfg(feature = "dns")] 278 #[cfg(feature = "dns")]
@@ -326,6 +328,7 @@ pub fn new<'d, D: Driver, const SOCK: usize>(
326 sockets, 328 sockets,
327 iface, 329 iface,
328 waker: WakerRegistration::new(), 330 waker: WakerRegistration::new(),
331 state_waker: WakerRegistration::new(),
329 next_local_port, 332 next_local_port,
330 hardware_address, 333 hardware_address,
331 link_up: false, 334 link_up: false,
@@ -335,7 +338,6 @@ pub fn new<'d, D: Driver, const SOCK: usize>(
335 static_v6: None, 338 static_v6: None,
336 #[cfg(feature = "dhcpv4")] 339 #[cfg(feature = "dhcpv4")]
337 dhcp_socket: None, 340 dhcp_socket: None,
338 config_waker: WakerRegistration::new(),
339 #[cfg(feature = "dns")] 341 #[cfg(feature = "dns")]
340 dns_socket, 342 dns_socket,
341 #[cfg(feature = "dns")] 343 #[cfg(feature = "dns")]
@@ -421,10 +423,20 @@ impl<'d> Stack<'d> {
421 v4_up || v6_up 423 v4_up || v6_up
422 } 424 }
423 425
426 /// Wait for the network device to obtain a link signal.
427 pub async fn wait_link_up(&self) {
428 self.wait(|| self.is_link_up()).await
429 }
430
431 /// Wait for the network device to lose link signal.
432 pub async fn wait_link_down(&self) {
433 self.wait(|| !self.is_link_up()).await
434 }
435
424 /// Wait for the network stack to obtain a valid IP configuration. 436 /// Wait for the network stack to obtain a valid IP configuration.
425 /// 437 ///
426 /// ## Notes: 438 /// ## Notes:
427 /// - Ensure [`Stack::run`] has been called before using this function. 439 /// - Ensure [`Runner::run`] has been started before using this function.
428 /// 440 ///
429 /// - This function may never return (e.g. if no configuration is obtained through DHCP). 441 /// - This function may never return (e.g. if no configuration is obtained through DHCP).
430 /// The caller is supposed to handle a timeout for this case. 442 /// The caller is supposed to handle a timeout for this case.
@@ -451,13 +463,17 @@ impl<'d> Stack<'d> {
451 /// // ... 463 /// // ...
452 /// ``` 464 /// ```
453 pub async fn wait_config_up(&self) { 465 pub async fn wait_config_up(&self) {
454 // If the config is up already, we can return immediately. 466 self.wait(|| self.is_config_up()).await
455 if self.is_config_up() { 467 }
456 return;
457 }
458 468
459 poll_fn(|cx| { 469 /// Wait for the network stack to lose a valid IP configuration.
460 if self.is_config_up() { 470 pub async fn wait_config_down(&self) {
471 self.wait(|| !self.is_config_up()).await
472 }
473
474 fn wait<'a>(&'a self, mut predicate: impl FnMut() -> bool + 'a) -> impl Future<Output = ()> + 'a {
475 poll_fn(move |cx| {
476 if predicate() {
461 Poll::Ready(()) 477 Poll::Ready(())
462 } else { 478 } else {
463 // If the config is not up, we register a waker that is woken up 479 // If the config is not up, we register a waker that is woken up
@@ -465,13 +481,12 @@ impl<'d> Stack<'d> {
465 trace!("Waiting for config up"); 481 trace!("Waiting for config up");
466 482
467 self.with_mut(|i| { 483 self.with_mut(|i| {
468 i.config_waker.register(cx.waker()); 484 i.state_waker.register(cx.waker());
469 }); 485 });
470 486
471 Poll::Pending 487 Poll::Pending
472 } 488 }
473 }) 489 })
474 .await;
475 } 490 }
476 491
477 /// Get the current IPv4 configuration. 492 /// Get the current IPv4 configuration.
@@ -775,7 +790,7 @@ impl Inner {
775 .update_servers(&dns_servers[..count]); 790 .update_servers(&dns_servers[..count]);
776 } 791 }
777 792
778 self.config_waker.wake(); 793 self.state_waker.wake();
779 } 794 }
780 795
781 fn poll<D: Driver>(&mut self, cx: &mut Context<'_>, driver: &mut D) { 796 fn poll<D: Driver>(&mut self, cx: &mut Context<'_>, driver: &mut D) {
@@ -813,6 +828,7 @@ impl Inner {
813 // Print when changed 828 // Print when changed
814 if old_link_up != self.link_up { 829 if old_link_up != self.link_up {
815 info!("link_up = {:?}", self.link_up); 830 info!("link_up = {:?}", self.link_up);
831 self.state_waker.wake();
816 } 832 }
817 833
818 #[allow(unused_mut)] 834 #[allow(unused_mut)]
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index ed146844c..f229a5acd 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -847,6 +847,10 @@ impl<'d, T: GpinPin> Gpin<'d, T> {
847 into_ref!(gpin); 847 into_ref!(gpin);
848 848
849 gpin.gpio().ctrl().write(|w| w.set_funcsel(0x08)); 849 gpin.gpio().ctrl().write(|w| w.set_funcsel(0x08));
850 #[cfg(feature = "_rp235x")]
851 gpin.pad_ctrl().write(|w| {
852 w.set_iso(false);
853 });
850 854
851 Gpin { 855 Gpin {
852 gpin: gpin.map_into(), 856 gpin: gpin.map_into(),
@@ -861,6 +865,7 @@ impl<'d, T: GpinPin> Gpin<'d, T> {
861 865
862impl<'d, T: GpinPin> Drop for Gpin<'d, T> { 866impl<'d, T: GpinPin> Drop for Gpin<'d, T> {
863 fn drop(&mut self) { 867 fn drop(&mut self) {
868 self.gpin.pad_ctrl().write(|_| {});
864 self.gpin 869 self.gpin
865 .gpio() 870 .gpio()
866 .ctrl() 871 .ctrl()
@@ -921,11 +926,15 @@ pub struct Gpout<'d, T: GpoutPin> {
921} 926}
922 927
923impl<'d, T: GpoutPin> Gpout<'d, T> { 928impl<'d, T: GpoutPin> Gpout<'d, T> {
924 /// Create new general purpose cloud output. 929 /// Create new general purpose clock output.
925 pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { 930 pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self {
926 into_ref!(gpout); 931 into_ref!(gpout);
927 932
928 gpout.gpio().ctrl().write(|w| w.set_funcsel(0x08)); 933 gpout.gpio().ctrl().write(|w| w.set_funcsel(0x08));
934 #[cfg(feature = "_rp235x")]
935 gpout.pad_ctrl().write(|w| {
936 w.set_iso(false);
937 });
929 938
930 Self { gpout } 939 Self { gpout }
931 } 940 }
@@ -1005,6 +1014,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
1005impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { 1014impl<'d, T: GpoutPin> Drop for Gpout<'d, T> {
1006 fn drop(&mut self) { 1015 fn drop(&mut self) {
1007 self.disable(); 1016 self.disable();
1017 self.gpout.pad_ctrl().write(|_| {});
1008 self.gpout 1018 self.gpout
1009 .gpio() 1019 .gpio()
1010 .ctrl() 1020 .ctrl()
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index 31397172c..cb54375e4 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -16,9 +16,9 @@ use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
16const NEW_AW: AtomicWaker = AtomicWaker::new(); 16const NEW_AW: AtomicWaker = AtomicWaker::new();
17 17
18#[cfg(any(feature = "rp2040", feature = "rp235xa"))] 18#[cfg(any(feature = "rp2040", feature = "rp235xa"))]
19const BANK0_PIN_COUNT: usize = 30; 19pub(crate) const BANK0_PIN_COUNT: usize = 30;
20#[cfg(feature = "rp235xb")] 20#[cfg(feature = "rp235xb")]
21const BANK0_PIN_COUNT: usize = 48; 21pub(crate) const BANK0_PIN_COUNT: usize = 48;
22 22
23static BANK0_WAKERS: [AtomicWaker; BANK0_PIN_COUNT] = [NEW_AW; BANK0_PIN_COUNT]; 23static BANK0_WAKERS: [AtomicWaker; BANK0_PIN_COUNT] = [NEW_AW; BANK0_PIN_COUNT];
24#[cfg(feature = "qspi-as-gpio")] 24#[cfg(feature = "qspi-as-gpio")]
@@ -603,7 +603,7 @@ impl<'d> Flex<'d> {
603 603
604 #[inline] 604 #[inline]
605 fn bit(&self) -> u32 { 605 fn bit(&self) -> u32 {
606 1 << self.pin.pin() 606 1 << (self.pin.pin() % 32)
607 } 607 }
608 608
609 /// Set the pin's pull. 609 /// Set the pin's pull.
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index c357c14c2..d402cf793 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -42,6 +42,8 @@ pub mod rtc;
42pub mod spi; 42pub mod spi;
43#[cfg(feature = "time-driver")] 43#[cfg(feature = "time-driver")]
44pub mod time_driver; 44pub mod time_driver;
45#[cfg(feature = "_rp235x")]
46pub mod trng;
45pub mod uart; 47pub mod uart;
46pub mod usb; 48pub mod usb;
47pub mod watchdog; 49pub mod watchdog;
@@ -402,6 +404,8 @@ embassy_hal_internal::peripherals! {
402 404
403 WATCHDOG, 405 WATCHDOG,
404 BOOTSEL, 406 BOOTSEL,
407
408 TRNG
405} 409}
406 410
407#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))] 411#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))]
diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs
index 68b1d6849..72aa8f104 100644
--- a/embassy-rp/src/pio/mod.rs
+++ b/embassy-rp/src/pio/mod.rs
@@ -5,7 +5,7 @@ use core::pin::Pin as FuturePin;
5use core::sync::atomic::{compiler_fence, Ordering}; 5use core::sync::atomic::{compiler_fence, Ordering};
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use atomic_polyfill::{AtomicU32, AtomicU8}; 8use atomic_polyfill::{AtomicU64, AtomicU8};
9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11use fixed::types::extra::U8; 11use fixed::types::extra::U8;
@@ -731,6 +731,8 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
731 w.set_autopull(config.shift_out.auto_fill); 731 w.set_autopull(config.shift_out.auto_fill);
732 w.set_autopush(config.shift_in.auto_fill); 732 w.set_autopush(config.shift_in.auto_fill);
733 }); 733 });
734
735 #[cfg(feature = "rp2040")]
734 sm.pinctrl().write(|w| { 736 sm.pinctrl().write(|w| {
735 w.set_sideset_count(config.pins.sideset_count); 737 w.set_sideset_count(config.pins.sideset_count);
736 w.set_set_count(config.pins.set_count); 738 w.set_set_count(config.pins.set_count);
@@ -740,6 +742,52 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
740 w.set_set_base(config.pins.set_base); 742 w.set_set_base(config.pins.set_base);
741 w.set_out_base(config.pins.out_base); 743 w.set_out_base(config.pins.out_base);
742 }); 744 });
745
746 #[cfg(feature = "_rp235x")]
747 {
748 let mut low_ok = true;
749 let mut high_ok = true;
750
751 let in_pins = config.pins.in_base..config.pins.in_base + config.in_count;
752 let side_pins = config.pins.sideset_base..config.pins.sideset_base + config.pins.sideset_count;
753 let set_pins = config.pins.set_base..config.pins.set_base + config.pins.set_count;
754 let out_pins = config.pins.out_base..config.pins.out_base + config.pins.out_count;
755
756 for pin_range in [in_pins, side_pins, set_pins, out_pins] {
757 for pin in pin_range {
758 low_ok &= pin < 32;
759 high_ok &= pin >= 16;
760 }
761 }
762
763 if !low_ok && !high_ok {
764 panic!(
765 "All pins must either be <32 or >=16, in:{:?}-{:?}, side:{:?}-{:?}, set:{:?}-{:?}, out:{:?}-{:?}",
766 config.pins.in_base,
767 config.pins.in_base + config.in_count - 1,
768 config.pins.sideset_base,
769 config.pins.sideset_base + config.pins.sideset_count - 1,
770 config.pins.set_base,
771 config.pins.set_base + config.pins.set_count - 1,
772 config.pins.out_base,
773 config.pins.out_base + config.pins.out_count - 1,
774 )
775 }
776 let shift = if low_ok { 0 } else { 16 };
777
778 sm.pinctrl().write(|w| {
779 w.set_sideset_count(config.pins.sideset_count);
780 w.set_set_count(config.pins.set_count);
781 w.set_out_count(config.pins.out_count);
782 w.set_in_base(config.pins.in_base.checked_sub(shift).unwrap_or_default());
783 w.set_sideset_base(config.pins.sideset_base.checked_sub(shift).unwrap_or_default());
784 w.set_set_base(config.pins.set_base.checked_sub(shift).unwrap_or_default());
785 w.set_out_base(config.pins.out_base.checked_sub(shift).unwrap_or_default());
786 });
787
788 PIO::PIO.gpiobase().write(|w| w.set_gpiobase(shift == 16));
789 }
790
743 if let Some(origin) = config.origin { 791 if let Some(origin) = config.origin {
744 unsafe { instr::exec_jmp(self, origin) } 792 unsafe { instr::exec_jmp(self, origin) }
745 } 793 }
@@ -1006,6 +1054,10 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
1006 pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> { 1054 pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> {
1007 into_ref!(pin); 1055 into_ref!(pin);
1008 pin.gpio().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _)); 1056 pin.gpio().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _));
1057 #[cfg(feature = "_rp235x")]
1058 pin.pad_ctrl().modify(|w| {
1059 w.set_iso(false);
1060 });
1009 // we can be relaxed about this because we're &mut here and nothing is cached 1061 // we can be relaxed about this because we're &mut here and nothing is cached
1010 PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); 1062 PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed);
1011 Pin { 1063 Pin {
@@ -1187,7 +1239,7 @@ impl<'d, PIO: Instance> Pio<'d, PIO> {
1187// other way. 1239// other way.
1188pub struct State { 1240pub struct State {
1189 users: AtomicU8, 1241 users: AtomicU8,
1190 used_pins: AtomicU32, 1242 used_pins: AtomicU64,
1191} 1243}
1192 1244
1193fn on_pio_drop<PIO: Instance>() { 1245fn on_pio_drop<PIO: Instance>() {
@@ -1195,8 +1247,7 @@ fn on_pio_drop<PIO: Instance>() {
1195 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { 1247 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 {
1196 let used_pins = state.used_pins.load(Ordering::Relaxed); 1248 let used_pins = state.used_pins.load(Ordering::Relaxed);
1197 let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _; 1249 let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _;
1198 // we only have 30 pins. don't test the other two since gpio() asserts. 1250 for i in 0..crate::gpio::BANK0_PIN_COUNT {
1199 for i in 0..30 {
1200 if used_pins & (1 << i) != 0 { 1251 if used_pins & (1 << i) != 0 {
1201 pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null)); 1252 pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
1202 } 1253 }
@@ -1221,7 +1272,7 @@ trait SealedInstance {
1221 fn state() -> &'static State { 1272 fn state() -> &'static State {
1222 static STATE: State = State { 1273 static STATE: State = State {
1223 users: AtomicU8::new(0), 1274 users: AtomicU8::new(0),
1224 used_pins: AtomicU32::new(0), 1275 used_pins: AtomicU64::new(0),
1225 }; 1276 };
1226 1277
1227 &STATE 1278 &STATE
diff --git a/embassy-rp/src/trng.rs b/embassy-rp/src/trng.rs
new file mode 100644
index 000000000..9f2f33c4b
--- /dev/null
+++ b/embassy-rp/src/trng.rs
@@ -0,0 +1,405 @@
1//! True Random Number Generator (TRNG) driver.
2
3use core::future::poll_fn;
4use core::marker::PhantomData;
5use core::ops::Not;
6use core::task::Poll;
7
8use embassy_hal_internal::Peripheral;
9use embassy_sync::waitqueue::AtomicWaker;
10use rand_core::Error;
11
12use crate::interrupt::typelevel::{Binding, Interrupt};
13use crate::peripherals::TRNG;
14use crate::{interrupt, pac};
15
16trait SealedInstance {
17 fn regs() -> pac::trng::Trng;
18 fn waker() -> &'static AtomicWaker;
19}
20
21/// TRNG peripheral instance.
22#[allow(private_bounds)]
23pub trait Instance: SealedInstance {
24 /// Interrupt for this peripheral.
25 type Interrupt: Interrupt;
26}
27
28impl SealedInstance for TRNG {
29 fn regs() -> rp_pac::trng::Trng {
30 pac::TRNG
31 }
32
33 fn waker() -> &'static AtomicWaker {
34 static WAKER: AtomicWaker = AtomicWaker::new();
35 &WAKER
36 }
37}
38
39impl Instance for TRNG {
40 type Interrupt = interrupt::typelevel::TRNG_IRQ;
41}
42
43#[derive(Copy, Clone, Debug)]
44#[allow(missing_docs)]
45/// TRNG ROSC Inverter chain length options.
46pub enum InverterChainLength {
47 None = 0,
48 One,
49 Two,
50 Three,
51 Four,
52}
53
54impl From<InverterChainLength> for u8 {
55 fn from(value: InverterChainLength) -> Self {
56 value as u8
57 }
58}
59
60/// Configuration for the TRNG.
61///
62/// - Three built in entropy checks
63/// - ROSC frequency controlled by selecting one of ROSC chain lengths
64/// - Sample period in terms of system clock ticks
65///
66///
67/// Default configuration is based on the following from documentation:
68///
69/// ----
70///
71/// RP2350 Datasheet 12.12.2
72///
73/// ...
74///
75/// When configuring the TRNG block, consider the following principles:
76/// • As average generation time increases, result quality increases and failed entropy checks decrease.
77/// • A low sample count decreases average generation time, but increases the chance of NIST test-failing results and
78/// failed entropy checks.
79/// For acceptable results with an average generation time of about 2 milliseconds, use ROSC chain length settings of 0 or
80/// 1 and sample count settings of 20-25.
81///
82/// ---
83///
84/// Note, Pico SDK and Bootrom don't use any of the entropy checks and sample the ROSC directly
85/// by setting the sample period to 0. Random data collected this way is then passed through
86/// either hardware accelerated SHA256 (Bootrom) or xoroshiro128** (version 1.0!).
87#[non_exhaustive]
88#[derive(Copy, Clone, Debug)]
89pub struct Config {
90 /// Bypass TRNG autocorrelation test
91 pub disable_autocorrelation_test: bool,
92 /// Bypass CRNGT test
93 pub disable_crngt_test: bool,
94 /// When set, the Von-Neuman balancer is bypassed (including the
95 /// 32 consecutive bits test)
96 pub disable_von_neumann_balancer: bool,
97 /// Sets the number of rng_clk cycles between two consecutive
98 /// ring oscillator samples.
99 /// Note: If the von Neumann decorrelator is bypassed, the minimum value for
100 /// sample counter must not be less than seventeen
101 pub sample_count: u32,
102 /// Selects the number of inverters (out of four possible
103 /// selections) in the ring oscillator (the entropy source). Higher values select
104 /// longer inverter chain lengths.
105 pub inverter_chain_length: InverterChainLength,
106}
107
108impl Default for Config {
109 fn default() -> Self {
110 Config {
111 disable_autocorrelation_test: true,
112 disable_crngt_test: true,
113 disable_von_neumann_balancer: true,
114 sample_count: 25,
115 inverter_chain_length: InverterChainLength::One,
116 }
117 }
118}
119
120/// True Random Number Generator Driver for RP2350
121///
122/// This driver provides async and blocking options.
123///
124/// See [Config] for configuration details.
125///
126/// Usage example:
127/// ```no_run
128/// use embassy_executor::Spawner;
129/// use embassy_rp::trng::Trng;
130/// use embassy_rp::peripherals::TRNG;
131/// use embassy_rp::bind_interrupts;
132///
133/// bind_interrupts!(struct Irqs {
134/// TRNG_IRQ => embassy_rp::trng::InterruptHandler<TRNG>;
135/// });
136///
137/// #[embassy_executor::main]
138/// async fn main(spawner: Spawner) {
139/// let peripherals = embassy_rp::init(Default::default());
140/// let mut trng = Trng::new(peripherals.TRNG, Irqs, embassy_rp::trng::Config::default());
141///
142/// let mut randomness = [0u8; 58];
143/// loop {
144/// trng.fill_bytes(&mut randomness).await;
145/// assert_ne!(randomness, [0u8; 58]);
146/// }
147///}
148/// ```
149pub struct Trng<'d, T: Instance> {
150 phantom: PhantomData<&'d mut T>,
151}
152
153/// 12.12.1. Overview
154/// On request, the TRNG block generates a block of 192 entropy bits generated by automatically processing a series of
155/// periodic samples from the TRNG block’s internal Ring Oscillator (ROSC).
156const TRNG_BLOCK_SIZE_BITS: usize = 192;
157const TRNG_BLOCK_SIZE_BYTES: usize = TRNG_BLOCK_SIZE_BITS / 8;
158
159impl<'d, T: Instance> Trng<'d, T> {
160 /// Create a new TRNG driver.
161 pub fn new(
162 _trng: impl Peripheral<P = T> + 'd,
163 _irq: impl Binding<T::Interrupt, InterruptHandler<T>> + 'd,
164 config: Config,
165 ) -> Self {
166 let regs = T::regs();
167
168 regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false));
169
170 let trng_config_register = regs.trng_config();
171 trng_config_register.write(|w| {
172 w.set_rnd_src_sel(config.inverter_chain_length.clone().into());
173 });
174
175 let sample_count_register = regs.sample_cnt1();
176 sample_count_register.write(|w| {
177 *w = config.sample_count;
178 });
179
180 let debug_control_register = regs.trng_debug_control();
181 debug_control_register.write(|w| {
182 w.set_auto_correlate_bypass(config.disable_autocorrelation_test);
183 w.set_trng_crngt_bypass(config.disable_crngt_test);
184 w.set_vnc_bypass(config.disable_von_neumann_balancer)
185 });
186
187 Trng { phantom: PhantomData }
188 }
189
190 fn start_rng(&self) {
191 let regs = T::regs();
192 let source_enable_register = regs.rnd_source_enable();
193 // Enable TRNG ROSC
194 source_enable_register.write(|w| w.set_rnd_src_en(true));
195 }
196
197 fn stop_rng(&self) {
198 let regs = T::regs();
199 let source_enable_register = regs.rnd_source_enable();
200 source_enable_register.write(|w| w.set_rnd_src_en(false));
201 let reset_bits_counter_register = regs.rst_bits_counter();
202 reset_bits_counter_register.write(|w| w.set_rst_bits_counter(true));
203 }
204
205 fn enable_irq(&self) {
206 unsafe { T::Interrupt::enable() }
207 }
208
209 fn disable_irq(&self) {
210 T::Interrupt::disable();
211 }
212
213 fn blocking_wait_for_successful_generation(&self) {
214 let regs = T::regs();
215
216 let trng_busy_register = regs.trng_busy();
217 let trng_valid_register = regs.trng_valid();
218
219 let mut success = false;
220 while success.not() {
221 while trng_busy_register.read().trng_busy() {}
222 if trng_valid_register.read().ehr_valid().not() {
223 if regs.rng_isr().read().autocorr_err() {
224 regs.trng_sw_reset().write(|w| w.set_trng_sw_reset(true));
225 } else {
226 panic!("RNG not busy, but ehr is not valid!")
227 }
228 } else {
229 success = true
230 }
231 }
232 }
233
234 fn read_ehr_registers_into_array(&mut self, buffer: &mut [u8; TRNG_BLOCK_SIZE_BYTES]) {
235 let regs = T::regs();
236 let ehr_data_regs = [
237 regs.ehr_data0(),
238 regs.ehr_data1(),
239 regs.ehr_data2(),
240 regs.ehr_data3(),
241 regs.ehr_data4(),
242 regs.ehr_data5(),
243 ];
244
245 for (i, reg) in ehr_data_regs.iter().enumerate() {
246 buffer[i * 4..i * 4 + 4].copy_from_slice(&reg.read().to_ne_bytes());
247 }
248 }
249
250 fn blocking_read_ehr_registers_into_array(&mut self, buffer: &mut [u8; TRNG_BLOCK_SIZE_BYTES]) {
251 self.blocking_wait_for_successful_generation();
252 self.read_ehr_registers_into_array(buffer);
253 }
254
255 /// Fill the buffer with random bytes, async version.
256 pub async fn fill_bytes(&mut self, destination: &mut [u8]) {
257 if destination.is_empty() {
258 return; // Nothing to fill
259 }
260
261 self.start_rng();
262 self.enable_irq();
263
264 let mut bytes_transferred = 0usize;
265 let mut buffer = [0u8; TRNG_BLOCK_SIZE_BYTES];
266
267 let regs = T::regs();
268
269 let trng_busy_register = regs.trng_busy();
270 let trng_valid_register = regs.trng_valid();
271
272 let waker = T::waker();
273
274 let destination_length = destination.len();
275
276 poll_fn(|context| {
277 waker.register(context.waker());
278 if bytes_transferred == destination_length {
279 self.stop_rng();
280 self.disable_irq();
281 Poll::Ready(())
282 } else {
283 if trng_busy_register.read().trng_busy() {
284 Poll::Pending
285 } else {
286 if trng_valid_register.read().ehr_valid().not() {
287 panic!("RNG not busy, but ehr is not valid!")
288 }
289 self.read_ehr_registers_into_array(&mut buffer);
290 let remaining = destination_length - bytes_transferred;
291 if remaining > TRNG_BLOCK_SIZE_BYTES {
292 destination[bytes_transferred..bytes_transferred + TRNG_BLOCK_SIZE_BYTES]
293 .copy_from_slice(&buffer);
294 bytes_transferred += TRNG_BLOCK_SIZE_BYTES
295 } else {
296 destination[bytes_transferred..bytes_transferred + remaining]
297 .copy_from_slice(&buffer[0..remaining]);
298 bytes_transferred += remaining
299 }
300 if bytes_transferred == destination_length {
301 self.stop_rng();
302 self.disable_irq();
303 Poll::Ready(())
304 } else {
305 Poll::Pending
306 }
307 }
308 }
309 })
310 .await
311 }
312
313 /// Fill the buffer with random bytes, blocking version.
314 pub fn blocking_fill_bytes(&mut self, destination: &mut [u8]) {
315 if destination.is_empty() {
316 return; // Nothing to fill
317 }
318 self.start_rng();
319
320 let mut buffer = [0u8; TRNG_BLOCK_SIZE_BYTES];
321
322 for chunk in destination.chunks_mut(TRNG_BLOCK_SIZE_BYTES) {
323 self.blocking_wait_for_successful_generation();
324 self.blocking_read_ehr_registers_into_array(&mut buffer);
325 chunk.copy_from_slice(&buffer[..chunk.len()])
326 }
327 self.stop_rng()
328 }
329
330 /// Return a random u32, blocking.
331 pub fn blocking_next_u32(&mut self) -> u32 {
332 let regs = T::regs();
333 self.start_rng();
334 self.blocking_wait_for_successful_generation();
335 // 12.12.3 After successful generation, read the last result register, EHR_DATA[5] to
336 // clear all of the result registers.
337 let result = regs.ehr_data5().read();
338 self.stop_rng();
339 result
340 }
341
342 /// Return a random u64, blocking.
343 pub fn blocking_next_u64(&mut self) -> u64 {
344 let regs = T::regs();
345 self.start_rng();
346 self.blocking_wait_for_successful_generation();
347
348 let low = regs.ehr_data4().read() as u64;
349 // 12.12.3 After successful generation, read the last result register, EHR_DATA[5] to
350 // clear all of the result registers.
351 let result = (regs.ehr_data5().read() as u64) << 32 | low;
352 self.stop_rng();
353 result
354 }
355}
356
357impl<'d, T: Instance> rand_core::RngCore for Trng<'d, T> {
358 fn next_u32(&mut self) -> u32 {
359 self.blocking_next_u32()
360 }
361
362 fn next_u64(&mut self) -> u64 {
363 self.blocking_next_u64()
364 }
365
366 fn fill_bytes(&mut self, dest: &mut [u8]) {
367 self.blocking_fill_bytes(dest)
368 }
369
370 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
371 self.blocking_fill_bytes(dest);
372 Ok(())
373 }
374}
375/// TRNG interrupt handler.
376pub struct InterruptHandler<T: Instance> {
377 _trng: PhantomData<T>,
378}
379
380impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
381 unsafe fn on_interrupt() {
382 let regs = T::regs();
383 let isr = regs.rng_isr().read();
384 // Clear ehr bit
385 regs.rng_icr().write(|w| {
386 w.set_ehr_valid(true);
387 });
388 if isr.ehr_valid() {
389 T::waker().wake();
390 } else {
391 // 12.12.5. List of Registers
392 // ...
393 // TRNG: RNG_ISR Register
394 // ...
395 // AUTOCORR_ERR: 1 indicates Autocorrelation test failed four times in a row.
396 // When set, RNG ceases functioning until next reset
397 if isr.autocorr_err() {
398 warn!("TRNG Autocorrect error! Resetting TRNG");
399 regs.trng_sw_reset().write(|w| {
400 w.set_trng_sw_reset(true);
401 });
402 }
403 }
404 }
405}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 3c6484c96..8fc8da006 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -47,7 +47,7 @@ embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
47embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } 47embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
48embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 48embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
49embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } 49embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
50embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } 50embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false }
51embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 51embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
52embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } 52embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
53embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } 53embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" }
@@ -72,7 +72,7 @@ rand_core = "0.6.3"
72sdio-host = "0.5.0" 72sdio-host = "0.5.0"
73critical-section = "1.1" 73critical-section = "1.1"
74#stm32-metapac = { version = "15" } 74#stm32-metapac = { version = "15" }
75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" } 75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9b7414490b10ffbd5beb1b0dcf14adb018cbe37f" }
76 76
77vcell = "0.1.3" 77vcell = "0.1.3"
78nb = "1.0.0" 78nb = "1.0.0"
@@ -99,7 +99,7 @@ proc-macro2 = "1.0.36"
99quote = "1.0.15" 99quote = "1.0.15"
100 100
101#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 101#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
102stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] } 102stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9b7414490b10ffbd5beb1b0dcf14adb018cbe37f", default-features = false, features = ["metadata"] }
103 103
104[features] 104[features]
105default = ["rt"] 105default = ["rt"]
@@ -129,7 +129,7 @@ unstable-pac = []
129#! ## Time 129#! ## Time
130 130
131## Enables additional driver features that depend on embassy-time 131## Enables additional driver features that depend on embassy-time
132time = ["dep:embassy-time"] 132time = ["dep:embassy-time", "embassy-embedded-hal/time"]
133 133
134# Features starting with `_` are for internal use only. They're not intended 134# Features starting with `_` are for internal use only. They're not intended
135# to be enabled by other crates, and are not covered by semver guarantees. 135# to be enabled by other crates, and are not covered by semver guarantees.
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index e4cd001e6..fe04dd815 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -55,7 +55,7 @@ fn main() {
55 let mut singletons: Vec<String> = Vec::new(); 55 let mut singletons: Vec<String> = Vec::new();
56 for p in METADATA.peripherals { 56 for p in METADATA.peripherals {
57 if let Some(r) = &p.registers { 57 if let Some(r) = &p.registers {
58 if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" { 58 if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" || r.kind == "otg" {
59 // TODO: should we emit this for all peripherals? if so, we will need a list of all 59 // TODO: should we emit this for all peripherals? if so, we will need a list of all
60 // possible peripherals across all chips, so that we can declare the configs 60 // possible peripherals across all chips, so that we can declare the configs
61 // (replacing the hard-coded list of `peri_*` cfgs below) 61 // (replacing the hard-coded list of `peri_*` cfgs below)
@@ -111,6 +111,8 @@ fn main() {
111 "peri_sai4", 111 "peri_sai4",
112 "peri_ucpd1", 112 "peri_ucpd1",
113 "peri_ucpd2", 113 "peri_ucpd2",
114 "peri_usb_otg_fs",
115 "peri_usb_otg_hs",
114 ]); 116 ]);
115 cfgs.declare_all(&["mco", "mco1", "mco2"]); 117 cfgs.declare_all(&["mco", "mco1", "mco2"]);
116 118
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index 07e3dddad..1c7abfcb2 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -200,7 +200,7 @@ impl Registers {
200 if header_reg.rtr().bit() { 200 if header_reg.rtr().bit() {
201 F::new_remote(id, len as usize) 201 F::new_remote(id, len as usize)
202 } else { 202 } else {
203 F::new(id, &data) 203 F::new(id, &data[0..(len as usize)])
204 } 204 }
205 } else { 205 } else {
206 // Abort request failed because the frame was already sent (or being sent) on 206 // Abort request failed because the frame was already sent (or being sent) on
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs
index df041c4e9..d10b5554f 100644
--- a/embassy-stm32/src/dma/dma_bdma.rs
+++ b/embassy-stm32/src/dma/dma_bdma.rs
@@ -493,6 +493,26 @@ impl AnyChannel {
493 } 493 }
494 } 494 }
495 495
496 fn request_pause(&self) {
497 let info = self.info();
498 match self.info().dma {
499 #[cfg(dma)]
500 DmaInfo::Dma(r) => {
501 // Disable the channel without overwriting the existing configuration
502 r.st(info.num).cr().modify(|w| {
503 w.set_en(false);
504 });
505 }
506 #[cfg(bdma)]
507 DmaInfo::Bdma(r) => {
508 // Disable the channel without overwriting the existing configuration
509 r.ch(info.num).cr().modify(|w| {
510 w.set_en(false);
511 });
512 }
513 }
514 }
515
496 fn is_running(&self) -> bool { 516 fn is_running(&self) -> bool {
497 let info = self.info(); 517 let info = self.info();
498 match self.info().dma { 518 match self.info().dma {
@@ -667,12 +687,22 @@ impl<'a> Transfer<'a> {
667 } 687 }
668 688
669 /// Request the transfer to stop. 689 /// Request the transfer to stop.
690 /// The configuration for this channel will **not be preserved**. If you need to restart the transfer
691 /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead.
670 /// 692 ///
671 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. 693 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
672 pub fn request_stop(&mut self) { 694 pub fn request_stop(&mut self) {
673 self.channel.request_stop() 695 self.channel.request_stop()
674 } 696 }
675 697
698 /// Request the transfer to pause, keeping the existing configuration for this channel.
699 /// To restart the transfer, call [`start`](Self::start) again.
700 ///
701 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
702 pub fn request_pause(&mut self) {
703 self.channel.request_pause()
704 }
705
676 /// Return whether this transfer is still running. 706 /// Return whether this transfer is still running.
677 /// 707 ///
678 /// If this returns `false`, it can be because either the transfer finished, or 708 /// If this returns `false`, it can be because either the transfer finished, or
@@ -846,13 +876,23 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
846 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 876 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
847 } 877 }
848 878
849 /// Request DMA to stop. 879 /// Request the DMA to stop.
880 /// The configuration for this channel will **not be preserved**. If you need to restart the transfer
881 /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead.
850 /// 882 ///
851 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. 883 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
852 pub fn request_stop(&mut self) { 884 pub fn request_stop(&mut self) {
853 self.channel.request_stop() 885 self.channel.request_stop()
854 } 886 }
855 887
888 /// Request the transfer to pause, keeping the existing configuration for this channel.
889 /// To restart the transfer, call [`start`](Self::start) again.
890 ///
891 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
892 pub fn request_pause(&mut self) {
893 self.channel.request_pause()
894 }
895
856 /// Return whether DMA is still running. 896 /// Return whether DMA is still running.
857 /// 897 ///
858 /// If this returns `false`, it can be because either the transfer finished, or 898 /// If this returns `false`, it can be because either the transfer finished, or
@@ -977,13 +1017,23 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
977 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 1017 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
978 } 1018 }
979 1019
980 /// Request DMA to stop. 1020 /// Request the DMA to stop.
1021 /// The configuration for this channel will **not be preserved**. If you need to restart the transfer
1022 /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead.
981 /// 1023 ///
982 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. 1024 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
983 pub fn request_stop(&mut self) { 1025 pub fn request_stop(&mut self) {
984 self.channel.request_stop() 1026 self.channel.request_stop()
985 } 1027 }
986 1028
1029 /// Request the transfer to pause, keeping the existing configuration for this channel.
1030 /// To restart the transfer, call [`start`](Self::start) again.
1031 ///
1032 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
1033 pub fn request_pause(&mut self) {
1034 self.channel.request_pause()
1035 }
1036
987 /// Return whether DMA is still running. 1037 /// Return whether DMA is still running.
988 /// 1038 ///
989 /// If this returns `false`, it can be because either the transfer finished, or 1039 /// If this returns `false`, it can be because either the transfer finished, or
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index f9d66ca86..a877bb8d4 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -216,7 +216,10 @@ impl<'a> Transfer<'a> {
216 data_size: WordSize, 216 data_size: WordSize,
217 _options: TransferOptions, 217 _options: TransferOptions,
218 ) -> Self { 218 ) -> Self {
219 assert!(mem_len > 0 && mem_len <= 0xFFFF); 219 // BNDT is specified as bytes, not as number of transfers.
220 let Ok(bndt) = (mem_len * data_size.bytes()).try_into() else {
221 panic!("DMA transfers may not be larger than 65535 bytes.");
222 };
220 223
221 let info = channel.info(); 224 let info = channel.info();
222 let ch = info.dma.ch(info.num); 225 let ch = info.dma.ch(info.num);
@@ -226,9 +229,6 @@ impl<'a> Transfer<'a> {
226 229
227 let this = Self { channel }; 230 let this = Self { channel };
228 231
229 #[cfg(dmamux)]
230 super::dmamux::configure_dmamux(&*this.channel, request);
231
232 ch.cr().write(|w| w.set_reset(true)); 232 ch.cr().write(|w| w.set_reset(true));
233 ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs 233 ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs
234 ch.llr().write(|_| {}); // no linked list 234 ch.llr().write(|_| {}); // no linked list
@@ -245,10 +245,8 @@ impl<'a> Transfer<'a> {
245 }); 245 });
246 w.set_reqsel(request); 246 w.set_reqsel(request);
247 }); 247 });
248 ch.br1().write(|w| { 248 ch.tr3().write(|_| {}); // no address offsets.
249 // BNDT is specified as bytes, not as number of transfers. 249 ch.br1().write(|w| w.set_bndt(bndt));
250 w.set_bndt((mem_len * data_size.bytes()) as u16)
251 });
252 250
253 match dir { 251 match dir {
254 Dir::MemoryToPeripheral => { 252 Dir::MemoryToPeripheral => {
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index bfe8a60d6..6442176da 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -177,6 +177,20 @@ pub unsafe trait PHY {
177 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool; 177 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool;
178} 178}
179 179
180impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
181 /// Directly expose the SMI interface used by the Ethernet driver.
182 ///
183 /// This can be used to for example configure special PHY registers for compliance testing.
184 ///
185 /// # Safety
186 ///
187 /// Revert any temporary PHY register changes such as to enable test modes before handing
188 /// the Ethernet device over to the networking stack otherwise things likely won't work.
189 pub unsafe fn station_management(&mut self) -> &mut impl StationManagement {
190 &mut self.station_management
191 }
192}
193
180trait SealedInstance { 194trait SealedInstance {
181 fn regs() -> crate::pac::eth::Eth; 195 fn regs() -> crate::pac::eth::Eth;
182} 196}
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 376a0b454..55fe8ca9d 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -34,8 +34,10 @@ pub enum VoltageScale {
34 Scale2, 34 Scale2,
35 Scale3, 35 Scale3,
36} 36}
37#[cfg(any(stm32h7rs))] 37#[cfg(stm32h7rs)]
38pub use crate::pac::pwr::vals::Vos as VoltageScale; 38pub use crate::pac::pwr::vals::Vos as VoltageScale;
39#[cfg(all(stm32h7rs, peri_usb_otg_hs))]
40pub use crate::pac::rcc::vals::{Usbphycsel, Usbrefcksel};
39 41
40#[derive(Clone, Copy, Eq, PartialEq)] 42#[derive(Clone, Copy, Eq, PartialEq)]
41pub enum HseMode { 43pub enum HseMode {
@@ -557,6 +559,27 @@ pub(crate) unsafe fn init(config: Config) {
557 559
558 let rtc = config.ls.init(); 560 let rtc = config.ls.init();
559 561
562 #[cfg(all(stm32h7rs, peri_usb_otg_hs))]
563 let usb_refck = match config.mux.usbphycsel {
564 Usbphycsel::HSE => hse,
565 Usbphycsel::HSE_DIV_2 => hse.map(|hse_val| hse_val / 2u8),
566 Usbphycsel::PLL3_Q => pll3.q,
567 _ => None,
568 };
569 #[cfg(all(stm32h7rs, peri_usb_otg_hs))]
570 let usb_refck_sel = match usb_refck {
571 Some(clk_val) => match clk_val {
572 Hertz(16_000_000) => Usbrefcksel::MHZ16,
573 Hertz(19_200_000) => Usbrefcksel::MHZ19_2,
574 Hertz(20_000_000) => Usbrefcksel::MHZ20,
575 Hertz(24_000_000) => Usbrefcksel::MHZ24,
576 Hertz(26_000_000) => Usbrefcksel::MHZ26,
577 Hertz(32_000_000) => Usbrefcksel::MHZ32,
578 _ => panic!("cannot select USBPHYC reference clock with source frequency of {} Hz, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val),
579 },
580 None => Usbrefcksel::MHZ24,
581 };
582
560 #[cfg(stm32h7)] 583 #[cfg(stm32h7)]
561 { 584 {
562 RCC.d1cfgr().modify(|w| { 585 RCC.d1cfgr().modify(|w| {
@@ -593,6 +616,11 @@ pub(crate) unsafe fn init(config: Config) {
593 w.set_ppre4(config.apb4_pre); 616 w.set_ppre4(config.apb4_pre);
594 w.set_ppre5(config.apb5_pre); 617 w.set_ppre5(config.apb5_pre);
595 }); 618 });
619
620 #[cfg(peri_usb_otg_hs)]
621 RCC.ahbperckselr().modify(|w| {
622 w.set_usbrefcksel(usb_refck_sel);
623 });
596 } 624 }
597 #[cfg(stm32h5)] 625 #[cfg(stm32h5)]
598 { 626 {
@@ -698,7 +726,9 @@ pub(crate) unsafe fn init(config: Config) {
698 #[cfg(stm32h7rs)] 726 #[cfg(stm32h7rs)]
699 clk48mohci: None, // TODO 727 clk48mohci: None, // TODO
700 #[cfg(stm32h7rs)] 728 #[cfg(stm32h7rs)]
701 usb: None, // TODO 729 hse_div_2: hse.map(|clk| clk / 2u32),
730 #[cfg(stm32h7rs)]
731 usb: Some(Hertz(48_000_000)),
702 ); 732 );
703} 733}
704 734
@@ -769,7 +799,7 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
769 if num == 0 { 799 if num == 0 {
770 // on PLL1, DIVP must be even for most series. 800 // on PLL1, DIVP must be even for most series.
771 // The enum value is 1 less than the divider, so check it's odd. 801 // The enum value is 1 less than the divider, so check it's odd.
772 #[cfg(not(pwr_h7rm0468))] 802 #[cfg(not(any(pwr_h7rm0468, stm32h7rs)))]
773 assert!(div.to_bits() % 2 == 1); 803 assert!(div.to_bits() % 2 == 1);
774 #[cfg(pwr_h7rm0468)] 804 #[cfg(pwr_h7rm0468)]
775 assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0); 805 assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0);
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 20718147a..d034c028e 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -311,51 +311,29 @@ impl<'d, M: PeriMode> Spi<'d, M> {
311 } 311 }
312 } 312 }
313 313
314 /// Set SPI word size. Disables SPI if needed, you have to enable it back yourself.
314 fn set_word_size(&mut self, word_size: word_impl::Config) { 315 fn set_word_size(&mut self, word_size: word_impl::Config) {
315 if self.current_word_size == word_size { 316 if self.current_word_size == word_size {
316 return; 317 return;
317 } 318 }
318 319
320 self.info.regs.cr1().modify(|w| {
321 w.set_spe(false);
322 });
323
319 #[cfg(any(spi_v1, spi_f1))] 324 #[cfg(any(spi_v1, spi_f1))]
320 { 325 self.info.regs.cr1().modify(|reg| {
321 self.info.regs.cr1().modify(|reg| { 326 reg.set_dff(word_size);
322 reg.set_spe(false); 327 });
323 reg.set_dff(word_size)
324 });
325 self.info.regs.cr1().modify(|reg| {
326 reg.set_spe(true);
327 });
328 }
329 #[cfg(spi_v2)] 328 #[cfg(spi_v2)]
330 { 329 self.info.regs.cr2().modify(|w| {
331 self.info.regs.cr1().modify(|w| { 330 w.set_frxth(word_size.1);
332 w.set_spe(false); 331 w.set_ds(word_size.0);
333 }); 332 });
334 self.info.regs.cr2().modify(|w| {
335 w.set_frxth(word_size.1);
336 w.set_ds(word_size.0);
337 });
338 self.info.regs.cr1().modify(|w| {
339 w.set_spe(true);
340 });
341 }
342 #[cfg(any(spi_v3, spi_v4, spi_v5))] 333 #[cfg(any(spi_v3, spi_v4, spi_v5))]
343 { 334 self.info.regs.cfg1().modify(|w| {
344 self.info.regs.cr1().modify(|w| { 335 w.set_dsize(word_size);
345 w.set_csusp(true); 336 });
346 });
347 while self.info.regs.sr().read().eot() {}
348 self.info.regs.cr1().modify(|w| {
349 w.set_spe(false);
350 });
351 self.info.regs.cfg1().modify(|w| {
352 w.set_dsize(word_size);
353 });
354 self.info.regs.cr1().modify(|w| {
355 w.set_csusp(false);
356 w.set_spe(true);
357 });
358 }
359 337
360 self.current_word_size = word_size; 338 self.current_word_size = word_size;
361 } 339 }
@@ -365,9 +343,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
365 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 343 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
366 #[cfg(any(spi_v3, spi_v4, spi_v5))] 344 #[cfg(any(spi_v3, spi_v4, spi_v5))]
367 self.info.regs.cr1().modify(|w| w.set_spe(false)); 345 self.info.regs.cr1().modify(|w| w.set_spe(false));
346 self.set_word_size(W::CONFIG);
368 self.info.regs.cr1().modify(|w| w.set_spe(true)); 347 self.info.regs.cr1().modify(|w| w.set_spe(true));
369 flush_rx_fifo(self.info.regs); 348 flush_rx_fifo(self.info.regs);
370 self.set_word_size(W::CONFIG);
371 for word in words.iter() { 349 for word in words.iter() {
372 // this cannot use `transfer_word` because on SPIv2 and higher, 350 // this cannot use `transfer_word` because on SPIv2 and higher,
373 // the SPI RX state machine hangs if no physical pin is connected to the SCK AF. 351 // the SPI RX state machine hangs if no physical pin is connected to the SCK AF.
@@ -402,9 +380,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
402 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 380 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
403 #[cfg(any(spi_v3, spi_v4, spi_v5))] 381 #[cfg(any(spi_v3, spi_v4, spi_v5))]
404 self.info.regs.cr1().modify(|w| w.set_spe(false)); 382 self.info.regs.cr1().modify(|w| w.set_spe(false));
383 self.set_word_size(W::CONFIG);
405 self.info.regs.cr1().modify(|w| w.set_spe(true)); 384 self.info.regs.cr1().modify(|w| w.set_spe(true));
406 flush_rx_fifo(self.info.regs); 385 flush_rx_fifo(self.info.regs);
407 self.set_word_size(W::CONFIG);
408 for word in words.iter_mut() { 386 for word in words.iter_mut() {
409 *word = transfer_word(self.info.regs, W::default())?; 387 *word = transfer_word(self.info.regs, W::default())?;
410 } 388 }
@@ -418,9 +396,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
418 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 396 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
419 #[cfg(any(spi_v3, spi_v4, spi_v5))] 397 #[cfg(any(spi_v3, spi_v4, spi_v5))]
420 self.info.regs.cr1().modify(|w| w.set_spe(false)); 398 self.info.regs.cr1().modify(|w| w.set_spe(false));
399 self.set_word_size(W::CONFIG);
421 self.info.regs.cr1().modify(|w| w.set_spe(true)); 400 self.info.regs.cr1().modify(|w| w.set_spe(true));
422 flush_rx_fifo(self.info.regs); 401 flush_rx_fifo(self.info.regs);
423 self.set_word_size(W::CONFIG);
424 for word in words.iter_mut() { 402 for word in words.iter_mut() {
425 *word = transfer_word(self.info.regs, *word)?; 403 *word = transfer_word(self.info.regs, *word)?;
426 } 404 }
@@ -437,9 +415,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
437 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 415 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
438 #[cfg(any(spi_v3, spi_v4, spi_v5))] 416 #[cfg(any(spi_v3, spi_v4, spi_v5))]
439 self.info.regs.cr1().modify(|w| w.set_spe(false)); 417 self.info.regs.cr1().modify(|w| w.set_spe(false));
418 self.set_word_size(W::CONFIG);
440 self.info.regs.cr1().modify(|w| w.set_spe(true)); 419 self.info.regs.cr1().modify(|w| w.set_spe(true));
441 flush_rx_fifo(self.info.regs); 420 flush_rx_fifo(self.info.regs);
442 self.set_word_size(W::CONFIG);
443 let len = read.len().max(write.len()); 421 let len = read.len().max(write.len());
444 for i in 0..len { 422 for i in 0..len {
445 let wb = write.get(i).copied().unwrap_or_default(); 423 let wb = write.get(i).copied().unwrap_or_default();
@@ -648,10 +626,10 @@ impl<'d> Spi<'d, Async> {
648 return Ok(()); 626 return Ok(());
649 } 627 }
650 628
651 self.set_word_size(W::CONFIG);
652 self.info.regs.cr1().modify(|w| { 629 self.info.regs.cr1().modify(|w| {
653 w.set_spe(false); 630 w.set_spe(false);
654 }); 631 });
632 self.set_word_size(W::CONFIG);
655 633
656 let tx_dst = self.info.regs.tx_ptr(); 634 let tx_dst = self.info.regs.tx_ptr();
657 let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) }; 635 let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) };
@@ -685,6 +663,8 @@ impl<'d> Spi<'d, Async> {
685 w.set_spe(false); 663 w.set_spe(false);
686 }); 664 });
687 665
666 self.set_word_size(W::CONFIG);
667
688 let comm = regs.cfg2().modify(|w| { 668 let comm = regs.cfg2().modify(|w| {
689 let prev = w.comm(); 669 let prev = w.comm();
690 w.set_comm(vals::Comm::RECEIVER); 670 w.set_comm(vals::Comm::RECEIVER);
@@ -707,7 +687,6 @@ impl<'d> Spi<'d, Async> {
707 let rx_src = regs.rx_ptr(); 687 let rx_src = regs.rx_ptr();
708 688
709 for mut chunk in data.chunks_mut(u16::max_value().into()) { 689 for mut chunk in data.chunks_mut(u16::max_value().into()) {
710 self.set_word_size(W::CONFIG);
711 set_rxdmaen(regs, true); 690 set_rxdmaen(regs, true);
712 691
713 let tsize = chunk.len(); 692 let tsize = chunk.len();
@@ -765,12 +744,12 @@ impl<'d> Spi<'d, Async> {
765 return Ok(()); 744 return Ok(());
766 } 745 }
767 746
768 self.set_word_size(W::CONFIG);
769
770 self.info.regs.cr1().modify(|w| { 747 self.info.regs.cr1().modify(|w| {
771 w.set_spe(false); 748 w.set_spe(false);
772 }); 749 });
773 750
751 self.set_word_size(W::CONFIG);
752
774 // SPIv3 clears rxfifo on SPE=0 753 // SPIv3 clears rxfifo on SPE=0
775 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 754 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
776 flush_rx_fifo(self.info.regs); 755 flush_rx_fifo(self.info.regs);
@@ -783,7 +762,7 @@ impl<'d> Spi<'d, Async> {
783 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) }; 762 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) };
784 763
785 let tx_dst = self.info.regs.tx_ptr(); 764 let tx_dst = self.info.regs.tx_ptr();
786 let clock_byte = 0x00u8; 765 let clock_byte = W::default();
787 let tx_f = unsafe { 766 let tx_f = unsafe {
788 self.tx_dma 767 self.tx_dma
789 .as_mut() 768 .as_mut()
@@ -813,11 +792,12 @@ impl<'d> Spi<'d, Async> {
813 return Ok(()); 792 return Ok(());
814 } 793 }
815 794
816 self.set_word_size(W::CONFIG);
817 self.info.regs.cr1().modify(|w| { 795 self.info.regs.cr1().modify(|w| {
818 w.set_spe(false); 796 w.set_spe(false);
819 }); 797 });
820 798
799 self.set_word_size(W::CONFIG);
800
821 // SPIv3 clears rxfifo on SPE=0 801 // SPIv3 clears rxfifo on SPE=0
822 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 802 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
823 flush_rx_fifo(self.info.regs); 803 flush_rx_fifo(self.info.regs);
@@ -1195,7 +1175,7 @@ trait SealedWord {
1195 1175
1196/// Word sizes usable for SPI. 1176/// Word sizes usable for SPI.
1197#[allow(private_bounds)] 1177#[allow(private_bounds)]
1198pub trait Word: word::Word + SealedWord {} 1178pub trait Word: word::Word + SealedWord + Default {}
1199 1179
1200macro_rules! impl_word { 1180macro_rules! impl_word {
1201 ($T:ty, $config:expr) => { 1181 ($T:ty, $config:expr) => {
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index b0652046c..75834bf37 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -71,34 +71,19 @@ impl<'d> UartRx<'d, Async> {
71} 71}
72 72
73impl<'d> RingBufferedUartRx<'d> { 73impl<'d> RingBufferedUartRx<'d> {
74 /// Clear the ring buffer and start receiving in the background
75 pub fn start(&mut self) -> Result<(), Error> {
76 // Clear the ring buffer so that it is ready to receive data
77 self.ring_buf.clear();
78
79 self.setup_uart();
80
81 Ok(())
82 }
83
84 fn stop(&mut self, err: Error) -> Result<usize, Error> {
85 self.teardown_uart();
86
87 Err(err)
88 }
89
90 /// Reconfigure the driver 74 /// Reconfigure the driver
91 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 75 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
92 reconfigure(self.info, self.kernel_clock, config) 76 reconfigure(self.info, self.kernel_clock, config)
93 } 77 }
94 78
95 /// Start uart background receive 79 /// Configure and start the DMA backed UART receiver
96 fn setup_uart(&mut self) { 80 ///
97 // fence before starting DMA. 81 /// Note: This is also done automatically by [`read()`] if required.
82 pub fn start_uart(&mut self) {
83 // Clear the buffer so that it is ready to receive data
98 compiler_fence(Ordering::SeqCst); 84 compiler_fence(Ordering::SeqCst);
99
100 // start the dma controller
101 self.ring_buf.start(); 85 self.ring_buf.start();
86 self.ring_buf.clear();
102 87
103 let r = self.info.regs; 88 let r = self.info.regs;
104 // clear all interrupts and DMA Rx Request 89 // clear all interrupts and DMA Rx Request
@@ -118,9 +103,9 @@ impl<'d> RingBufferedUartRx<'d> {
118 }); 103 });
119 } 104 }
120 105
121 /// Stop uart background receive 106 /// Stop DMA backed UART receiver
122 fn teardown_uart(&mut self) { 107 fn stop_uart(&mut self) {
123 self.ring_buf.request_stop(); 108 self.ring_buf.request_pause();
124 109
125 let r = self.info.regs; 110 let r = self.info.regs;
126 // clear all interrupts and DMA Rx Request 111 // clear all interrupts and DMA Rx Request
@@ -153,13 +138,15 @@ impl<'d> RingBufferedUartRx<'d> {
153 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 138 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
154 let r = self.info.regs; 139 let r = self.info.regs;
155 140
156 // Start background receive if it was not already started 141 // Start DMA and Uart if it was not already started,
142 // otherwise check for errors in status register.
143 let sr = clear_idle_flag(r);
157 if !r.cr3().read().dmar() { 144 if !r.cr3().read().dmar() {
158 self.start()?; 145 self.start_uart();
146 } else {
147 check_for_errors(sr)?;
159 } 148 }
160 149
161 check_for_errors(clear_idle_flag(r))?;
162
163 loop { 150 loop {
164 match self.ring_buf.read(buf) { 151 match self.ring_buf.read(buf) {
165 Ok((0, _)) => {} 152 Ok((0, _)) => {}
@@ -167,14 +154,16 @@ impl<'d> RingBufferedUartRx<'d> {
167 return Ok(len); 154 return Ok(len);
168 } 155 }
169 Err(_) => { 156 Err(_) => {
170 return self.stop(Error::Overrun); 157 self.stop_uart();
158 return Err(Error::Overrun);
171 } 159 }
172 } 160 }
173 161
174 match self.wait_for_data_or_idle().await { 162 match self.wait_for_data_or_idle().await {
175 Ok(_) => {} 163 Ok(_) => {}
176 Err(err) => { 164 Err(err) => {
177 return self.stop(err); 165 self.stop_uart();
166 return Err(err);
178 } 167 }
179 } 168 }
180 } 169 }
@@ -228,7 +217,7 @@ impl<'d> RingBufferedUartRx<'d> {
228 217
229impl Drop for RingBufferedUartRx<'_> { 218impl Drop for RingBufferedUartRx<'_> {
230 fn drop(&mut self) { 219 fn drop(&mut self) {
231 self.teardown_uart(); 220 self.stop_uart();
232 self.rx.as_ref().map(|x| x.set_as_disconnected()); 221 self.rx.as_ref().map(|x| x.set_as_disconnected());
233 self.rts.as_ref().map(|x| x.set_as_disconnected()); 222 self.rts.as_ref().map(|x| x.set_as_disconnected());
234 super::drop_tx_rx(self.info, self.state); 223 super::drop_tx_rx(self.info, self.state);
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index ce9fe0a9b..a473285bf 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -13,9 +13,19 @@ fn common_init<T: Instance>() {
13 // Check the USB clock is enabled and running at exactly 48 MHz. 13 // Check the USB clock is enabled and running at exactly 48 MHz.
14 // frequency() will panic if not enabled 14 // frequency() will panic if not enabled
15 let freq = T::frequency(); 15 let freq = T::frequency();
16
17 // On the H7RS, the USBPHYC embeds a PLL accepting one of the input frequencies listed below and providing 48MHz to OTG_FS and 60MHz to OTG_HS internally
18 #[cfg(stm32h7rs)]
19 if ![16_000_000, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&freq.0) {
20 panic!(
21 "USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but is {} Hz. Please double-check your RCC settings.",
22 freq.0
23 )
24 }
16 // Check frequency is within the 0.25% tolerance allowed by the spec. 25 // Check frequency is within the 0.25% tolerance allowed by the spec.
17 // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user 26 // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user
18 // has tight clock restrictions due to something else (like audio). 27 // has tight clock restrictions due to something else (like audio).
28 #[cfg(not(stm32h7rs))]
19 if freq.0.abs_diff(48_000_000) > 120_000 { 29 if freq.0.abs_diff(48_000_000) > 120_000 {
20 panic!( 30 panic!(
21 "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.", 31 "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.",
@@ -48,6 +58,26 @@ fn common_init<T: Instance>() {
48 while !crate::pac::PWR.cr3().read().usb33rdy() {} 58 while !crate::pac::PWR.cr3().read().usb33rdy() {}
49 } 59 }
50 60
61 #[cfg(stm32h7rs)]
62 {
63 // If true, VDD33USB is generated by internal regulator from VDD50USB
64 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
65 // TODO: unhardcode
66 let internal_regulator = false;
67
68 // Enable USB power
69 critical_section::with(|_| {
70 crate::pac::PWR.csr2().modify(|w| {
71 w.set_usbregen(internal_regulator);
72 w.set_usb33den(true);
73 w.set_usbhsregen(true);
74 })
75 });
76
77 // Wait for USB power to stabilize
78 while !crate::pac::PWR.csr2().read().usb33rdy() {}
79 }
80
51 #[cfg(stm32u5)] 81 #[cfg(stm32u5)]
52 { 82 {
53 // Enable USB power 83 // Enable USB power
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index e27b164e4..00cafe6e4 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -97,6 +97,45 @@ impl<'d, T: Instance> Driver<'d, T> {
97 } 97 }
98 } 98 }
99 99
100 /// Initializes USB OTG peripheral with internal High-Speed PHY.
101 ///
102 /// # Arguments
103 ///
104 /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
105 /// Must be large enough to fit all OUT endpoint max packet sizes.
106 /// Endpoint allocation will fail if it is too small.
107 pub fn new_hs(
108 _peri: impl Peripheral<P = T> + 'd,
109 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
110 dp: impl Peripheral<P = impl DpPin<T>> + 'd,
111 dm: impl Peripheral<P = impl DmPin<T>> + 'd,
112 ep_out_buffer: &'d mut [u8],
113 config: Config,
114 ) -> Self {
115 into_ref!(dp, dm);
116
117 dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
118 dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
119
120 let regs = T::regs();
121
122 let instance = OtgInstance {
123 regs,
124 state: T::state(),
125 fifo_depth_words: T::FIFO_DEPTH_WORDS,
126 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
127 endpoint_count: T::ENDPOINT_COUNT,
128 phy_type: PhyType::InternalHighSpeed,
129 quirk_setup_late_cnak: quirk_setup_late_cnak(regs),
130 calculate_trdt_fn: calculate_trdt::<T>,
131 };
132
133 Self {
134 inner: OtgDriver::new(ep_out_buffer, instance, config),
135 phantom: PhantomData,
136 }
137 }
138
100 /// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode). 139 /// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode).
101 /// 140 ///
102 /// # Arguments 141 /// # Arguments
@@ -272,6 +311,19 @@ impl<'d, T: Instance> Bus<'d, T> {
272 } 311 }
273 }); 312 });
274 313
314 #[cfg(stm32h7rs)]
315 critical_section::with(|_| {
316 let rcc = crate::pac::RCC;
317 rcc.ahb1enr().modify(|w| {
318 w.set_usbphycen(true);
319 w.set_usb_otg_hsen(true);
320 });
321 rcc.ahb1lpenr().modify(|w| {
322 w.set_usbphyclpen(true);
323 w.set_usb_otg_hslpen(true);
324 });
325 });
326
275 let r = T::regs(); 327 let r = T::regs();
276 let core_id = r.cid().read().0; 328 let core_id = r.cid().read().0;
277 trace!("Core id {:08x}", core_id); 329 trace!("Core id {:08x}", core_id);
@@ -286,6 +338,7 @@ impl<'d, T: Instance> Bus<'d, T> {
286 match core_id { 338 match core_id {
287 0x0000_1200 | 0x0000_1100 => self.inner.config_v1(), 339 0x0000_1200 | 0x0000_1100 => self.inner.config_v1(),
288 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(), 340 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(),
341 0x0000_5000 => self.inner.config_v5(),
289 _ => unimplemented!("Unknown USB core id {:X}", core_id), 342 _ => unimplemented!("Unknown USB core id {:X}", core_id),
290 } 343 }
291 } 344 }
@@ -501,7 +554,7 @@ fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 {
501 match speed { 554 match speed {
502 Dspd::HIGH_SPEED => { 555 Dspd::HIGH_SPEED => {
503 // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446) 556 // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446)
504 if ahb_freq >= 30_000_000 { 557 if ahb_freq >= 30_000_000 || cfg!(stm32h7rs) {
505 0x9 558 0x9
506 } else { 559 } else {
507 panic!("AHB frequency is too low") 560 panic!("AHB frequency is too low")
diff --git a/embassy-sync/src/pubsub/mod.rs b/embassy-sync/src/pubsub/mod.rs
index a97eb7d5b..812302e2b 100644
--- a/embassy-sync/src/pubsub/mod.rs
+++ b/embassy-sync/src/pubsub/mod.rs
@@ -194,6 +194,25 @@ impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usi
194 } 194 }
195} 195}
196 196
197impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> crate::pubsub::PubSubBehavior<T>
198 for PubSubChannel<M, T, CAP, SUBS, PUBS>
199{
200 fn publish_immediate(&self, message: T) {
201 self.inner.lock(|s| {
202 let mut s = s.borrow_mut();
203 s.publish_immediate(message)
204 })
205 }
206
207 fn capacity(&self) -> usize {
208 self.capacity()
209 }
210
211 fn is_full(&self) -> bool {
212 self.is_full()
213 }
214}
215
197impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> SealedPubSubBehavior<T> 216impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> SealedPubSubBehavior<T>
198 for PubSubChannel<M, T, CAP, SUBS, PUBS> 217 for PubSubChannel<M, T, CAP, SUBS, PUBS>
199{ 218{
@@ -246,13 +265,6 @@ impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usi
246 }) 265 })
247 } 266 }
248 267
249 fn publish_immediate(&self, message: T) {
250 self.inner.lock(|s| {
251 let mut s = s.borrow_mut();
252 s.publish_immediate(message)
253 })
254 }
255
256 fn unregister_subscriber(&self, subscriber_next_message_id: u64) { 268 fn unregister_subscriber(&self, subscriber_next_message_id: u64) {
257 self.inner.lock(|s| { 269 self.inner.lock(|s| {
258 let mut s = s.borrow_mut(); 270 let mut s = s.borrow_mut();
@@ -267,10 +279,6 @@ impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usi
267 }) 279 })
268 } 280 }
269 281
270 fn capacity(&self) -> usize {
271 self.capacity()
272 }
273
274 fn free_capacity(&self) -> usize { 282 fn free_capacity(&self) -> usize {
275 self.free_capacity() 283 self.free_capacity()
276 } 284 }
@@ -286,10 +294,6 @@ impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usi
286 fn is_empty(&self) -> bool { 294 fn is_empty(&self) -> bool {
287 self.is_empty() 295 self.is_empty()
288 } 296 }
289
290 fn is_full(&self) -> bool {
291 self.is_full()
292 }
293} 297}
294 298
295/// Internal state for the PubSub channel 299/// Internal state for the PubSub channel
@@ -445,8 +449,6 @@ pub enum Error {
445 MaximumPublishersReached, 449 MaximumPublishersReached,
446} 450}
447 451
448/// 'Middle level' behaviour of the pubsub channel.
449/// This trait is used so that Sub and Pub can be generic over the channel.
450trait SealedPubSubBehavior<T> { 452trait SealedPubSubBehavior<T> {
451 /// Try to get a message from the queue with the given message id. 453 /// Try to get a message from the queue with the given message id.
452 /// 454 ///
@@ -462,12 +464,6 @@ trait SealedPubSubBehavior<T> {
462 /// If the queue is full and a context is given, then its waker is registered in the publisher wakers. 464 /// If the queue is full and a context is given, then its waker is registered in the publisher wakers.
463 fn publish_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), T>; 465 fn publish_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), T>;
464 466
465 /// Publish a message immediately
466 fn publish_immediate(&self, message: T);
467
468 /// Returns the maximum number of elements the channel can hold.
469 fn capacity(&self) -> usize;
470
471 /// Returns the free capacity of the channel. 467 /// Returns the free capacity of the channel.
472 /// 468 ///
473 /// This is equivalent to `capacity() - len()` 469 /// This is equivalent to `capacity() - len()`
@@ -482,9 +478,6 @@ trait SealedPubSubBehavior<T> {
482 /// Returns whether the channel is empty. 478 /// Returns whether the channel is empty.
483 fn is_empty(&self) -> bool; 479 fn is_empty(&self) -> bool;
484 480
485 /// Returns whether the channel is full.
486 fn is_full(&self) -> bool;
487
488 /// Let the channel know that a subscriber has dropped 481 /// Let the channel know that a subscriber has dropped
489 fn unregister_subscriber(&self, subscriber_next_message_id: u64); 482 fn unregister_subscriber(&self, subscriber_next_message_id: u64);
490 483
@@ -495,9 +488,16 @@ trait SealedPubSubBehavior<T> {
495/// 'Middle level' behaviour of the pubsub channel. 488/// 'Middle level' behaviour of the pubsub channel.
496/// This trait is used so that Sub and Pub can be generic over the channel. 489/// This trait is used so that Sub and Pub can be generic over the channel.
497#[allow(private_bounds)] 490#[allow(private_bounds)]
498pub trait PubSubBehavior<T>: SealedPubSubBehavior<T> {} 491pub trait PubSubBehavior<T>: SealedPubSubBehavior<T> {
492 /// Publish a message immediately
493 fn publish_immediate(&self, message: T);
499 494
500impl<T, C: SealedPubSubBehavior<T>> PubSubBehavior<T> for C {} 495 /// Returns the maximum number of elements the channel can hold.
496 fn capacity(&self) -> usize;
497
498 /// Returns whether the channel is full.
499 fn is_full(&self) -> bool;
500}
501 501
502/// The result of the subscriber wait procedure 502/// The result of the subscriber wait procedure
503#[derive(Debug, Clone, PartialEq, Eq)] 503#[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs
index b145f4aa8..f90403936 100644
--- a/embassy-usb-synopsys-otg/src/lib.rs
+++ b/embassy-usb-synopsys-otg/src/lib.rs
@@ -584,6 +584,29 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> {
584 }); 584 });
585 } 585 }
586 586
587 /// Applies configuration specific to
588 /// Core ID 0x0000_5000
589 pub fn config_v5(&mut self) {
590 let r = self.instance.regs;
591 let phy_type = self.instance.phy_type;
592
593 if phy_type == PhyType::InternalHighSpeed {
594 r.gccfg_v3().modify(|w| {
595 w.set_vbvaloven(!self.config.vbus_detection);
596 w.set_vbvaloval(!self.config.vbus_detection);
597 w.set_vbden(self.config.vbus_detection);
598 });
599 } else {
600 r.gotgctl().modify(|w| {
601 w.set_bvaloen(!self.config.vbus_detection);
602 w.set_bvaloval(!self.config.vbus_detection);
603 });
604 r.gccfg_v3().modify(|w| {
605 w.set_vbden(self.config.vbus_detection);
606 });
607 }
608 }
609
587 fn init(&mut self) { 610 fn init(&mut self) {
588 let r = self.instance.regs; 611 let r = self.instance.regs;
589 let phy_type = self.instance.phy_type; 612 let phy_type = self.instance.phy_type;
diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs
index d3abc328d..18e760fd1 100644
--- a/embassy-usb-synopsys-otg/src/otg_v1.rs
+++ b/embassy-usb-synopsys-otg/src/otg_v1.rs
@@ -186,6 +186,11 @@ impl Otg {
186 pub const fn gccfg_v2(self) -> Reg<regs::GccfgV2, RW> { 186 pub const fn gccfg_v2(self) -> Reg<regs::GccfgV2, RW> {
187 unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) } 187 unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) }
188 } 188 }
189 #[doc = "General core configuration register, for core_id 0x0000_5xxx"]
190 #[inline(always)]
191 pub const fn gccfg_v3(self) -> Reg<regs::GccfgV3, RW> {
192 unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) }
193 }
189 #[doc = "Core ID register"] 194 #[doc = "Core ID register"]
190 #[inline(always)] 195 #[inline(always)]
191 pub const fn cid(self) -> Reg<regs::Cid, RW> { 196 pub const fn cid(self) -> Reg<regs::Cid, RW> {
@@ -1831,6 +1836,172 @@ pub mod regs {
1831 GccfgV2(0) 1836 GccfgV2(0)
1832 } 1837 }
1833 } 1838 }
1839 #[doc = "OTG general core configuration register."]
1840 #[repr(transparent)]
1841 #[derive(Copy, Clone, Eq, PartialEq)]
1842 pub struct GccfgV3(pub u32);
1843 impl GccfgV3 {
1844 #[doc = "Charger detection, result of the current mode (primary or secondary)."]
1845 #[inline(always)]
1846 pub const fn chgdet(&self) -> bool {
1847 let val = (self.0 >> 0usize) & 0x01;
1848 val != 0
1849 }
1850 #[doc = "Charger detection, result of the current mode (primary or secondary)."]
1851 #[inline(always)]
1852 pub fn set_chgdet(&mut self, val: bool) {
1853 self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize);
1854 }
1855 #[doc = "Single-Ended DP indicator This bit gives the voltage level on DP (also result of the comparison with V<sub>LGC</sub> threshold as defined in BC v1.2 standard)."]
1856 #[inline(always)]
1857 pub const fn fsvplus(&self) -> bool {
1858 let val = (self.0 >> 1usize) & 0x01;
1859 val != 0
1860 }
1861 #[doc = "Single-Ended DP indicator This bit gives the voltage level on DP (also result of the comparison with V<sub>LGC</sub> threshold as defined in BC v1.2 standard)."]
1862 #[inline(always)]
1863 pub fn set_fsvplus(&mut self, val: bool) {
1864 self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize);
1865 }
1866 #[doc = "Single-Ended DM indicator This bit gives the voltage level on DM (also result of the comparison with V<sub>LGC</sub> threshold as defined in BC v1.2 standard)."]
1867 #[inline(always)]
1868 pub const fn fsvminus(&self) -> bool {
1869 let val = (self.0 >> 2usize) & 0x01;
1870 val != 0
1871 }
1872 #[doc = "Single-Ended DM indicator This bit gives the voltage level on DM (also result of the comparison with V<sub>LGC</sub> threshold as defined in BC v1.2 standard)."]
1873 #[inline(always)]
1874 pub fn set_fsvminus(&mut self, val: bool) {
1875 self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize);
1876 }
1877 #[doc = "VBUS session indicator Indicates if VBUS is above VBUS session threshold."]
1878 #[inline(always)]
1879 pub const fn sessvld(&self) -> bool {
1880 let val = (self.0 >> 3usize) & 0x01;
1881 val != 0
1882 }
1883 #[doc = "VBUS session indicator Indicates if VBUS is above VBUS session threshold."]
1884 #[inline(always)]
1885 pub fn set_sessvld(&mut self, val: bool) {
1886 self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize);
1887 }
1888 #[doc = "Host CDP behavior enable."]
1889 #[inline(always)]
1890 pub const fn hcdpen(&self) -> bool {
1891 let val = (self.0 >> 16usize) & 0x01;
1892 val != 0
1893 }
1894 #[doc = "Host CDP behavior enable."]
1895 #[inline(always)]
1896 pub fn set_hcdpen(&mut self, val: bool) {
1897 self.0 = (self.0 & !(0x01 << 16usize)) | (((val as u32) & 0x01) << 16usize);
1898 }
1899 #[doc = "Host CDP port voltage detector enable on DP."]
1900 #[inline(always)]
1901 pub const fn hcdpdeten(&self) -> bool {
1902 let val = (self.0 >> 17usize) & 0x01;
1903 val != 0
1904 }
1905 #[doc = "Host CDP port voltage detector enable on DP."]
1906 #[inline(always)]
1907 pub fn set_hcdpdeten(&mut self, val: bool) {
1908 self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize);
1909 }
1910 #[doc = "Host CDP port Voltage source enable on DM."]
1911 #[inline(always)]
1912 pub const fn hvdmsrcen(&self) -> bool {
1913 let val = (self.0 >> 18usize) & 0x01;
1914 val != 0
1915 }
1916 #[doc = "Host CDP port Voltage source enable on DM."]
1917 #[inline(always)]
1918 pub fn set_hvdmsrcen(&mut self, val: bool) {
1919 self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize);
1920 }
1921 #[doc = "Data Contact Detection enable."]
1922 #[inline(always)]
1923 pub const fn dcden(&self) -> bool {
1924 let val = (self.0 >> 19usize) & 0x01;
1925 val != 0
1926 }
1927 #[doc = "Data Contact Detection enable."]
1928 #[inline(always)]
1929 pub fn set_dcden(&mut self, val: bool) {
1930 self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize);
1931 }
1932 #[doc = "Primary detection enable."]
1933 #[inline(always)]
1934 pub const fn pden(&self) -> bool {
1935 let val = (self.0 >> 20usize) & 0x01;
1936 val != 0
1937 }
1938 #[doc = "Primary detection enable."]
1939 #[inline(always)]
1940 pub fn set_pden(&mut self, val: bool) {
1941 self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize);
1942 }
1943 #[doc = "VBUS detection enable Enables VBUS Sensing Comparators in order to detect VBUS presence and/or perform OTG operation."]
1944 #[inline(always)]
1945 pub const fn vbden(&self) -> bool {
1946 let val = (self.0 >> 21usize) & 0x01;
1947 val != 0
1948 }
1949 #[doc = "VBUS detection enable Enables VBUS Sensing Comparators in order to detect VBUS presence and/or perform OTG operation."]
1950 #[inline(always)]
1951 pub fn set_vbden(&mut self, val: bool) {
1952 self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize);
1953 }
1954 #[doc = "Secondary detection enable."]
1955 #[inline(always)]
1956 pub const fn sden(&self) -> bool {
1957 let val = (self.0 >> 22usize) & 0x01;
1958 val != 0
1959 }
1960 #[doc = "Secondary detection enable."]
1961 #[inline(always)]
1962 pub fn set_sden(&mut self, val: bool) {
1963 self.0 = (self.0 & !(0x01 << 22usize)) | (((val as u32) & 0x01) << 22usize);
1964 }
1965 #[doc = "Software override value of the VBUS B-session detection."]
1966 #[inline(always)]
1967 pub const fn vbvaloval(&self) -> bool {
1968 let val = (self.0 >> 23usize) & 0x01;
1969 val != 0
1970 }
1971 #[doc = "Software override value of the VBUS B-session detection."]
1972 #[inline(always)]
1973 pub fn set_vbvaloval(&mut self, val: bool) {
1974 self.0 = (self.0 & !(0x01 << 23usize)) | (((val as u32) & 0x01) << 23usize);
1975 }
1976 #[doc = "Enables a software override of the VBUS B-session detection."]
1977 #[inline(always)]
1978 pub const fn vbvaloven(&self) -> bool {
1979 let val = (self.0 >> 24usize) & 0x01;
1980 val != 0
1981 }
1982 #[doc = "Enables a software override of the VBUS B-session detection."]
1983 #[inline(always)]
1984 pub fn set_vbvaloven(&mut self, val: bool) {
1985 self.0 = (self.0 & !(0x01 << 24usize)) | (((val as u32) & 0x01) << 24usize);
1986 }
1987 #[doc = "Force host mode pull-downs If the ID pin functions are enabled, the host mode pull-downs on DP and DM activate automatically. However, whenever that is not the case, yet host mode is required, this bit must be used to force the pull-downs active."]
1988 #[inline(always)]
1989 pub const fn forcehostpd(&self) -> bool {
1990 let val = (self.0 >> 25usize) & 0x01;
1991 val != 0
1992 }
1993 #[doc = "Force host mode pull-downs If the ID pin functions are enabled, the host mode pull-downs on DP and DM activate automatically. However, whenever that is not the case, yet host mode is required, this bit must be used to force the pull-downs active."]
1994 #[inline(always)]
1995 pub fn set_forcehostpd(&mut self, val: bool) {
1996 self.0 = (self.0 & !(0x01 << 25usize)) | (((val as u32) & 0x01) << 25usize);
1997 }
1998 }
1999 impl Default for GccfgV3 {
2000 #[inline(always)]
2001 fn default() -> GccfgV3 {
2002 GccfgV3(0)
2003 }
2004 }
1834 #[doc = "I2C access register"] 2005 #[doc = "I2C access register"]
1835 #[repr(transparent)] 2006 #[repr(transparent)]
1836 #[derive(Copy, Clone, Eq, PartialEq)] 2007 #[derive(Copy, Clone, Eq, PartialEq)]
diff --git a/examples/boot/application/nrf/build.rs b/examples/boot/application/nrf/build.rs
index cd1a264c4..e1da69328 100644
--- a/examples/boot/application/nrf/build.rs
+++ b/examples/boot/application/nrf/build.rs
@@ -31,4 +31,7 @@ fn main() {
31 31
32 println!("cargo:rustc-link-arg-bins=--nmagic"); 32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x"); 33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 if env::var("CARGO_FEATURE_DEFMT").is_ok() {
35 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
36 }
34} 37}
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs
index 851a3d721..2c1d1a7bb 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -2,6 +2,9 @@
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4 4
5#[cfg(feature = "defmt")]
6use defmt_rtt as _;
7use embassy_boot::State;
5use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; 8use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig};
6use embassy_embedded_hal::adapter::BlockingAsync; 9use embassy_embedded_hal::adapter::BlockingAsync;
7use embassy_executor::Spawner; 10use embassy_executor::Spawner;
@@ -22,6 +25,7 @@ async fn main(_spawner: Spawner) {
22 25
23 let mut button = Input::new(p.P0_11, Pull::Up); 26 let mut button = Input::new(p.P0_11, Pull::Up);
24 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); 27 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
28 let mut led_reverted = Output::new(p.P0_14, Level::High, OutputDrive::Standard);
25 29
26 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); 30 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
27 //let mut button = Input::new(p.P1_02, Pull::Up); 31 //let mut button = Input::new(p.P1_02, Pull::Up);
@@ -53,6 +57,13 @@ async fn main(_spawner: Spawner) {
53 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); 57 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc);
54 let mut magic = [0; 4]; 58 let mut magic = [0; 4];
55 let mut updater = FirmwareUpdater::new(config, &mut magic); 59 let mut updater = FirmwareUpdater::new(config, &mut magic);
60 let state = updater.get_state().await.unwrap();
61 if state == State::Revert {
62 led_reverted.set_low();
63 } else {
64 led_reverted.set_high();
65 }
66
56 loop { 67 loop {
57 led.set_low(); 68 led.set_low();
58 button.wait_for_any_edge().await; 69 button.wait_for_any_edge().await;
diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs
new file mode 100644
index 000000000..5076101ec
--- /dev/null
+++ b/examples/rp/src/bin/pio_onewire.rs
@@ -0,0 +1,155 @@
1//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor.
2
3#![no_std]
4#![no_main]
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::bind_interrupts;
8use embassy_rp::peripherals::PIO0;
9use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 PIO0_IRQ_0 => InterruptHandler<PIO0>;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_rp::init(Default::default());
20 let mut pio = Pio::new(p.PIO0, Irqs);
21 let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2);
22
23 loop {
24 sensor.start().await; // Start a new measurement
25 Timer::after_secs(1).await; // Allow 1s for the measurement to finish
26 match sensor.temperature().await {
27 Ok(temp) => info!("temp = {:?} deg C", temp),
28 _ => error!("sensor error"),
29 }
30 Timer::after_secs(1).await;
31 }
32}
33
34/// DS18B20 temperature sensor driver
35pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> {
36 sm: StateMachine<'d, PIO, SM>,
37}
38
39impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> {
40 /// Create a new instance the driver
41 pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self {
42 let prg = pio_proc::pio_asm!(
43 r#"
44 .wrap_target
45 again:
46 pull block
47 mov x, osr
48 jmp !x, read
49 write:
50 set pindirs, 1
51 set pins, 0
52 loop1:
53 jmp x--,loop1
54 set pindirs, 0 [31]
55 wait 1 pin 0 [31]
56 pull block
57 mov x, osr
58 bytes1:
59 pull block
60 set y, 7
61 set pindirs, 1
62 bit1:
63 set pins, 0 [1]
64 out pins,1 [31]
65 set pins, 1 [20]
66 jmp y--,bit1
67 jmp x--,bytes1
68 set pindirs, 0 [31]
69 jmp again
70 read:
71 pull block
72 mov x, osr
73 bytes2:
74 set y, 7
75 bit2:
76 set pindirs, 1
77 set pins, 0 [1]
78 set pindirs, 0 [5]
79 in pins,1 [10]
80 jmp y--,bit2
81 jmp x--,bytes2
82 .wrap
83 "#,
84 );
85
86 let pin = common.make_pio_pin(pin);
87 let mut cfg = Config::default();
88 cfg.use_program(&common.load_program(&prg.program), &[]);
89 cfg.set_out_pins(&[&pin]);
90 cfg.set_in_pins(&[&pin]);
91 cfg.set_set_pins(&[&pin]);
92 cfg.shift_in = ShiftConfig {
93 auto_fill: true,
94 direction: ShiftDirection::Right,
95 threshold: 8,
96 };
97 cfg.clock_divider = 255_u8.into();
98 sm.set_config(&cfg);
99 sm.set_enable(true);
100 Self { sm }
101 }
102
103 /// Write bytes over the wire
104 async fn write_bytes(&mut self, bytes: &[u8]) {
105 self.sm.tx().wait_push(250).await;
106 self.sm.tx().wait_push(bytes.len() as u32 - 1).await;
107 for b in bytes {
108 self.sm.tx().wait_push(*b as u32).await;
109 }
110 }
111
112 /// Read bytes from the wire
113 async fn read_bytes(&mut self, bytes: &mut [u8]) {
114 self.sm.tx().wait_push(0).await;
115 self.sm.tx().wait_push(bytes.len() as u32 - 1).await;
116 for b in bytes.iter_mut() {
117 *b = (self.sm.rx().wait_pull().await >> 24) as u8;
118 }
119 }
120
121 /// Calculate CRC8 of the data
122 fn crc8(data: &[u8]) -> u8 {
123 let mut temp;
124 let mut data_byte;
125 let mut crc = 0;
126 for b in data {
127 data_byte = *b;
128 for _ in 0..8 {
129 temp = (crc ^ data_byte) & 0x01;
130 crc >>= 1;
131 if temp != 0 {
132 crc ^= 0x8C;
133 }
134 data_byte >>= 1;
135 }
136 }
137 crc
138 }
139
140 /// Start a new measurement. Allow at least 1000ms before getting `temperature`.
141 pub async fn start(&mut self) {
142 self.write_bytes(&[0xCC, 0x44]).await;
143 }
144
145 /// Read the temperature. Ensure >1000ms has passed since `start` before calling this.
146 pub async fn temperature(&mut self) -> Result<f32, ()> {
147 self.write_bytes(&[0xCC, 0xBE]).await;
148 let mut data = [0; 9];
149 self.read_bytes(&mut data).await;
150 match Self::crc8(&data) == 0 {
151 true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.),
152 false => Err(()),
153 }
154 }
155}
diff --git a/examples/rp23/src/bin/trng.rs b/examples/rp23/src/bin/trng.rs
new file mode 100644
index 000000000..e146baa2e
--- /dev/null
+++ b/examples/rp23/src/bin/trng.rs
@@ -0,0 +1,64 @@
1//! This example shows TRNG usage
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::bind_interrupts;
9use embassy_rp::block::ImageDef;
10use embassy_rp::gpio::{Level, Output};
11use embassy_rp::peripherals::TRNG;
12use embassy_rp::trng::Trng;
13use embassy_time::Timer;
14use rand::RngCore;
15use {defmt_rtt as _, panic_probe as _};
16
17#[link_section = ".start_block"]
18#[used]
19pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
20
21// Program metadata for `picotool info`
22#[link_section = ".bi_entries"]
23#[used]
24pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
25 embassy_rp::binary_info::rp_program_name!(c"example"),
26 embassy_rp::binary_info::rp_cargo_version!(),
27 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
28 embassy_rp::binary_info::rp_program_build_attribute!(),
29];
30
31bind_interrupts!(struct Irqs {
32 TRNG_IRQ => embassy_rp::trng::InterruptHandler<TRNG>;
33});
34
35#[embassy_executor::main]
36async fn main(_spawner: Spawner) {
37 let peripherals = embassy_rp::init(Default::default());
38
39 // Initialize the TRNG with default configuration
40 let mut trng = Trng::new(peripherals.TRNG, Irqs, embassy_rp::trng::Config::default());
41 // A buffer to collect random bytes in.
42 let mut randomness = [0u8; 58];
43
44 let mut led = Output::new(peripherals.PIN_25, Level::Low);
45
46 loop {
47 trng.fill_bytes(&mut randomness).await;
48 info!("Random bytes async {}", &randomness);
49 trng.blocking_fill_bytes(&mut randomness);
50 info!("Random bytes blocking {}", &randomness);
51 let random_u32 = trng.next_u32();
52 let random_u64 = trng.next_u64();
53 info!("Random u32 {} u64 {}", random_u32, random_u64);
54 // Random number of blinks between 0 and 31
55 let blinks = random_u32 % 32;
56 for _ in 0..blinks {
57 led.set_high();
58 Timer::after_millis(20).await;
59 led.set_low();
60 Timer::after_millis(20).await;
61 }
62 Timer::after_millis(1000).await;
63 }
64}
diff --git a/examples/stm32f4/src/bin/eth_compliance_test.rs b/examples/stm32f4/src/bin/eth_compliance_test.rs
new file mode 100644
index 000000000..5946fed79
--- /dev/null
+++ b/examples/stm32f4/src/bin/eth_compliance_test.rs
@@ -0,0 +1,77 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::eth::generic_smi::GenericSMI;
7use embassy_stm32::eth::{Ethernet, PacketQueue, StationManagement};
8use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
10use embassy_time::Timer;
11use static_cell::StaticCell;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 ETH => eth::InterruptHandler;
16 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) -> ! {
21 let mut config = Config::default();
22 {
23 use embassy_stm32::rcc::*;
24 config.rcc.hse = Some(Hse {
25 freq: Hertz(8_000_000),
26 mode: HseMode::Bypass,
27 });
28 config.rcc.pll_src = PllSource::HSE;
29 config.rcc.pll = Some(Pll {
30 prediv: PllPreDiv::DIV4,
31 mul: PllMul::MUL180,
32 divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz.
33 divq: None,
34 divr: None,
35 });
36 config.rcc.ahb_pre = AHBPrescaler::DIV1;
37 config.rcc.apb1_pre = APBPrescaler::DIV4;
38 config.rcc.apb2_pre = APBPrescaler::DIV2;
39 config.rcc.sys = Sysclk::PLL1_P;
40 }
41 let p = embassy_stm32::init(config);
42
43 info!("Hello Compliance World!");
44
45 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
46
47 const PHY_ADDR: u8 = 0;
48 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
49 let mut device = Ethernet::new(
50 PACKETS.init(PacketQueue::<4, 4>::new()),
51 p.ETH,
52 Irqs,
53 p.PA1,
54 p.PA2,
55 p.PC1,
56 p.PA7,
57 p.PC4,
58 p.PC5,
59 p.PG13,
60 p.PB13,
61 p.PG11,
62 GenericSMI::new(PHY_ADDR),
63 mac_addr,
64 );
65
66 let sm = unsafe { device.station_management() };
67
68 // Just an example. Exact register settings depend on the specific PHY and test.
69 sm.smi_write(PHY_ADDR, 0, 0x2100);
70 sm.smi_write(PHY_ADDR, 11, 0xA000);
71
72 // NB: Remember to reset the PHY after testing before starting the networking stack
73
74 loop {
75 Timer::after_secs(1).await;
76 }
77}
diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs
new file mode 100644
index 000000000..6773f7843
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/usb_serial.rs
@@ -0,0 +1,140 @@
1#![no_std]
2#![no_main]
3
4use defmt::{panic, *};
5use embassy_executor::Spawner;
6use embassy_futures::join::join;
7use embassy_stm32::time::Hertz;
8use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
17});
18
19// If you are trying this and your USB device doesn't connect, the most
20// common issues are the RCC config and vbus_detection
21//
22// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
23// for more information.
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 info!("Hello World!");
27
28 let mut config = Config::default();
29
30 {
31 use embassy_stm32::rcc::*;
32 config.rcc.hse = Some(Hse {
33 freq: Hertz(24_000_000),
34 mode: HseMode::Oscillator,
35 });
36 config.rcc.pll1 = Some(Pll {
37 source: PllSource::HSE,
38 prediv: PllPreDiv::DIV12,
39 mul: PllMul::MUL300,
40 divp: Some(PllDiv::DIV1), //600 MHz
41 divq: Some(PllDiv::DIV2), // 300 MHz
42 divr: Some(PllDiv::DIV2), // 300 MHz
43 });
44 config.rcc.sys = Sysclk::PLL1_P; // 600 MHz
45 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz
46 config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 MHz
47 config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 MHz
48 config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 MHz
49 config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 MHz
50 config.rcc.voltage_scale = VoltageScale::HIGH;
51 config.rcc.mux.usbphycsel = mux::Usbphycsel::HSE;
52 }
53
54 let p = embassy_stm32::init(config);
55
56 // Create the driver, from the HAL.
57 let mut ep_out_buffer = [0u8; 256];
58 let mut config = embassy_stm32::usb::Config::default();
59
60 // Do not enable vbus_detection. This is a safe default that works in all boards.
61 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
62 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
63 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
64 config.vbus_detection = false;
65
66 let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PM6, p.PM5, &mut ep_out_buffer, config);
67
68 // Create embassy-usb Config
69 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
70 config.manufacturer = Some("Embassy");
71 config.product = Some("USB-serial example");
72 config.serial_number = Some("12345678");
73 // Required for windows compatibility.
74 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
75 config.device_class = 0xEF;
76 config.device_sub_class = 0x02;
77 config.device_protocol = 0x01;
78 config.composite_with_iads = true;
79
80 // Create embassy-usb DeviceBuilder using the driver and config.
81 // It needs some buffers for building the descriptors.
82 let mut config_descriptor = [0; 256];
83 let mut bos_descriptor = [0; 256];
84 let mut control_buf = [0; 64];
85
86 let mut state = State::new();
87
88 let mut builder = Builder::new(
89 driver,
90 config,
91 &mut config_descriptor,
92 &mut bos_descriptor,
93 &mut [], // no msos descriptors
94 &mut control_buf,
95 );
96
97 // Create classes on the builder.
98 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
99
100 // Build the builder.
101 let mut usb = builder.build();
102
103 // Run the USB device.
104 let usb_fut = usb.run();
105
106 // Do stuff with the class!
107 let echo_fut = async {
108 loop {
109 class.wait_connection().await;
110 info!("Connected");
111 let _ = echo(&mut class).await;
112 info!("Disconnected");
113 }
114 };
115
116 // Run everything concurrently.
117 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
118 join(usb_fut, echo_fut).await;
119}
120
121struct Disconnected {}
122
123impl From<EndpointError> for Disconnected {
124 fn from(val: EndpointError) -> Self {
125 match val {
126 EndpointError::BufferOverflow => panic!("Buffer overflow"),
127 EndpointError::Disabled => Disconnected {},
128 }
129 }
130}
131
132async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
133 let mut buf = [0; 64];
134 loop {
135 let n = class.read_packet(&mut buf).await?;
136 let data = &buf[..n];
137 info!("data: {:x}", data);
138 class.write_packet(data).await?;
139 }
140}
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index 53d44a94a..9712a8c5a 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -7,7 +7,8 @@ use common::*;
7use defmt::assert_eq; 7use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Level, Output, Speed}; 9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::spi::{self, Spi}; 10use embassy_stm32::mode::Blocking;
11use embassy_stm32::spi::{self, Spi, Word};
11use embassy_stm32::time::Hertz; 12use embassy_stm32::time::Hertz;
12 13
13#[embassy_executor::main] 14#[embassy_executor::main]
@@ -31,11 +32,58 @@ async fn main(_spawner: Spawner) {
31 spi_config, 32 spi_config,
32 ); 33 );
33 34
34 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; 35 test_txrx::<u8>(&mut spi);
36 test_txrx::<u16>(&mut spi);
37
38 // Assert the RCC bit gets disabled on drop.
39 #[cfg(feature = "stm32f429zi")]
40 defmt::assert!(embassy_stm32::pac::RCC.apb2enr().read().spi1en());
41 drop(spi);
42 #[cfg(feature = "stm32f429zi")]
43 defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en());
44
45 // test rx-only configuration
46 let mut spi = Spi::new_blocking_rxonly(&mut spi_peri, &mut sck, &mut miso, spi_config);
47 let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
48
49 test_rx::<u8>(&mut spi, &mut mosi_out);
50 test_rx::<u16>(&mut spi, &mut mosi_out);
51 drop(spi);
52 drop(mosi_out);
53
54 let mut spi = Spi::new_blocking_txonly(&mut spi_peri, &mut sck, &mut mosi, spi_config);
55 test_tx::<u8>(&mut spi);
56 test_tx::<u16>(&mut spi);
57 drop(spi);
58
59 let mut spi = Spi::new_blocking_txonly_nosck(&mut spi_peri, &mut mosi, spi_config);
60 test_tx::<u8>(&mut spi);
61 test_tx::<u16>(&mut spi);
62 drop(spi);
63
64 info!("Test OK");
65 cortex_m::asm::bkpt();
66}
67
68fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>)
69where
70 W: core::ops::Not<Output = W>,
71{
72 let data: [W; 9] = [
73 0x00u8.into(),
74 0xFFu8.into(),
75 0xAAu8.into(),
76 0x55u8.into(),
77 0xC0u8.into(),
78 0xFFu8.into(),
79 0xEEu8.into(),
80 0xC0u8.into(),
81 0xDEu8.into(),
82 ];
35 83
36 // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor. 84 // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor.
37 // so we should get the data we sent back. 85 // so we should get the data we sent back.
38 let mut buf = [0; 9]; 86 let mut buf = [W::default(); 9];
39 spi.blocking_transfer(&mut buf, &data).unwrap(); 87 spi.blocking_transfer(&mut buf, &data).unwrap();
40 assert_eq!(buf, data); 88 assert_eq!(buf, data);
41 89
@@ -59,47 +107,33 @@ async fn main(_spawner: Spawner) {
59 spi.blocking_transfer_in_place::<u8>(&mut []).unwrap(); 107 spi.blocking_transfer_in_place::<u8>(&mut []).unwrap();
60 spi.blocking_read::<u8>(&mut []).unwrap(); 108 spi.blocking_read::<u8>(&mut []).unwrap();
61 spi.blocking_write::<u8>(&[]).unwrap(); 109 spi.blocking_write::<u8>(&[]).unwrap();
110}
62 111
63 // Assert the RCC bit gets disabled on drop. 112fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>, mosi_out: &mut Output<'_>)
64 #[cfg(feature = "stm32f429zi")] 113where
65 defmt::assert!(embassy_stm32::pac::RCC.apb2enr().read().spi1en()); 114 W: core::ops::Not<Output = W>,
66 drop(spi); 115{
67 #[cfg(feature = "stm32f429zi")] 116 let mut buf = [W::default(); 9];
68 defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en());
69 117
70 // test rx-only configuration
71 let mut spi = Spi::new_blocking_rxonly(&mut spi_peri, &mut sck, &mut miso, spi_config);
72 let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
73 mosi_out.set_high(); 118 mosi_out.set_high();
74 spi.blocking_read(&mut buf).unwrap(); 119 spi.blocking_read(&mut buf).unwrap();
75 assert_eq!(buf, [0xff; 9]); 120 assert_eq!(buf, [!W::default(); 9]);
76 mosi_out.set_low(); 121 mosi_out.set_low();
77 spi.blocking_read(&mut buf).unwrap(); 122 spi.blocking_read(&mut buf).unwrap();
78 assert_eq!(buf, [0x00; 9]); 123 assert_eq!(buf, [W::default(); 9]);
79 spi.blocking_read::<u8>(&mut []).unwrap(); 124 spi.blocking_read::<u8>(&mut []).unwrap();
80 spi.blocking_read::<u8>(&mut []).unwrap(); 125 spi.blocking_read::<u8>(&mut []).unwrap();
81 drop(mosi_out); 126}
82 drop(spi); 127
128fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>)
129where
130 W: core::ops::Not<Output = W>,
131{
132 let buf = [W::default(); 9];
83 133
84 // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave. 134 // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave.
85 let mut spi = Spi::new_blocking_txonly(&mut spi_peri, &mut sck, &mut mosi, spi_config);
86 spi.blocking_transfer(&mut buf, &data).unwrap();
87 spi.blocking_transfer_in_place(&mut buf).unwrap();
88 spi.blocking_write(&buf).unwrap(); 135 spi.blocking_write(&buf).unwrap();
89 spi.blocking_read(&mut buf).unwrap();
90 spi.blocking_transfer::<u8>(&mut [], &[]).unwrap();
91 spi.blocking_transfer_in_place::<u8>(&mut []).unwrap();
92 spi.blocking_read::<u8>(&mut []).unwrap();
93 spi.blocking_write::<u8>(&[]).unwrap(); 136 spi.blocking_write::<u8>(&[]).unwrap();
94 drop(spi);
95
96 // Test tx-only nosck.
97 let mut spi = Spi::new_blocking_txonly_nosck(&mut spi_peri, &mut mosi, spi_config);
98 spi.blocking_write(&buf).unwrap(); 137 spi.blocking_write(&buf).unwrap();
99 spi.blocking_write::<u8>(&[]).unwrap(); 138 spi.blocking_write::<u8>(&[]).unwrap();
100 spi.blocking_write(&buf).unwrap();
101 drop(spi);
102
103 info!("Test OK");
104 cortex_m::asm::bkpt();
105} 139}
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index a1cbc0ed1..307409a16 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -7,7 +7,8 @@ use common::*;
7use defmt::assert_eq; 7use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Level, Output, Speed}; 9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::spi::{self, Spi}; 10use embassy_stm32::mode::Async;
11use embassy_stm32::spi::{self, Spi, Word};
11use embassy_stm32::time::Hertz; 12use embassy_stm32::time::Hertz;
12 13
13#[embassy_executor::main] 14#[embassy_executor::main]
@@ -35,11 +36,61 @@ async fn main(_spawner: Spawner) {
35 spi_config, 36 spi_config,
36 ); 37 );
37 38
38 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; 39 test_txrx::<u8>(&mut spi).await;
40 test_txrx::<u16>(&mut spi).await;
41 drop(spi);
42
43 // test rx-only configuration
44 let mut spi = Spi::new_rxonly(
45 &mut spi_peri,
46 &mut sck,
47 &mut miso,
48 // SPIv1/f1 requires txdma even if rxonly.
49 #[cfg(not(feature = "spi-v345"))]
50 &mut tx_dma,
51 &mut rx_dma,
52 spi_config,
53 );
54 let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
55
56 test_rx::<u8>(&mut spi, &mut mosi_out).await;
57 test_rx::<u16>(&mut spi, &mut mosi_out).await;
58 drop(spi);
59 drop(mosi_out);
60
61 let mut spi = Spi::new_txonly(&mut spi_peri, &mut sck, &mut mosi, &mut tx_dma, spi_config);
62 test_tx::<u8>(&mut spi).await;
63 test_tx::<u16>(&mut spi).await;
64 drop(spi);
65
66 let mut spi = Spi::new_txonly_nosck(&mut spi_peri, &mut mosi, &mut tx_dma, spi_config);
67 test_tx::<u8>(&mut spi).await;
68 test_tx::<u16>(&mut spi).await;
69 drop(spi);
70
71 info!("Test OK");
72 cortex_m::asm::bkpt();
73}
74
75async fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>)
76where
77 W: core::ops::Not<Output = W>,
78{
79 let data: [W; 9] = [
80 0x00u8.into(),
81 0xFFu8.into(),
82 0xAAu8.into(),
83 0x55u8.into(),
84 0xC0u8.into(),
85 0xFFu8.into(),
86 0xEEu8.into(),
87 0xC0u8.into(),
88 0xDEu8.into(),
89 ];
39 90
40 // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor. 91 // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor.
41 // so we should get the data we sent back. 92 // so we should get the data we sent back.
42 let mut buf = [0; 9]; 93 let mut buf = [W::default(); 9];
43 spi.transfer(&mut buf, &data).await.unwrap(); 94 spi.transfer(&mut buf, &data).await.unwrap();
44 assert_eq!(buf, data); 95 assert_eq!(buf, data);
45 96
@@ -83,56 +134,41 @@ async fn main(_spawner: Spawner) {
83 spi.blocking_write(&buf).unwrap(); 134 spi.blocking_write(&buf).unwrap();
84 spi.blocking_read(&mut buf).unwrap(); 135 spi.blocking_read(&mut buf).unwrap();
85 spi.write(&buf).await.unwrap(); 136 spi.write(&buf).await.unwrap();
137}
86 138
87 core::mem::drop(spi); 139async fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>, mosi_out: &mut Output<'_>)
140where
141 W: core::ops::Not<Output = W>,
142{
143 let mut buf = [W::default(); 9];
88 144
89 // test rx-only configuration
90 let mut spi = Spi::new_rxonly(
91 &mut spi_peri,
92 &mut sck,
93 &mut miso,
94 // SPIv1/f1 requires txdma even if rxonly.
95 #[cfg(not(feature = "spi-v345"))]
96 &mut tx_dma,
97 &mut rx_dma,
98 spi_config,
99 );
100 let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
101 mosi_out.set_high(); 145 mosi_out.set_high();
102 spi.read(&mut buf).await.unwrap(); 146 spi.read(&mut buf).await.unwrap();
103 assert_eq!(buf, [0xff; 9]); 147 assert_eq!(buf, [!W::default(); 9]);
104 spi.blocking_read(&mut buf).unwrap(); 148 spi.blocking_read(&mut buf).unwrap();
105 assert_eq!(buf, [0xff; 9]); 149 assert_eq!(buf, [!W::default(); 9]);
106 spi.read(&mut buf).await.unwrap(); 150 spi.read(&mut buf).await.unwrap();
107 assert_eq!(buf, [0xff; 9]); 151 assert_eq!(buf, [!W::default(); 9]);
108 spi.read(&mut buf).await.unwrap(); 152 spi.read(&mut buf).await.unwrap();
109 assert_eq!(buf, [0xff; 9]); 153 assert_eq!(buf, [!W::default(); 9]);
110 spi.blocking_read(&mut buf).unwrap(); 154 spi.blocking_read(&mut buf).unwrap();
111 assert_eq!(buf, [0xff; 9]); 155 assert_eq!(buf, [!W::default(); 9]);
112 spi.blocking_read(&mut buf).unwrap(); 156 spi.blocking_read(&mut buf).unwrap();
113 assert_eq!(buf, [0xff; 9]); 157 assert_eq!(buf, [!W::default(); 9]);
114 mosi_out.set_low(); 158 mosi_out.set_low();
115 spi.read(&mut buf).await.unwrap(); 159 spi.read(&mut buf).await.unwrap();
116 assert_eq!(buf, [0x00; 9]); 160 assert_eq!(buf, [W::default(); 9]);
117 spi.read::<u8>(&mut []).await.unwrap(); 161 spi.read::<u8>(&mut []).await.unwrap();
118 spi.blocking_read::<u8>(&mut []).unwrap(); 162 spi.blocking_read::<u8>(&mut []).unwrap();
119 drop(mosi_out); 163}
120 drop(spi);
121 164
122 // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave. 165async fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>)
123 let mut spi = Spi::new_txonly(&mut spi_peri, &mut sck, &mut mosi, &mut tx_dma, spi_config); 166where
124 spi.blocking_write(&buf).unwrap(); 167 W: core::ops::Not<Output = W>,
125 spi.write(&buf).await.unwrap(); 168{
126 spi.blocking_write(&buf).unwrap(); 169 let buf = [W::default(); 9];
127 spi.blocking_write(&buf).unwrap();
128 spi.write(&buf).await.unwrap();
129 spi.write(&buf).await.unwrap();
130 spi.write::<u8>(&[]).await.unwrap();
131 spi.blocking_write::<u8>(&[]).unwrap();
132 drop(spi);
133 170
134 // Test tx-only nosck. 171 // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave.
135 let mut spi = Spi::new_txonly_nosck(&mut spi_peri, &mut mosi, &mut tx_dma, spi_config);
136 spi.blocking_write(&buf).unwrap(); 172 spi.blocking_write(&buf).unwrap();
137 spi.write(&buf).await.unwrap(); 173 spi.write(&buf).await.unwrap();
138 spi.blocking_write(&buf).unwrap(); 174 spi.blocking_write(&buf).unwrap();
@@ -141,8 +177,4 @@ async fn main(_spawner: Spawner) {
141 spi.write(&buf).await.unwrap(); 177 spi.write(&buf).await.unwrap();
142 spi.write::<u8>(&[]).await.unwrap(); 178 spi.write::<u8>(&[]).await.unwrap();
143 spi.blocking_write::<u8>(&[]).unwrap(); 179 spi.blocking_write::<u8>(&[]).unwrap();
144 drop(spi);
145
146 info!("Test OK");
147 cortex_m::asm::bkpt();
148} 180}