aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjorn <[email protected]>2024-04-20 22:12:28 -0700
committerBjorn <[email protected]>2024-04-20 22:12:28 -0700
commit7658966486c44fa919124ce9261b0a3f00e8fc61 (patch)
tree0741169b7a3ec81be4b7687c3ceb7820e3b37dfe
parent0a2d58ec5b8d1d7663108ebb4add02083222874b (diff)
parentda86c086510490602ffdd688760fb59cc7a1e524 (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy
-rwxr-xr-xci.sh1
-rw-r--r--docs/modules/ROOT/pages/faq.adoc31
-rw-r--r--docs/modules/ROOT/pages/layer_by_layer.adoc2
-rw-r--r--embassy-nrf/src/pdm.rs2
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/adc/g4.rs2
-rw-r--r--embassy-stm32/src/adc/mod.rs11
-rw-r--r--embassy-stm32/src/adc/v3.rs40
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs1
-rw-r--r--embassy-stm32/src/can/fdcan.rs60
-rw-r--r--embassy-stm32/src/crc/v2v3.rs2
-rw-r--r--embassy-stm32/src/dac/tsel.rs17
-rw-r--r--embassy-stm32/src/flash/mod.rs3
-rw-r--r--embassy-stm32/src/flash/u0.rs96
-rw-r--r--embassy-stm32/src/usart/mod.rs15
-rw-r--r--embassy-stm32/src/usb/mod.rs2
-rw-r--r--embassy-stm32/src/usb/otg.rs106
-rw-r--r--embassy-stm32/src/usb/usb.rs14
-rw-r--r--examples/stm32f334/.cargo/config.toml2
-rw-r--r--examples/stm32l4/.cargo/config.toml2
-rw-r--r--examples/stm32u0/Cargo.toml6
-rw-r--r--examples/stm32u0/src/bin/adc.rs30
-rw-r--r--examples/stm32u0/src/bin/crc.rs31
-rw-r--r--examples/stm32u0/src/bin/dac.rs35
-rw-r--r--examples/stm32u0/src/bin/flash.rs43
-rw-r--r--examples/stm32u0/src/bin/i2c.rs21
-rw-r--r--examples/stm32u0/src/bin/rng.rs43
-rw-r--r--examples/stm32u0/src/bin/rtc.rs49
-rw-r--r--examples/stm32u0/src/bin/spi.rs30
-rw-r--r--examples/stm32u0/src/bin/usart.rs25
-rw-r--r--examples/stm32u0/src/bin/usb_serial.rs109
-rw-r--r--examples/stm32u0/src/bin/wdt.rs41
-rw-r--r--examples/stm32wb/.cargo/config.toml2
33 files changed, 762 insertions, 116 deletions
diff --git a/ci.sh b/ci.sh
index 514c6769b..e95714b65 100755
--- a/ci.sh
+++ b/ci.sh
@@ -189,6 +189,7 @@ cargo batch \
189 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ 189 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
190 --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \ 190 --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \
191 --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ 191 --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \
192 --- build --release --manifest-path examples/stm32u0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32u0 \
192 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ 193 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
193 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wb \ 194 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wb \
194 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \ 195 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \
diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc
index c6b893de5..0944127a5 100644
--- a/docs/modules/ROOT/pages/faq.adoc
+++ b/docs/modules/ROOT/pages/faq.adoc
@@ -231,3 +231,34 @@ Please refer to the STM32 documentation for the specific values suitable for you
231Look for the `MEMORY` section and try to determine the FLASH and RAM sizes and section start. 231Look for the `MEMORY` section and try to determine the FLASH and RAM sizes and section start.
232 232
233If you find a case where the memory.x is wrong, please report it on [this Github issue](https://github.com/embassy-rs/stm32-data/issues/301) so other users are not caught by surprise. 233If you find a case where the memory.x is wrong, please report it on [this Github issue](https://github.com/embassy-rs/stm32-data/issues/301) so other users are not caught by surprise.
234
235== Known issues (details and/or mitigations)
236
237These are issues that are commonly reported. Help wanted fixing them, or improving the UX when possible!
238
239=== STM32H5 and STM32H7 power issues
240
241STM32 chips with built-in power management (SMPS and LDO) settings often cause user problems when the configuration does not match how the board was designed.
242
243Settings from the examples, or even from other working boards, may not work on YOUR board, because they are wired differently.
244
245Additionally, some PWR settings require a full device reboot (and enough time to discharge any power capacitors!), making this hard to troubleshoot. Also, some
246"wrong" power settings will ALMOST work, meaning it will sometimes work on some boots, or for a while, but crash unexpectedly.
247
248There is not a fix for this yet, as it is board/hardware dependant. See link:https://github.com/embassy-rs/embassy/issues/2806[this tracking issue] for more details
249
250=== STM32 BDMA only work out of some RAM regions
251
252The STM32 BDMA controller included in some chips (TODO: list which ones) has a limitation in that it only works out of certain regions of RAM (TODO: list which ones), otherwise the transfer
253will fail.
254
255If you see errors that look like this:
256
257[source,plain]
258----
259DMA: error on BDMA@1234ABCD channel 4
260----
261
262You likely need to set up your linker script to define a special region for this area, and copy data to that region before using with BDMA.
263
264TODO: show how to do that
diff --git a/docs/modules/ROOT/pages/layer_by_layer.adoc b/docs/modules/ROOT/pages/layer_by_layer.adoc
index 1d7bdc89b..fa419f75e 100644
--- a/docs/modules/ROOT/pages/layer_by_layer.adoc
+++ b/docs/modules/ROOT/pages/layer_by_layer.adoc
@@ -63,7 +63,7 @@ Luckily, there is an elegant solution to this problem when using Embassy.
63 63
64== Async version 64== Async version
65 65
66It's time to use the Embassy capabilities to its fullest. At the core, Embassy has an async excecutor, or a runtime for async tasks if you will. The executor polls a set of tasks (defined at compile time), and whenever a task `blocks`, the executor will run another task, or put the microcontroller to sleep. 66It's time to use the Embassy capabilities to its fullest. At the core, Embassy has an async executor, or a runtime for async tasks if you will. The executor polls a set of tasks (defined at compile time), and whenever a task `blocks`, the executor will run another task, or put the microcontroller to sleep.
67 67
68[source,rust] 68[source,rust]
69---- 69----
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index ef2662c85..c1501e02e 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -1,4 +1,4 @@
1//! Pulse Density Modulation (PDM) mirophone driver 1//! Pulse Density Modulation (PDM) microphone driver
2 2
3#![macro_use] 3#![macro_use]
4 4
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 1f9a51678..095427171 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -71,7 +71,7 @@ rand_core = "0.6.3"
71sdio-host = "0.5.0" 71sdio-host = "0.5.0"
72critical-section = "1.1" 72critical-section = "1.1"
73#stm32-metapac = { version = "15" } 73#stm32-metapac = { version = "15" }
74stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d674277b78ca7400ecfeeb1b5af4e460a65c1a61" } 74stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-01ac9bfd035961dc75f32dcd6080501538246d5c" }
75 75
76vcell = "0.1.3" 76vcell = "0.1.3"
77nb = "1.0.0" 77nb = "1.0.0"
@@ -97,7 +97,7 @@ proc-macro2 = "1.0.36"
97quote = "1.0.15" 97quote = "1.0.15"
98 98
99#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 99#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
100stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d674277b78ca7400ecfeeb1b5af4e460a65c1a61", default-features = false, features = ["metadata"]} 100stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-01ac9bfd035961dc75f32dcd6080501538246d5c", default-features = false, features = ["metadata"]}
101 101
102[features] 102[features]
103default = ["rt"] 103default = ["rt"]
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index f6741f019..221cc2a40 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -170,7 +170,7 @@ impl<'d, T: Instance> Adc<'d, T> {
170 170
171 fn configure_differential_inputs(&mut self) { 171 fn configure_differential_inputs(&mut self) {
172 T::regs().difsel().modify(|w| { 172 T::regs().difsel().modify(|w| {
173 for n in 0..20 { 173 for n in 0..18 {
174 w.set_difsel(n, Difsel::SINGLEENDED); 174 w.set_difsel(n, Difsel::SINGLEENDED);
175 } 175 }
176 }); 176 });
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 12c5751bd..8ef68490b 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -10,7 +10,7 @@
10#[cfg_attr(adc_v1, path = "v1.rs")] 10#[cfg_attr(adc_v1, path = "v1.rs")]
11#[cfg_attr(adc_l0, path = "v1.rs")] 11#[cfg_attr(adc_l0, path = "v1.rs")]
12#[cfg_attr(adc_v2, path = "v2.rs")] 12#[cfg_attr(adc_v2, path = "v2.rs")]
13#[cfg_attr(any(adc_v3, adc_g0, adc_h5), path = "v3.rs")] 13#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")]
14#[cfg_attr(adc_v4, path = "v4.rs")] 14#[cfg_attr(adc_v4, path = "v4.rs")]
15#[cfg_attr(adc_g4, path = "g4.rs")] 15#[cfg_attr(adc_g4, path = "g4.rs")]
16mod _version; 16mod _version;
@@ -76,7 +76,12 @@ pub(crate) fn blocking_delay_us(us: u32) {
76 #[cfg(time)] 76 #[cfg(time)]
77 embassy_time::block_for(embassy_time::Duration::from_micros(us)); 77 embassy_time::block_for(embassy_time::Duration::from_micros(us));
78 #[cfg(not(time))] 78 #[cfg(not(time))]
79 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 * us / 1_000_000); 79 {
80 let freq = unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 as u64;
81 let us = us as u64;
82 let cycles = freq * us / 1_000_000;
83 cortex_m::asm::delay(cycles as u32);
84 }
80} 85}
81 86
82/// ADC instance. 87/// ADC instance.
@@ -91,6 +96,7 @@ pub(crate) fn blocking_delay_us(us: u32) {
91 adc_f3, 96 adc_f3,
92 adc_f3_v1_1, 97 adc_f3_v1_1,
93 adc_g0, 98 adc_g0,
99 adc_u0,
94 adc_h5 100 adc_h5
95)))] 101)))]
96#[allow(private_bounds)] 102#[allow(private_bounds)]
@@ -109,6 +115,7 @@ pub trait Instance: SealedInstance + crate::Peripheral<P = Self> {
109 adc_f3, 115 adc_f3,
110 adc_f3_v1_1, 116 adc_f3_v1_1,
111 adc_g0, 117 adc_g0,
118 adc_u0,
112 adc_h5 119 adc_h5
113))] 120))]
114#[allow(private_bounds)] 121#[allow(private_bounds)]
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 4fd8558ba..dc418297e 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -19,6 +19,8 @@ impl<T: Instance> super::SealedAdcPin<T> for VrefInt {
19 let val = 13; 19 let val = 13;
20 } else if #[cfg(adc_h5)] { 20 } else if #[cfg(adc_h5)] {
21 let val = 17; 21 let val = 17;
22 } else if #[cfg(adc_u0)] {
23 let val = 12;
22 } else { 24 } else {
23 let val = 0; 25 let val = 0;
24 } 26 }
@@ -36,6 +38,8 @@ impl<T: Instance> super::SealedAdcPin<T> for Temperature {
36 let val = 12; 38 let val = 12;
37 } else if #[cfg(adc_h5)] { 39 } else if #[cfg(adc_h5)] {
38 let val = 16; 40 let val = 16;
41 } else if #[cfg(adc_u0)] {
42 let val = 11;
39 } else { 43 } else {
40 let val = 17; 44 let val = 17;
41 } 45 }
@@ -53,6 +57,8 @@ impl<T: Instance> super::SealedAdcPin<T> for Vbat {
53 let val = 14; 57 let val = 14;
54 } else if #[cfg(adc_h5)] { 58 } else if #[cfg(adc_h5)] {
55 let val = 2; 59 let val = 2;
60 } else if #[cfg(adc_h5)] {
61 let val = 13;
56 } else { 62 } else {
57 let val = 18; 63 let val = 18;
58 } 64 }
@@ -73,17 +79,29 @@ cfg_if! {
73 } 79 }
74} 80}
75 81
82cfg_if! {
83 if #[cfg(adc_u0)] {
84 pub struct DacOut;
85 impl<T: Instance> AdcPin<T> for DacOut {}
86 impl<T: Instance> super::SealedAdcPin<T> for DacOut {
87 fn channel(&self) -> u8 {
88 19
89 }
90 }
91 }
92}
93
76impl<'d, T: Instance> Adc<'d, T> { 94impl<'d, T: Instance> Adc<'d, T> {
77 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 95 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
78 into_ref!(adc); 96 into_ref!(adc);
79 T::enable_and_reset(); 97 T::enable_and_reset();
80 T::regs().cr().modify(|reg| { 98 T::regs().cr().modify(|reg| {
81 #[cfg(not(adc_g0))] 99 #[cfg(not(any(adc_g0, adc_u0)))]
82 reg.set_deeppwd(false); 100 reg.set_deeppwd(false);
83 reg.set_advregen(true); 101 reg.set_advregen(true);
84 }); 102 });
85 103
86 #[cfg(adc_g0)] 104 #[cfg(any(adc_g0, adc_u0))]
87 T::regs().cfgr1().modify(|reg| { 105 T::regs().cfgr1().modify(|reg| {
88 reg.set_chselrmod(false); 106 reg.set_chselrmod(false);
89 }); 107 });
@@ -107,11 +125,11 @@ impl<'d, T: Instance> Adc<'d, T> {
107 } 125 }
108 126
109 pub fn enable_vrefint(&self) -> VrefInt { 127 pub fn enable_vrefint(&self) -> VrefInt {
110 #[cfg(not(adc_g0))] 128 #[cfg(not(any(adc_g0, adc_u0)))]
111 T::common_regs().ccr().modify(|reg| { 129 T::common_regs().ccr().modify(|reg| {
112 reg.set_vrefen(true); 130 reg.set_vrefen(true);
113 }); 131 });
114 #[cfg(adc_g0)] 132 #[cfg(any(adc_g0, adc_u0))]
115 T::regs().ccr().modify(|reg| { 133 T::regs().ccr().modify(|reg| {
116 reg.set_vrefen(true); 134 reg.set_vrefen(true);
117 }); 135 });
@@ -125,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> {
125 143
126 pub fn enable_temperature(&self) -> Temperature { 144 pub fn enable_temperature(&self) -> Temperature {
127 cfg_if! { 145 cfg_if! {
128 if #[cfg(adc_g0)] { 146 if #[cfg(any(adc_g0, adc_u0))] {
129 T::regs().ccr().modify(|reg| { 147 T::regs().ccr().modify(|reg| {
130 reg.set_tsen(true); 148 reg.set_tsen(true);
131 }); 149 });
@@ -145,7 +163,7 @@ impl<'d, T: Instance> Adc<'d, T> {
145 163
146 pub fn enable_vbat(&self) -> Vbat { 164 pub fn enable_vbat(&self) -> Vbat {
147 cfg_if! { 165 cfg_if! {
148 if #[cfg(adc_g0)] { 166 if #[cfg(any(adc_g0, adc_u0))] {
149 T::regs().ccr().modify(|reg| { 167 T::regs().ccr().modify(|reg| {
150 reg.set_vbaten(true); 168 reg.set_vbaten(true);
151 }); 169 });
@@ -168,9 +186,9 @@ impl<'d, T: Instance> Adc<'d, T> {
168 } 186 }
169 187
170 pub fn set_resolution(&mut self, resolution: Resolution) { 188 pub fn set_resolution(&mut self, resolution: Resolution) {
171 #[cfg(not(adc_g0))] 189 #[cfg(not(any(adc_g0, adc_u0)))]
172 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 190 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
173 #[cfg(adc_g0)] 191 #[cfg(any(adc_g0, adc_u0))]
174 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); 192 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
175 } 193 }
176 194
@@ -231,9 +249,9 @@ impl<'d, T: Instance> Adc<'d, T> {
231 Self::set_channel_sample_time(pin.channel(), self.sample_time); 249 Self::set_channel_sample_time(pin.channel(), self.sample_time);
232 250
233 // Select channel 251 // Select channel
234 #[cfg(not(adc_g0))] 252 #[cfg(not(any(adc_g0, adc_u0)))]
235 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); 253 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
236 #[cfg(adc_g0)] 254 #[cfg(any(adc_g0, adc_u0))]
237 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); 255 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel()));
238 256
239 // Some models are affected by an erratum: 257 // Some models are affected by an erratum:
@@ -261,7 +279,7 @@ impl<'d, T: Instance> Adc<'d, T> {
261 279
262 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { 280 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
263 cfg_if! { 281 cfg_if! {
264 if #[cfg(adc_g0)] { 282 if #[cfg(any(adc_g0, adc_u0))] {
265 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 283 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
266 } else if #[cfg(adc_h5)] { 284 } else if #[cfg(adc_h5)] {
267 match _ch { 285 match _ch {
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index e32f19d91..e5cfee528 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -368,6 +368,7 @@ impl Registers {
368 w.set_rfne(0, true); // Rx Fifo 0 New Msg 368 w.set_rfne(0, true); // Rx Fifo 0 New Msg
369 w.set_rfne(1, true); // Rx Fifo 1 New Msg 369 w.set_rfne(1, true); // Rx Fifo 1 New Msg
370 w.set_tce(true); // Tx Complete 370 w.set_tce(true); // Tx Complete
371 w.set_boe(true); // Bus-Off Status Changed
371 }); 372 });
372 self.regs.ile().modify(|w| { 373 self.regs.ile().modify(|w| {
373 w.set_eint0(true); // Interrupt Line 0 374 w.set_eint0(true); // Interrupt Line 0
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index e31821ca2..563f542d4 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -44,53 +44,51 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
44 44
45 let ir = regs.ir().read(); 45 let ir = regs.ir().read();
46 46
47 { 47 if ir.tc() {
48 if ir.tc() { 48 regs.ir().write(|w| w.set_tc(true));
49 regs.ir().write(|w| w.set_tc(true)); 49 }
50 } 50 if ir.tefn() {
51 if ir.tefn() { 51 regs.ir().write(|w| w.set_tefn(true));
52 regs.ir().write(|w| w.set_tefn(true)); 52 }
53 }
54 53
55 match &T::state().tx_mode { 54 match &T::state().tx_mode {
56 TxMode::NonBuffered(waker) => waker.wake(), 55 TxMode::NonBuffered(waker) => waker.wake(),
57 TxMode::ClassicBuffered(buf) => { 56 TxMode::ClassicBuffered(buf) => {
58 if !T::registers().tx_queue_is_full() { 57 if !T::registers().tx_queue_is_full() {
59 match buf.tx_receiver.try_receive() { 58 match buf.tx_receiver.try_receive() {
60 Ok(frame) => { 59 Ok(frame) => {
61 _ = T::registers().write(&frame); 60 _ = T::registers().write(&frame);
62 }
63 Err(_) => {}
64 } 61 }
62 Err(_) => {}
65 } 63 }
66 } 64 }
67 TxMode::FdBuffered(buf) => { 65 }
68 if !T::registers().tx_queue_is_full() { 66 TxMode::FdBuffered(buf) => {
69 match buf.tx_receiver.try_receive() { 67 if !T::registers().tx_queue_is_full() {
70 Ok(frame) => { 68 match buf.tx_receiver.try_receive() {
71 _ = T::registers().write(&frame); 69 Ok(frame) => {
72 } 70 _ = T::registers().write(&frame);
73 Err(_) => {}
74 } 71 }
72 Err(_) => {}
75 } 73 }
76 } 74 }
77 } 75 }
78 } 76 }
79 77
80 if ir.ped() || ir.pea() {
81 regs.ir().write(|w| {
82 w.set_ped(true);
83 w.set_pea(true);
84 });
85 }
86
87 if ir.rfn(0) { 78 if ir.rfn(0) {
88 T::state().rx_mode.on_interrupt::<T>(0); 79 T::state().rx_mode.on_interrupt::<T>(0);
89 } 80 }
90
91 if ir.rfn(1) { 81 if ir.rfn(1) {
92 T::state().rx_mode.on_interrupt::<T>(1); 82 T::state().rx_mode.on_interrupt::<T>(1);
93 } 83 }
84
85 if ir.bo() {
86 regs.ir().write(|w| w.set_bo(true));
87 if regs.psr().read().bo() {
88 // Initiate bus-off recovery sequence by resetting CCCR.INIT
89 regs.cccr().modify(|w| w.set_init(false));
90 }
91 }
94 } 92 }
95} 93}
96 94
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index 13fb6778c..ad7c79f12 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -13,6 +13,8 @@ pub struct Crc<'d> {
13} 13}
14 14
15/// CRC configuration errlr 15/// CRC configuration errlr
16#[derive(Debug)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16pub enum ConfigError { 18pub enum ConfigError {
17 /// The selected polynomial is invalid. 19 /// The selected polynomial is invalid.
18 InvalidPolynomial, 20 InvalidPolynomial,
diff --git a/embassy-stm32/src/dac/tsel.rs b/embassy-stm32/src/dac/tsel.rs
index 22d8d3dfa..1877954b9 100644
--- a/embassy-stm32/src/dac/tsel.rs
+++ b/embassy-stm32/src/dac/tsel.rs
@@ -235,6 +235,23 @@ pub enum TriggerSel {
235 Exti9 = 13, 235 Exti9 = 13,
236} 236}
237 237
238/// Trigger selection for U0.
239#[cfg(stm32u0)]
240#[derive(Debug, Copy, Clone, Eq, PartialEq)]
241#[cfg_attr(feature = "defmt", derive(defmt::Format))]
242pub enum TriggerSel {
243 Software = 0,
244 Tim1 = 1,
245 Tim2 = 2,
246 Tim3 = 3,
247 Tim6 = 5,
248 Tim7 = 6,
249 Tim15 = 8,
250 Lptim1 = 11,
251 Lptim2 = 12,
252 Exti9 = 14,
253}
254
238/// Trigger selection for G4. 255/// Trigger selection for G4.
239#[cfg(stm32g4)] 256#[cfg(stm32g4)]
240#[derive(Debug, Copy, Clone, Eq, PartialEq)] 257#[derive(Debug, Copy, Clone, Eq, PartialEq)]
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 9d7861816..8c6ca2471 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -101,10 +101,11 @@ pub enum FlashBank {
101#[cfg_attr(flash_h7ab, path = "h7.rs")] 101#[cfg_attr(flash_h7ab, path = "h7.rs")]
102#[cfg_attr(flash_u5, path = "u5.rs")] 102#[cfg_attr(flash_u5, path = "u5.rs")]
103#[cfg_attr(flash_h50, path = "h50.rs")] 103#[cfg_attr(flash_h50, path = "h50.rs")]
104#[cfg_attr(flash_u0, path = "u0.rs")]
104#[cfg_attr( 105#[cfg_attr(
105 not(any( 106 not(any(
106 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, 107 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0,
107 flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50 108 flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0
108 )), 109 )),
109 path = "other.rs" 110 path = "other.rs"
110)] 111)]
diff --git a/embassy-stm32/src/flash/u0.rs b/embassy-stm32/src/flash/u0.rs
new file mode 100644
index 000000000..dfc5a2f76
--- /dev/null
+++ b/embassy-stm32/src/flash/u0.rs
@@ -0,0 +1,96 @@
1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering};
3
4use cortex_m::interrupt;
5
6use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
7use crate::flash::Error;
8use crate::pac;
9
10pub(crate) const fn is_default_layout() -> bool {
11 true
12}
13
14pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
15 &FLASH_REGIONS
16}
17
18pub(crate) unsafe fn lock() {
19 pac::FLASH.cr().modify(|w| w.set_lock(true));
20}
21pub(crate) unsafe fn unlock() {
22 // Wait, while the memory interface is busy.
23 while pac::FLASH.sr().read().bsy1() {}
24
25 // Unlock flash
26 if pac::FLASH.cr().read().lock() {
27 pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123));
28 pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
29 }
30}
31
32pub(crate) unsafe fn enable_blocking_write() {
33 assert_eq!(0, WRITE_SIZE % 4);
34 pac::FLASH.cr().write(|w| w.set_pg(true));
35}
36
37pub(crate) unsafe fn disable_blocking_write() {
38 pac::FLASH.cr().write(|w| w.set_pg(false));
39}
40
41pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
42 let mut address = start_address;
43 for val in buf.chunks(4) {
44 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
45 address += val.len() as u32;
46
47 // prevents parallelism errors
48 fence(Ordering::SeqCst);
49 }
50
51 wait_ready_blocking()
52}
53
54pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
55 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
56 while pac::FLASH.sr().read().bsy1() {}
57 clear_all_err();
58
59 interrupt::free(|_| {
60 pac::FLASH.cr().modify(|w| {
61 w.set_per(true);
62 w.set_pnb(idx as u8);
63 w.set_strt(true);
64 });
65 });
66
67 let ret: Result<(), Error> = wait_ready_blocking();
68 pac::FLASH.cr().modify(|w| w.set_per(false));
69 ret
70}
71
72pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
73 while pac::FLASH.sr().read().bsy1() {}
74
75 let sr = pac::FLASH.sr().read();
76
77 if sr.progerr() {
78 return Err(Error::Prog);
79 }
80
81 if sr.wrperr() {
82 return Err(Error::Protected);
83 }
84
85 if sr.pgaerr() {
86 return Err(Error::Unaligned);
87 }
88
89 Ok(())
90}
91
92pub(crate) unsafe fn clear_all_err() {
93 // read and write back the same value.
94 // This clears all "write 1 to clear" bits.
95 pac::FLASH.sr().modify(|_| {});
96}
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index e7fdf4da6..d21e5c47c 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -933,7 +933,6 @@ impl<'d, T: BasicInstance> Uart<'d, T, Async> {
933 /// I/O in idle or in reception. 933 /// I/O in idle or in reception.
934 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict 934 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
935 /// on the line must be managed by software (for instance by using a centralized arbiter). 935 /// on the line must be managed by software (for instance by using a centralized arbiter).
936 #[cfg(not(any(usart_v1, usart_v2)))]
937 #[doc(alias("HDSEL"))] 936 #[doc(alias("HDSEL"))]
938 pub fn new_half_duplex( 937 pub fn new_half_duplex(
939 peri: impl Peripheral<P = T> + 'd, 938 peri: impl Peripheral<P = T> + 'd,
@@ -943,7 +942,10 @@ impl<'d, T: BasicInstance> Uart<'d, T, Async> {
943 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 942 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
944 mut config: Config, 943 mut config: Config,
945 ) -> Result<Self, ConfigError> { 944 ) -> Result<Self, ConfigError> {
946 config.swap_rx_tx = false; 945 #[cfg(not(any(usart_v1, usart_v2)))]
946 {
947 config.swap_rx_tx = false;
948 }
947 config.half_duplex = true; 949 config.half_duplex = true;
948 950
949 Self::new_inner( 951 Self::new_inner(
@@ -1084,14 +1086,16 @@ impl<'d, T: BasicInstance> Uart<'d, T, Blocking> {
1084 /// I/O in idle or in reception. 1086 /// I/O in idle or in reception.
1085 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict 1087 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
1086 /// on the line must be managed by software (for instance by using a centralized arbiter). 1088 /// on the line must be managed by software (for instance by using a centralized arbiter).
1087 #[cfg(not(any(usart_v1, usart_v2)))]
1088 #[doc(alias("HDSEL"))] 1089 #[doc(alias("HDSEL"))]
1089 pub fn new_blocking_half_duplex( 1090 pub fn new_blocking_half_duplex(
1090 peri: impl Peripheral<P = T> + 'd, 1091 peri: impl Peripheral<P = T> + 'd,
1091 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1092 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
1092 mut config: Config, 1093 mut config: Config,
1093 ) -> Result<Self, ConfigError> { 1094 ) -> Result<Self, ConfigError> {
1094 config.swap_rx_tx = false; 1095 #[cfg(not(any(usart_v1, usart_v2)))]
1096 {
1097 config.swap_rx_tx = false;
1098 }
1095 config.half_duplex = true; 1099 config.half_duplex = true;
1096 1100
1097 Self::new_inner( 1101 Self::new_inner(
@@ -1354,10 +1358,9 @@ fn configure(
1354 } 1358 }
1355 }); 1359 });
1356 1360
1357 #[cfg(not(usart_v1))]
1358 r.cr3().modify(|w| { 1361 r.cr3().modify(|w| {
1362 #[cfg(not(usart_v1))]
1359 w.set_onebit(config.assume_noise_free); 1363 w.set_onebit(config.assume_noise_free);
1360 #[cfg(any(usart_v3, usart_v4))]
1361 w.set_hdsel(config.half_duplex); 1364 w.set_hdsel(config.half_duplex);
1362 }); 1365 });
1363 1366
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index 1e3c44167..349438ec5 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -23,7 +23,7 @@ fn common_init<T: Instance>() {
23 ) 23 )
24 } 24 }
25 25
26 #[cfg(any(stm32l4, stm32l5, stm32wb))] 26 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32u0))]
27 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); 27 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
28 28
29 #[cfg(pwr_h5)] 29 #[cfg(pwr_h5)]
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index cabc06367..b386c6977 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -672,45 +672,51 @@ impl<'d, T: Instance> Bus<'d, T> {
672 672
673 let r = T::regs(); 673 let r = T::regs();
674 674
675 // Configure RX fifo size. All endpoints share the same FIFO area. 675 // ERRATA NOTE: Don't interrupt FIFOs being written to. The interrupt
676 let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); 676 // handler COULD interrupt us here and do FIFO operations, so ensure
677 trace!("configuring rx fifo size={}", rx_fifo_size_words); 677 // the interrupt does not occur.
678 678 critical_section::with(|_| {
679 r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)); 679 // Configure RX fifo size. All endpoints share the same FIFO area.
680 680 let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
681 // Configure TX (USB in direction) fifo size for each endpoint 681 trace!("configuring rx fifo size={}", rx_fifo_size_words);
682 let mut fifo_top = rx_fifo_size_words; 682
683 for i in 0..T::ENDPOINT_COUNT { 683 r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
684 if let Some(ep) = self.ep_in[i] { 684
685 trace!( 685 // Configure TX (USB in direction) fifo size for each endpoint
686 "configuring tx fifo ep={}, offset={}, size={}", 686 let mut fifo_top = rx_fifo_size_words;
687 i, 687 for i in 0..T::ENDPOINT_COUNT {
688 fifo_top, 688 if let Some(ep) = self.ep_in[i] {
689 ep.fifo_size_words 689 trace!(
690 ); 690 "configuring tx fifo ep={}, offset={}, size={}",
691 691 i,
692 let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; 692 fifo_top,
693 693 ep.fifo_size_words
694 dieptxf.write(|w| { 694 );
695 w.set_fd(ep.fifo_size_words); 695
696 w.set_sa(fifo_top); 696 let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
697 }); 697
698 dieptxf.write(|w| {
699 w.set_fd(ep.fifo_size_words);
700 w.set_sa(fifo_top);
701 });
698 702
699 fifo_top += ep.fifo_size_words; 703 fifo_top += ep.fifo_size_words;
704 }
700 } 705 }
701 }
702 706
703 assert!( 707 assert!(
704 fifo_top <= T::FIFO_DEPTH_WORDS, 708 fifo_top <= T::FIFO_DEPTH_WORDS,
705 "FIFO allocations exceeded maximum capacity" 709 "FIFO allocations exceeded maximum capacity"
706 ); 710 );
707 711
708 // Flush fifos 712 // Flush fifos
709 r.grstctl().write(|w| { 713 r.grstctl().write(|w| {
710 w.set_rxfflsh(true); 714 w.set_rxfflsh(true);
711 w.set_txfflsh(true); 715 w.set_txfflsh(true);
712 w.set_txfnum(0x10); 716 w.set_txfnum(0x10);
717 });
713 }); 718 });
719
714 loop { 720 loop {
715 let x = r.grstctl().read(); 721 let x = r.grstctl().read();
716 if !x.rxfflsh() && !x.txfflsh() { 722 if !x.rxfflsh() && !x.txfflsh() {
@@ -1208,27 +1214,31 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1208 .await 1214 .await
1209 } 1215 }
1210 1216
1211 // Setup transfer size 1217 // ERRATA: Transmit data FIFO is corrupted when a write sequence to the FIFO is interrupted with
1212 r.dieptsiz(index).write(|w| { 1218 // accesses to certain OTG_FS registers.
1213 w.set_mcnt(1); 1219 //
1214 w.set_pktcnt(1); 1220 // Prevent the interrupt (which might poke FIFOs) from executing while copying data to FIFOs.
1215 w.set_xfrsiz(buf.len() as _);
1216 });
1217
1218 critical_section::with(|_| { 1221 critical_section::with(|_| {
1222 // Setup transfer size
1223 r.dieptsiz(index).write(|w| {
1224 w.set_mcnt(1);
1225 w.set_pktcnt(1);
1226 w.set_xfrsiz(buf.len() as _);
1227 });
1228
1219 // Enable endpoint 1229 // Enable endpoint
1220 r.diepctl(index).modify(|w| { 1230 r.diepctl(index).modify(|w| {
1221 w.set_cnak(true); 1231 w.set_cnak(true);
1222 w.set_epena(true); 1232 w.set_epena(true);
1223 }); 1233 });
1224 });
1225 1234
1226 // Write data to FIFO 1235 // Write data to FIFO
1227 for chunk in buf.chunks(4) { 1236 for chunk in buf.chunks(4) {
1228 let mut tmp = [0u8; 4]; 1237 let mut tmp = [0u8; 4];
1229 tmp[0..chunk.len()].copy_from_slice(chunk); 1238 tmp[0..chunk.len()].copy_from_slice(chunk);
1230 r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))); 1239 r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp)));
1231 } 1240 }
1241 });
1232 1242
1233 trace!("write done ep={:?}", self.info.addr); 1243 trace!("write done ep={:?}", self.info.addr);
1234 1244
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index f48808cb3..81a2d2623 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -107,14 +107,14 @@ const EP_COUNT: usize = 8;
107 107
108#[cfg(any(usbram_16x1_512, usbram_16x2_512))] 108#[cfg(any(usbram_16x1_512, usbram_16x2_512))]
109const USBRAM_SIZE: usize = 512; 109const USBRAM_SIZE: usize = 512;
110#[cfg(usbram_16x2_1024)] 110#[cfg(any(usbram_16x2_1024, usbram_32_1024))]
111const USBRAM_SIZE: usize = 1024; 111const USBRAM_SIZE: usize = 1024;
112#[cfg(usbram_32_2048)] 112#[cfg(usbram_32_2048)]
113const USBRAM_SIZE: usize = 2048; 113const USBRAM_SIZE: usize = 2048;
114 114
115#[cfg(not(usbram_32_2048))] 115#[cfg(not(any(usbram_32_2048, usbram_32_1024)))]
116const USBRAM_ALIGN: usize = 2; 116const USBRAM_ALIGN: usize = 2;
117#[cfg(usbram_32_2048)] 117#[cfg(any(usbram_32_2048, usbram_32_1024))]
118const USBRAM_ALIGN: usize = 4; 118const USBRAM_ALIGN: usize = 4;
119 119
120const NEW_AW: AtomicWaker = AtomicWaker::new(); 120const NEW_AW: AtomicWaker = AtomicWaker::new();
@@ -159,7 +159,7 @@ fn calc_out_len(len: u16) -> (u16, u16) {
159 } 159 }
160} 160}
161 161
162#[cfg(not(usbram_32_2048))] 162#[cfg(not(any(usbram_32_2048, usbram_32_1024)))]
163mod btable { 163mod btable {
164 use super::*; 164 use super::*;
165 165
@@ -180,7 +180,7 @@ mod btable {
180 USBRAM.mem(index * 4 + 3).read() 180 USBRAM.mem(index * 4 + 3).read()
181 } 181 }
182} 182}
183#[cfg(usbram_32_2048)] 183#[cfg(any(usbram_32_2048, usbram_32_1024))]
184mod btable { 184mod btable {
185 use super::*; 185 use super::*;
186 186
@@ -224,9 +224,9 @@ impl<T: Instance> EndpointBuffer<T> {
224 let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); 224 let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
225 val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]); 225 val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]);
226 226
227 #[cfg(not(usbram_32_2048))] 227 #[cfg(not(any(usbram_32_2048, usbram_32_1024)))]
228 let val = u16::from_le_bytes(val); 228 let val = u16::from_le_bytes(val);
229 #[cfg(usbram_32_2048)] 229 #[cfg(any(usbram_32_2048, usbram_32_1024))]
230 let val = u32::from_le_bytes(val); 230 let val = u32::from_le_bytes(val);
231 USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val); 231 USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val);
232 } 232 }
diff --git a/examples/stm32f334/.cargo/config.toml b/examples/stm32f334/.cargo/config.toml
index caf947be6..f38c90a31 100644
--- a/examples/stm32f334/.cargo/config.toml
+++ b/examples/stm32f334/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list`
3runner = "probe-run --chip STM32F334R8" 3runner = "probe-rs run --chip STM32F334R8"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml
index db3a7ceff..83fc6d6f8 100644
--- a/examples/stm32l4/.cargo/config.toml
+++ b/examples/stm32l4/.cargo/config.toml
@@ -2,7 +2,7 @@
2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3#runner = "probe-rs run --chip STM32L475VGT6" 3#runner = "probe-rs run --chip STM32L475VGT6"
4#runner = "probe-rs run --chip STM32L475VG" 4#runner = "probe-rs run --chip STM32L475VG"
5runner = "probe-run --chip STM32L4S5QI" 5runner = "probe-rs run --chip STM32L4S5QI"
6 6
7[build] 7[build]
8target = "thumbv7em-none-eabi" 8target = "thumbv7em-none-eabi"
diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml
index 495be3e75..5868372dd 100644
--- a/examples/stm32u0/Cargo.toml
+++ b/examples/stm32u0/Cargo.toml
@@ -6,10 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32u083rc to your chip name, if necessary. 8# Change stm32u083rc to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] }
13 14
14defmt = "0.3" 15defmt = "0.3"
15defmt-rtt = "0.4" 16defmt-rtt = "0.4"
@@ -21,5 +22,8 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 22futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
22heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
23 24
25micromath = "2.0.0"
26chrono = { version = "0.4.38", default-features = false }
27
24[profile.release] 28[profile.release]
25debug = 2 29debug = 2
diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs
new file mode 100644
index 000000000..4410448f1
--- /dev/null
+++ b/examples/stm32u0/src/bin/adc.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::adc::{Adc, Resolution};
6use embassy_stm32::Config;
7use embassy_time::Duration;
8use {defmt_rtt as _, panic_probe as _};
9
10#[cortex_m_rt::entry]
11fn main() -> ! {
12 info!("Hello World!");
13
14 let mut config = Config::default();
15 {
16 use embassy_stm32::rcc::*;
17 config.rcc.mux.adcsel = mux::Adcsel::SYS;
18 }
19 let p = embassy_stm32::init(config);
20
21 let mut adc = Adc::new(p.ADC1);
22 adc.set_resolution(Resolution::BITS8);
23 let mut channel = p.PC0;
24
25 loop {
26 let v = adc.read(&mut channel);
27 info!("--> {}", v);
28 embassy_time::block_for(Duration::from_millis(200));
29 }
30}
diff --git a/examples/stm32u0/src/bin/crc.rs b/examples/stm32u0/src/bin/crc.rs
new file mode 100644
index 000000000..d1b545d5b
--- /dev/null
+++ b/examples/stm32u0/src/bin/crc.rs
@@ -0,0 +1,31 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::crc::{Config, Crc, InputReverseConfig, PolySize};
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!");
13
14 // Setup for: https://crccalc.com/?crc=Life, it never dieWomen are my favorite guy&method=crc32&datatype=ascii&outtype=0
15 let mut crc = Crc::new(
16 p.CRC,
17 unwrap!(Config::new(
18 InputReverseConfig::Byte,
19 true,
20 PolySize::Width32,
21 0xFFFFFFFF,
22 0x04C11DB7
23 )),
24 );
25
26 let output = crc.feed_bytes(b"Life, it never die\nWomen are my favorite guy") ^ 0xFFFFFFFF;
27
28 defmt::assert_eq!(output, 0x33F0E26B);
29
30 cortex_m::asm::bkpt();
31}
diff --git a/examples/stm32u0/src/bin/dac.rs b/examples/stm32u0/src/bin/dac.rs
new file mode 100644
index 000000000..fdbf1d374
--- /dev/null
+++ b/examples/stm32u0/src/bin/dac.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::dac::{DacCh1, Value};
6use embassy_stm32::dma::NoDma;
7use {defmt_rtt as _, panic_probe as _};
8
9#[cortex_m_rt::entry]
10fn main() -> ! {
11 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!");
13
14 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
15
16 loop {
17 for v in 0..=255 {
18 dac.set(Value::Bit8(to_sine_wave(v)));
19 }
20 }
21}
22
23use micromath::F32Ext;
24
25fn to_sine_wave(v: u8) -> u8 {
26 if v >= 128 {
27 // top half
28 let r = 3.14 * ((v - 128) as f32 / 128.0);
29 (r.sin() * 128.0 + 127.0) as u8
30 } else {
31 // bottom half
32 let r = 3.14 + 3.14 * (v as f32 / 128.0);
33 (r.sin() * 128.0 + 127.0) as u8
34 }
35}
diff --git a/examples/stm32u0/src/bin/flash.rs b/examples/stm32u0/src/bin/flash.rs
new file mode 100644
index 000000000..01b80a76b
--- /dev/null
+++ b/examples/stm32u0/src/bin/flash.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::flash::Flash;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!");
13
14 let addr: u32 = 0x40000 - 2 * 1024;
15
16 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region;
17
18 info!("Reading...");
19 let mut buf = [0u8; 32];
20 unwrap!(f.blocking_read(addr, &mut buf));
21 info!("Read: {=[u8]:x}", buf);
22 info!("Erasing...");
23 unwrap!(f.blocking_erase(addr, addr + 2 * 1024));
24
25 info!("Reading...");
26 let mut buf = [0u8; 32];
27 unwrap!(f.blocking_read(addr, &mut buf));
28 info!("Read after erase: {=[u8]:x}", buf);
29
30 info!("Writing...");
31 unwrap!(f.blocking_write(
32 addr,
33 &[
34 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
35 30, 31, 32
36 ]
37 ));
38
39 info!("Reading...");
40 let mut buf = [0u8; 32];
41 unwrap!(f.blocking_read(addr, &mut buf));
42 info!("Read: {=[u8]:x}", buf);
43}
diff --git a/examples/stm32u0/src/bin/i2c.rs b/examples/stm32u0/src/bin/i2c.rs
new file mode 100644
index 000000000..2861bc091
--- /dev/null
+++ b/examples/stm32u0/src/bin/i2c.rs
@@ -0,0 +1,21 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::i2c::I2c;
7use embassy_stm32::time::Hertz;
8use {defmt_rtt as _, panic_probe as _};
9
10const ADDRESS: u8 = 0x5F;
11const WHOAMI: u8 = 0x0F;
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default());
16 let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
17
18 let mut data = [0u8; 1];
19 unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data));
20 info!("Whoami: {}", data[0]);
21}
diff --git a/examples/stm32u0/src/bin/rng.rs b/examples/stm32u0/src/bin/rng.rs
new file mode 100644
index 000000000..89445b042
--- /dev/null
+++ b/examples/stm32u0/src/bin/rng.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::rcc::mux::Clk48sel;
7use embassy_stm32::rng::Rng;
8use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 RNG_CRYP => rng::InterruptHandler<peripherals::RNG>;
13});
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let mut config = Config::default();
18 {
19 use embassy_stm32::rcc::*;
20 config.rcc.hsi = true;
21 config.rcc.pll = Some(Pll {
22 source: PllSource::HSI, // 16 MHz
23 prediv: PllPreDiv::DIV1,
24 mul: PllMul::MUL7, // 16 * 7 = 112 MHz
25 divp: None,
26 divq: None,
27 divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz
28 });
29 config.rcc.sys = Sysclk::PLL1_R;
30 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: false }); // needed for RNG
31 config.rcc.mux.clk48sel = Clk48sel::HSI48; // needed for RNG (or use MSI or PLLQ if you want)
32 }
33
34 let p = embassy_stm32::init(config);
35
36 info!("Hello World!");
37
38 let mut rng = Rng::new(p.RNG, Irqs);
39
40 let mut buf = [0u8; 16];
41 unwrap!(rng.async_fill_bytes(&mut buf).await);
42 info!("random bytes: {:02x}", buf);
43}
diff --git a/examples/stm32u0/src/bin/rtc.rs b/examples/stm32u0/src/bin/rtc.rs
new file mode 100644
index 000000000..72fa0fde4
--- /dev/null
+++ b/examples/stm32u0/src/bin/rtc.rs
@@ -0,0 +1,49 @@
1#![no_std]
2#![no_main]
3
4use chrono::{NaiveDate, NaiveDateTime};
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::rtc::{Rtc, RtcConfig};
8use embassy_stm32::Config;
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut config = Config::default();
15 {
16 use embassy_stm32::rcc::*;
17 config.rcc.sys = Sysclk::PLL1_R;
18 config.rcc.hsi = true;
19 config.rcc.pll = Some(Pll {
20 source: PllSource::HSI, // 16 MHz
21 prediv: PllPreDiv::DIV1,
22 mul: PllMul::MUL7, // 16 * 7 = 112 MHz
23 divp: None,
24 divq: None,
25 divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz
26 });
27 config.rcc.ls = LsConfig::default();
28 }
29
30 let p = embassy_stm32::init(config);
31
32 info!("Hello World!");
33
34 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
35 .unwrap()
36 .and_hms_opt(10, 30, 15)
37 .unwrap();
38
39 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
40 info!("Got RTC! {:?}", now.and_utc().timestamp());
41
42 rtc.set_datetime(now.into()).expect("datetime not set");
43
44 // In reality the delay would be much longer
45 Timer::after_millis(20000).await;
46
47 let then: NaiveDateTime = rtc.now().unwrap().into();
48 info!("Got RTC! {:?}", then.and_utc().timestamp());
49}
diff --git a/examples/stm32u0/src/bin/spi.rs b/examples/stm32u0/src/bin/spi.rs
new file mode 100644
index 000000000..5693a3765
--- /dev/null
+++ b/examples/stm32u0/src/bin/spi.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::gpio::{Level, Output, Speed};
6use embassy_stm32::spi::{Config, Spi};
7use embassy_stm32::time::Hertz;
8use {defmt_rtt as _, panic_probe as _};
9
10#[cortex_m_rt::entry]
11fn main() -> ! {
12 info!("Hello World!");
13
14 let p = embassy_stm32::init(Default::default());
15
16 let mut spi_config = Config::default();
17 spi_config.frequency = Hertz(1_000_000);
18
19 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
20
21 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
22
23 loop {
24 let mut buf = [0x0Au8; 4];
25 cs.set_low();
26 unwrap!(spi.blocking_transfer_in_place(&mut buf));
27 cs.set_high();
28 info!("xfer {=[u8]:x}", buf);
29 }
30}
diff --git a/examples/stm32u0/src/bin/usart.rs b/examples/stm32u0/src/bin/usart.rs
new file mode 100644
index 000000000..037a5c833
--- /dev/null
+++ b/examples/stm32u0/src/bin/usart.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_stm32::usart::{Config, Uart};
6use {defmt_rtt as _, panic_probe as _};
7
8#[cortex_m_rt::entry]
9fn main() -> ! {
10 info!("Hello World!");
11
12 let p = embassy_stm32::init(Default::default());
13
14 let config = Config::default();
15 let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap();
16
17 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
18 info!("wrote Hello, starting echo");
19
20 let mut buf = [0u8; 1];
21 loop {
22 unwrap!(usart.blocking_read(&mut buf));
23 unwrap!(usart.blocking_write(&buf));
24 }
25}
diff --git a/examples/stm32u0/src/bin/usb_serial.rs b/examples/stm32u0/src/bin/usb_serial.rs
new file mode 100644
index 000000000..9b38fd5dc
--- /dev/null
+++ b/examples/stm32u0/src/bin/usb_serial.rs
@@ -0,0 +1,109 @@
1#![no_std]
2#![no_main]
3
4use defmt::{panic, *};
5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner;
7use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder;
12use futures::future::join;
13use panic_probe as _;
14
15bind_interrupts!(struct Irqs {
16 USB_DRD_FS => usb::InterruptHandler<peripherals::USB>;
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.hsi = true;
25 config.rcc.pll = Some(Pll {
26 source: PllSource::HSI, // 16 MHz
27 prediv: PllPreDiv::DIV1,
28 mul: PllMul::MUL7,
29 divp: None,
30 divq: None,
31 divr: Some(PllRDiv::DIV2), // 56 MHz
32 });
33 config.rcc.sys = Sysclk::PLL1_R;
34 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
35 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; // USB uses ICLK
36 }
37
38 let p = embassy_stm32::init(config);
39
40 info!("Hello World!");
41
42 // Create the driver, from the HAL.
43 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
44
45 // Create embassy-usb Config
46 let config = embassy_usb::Config::new(0xc0de, 0xcafe);
47 //config.max_packet_size_0 = 64;
48
49 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors.
51 let mut config_descriptor = [0; 256];
52 let mut bos_descriptor = [0; 256];
53 let mut control_buf = [0; 7];
54
55 let mut state = State::new();
56
57 let mut builder = Builder::new(
58 driver,
59 config,
60 &mut config_descriptor,
61 &mut bos_descriptor,
62 &mut [], // no msos descriptors
63 &mut control_buf,
64 );
65
66 // Create classes on the builder.
67 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
68
69 // Build the builder.
70 let mut usb = builder.build();
71
72 // Run the USB device.
73 let usb_fut = usb.run();
74
75 // Do stuff with the class!
76 let echo_fut = async {
77 loop {
78 class.wait_connection().await;
79 info!("Connected");
80 let _ = echo(&mut class).await;
81 info!("Disconnected");
82 }
83 };
84
85 // Run everything concurrently.
86 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
87 join(usb_fut, echo_fut).await;
88}
89
90struct Disconnected {}
91
92impl From<EndpointError> for Disconnected {
93 fn from(val: EndpointError) -> Self {
94 match val {
95 EndpointError::BufferOverflow => panic!("Buffer overflow"),
96 EndpointError::Disabled => Disconnected {},
97 }
98 }
99}
100
101async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
102 let mut buf = [0; 64];
103 loop {
104 let n = class.read_packet(&mut buf).await?;
105 let data = &buf[..n];
106 info!("data: {:x}", data);
107 class.write_packet(data).await?;
108 }
109}
diff --git a/examples/stm32u0/src/bin/wdt.rs b/examples/stm32u0/src/bin/wdt.rs
new file mode 100644
index 000000000..f6276e2e9
--- /dev/null
+++ b/examples/stm32u0/src/bin/wdt.rs
@@ -0,0 +1,41 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::wdg::IndependentWatchdog;
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let mut led = Output::new(p.PA5, Level::High, Speed::Low);
17
18 let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000);
19 wdt.unleash();
20
21 let mut i = 0;
22
23 loop {
24 info!("high");
25 led.set_high();
26 Timer::after_millis(300).await;
27
28 info!("low");
29 led.set_low();
30 Timer::after_millis(300).await;
31
32 // Pet watchdog for 5 iterations and then stop.
33 // MCU should restart in 1 second after the last pet.
34 if i < 5 {
35 info!("Petting watchdog");
36 wdt.pet();
37 }
38
39 i += 1;
40 }
41}
diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml
index 51c499ee7..8b6d6d754 100644
--- a/examples/stm32wb/.cargo/config.toml
+++ b/examples/stm32wb/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list` 2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list`
3# runner = "probe-run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" 3# runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
4runner = "teleprobe local run --chip STM32WB55RG --elf" 4runner = "teleprobe local run --chip STM32WB55RG --elf"
5 5
6[build] 6[build]