aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaleb Garrett <[email protected]>2024-02-29 15:21:06 -0500
committerGitHub <[email protected]>2024-02-29 15:21:06 -0500
commit998532c33e037368fc3dcfa2ad59f7478c87f6ce (patch)
tree653909b504e3786492fbb1f1554ce703ba056fa3
parent54f502e5e6a355e0f132f33f3eecd2a0abe298bc (diff)
parent715b6d52e08944665728eed160a8408a8fbc4570 (diff)
Merge branch 'embassy-rs:main' into cryp
-rw-r--r--docs/modules/ROOT/pages/basic_application.adoc13
-rw-r--r--docs/modules/ROOT/pages/getting_started.adoc31
-rw-r--r--embassy-nrf/Cargo.toml2
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs5
-rw-r--r--embassy-nrf/src/lib.rs5
-rw-r--r--embassy-nrf/src/radio/ble.rs438
-rw-r--r--embassy-nrf/src/radio/mod.rs75
-rw-r--r--embassy-nrf/src/spim.rs4
-rw-r--r--embassy-stm32/Cargo.toml16
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs178
-rw-r--r--embassy-stm32/src/can/fdcan.rs66
-rw-r--r--embassy-stm32/src/can/frame.rs32
-rw-r--r--embassy-stm32/src/opamp.rs2
-rw-r--r--embassy-stm32/src/rcc/h.rs3
-rw-r--r--embassy-stm32/src/time_driver.rs38
-rw-r--r--embassy-stm32/src/timer/mod.rs31
-rw-r--r--embassy-stm32/src/wdg/mod.rs6
-rw-r--r--embassy-usb/Cargo.toml2
-rw-r--r--examples/nrf52840/Cargo.toml2
-rw-r--r--examples/nrf5340/Cargo.toml2
-rw-r--r--examples/rp/Cargo.toml2
-rw-r--r--examples/stm32g4/Cargo.toml2
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs4
-rw-r--r--examples/stm32l5/Cargo.toml2
24 files changed, 715 insertions, 246 deletions
diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc
index 95792d5a0..02b8981c9 100644
--- a/docs/modules/ROOT/pages/basic_application.adoc
+++ b/docs/modules/ROOT/pages/basic_application.adoc
@@ -17,15 +17,6 @@ The first thing you’ll notice are two attributes at the top of the file. These
17include::example$basic/src/main.rs[lines="1..2"] 17include::example$basic/src/main.rs[lines="1..2"]
18---- 18----
19 19
20=== Rust Nightly
21
22The next declaration is a Rust Unstable feature, which means that Embassy requires Rust Nightly:
23
24[source,rust]
25----
26include::example$basic/src/main.rs[lines="3"]
27----
28
29=== Dealing with errors 20=== Dealing with errors
30 21
31Then, what follows are some declarations on how to deal with panics and faults. During development, a good practice is to rely on `defmt-rtt` and `panic-probe` to print diagnostics to the terminal: 22Then, what follows are some declarations on how to deal with panics and faults. During development, a good practice is to rely on `defmt-rtt` and `panic-probe` to print diagnostics to the terminal:
@@ -41,7 +32,7 @@ After a bit of import declaration, the tasks run by the application should be de
41 32
42[source,rust] 33[source,rust]
43---- 34----
44include::example$basic/src/main.rs[lines="12..20"] 35include::example$basic/src/main.rs[lines="10..18"]
45---- 36----
46 37
47An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking. 38An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking.
@@ -56,7 +47,7 @@ We then initialize the HAL with a default config, which gives us a `Peripherals`
56 47
57[source,rust] 48[source,rust]
58---- 49----
59include::example$basic/src/main.rs[lines="22..-1"] 50include::example$basic/src/main.rs[lines="20..-1"]
60---- 51----
61 52
62What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following: 53What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following:
diff --git a/docs/modules/ROOT/pages/getting_started.adoc b/docs/modules/ROOT/pages/getting_started.adoc
index 24bde1c1f..73cb5530d 100644
--- a/docs/modules/ROOT/pages/getting_started.adoc
+++ b/docs/modules/ROOT/pages/getting_started.adoc
@@ -3,7 +3,7 @@
3So you want to try Embassy, great! To get started, there are a few tools you need to install: 3So you want to try Embassy, great! To get started, there are a few tools you need to install:
4 4
5* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code. 5* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code.
6* link:https://crates.io/crates/probe-rs[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well. 6* link:https://probe.rs/[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well.
7 7
8If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples. 8If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples.
9 9
@@ -82,19 +82,19 @@ If everything worked correctly, you should see a blinking LED on your board, and
82└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:27 82└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:27
83---- 83----
84 84
85NOTE: How does the `cargo run` command know how to connect to our board and program it? In each `examples` folder, there’s a `.cargo/config.toml` file which tells cargo to use link:https://probe.rs/[probe-rs] as the runner for ARM binaries in that folder. probe-rs handles communication with the debug probe and MCU. In order for this to work, probe-rs needs to know which chip it’s programming, so you’ll have to edit this file if you want to run examples on other chips. 85NOTE: How does the `+cargo run+` command know how to connect to our board and program it? In each `examples` folder, there’s a `.cargo/config.toml` file which tells cargo to use link:https://probe.rs/[probe-rs] as the runner for ARM binaries in that folder. probe-rs handles communication with the debug probe and MCU. In order for this to work, probe-rs needs to know which chip it’s programming, so you’ll have to edit this file if you want to run examples on other chips.
86 86
87=== It didn’t work! 87=== It didn’t work!
88 88
89If you hare having issues when running `cargo run --release`, please check the following: 89If you hare having issues when running `+cargo run --release+`, please check the following:
90 90
91* You are specifying the correct `--chip` on the command line, OR 91* You are specifying the correct `+--chip+` on the command line, OR
92* You have set `.cargo/config.toml`'s run line to the correct chip, AND 92* You have set `+.cargo/config.toml+`s run line to the correct chip, AND
93* You have changed `examples/Cargo.toml`'s HAL (e.g. embassy-stm32) dependency's feature to use the correct chip (replace the existing stm32xxxx feature) 93* You have changed `+examples/Cargo.toml+`’s HAL (e.g. embassy-stm32) dependency's feature to use the correct chip (replace the existing stm32xxxx feature)
94 94
95At this point the project should run. If you do not see a blinky LED for blinky, for example, be sure to check the code is toggling your board's LED pin. 95At this point the project should run. If you do not see a blinky LED for blinky, for example, be sure to check the code is toggling your board's LED pin.
96 96
97If you are trying to run an example with `cargo run --release` and you see the following output: 97If you are trying to run an example with `+cargo run --release+` and you see the following output:
98[source] 98[source]
99---- 99----
1000.000000 INFO Hello World! 1000.000000 INFO Hello World!
@@ -115,6 +115,22 @@ To get rid of the frame-index error add the following to your `Cargo.toml`:
115debug = 2 115debug = 2
116---- 116----
117 117
118If you’re getting an extremely long error message containing something like the following:
119
120[source]
121----
122error[E0463]: can't find crate for `std`
123 |
124 = note: the `thumbv6m-none-eabi` target may not support the standard library
125 = note: `std` is required by `stable_deref_trait` because it does not declare `#![no_std]`
126----
127
128Make sure that you didn’t accidentally run `+cargo add probe-rs+` (which adds it as a dependency) instead of link:https://probe.rs/docs/getting-started/installation/[correctly installing probe-rs].
129
130If you’re using a raspberry pi pico-w, make sure you’re running `+cargo run --bin wifi_blinky --release+` rather than the regular blinky. The pico-w’s on-board LED is connected to the WiFi chip, which needs to be initialized before the LED can be blinked.
131
132If you’re using an rp2040 debug probe (e.g. the pico probe) and are having issues after running `probe-rs info`, unplug and reconnect the probe, letting it power cycle. Running `probe-rs info` is link:https://github.com/probe-rs/probe-rs/issues/1849[known to put the pico probe into an unusable state].
133
118If you’re still having problems, check the link:https://embassy.dev/book/dev/faq.html[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room]. 134If you’re still having problems, check the link:https://embassy.dev/book/dev/faq.html[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room].
119 135
120== What's next? 136== What's next?
@@ -124,3 +140,4 @@ Congratulations, you have your first Embassy application running! Here are some
124* Read more about the xref:runtime.adoc[executor]. 140* Read more about the xref:runtime.adoc[executor].
125* Read more about the xref:hal.adoc[HAL]. 141* Read more about the xref:hal.adoc[HAL].
126* Start xref:basic_application.adoc[writing your application]. 142* Start xref:basic_application.adoc[writing your application].
143* Learn how to xref:new_project.adoc[start a new embassy project by adapting an example].
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 7e161df9b..0045d9f97 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -146,7 +146,7 @@ critical-section = "1.1"
146rand_core = "0.6.3" 146rand_core = "0.6.3"
147fixed = "1.10.0" 147fixed = "1.10.0"
148embedded-storage = "0.3.1" 148embedded-storage = "0.3.1"
149embedded-storage-async = "0.4.0" 149embedded-storage-async = "0.4.1"
150cfg-if = "1.0.0" 150cfg-if = "1.0.0"
151document-features = "0.2.7" 151document-features = "0.2.7"
152 152
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index 51c55cd4d..d3272b2e8 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -173,6 +173,9 @@ embassy_hal_internal::peripherals! {
173 173
174 // I2S 174 // I2S
175 I2S, 175 I2S,
176
177 // Radio
178 RADIO,
176} 179}
177 180
178impl_usb!(USBD, USBD, USBD); 181impl_usb!(USBD, USBD, USBD);
@@ -311,6 +314,8 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
311 314
312impl_i2s!(I2S, I2S, I2S); 315impl_i2s!(I2S, I2S, I2S);
313 316
317impl_radio!(RADIO, RADIO, RADIO);
318
314embassy_hal_internal::interrupt_mod!( 319embassy_hal_internal::interrupt_mod!(
315 POWER_CLOCK, 320 POWER_CLOCK,
316 RADIO, 321 RADIO,
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 358a7cc27..04a6293a4 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -45,6 +45,11 @@ pub mod buffered_uarte;
45pub mod gpio; 45pub mod gpio;
46#[cfg(feature = "gpiote")] 46#[cfg(feature = "gpiote")]
47pub mod gpiote; 47pub mod gpiote;
48
49// TODO: tested on other chips
50#[cfg(any(feature = "nrf52840"))]
51pub mod radio;
52
48#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] 53#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
49pub mod i2s; 54pub mod i2s;
50pub mod nvmc; 55pub mod nvmc;
diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs
new file mode 100644
index 000000000..24dba582f
--- /dev/null
+++ b/embassy-nrf/src/radio/ble.rs
@@ -0,0 +1,438 @@
1//! Radio driver implementation focused on Bluetooth Low-Energy transmission.
2
3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::Poll;
6
7use embassy_hal_internal::drop::OnDrop;
8use embassy_hal_internal::{into_ref, PeripheralRef};
9pub use pac::radio::mode::MODE_A as Mode;
10use pac::radio::pcnf0::PLEN_A as PreambleLength;
11use pac::radio::state::STATE_A as RadioState;
12pub use pac::radio::txpower::TXPOWER_A as TxPower;
13
14use crate::interrupt::typelevel::Interrupt;
15use crate::radio::*;
16use crate::util::slice_in_ram_or;
17
18/// RADIO error.
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21#[non_exhaustive]
22pub enum Error {
23 /// Buffer was too long.
24 BufferTooLong,
25 /// Buffer was to short.
26 BufferTooShort,
27 /// The buffer is not in data RAM. It is most likely in flash, and nRF's DMA cannot access flash.
28 BufferNotInRAM,
29}
30
31/// Radio driver.
32pub struct Radio<'d, T: Instance> {
33 _p: PeripheralRef<'d, T>,
34}
35
36impl<'d, T: Instance> Radio<'d, T> {
37 /// Create a new radio driver.
38 pub fn new(
39 radio: impl Peripheral<P = T> + 'd,
40 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
41 ) -> Self {
42 into_ref!(radio);
43
44 let r = T::regs();
45
46 r.pcnf1.write(|w| unsafe {
47 // It is 0 bytes long in a standard BLE packet
48 w.statlen()
49 .bits(0)
50 // MaxLen configures the maximum packet payload plus add-on size in
51 // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure
52 // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means
53 // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a
54 // packet larger than MAXLEN, the payload will be truncated at MAXLEN
55 //
56 // To simplify the implementation, It is setted as the maximum value
57 // and the length of the packet is controlled only by the LENGTH field in the packet
58 .maxlen()
59 .bits(255)
60 // Configure the length of the address field in the packet
61 // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address
62 // The base address is truncated from the least significant byte if the BALEN is less than 4
63 //
64 // BLE address is always 4 bytes long
65 .balen()
66 .bits(3) // 3 bytes base address (+ 1 prefix);
67 // Configure the endianess
68 // For BLE is always little endian (LSB first)
69 .endian()
70 .little()
71 // Data whitening is used to avoid long sequences of zeros or
72 // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream.
73 // The whitener and de-whitener are defined the same way,
74 // using a 7-bit linear feedback shift register with the
75 // polynomial x7 + x4 + 1.
76 //
77 // In BLE Whitening shall be applied on the PDU and CRC of all
78 // Link Layer packets and is performed after the CRC generation
79 // in the transmitter. No other parts of the packets are whitened.
80 // De-whitening is performed before the CRC checking in the receiver
81 // Before whitening or de-whitening, the shift register should be
82 // initialized based on the channel index.
83 .whiteen()
84 .set_bit()
85 });
86
87 // Configure CRC
88 r.crccnf.write(|w| {
89 // In BLE the CRC shall be calculated on the PDU of all Link Layer
90 // packets (even if the packet is encrypted).
91 // It skips the address field
92 w.skipaddr()
93 .skip()
94 // In BLE 24-bit CRC = 3 bytes
95 .len()
96 .three()
97 });
98
99 // Ch map between 2400 MHZ .. 2500 MHz
100 // All modes use this range
101 r.frequency.write(|w| w.map().default());
102
103 // Configure shortcuts to simplify and speed up sending and receiving packets.
104 r.shorts.write(|w| {
105 // start transmission/recv immediately after ramp-up
106 // disable radio when transmission/recv is done
107 w.ready_start().enabled().end_disable().enabled()
108 });
109
110 // Enable NVIC interrupt
111 T::Interrupt::unpend();
112 unsafe { T::Interrupt::enable() };
113
114 Self { _p: radio }
115 }
116
117 fn state(&self) -> RadioState {
118 match T::regs().state.read().state().variant() {
119 Some(s) => s,
120 None => unreachable!(),
121 }
122 }
123
124 #[allow(dead_code)]
125 fn trace_state(&self) {
126 match self.state() {
127 RadioState::DISABLED => trace!("radio:state:DISABLED"),
128 RadioState::RX_RU => trace!("radio:state:RX_RU"),
129 RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"),
130 RadioState::RX => trace!("radio:state:RX"),
131 RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"),
132 RadioState::TX_RU => trace!("radio:state:TX_RU"),
133 RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"),
134 RadioState::TX => trace!("radio:state:TX"),
135 RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"),
136 }
137 }
138
139 /// Set the radio mode
140 ///
141 /// The radio must be disabled before calling this function
142 pub fn set_mode(&mut self, mode: Mode) {
143 assert!(self.state() == RadioState::DISABLED);
144
145 let r = T::regs();
146 r.mode.write(|w| w.mode().variant(mode));
147
148 r.pcnf0.write(|w| {
149 w.plen().variant(match mode {
150 Mode::BLE_1MBIT => PreambleLength::_8BIT,
151 Mode::BLE_2MBIT => PreambleLength::_16BIT,
152 Mode::BLE_LR125KBIT | Mode::BLE_LR500KBIT => PreambleLength::LONG_RANGE,
153 _ => unimplemented!(),
154 })
155 });
156 }
157
158 /// Set the header size changing the S1's len field
159 ///
160 /// The radio must be disabled before calling this function
161 pub fn set_header_expansion(&mut self, use_s1_field: bool) {
162 assert!(self.state() == RadioState::DISABLED);
163
164 let r = T::regs();
165
166 // s1 len in bits
167 let s1len: u8 = match use_s1_field {
168 false => 0,
169 true => 8,
170 };
171
172 r.pcnf0.write(|w| unsafe {
173 w
174 // Configure S0 to 1 byte length, this will represent the Data/Adv header flags
175 .s0len()
176 .set_bit()
177 // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload
178 // and also be used to know how many bytes to read/write from/to the buffer
179 .lflen()
180 .bits(8)
181 // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE.
182 .s1len()
183 .bits(s1len)
184 });
185 }
186
187 /// Set initial data whitening value
188 /// Data whitening is used to avoid long sequences of zeros or ones, e.g., 0b0000000 or 0b1111111, in the data bit stream
189 /// On BLE the initial value is the channel index | 0x40
190 ///
191 /// The radio must be disabled before calling this function
192 pub fn set_whitening_init(&mut self, whitening_init: u8) {
193 assert!(self.state() == RadioState::DISABLED);
194
195 let r = T::regs();
196
197 r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) });
198 }
199
200 /// Set the central frequency to be used
201 /// It should be in the range 2400..2500
202 ///
203 /// [The radio must be disabled before calling this function](https://devzone.nordicsemi.com/f/nordic-q-a/15829/radio-frequency-change)
204 pub fn set_frequency(&mut self, frequency: u32) {
205 assert!(self.state() == RadioState::DISABLED);
206 assert!((2400..=2500).contains(&frequency));
207
208 let r = T::regs();
209
210 r.frequency
211 .write(|w| unsafe { w.frequency().bits((frequency - 2400) as u8) });
212 }
213
214 /// Set the acess address
215 /// This address is always constants for advertising
216 /// And a random value generate on each connection
217 /// It is used to filter the packages
218 ///
219 /// The radio must be disabled before calling this function
220 pub fn set_access_address(&mut self, access_address: u32) {
221 assert!(self.state() == RadioState::DISABLED);
222
223 let r = T::regs();
224
225 // Configure logical address
226 // The byte ordering on air is always least significant byte first for the address
227 // So for the address 0xAA_BB_CC_DD, the address on air will be DD CC BB AA
228 // The package order is BASE, PREFIX so BASE=0xBB_CC_DD and PREFIX=0xAA
229 r.prefix0
230 .write(|w| unsafe { w.ap0().bits((access_address >> 24) as u8) });
231
232 // The base address is truncated from the least significant byte (because the BALEN is less than 4)
233 // So it shifts the address to the right
234 r.base0.write(|w| unsafe { w.bits(access_address << 8) });
235
236 // Don't match tx address
237 r.txaddress.write(|w| unsafe { w.txaddress().bits(0) });
238
239 // Match on logical address
240 // This config only filter the packets by the address,
241 // so only packages send to the previous address
242 // will finish the reception (TODO: check the explanation)
243 r.rxaddresses.write(|w| {
244 w.addr0()
245 .enabled()
246 .addr1()
247 .enabled()
248 .addr2()
249 .enabled()
250 .addr3()
251 .enabled()
252 .addr4()
253 .enabled()
254 });
255 }
256
257 /// Set the CRC polynomial
258 /// It only uses the 24 least significant bits
259 ///
260 /// The radio must be disabled before calling this function
261 pub fn set_crc_poly(&mut self, crc_poly: u32) {
262 assert!(self.state() == RadioState::DISABLED);
263
264 let r = T::regs();
265
266 r.crcpoly.write(|w| unsafe {
267 // Configure the CRC polynomial
268 // Each term in the CRC polynomial is mapped to a bit in this
269 // register which index corresponds to the term's exponent.
270 // The least significant term/bit is hard-wired internally to
271 // 1, and bit number 0 of the register content is ignored by
272 // the hardware. The following example is for an 8 bit CRC
273 // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 .
274 w.crcpoly().bits(crc_poly & 0xFFFFFF)
275 });
276 }
277
278 /// Set the CRC init value
279 /// It only uses the 24 least significant bits
280 /// The CRC initial value varies depending of the PDU type
281 ///
282 /// The radio must be disabled before calling this function
283 pub fn set_crc_init(&mut self, crc_init: u32) {
284 assert!(self.state() == RadioState::DISABLED);
285
286 let r = T::regs();
287
288 r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) });
289 }
290
291 /// Set the radio tx power
292 ///
293 /// The radio must be disabled before calling this function
294 pub fn set_tx_power(&mut self, tx_power: TxPower) {
295 assert!(self.state() == RadioState::DISABLED);
296
297 let r = T::regs();
298
299 r.txpower.write(|w| w.txpower().variant(tx_power));
300 }
301
302 /// Set buffer to read/write
303 ///
304 /// This method is unsound. You should guarantee that the buffer will live
305 /// for the life time of the transmission or if the buffer will be modified.
306 /// Also if the buffer is smaller than the packet length, the radio will
307 /// read/write memory out of the buffer bounds.
308 fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
309 slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
310
311 let r = T::regs();
312
313 // Here it consider that the length of the packet is
314 // correctly set in the buffer, otherwise it will send
315 // unowned regions of memory
316 let ptr = buffer.as_ptr();
317
318 // Configure the payload
319 r.packetptr.write(|w| unsafe { w.bits(ptr as u32) });
320
321 Ok(())
322 }
323
324 /// Send packet
325 /// If the length byte in the package is greater than the buffer length
326 /// the radio will read memory out of the buffer bounds
327 pub async fn transmit(&mut self, buffer: &[u8]) -> Result<(), Error> {
328 self.set_buffer(buffer)?;
329
330 let r = T::regs();
331 self.trigger_and_wait_end(move || {
332 // Initialize the transmission
333 // trace!("txen");
334 r.tasks_txen.write(|w| w.tasks_txen().set_bit());
335 })
336 .await;
337
338 Ok(())
339 }
340
341 /// Receive packet
342 /// If the length byte in the received package is greater than the buffer length
343 /// the radio will write memory out of the buffer bounds
344 pub async fn receive(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
345 self.set_buffer(buffer)?;
346
347 let r = T::regs();
348 self.trigger_and_wait_end(move || {
349 // Initialize the transmission
350 // trace!("rxen");
351 r.tasks_rxen.write(|w| w.tasks_rxen().set_bit());
352 })
353 .await;
354
355 Ok(())
356 }
357
358 async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce()) {
359 //self.trace_state();
360
361 let r = T::regs();
362 let s = T::state();
363
364 // If the Future is dropped before the end of the transmission
365 // it disable the interrupt and stop the transmission
366 // to keep the state consistent
367 let drop = OnDrop::new(|| {
368 trace!("radio drop: stopping");
369
370 r.intenclr.write(|w| w.end().clear());
371 r.events_end.reset();
372
373 r.tasks_stop.write(|w| w.tasks_stop().set_bit());
374
375 // The docs don't explicitly mention any event to acknowledge the stop task
376 while r.events_end.read().events_end().bit_is_clear() {}
377
378 trace!("radio drop: stopped");
379 });
380
381 // trace!("radio:enable interrupt");
382 // Clear some remnant side-effects (TODO: check if this is necessary)
383 r.events_end.reset();
384
385 // Enable interrupt
386 r.intenset.write(|w| w.end().set());
387
388 compiler_fence(Ordering::SeqCst);
389
390 // Trigger the transmission
391 trigger();
392 // self.trace_state();
393
394 // On poll check if interrupt happen
395 poll_fn(|cx| {
396 s.end_waker.register(cx.waker());
397 if r.events_end.read().events_end().bit_is_set() {
398 // trace!("radio:end");
399 return core::task::Poll::Ready(());
400 }
401 Poll::Pending
402 })
403 .await;
404
405 compiler_fence(Ordering::SeqCst);
406 r.events_disabled.reset(); // ACK
407
408 // Everthing ends fine, so it disable the drop
409 drop.defuse();
410 }
411
412 /// Disable the radio
413 fn disable(&mut self) {
414 let r = T::regs();
415
416 compiler_fence(Ordering::SeqCst);
417 // If it is already disabled, do nothing
418 if self.state() != RadioState::DISABLED {
419 trace!("radio:disable");
420 // Trigger the disable task
421 r.tasks_disable.write(|w| w.tasks_disable().set_bit());
422
423 // Wait until the radio is disabled
424 while r.events_disabled.read().events_disabled().bit_is_clear() {}
425
426 compiler_fence(Ordering::SeqCst);
427
428 // Acknowledge it
429 r.events_disabled.reset();
430 }
431 }
432}
433
434impl<'d, T: Instance> Drop for Radio<'d, T> {
435 fn drop(&mut self) {
436 self.disable();
437 }
438}
diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs
new file mode 100644
index 000000000..03f967f87
--- /dev/null
+++ b/embassy-nrf/src/radio/mod.rs
@@ -0,0 +1,75 @@
1//! Integrated 2.4 GHz Radio
2//!
3//! The 2.4 GHz radio transceiver is compatible with multiple radio standards
4//! such as 1Mbps, 2Mbps and Long Range Bluetooth Low Energy.
5
6#![macro_use]
7
8/// Bluetooth Low Energy Radio driver.
9pub mod ble;
10
11use core::marker::PhantomData;
12
13use crate::{interrupt, pac, Peripheral};
14
15/// Interrupt handler
16pub struct InterruptHandler<T: Instance> {
17 _phantom: PhantomData<T>,
18}
19
20impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
21 unsafe fn on_interrupt() {
22 let r = T::regs();
23 let s = T::state();
24
25 if r.events_end.read().events_end().bit_is_set() {
26 s.end_waker.wake();
27 r.intenclr.write(|w| w.end().clear());
28 }
29 }
30}
31
32pub(crate) mod sealed {
33 use embassy_sync::waitqueue::AtomicWaker;
34
35 pub struct State {
36 /// end packet transmission or reception
37 pub end_waker: AtomicWaker,
38 }
39 impl State {
40 pub const fn new() -> Self {
41 Self {
42 end_waker: AtomicWaker::new(),
43 }
44 }
45 }
46
47 pub trait Instance {
48 fn regs() -> &'static crate::pac::radio::RegisterBlock;
49 fn state() -> &'static State;
50 }
51}
52
53macro_rules! impl_radio {
54 ($type:ident, $pac_type:ident, $irq:ident) => {
55 impl crate::radio::sealed::Instance for peripherals::$type {
56 fn regs() -> &'static pac::radio::RegisterBlock {
57 unsafe { &*pac::$pac_type::ptr() }
58 }
59
60 fn state() -> &'static crate::radio::sealed::State {
61 static STATE: crate::radio::sealed::State = crate::radio::sealed::State::new();
62 &STATE
63 }
64 }
65 impl crate::radio::Instance for peripherals::$type {
66 type Interrupt = crate::interrupt::typelevel::$irq;
67 }
68 };
69}
70
71/// Radio peripheral instance.
72pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
73 /// Interrupt for this peripheral.
74 type Interrupt: interrupt::typelevel::Interrupt;
75}
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 3538afa2b..c45d45e68 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -312,7 +312,7 @@ impl<'d, T: Instance> Spim<'d, T> {
312 match self.blocking_inner_from_ram(rx, tx) { 312 match self.blocking_inner_from_ram(rx, tx) {
313 Ok(_) => Ok(()), 313 Ok(_) => Ok(()),
314 Err(Error::BufferNotInRAM) => { 314 Err(Error::BufferNotInRAM) => {
315 trace!("Copying SPIM tx buffer into RAM for DMA"); 315 // trace!("Copying SPIM tx buffer into RAM for DMA");
316 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; 316 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
317 tx_ram_buf.copy_from_slice(tx); 317 tx_ram_buf.copy_from_slice(tx);
318 self.blocking_inner_from_ram(rx, tx_ram_buf) 318 self.blocking_inner_from_ram(rx, tx_ram_buf)
@@ -366,7 +366,7 @@ impl<'d, T: Instance> Spim<'d, T> {
366 match self.async_inner_from_ram(rx, tx).await { 366 match self.async_inner_from_ram(rx, tx).await {
367 Ok(_) => Ok(()), 367 Ok(_) => Ok(()),
368 Err(Error::BufferNotInRAM) => { 368 Err(Error::BufferNotInRAM) => {
369 trace!("Copying SPIM tx buffer into RAM for DMA"); 369 // trace!("Copying SPIM tx buffer into RAM for DMA");
370 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; 370 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
371 tx_ram_buf.copy_from_slice(tx); 371 tx_ram_buf.copy_from_slice(tx);
372 self.async_inner_from_ram(rx, tx_ram_buf).await 372 self.async_inner_from_ram(rx, tx_ram_buf).await
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 7d21383c3..08ccd35ae 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -70,7 +70,7 @@ rand_core = "0.6.3"
70sdio-host = "0.5.0" 70sdio-host = "0.5.0"
71critical-section = "1.1" 71critical-section = "1.1"
72#stm32-metapac = { version = "15" } 72#stm32-metapac = { version = "15" }
73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7c8b53413499acc3273b706318777a60f932d77a" } 73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a0bcec33362449fb733c066936d25cbabab396a" }
74vcell = "0.1.3" 74vcell = "0.1.3"
75bxcan = "0.7.0" 75bxcan = "0.7.0"
76nb = "1.0.0" 76nb = "1.0.0"
@@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] }
94proc-macro2 = "1.0.36" 94proc-macro2 = "1.0.36"
95quote = "1.0.15" 95quote = "1.0.15"
96#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 96#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
97stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7c8b53413499acc3273b706318777a60f932d77a", default-features = false, features = ["metadata"]} 97stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a0bcec33362449fb733c066936d25cbabab396a", default-features = false, features = ["metadata"]}
98 98
99 99
100[features] 100[features]
@@ -130,6 +130,8 @@ _time-driver = ["dep:embassy-time-driver", "time"]
130 130
131## Use any time driver 131## Use any time driver
132time-driver-any = ["_time-driver"] 132time-driver-any = ["_time-driver"]
133## Use TIM1 as time driver
134time-driver-tim1 = ["_time-driver"]
133## Use TIM2 as time driver 135## Use TIM2 as time driver
134time-driver-tim2 = ["_time-driver"] 136time-driver-tim2 = ["_time-driver"]
135## Use TIM3 as time driver 137## Use TIM3 as time driver
@@ -138,18 +140,24 @@ time-driver-tim3 = ["_time-driver"]
138time-driver-tim4 = ["_time-driver"] 140time-driver-tim4 = ["_time-driver"]
139## Use TIM5 as time driver 141## Use TIM5 as time driver
140time-driver-tim5 = ["_time-driver"] 142time-driver-tim5 = ["_time-driver"]
143## Use TIM8 as time driver
144time-driver-tim8 = ["_time-driver"]
141## Use TIM9 as time driver 145## Use TIM9 as time driver
142time-driver-tim9 = ["_time-driver"] 146time-driver-tim9 = ["_time-driver"]
143## Use TIM11 as time driver
144time-driver-tim11 = ["_time-driver"]
145## Use TIM12 as time driver 147## Use TIM12 as time driver
146time-driver-tim12 = ["_time-driver"] 148time-driver-tim12 = ["_time-driver"]
147## Use TIM15 as time driver 149## Use TIM15 as time driver
148time-driver-tim15 = ["_time-driver"] 150time-driver-tim15 = ["_time-driver"]
151## Use TIM20 as time driver
152time-driver-tim20 = ["_time-driver"]
149## Use TIM21 as time driver 153## Use TIM21 as time driver
150time-driver-tim21 = ["_time-driver"] 154time-driver-tim21 = ["_time-driver"]
151## Use TIM22 as time driver 155## Use TIM22 as time driver
152time-driver-tim22 = ["_time-driver"] 156time-driver-tim22 = ["_time-driver"]
157## Use TIM23 as time driver
158time-driver-tim23 = ["_time-driver"]
159## Use TIM24 as time driver
160time-driver-tim24 = ["_time-driver"]
153 161
154 162
155#! ## Analog Switch Pins (Pxy_C) on STM32H7 series 163#! ## Analog Switch Pins (Pxy_C) on STM32H7 series
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index 0771d6fbb..e87a3c213 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -37,7 +37,7 @@ impl Registers {
37 &mut self.msg_ram_mut().receive[fifonr].fxsa[bufnum] 37 &mut self.msg_ram_mut().receive[fifonr].fxsa[bufnum]
38 } 38 }
39 39
40 pub fn read_classic(&self, fifonr: usize) -> Option<(ClassicFrame, u16)> { 40 pub fn read<F: CanHeader>(&self, fifonr: usize) -> Option<(F, u16)> {
41 // Fill level - do we have a msg? 41 // Fill level - do we have a msg?
42 if self.regs.rxfs(fifonr).read().ffl() < 1 { 42 if self.regs.rxfs(fifonr).read().ffl() < 1 {
43 return None; 43 return None;
@@ -46,7 +46,7 @@ impl Registers {
46 let read_idx = self.regs.rxfs(fifonr).read().fgi(); 46 let read_idx = self.regs.rxfs(fifonr).read().fgi();
47 let mailbox = self.rx_fifo_element(fifonr, read_idx as usize); 47 let mailbox = self.rx_fifo_element(fifonr, read_idx as usize);
48 48
49 let mut buffer: [u8; 8] = [0; 8]; 49 let mut buffer = [0u8; 64];
50 let maybe_header = extract_frame(mailbox, &mut buffer); 50 let maybe_header = extract_frame(mailbox, &mut buffer);
51 51
52 // Clear FIFO, reduces count and increments read buf 52 // Clear FIFO, reduces count and increments read buf
@@ -54,43 +54,14 @@ impl Registers {
54 54
55 match maybe_header { 55 match maybe_header {
56 Some((header, ts)) => { 56 Some((header, ts)) => {
57 let data = ClassicData::new(&buffer[0..header.len() as usize]); 57 let data = &buffer[0..header.len() as usize];
58 Some((ClassicFrame::new(header, data.unwrap()), ts)) 58 Some((F::from_header(header, data)?, ts))
59 }
60 None => None,
61 }
62 }
63
64 pub fn read_fd(&self, fifonr: usize) -> Option<(FdFrame, u16)> {
65 // Fill level - do we have a msg?
66 if self.regs.rxfs(fifonr).read().ffl() < 1 {
67 return None;
68 }
69
70 let read_idx = self.regs.rxfs(fifonr).read().fgi();
71 let mailbox = self.rx_fifo_element(fifonr, read_idx as usize);
72
73 let mut buffer: [u8; 64] = [0; 64];
74 let maybe_header = extract_frame(mailbox, &mut buffer);
75
76 // Clear FIFO, reduces count and increments read buf
77 self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx));
78
79 match maybe_header {
80 Some((header, ts)) => {
81 let data = FdData::new(&buffer[0..header.len() as usize]);
82 Some((FdFrame::new(header, data.unwrap()), ts))
83 } 59 }
84 None => None, 60 None => None,
85 } 61 }
86 } 62 }
87 63
88 pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) { 64 pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) {
89 // Fill level - do we have a msg?
90 //if self.regs.rxfs(fifonr).read().ffl() < 1 { return None; }
91
92 //let read_idx = self.regs.rxfs(fifonr).read().fgi();
93
94 let mailbox = self.tx_buffer_element(bufidx); 65 let mailbox = self.tx_buffer_element(bufidx);
95 66
96 mailbox.reset(); 67 mailbox.reset();
@@ -193,11 +164,7 @@ impl Registers {
193 } 164 }
194 165
195 #[inline] 166 #[inline]
196 //fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R> 167 pub fn abort_pending_mailbox_generic<F: embedded_can::Frame>(&self, bufidx: usize) -> Option<F> {
197 pub fn abort_pending_mailbox(&self, bufidx: usize) -> Option<ClassicFrame>
198//where
199 // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R,
200 {
201 if self.abort(bufidx) { 168 if self.abort(bufidx) {
202 let mailbox = self.tx_buffer_element(bufidx); 169 let mailbox = self.tx_buffer_element(bufidx);
203 170
@@ -212,54 +179,14 @@ impl Registers {
212 return None; 179 return None;
213 } 180 }
214 181
215 //let tx_ram = self.tx_msg_ram();
216 let mut data = [0u8; 64];
217 data_from_tx_buffer(&mut data, mailbox, len as usize);
218
219 let cd = ClassicData::new(&data).unwrap();
220 Some(ClassicFrame::new(Header::new(id, len, header_reg.rtr().bit()), cd))
221 } else {
222 // Abort request failed because the frame was already sent (or being sent) on
223 // the bus. All mailboxes are now free. This can happen for small prescaler
224 // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR
225 // has preempted the execution.
226 None
227 }
228 }
229
230 #[inline]
231 //fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R>
232 pub fn abort_pending_fd_mailbox(&self, bufidx: usize) -> Option<FdFrame>
233//where
234 // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R,
235 {
236 if self.abort(bufidx) {
237 let mailbox = self.tx_buffer_element(bufidx);
238
239 let header_reg = mailbox.header.read();
240 let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
241
242 let len = match header_reg.to_data_length() {
243 DataLength::Fdcan(len) => len,
244 DataLength::Classic(len) => len,
245 };
246 if len as usize > FdFrame::MAX_DATA_LEN {
247 return None;
248 }
249
250 //let tx_ram = self.tx_msg_ram();
251 let mut data = [0u8; 64]; 182 let mut data = [0u8; 64];
252 data_from_tx_buffer(&mut data, mailbox, len as usize); 183 data_from_tx_buffer(&mut data, mailbox, len as usize);
253 184
254 let cd = FdData::new(&data).unwrap(); 185 if header_reg.rtr().bit() {
255 186 F::new_remote(id, len as usize)
256 let header = if header_reg.fdf().frame_format() == FrameFormat::Fdcan {
257 Header::new_fd(id, len, header_reg.rtr().bit(), header_reg.brs().bit())
258 } else { 187 } else {
259 Header::new(id, len, header_reg.rtr().bit()) 188 F::new(id, &data)
260 }; 189 }
261
262 Some(FdFrame::new(header, cd))
263 } else { 190 } else {
264 // Abort request failed because the frame was already sent (or being sent) on 191 // Abort request failed because the frame was already sent (or being sent) on
265 // the bus. All mailboxes are now free. This can happen for small prescaler 192 // the bus. All mailboxes are now free. This can happen for small prescaler
@@ -269,10 +196,7 @@ impl Registers {
269 } 196 }
270 } 197 }
271 198
272 /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can 199 pub fn write<F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> nb::Result<Option<F>, Infallible> {
273 /// be preserved.
274 //pub fn transmit_preserve<PTX, P>(
275 pub fn write_classic(&self, frame: &ClassicFrame) -> nb::Result<Option<ClassicFrame>, Infallible> {
276 let queue_is_full = self.tx_queue_is_full(); 200 let queue_is_full = self.tx_queue_is_full();
277 201
278 let id = frame.header().id(); 202 let id = frame.header().id();
@@ -281,45 +205,11 @@ impl Registers {
281 // Discard the first slot with a lower priority message 205 // Discard the first slot with a lower priority message
282 let (idx, pending_frame) = if queue_is_full { 206 let (idx, pending_frame) = if queue_is_full {
283 if self.is_available(0, id) { 207 if self.is_available(0, id) {
284 (0, self.abort_pending_mailbox(0)) 208 (0, self.abort_pending_mailbox_generic(0))
285 } else if self.is_available(1, id) { 209 } else if self.is_available(1, id) {
286 (1, self.abort_pending_mailbox(1)) 210 (1, self.abort_pending_mailbox_generic(1))
287 } else if self.is_available(2, id) { 211 } else if self.is_available(2, id) {
288 (2, self.abort_pending_mailbox(2)) 212 (2, self.abort_pending_mailbox_generic(2))
289 } else {
290 // For now we bail when there is no lower priority slot available
291 // Can this lead to priority inversion?
292 return Err(nb::Error::WouldBlock);
293 }
294 } else {
295 // Read the Write Pointer
296 let idx = self.regs.txfqs().read().tfqpi();
297
298 (idx, None)
299 };
300
301 self.put_tx_frame(idx as usize, frame.header(), frame.data());
302
303 Ok(pending_frame)
304 }
305
306 /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can
307 /// be preserved.
308 //pub fn transmit_preserve<PTX, P>(
309 pub fn write_fd(&self, frame: &FdFrame) -> nb::Result<Option<FdFrame>, Infallible> {
310 let queue_is_full = self.tx_queue_is_full();
311
312 let id = frame.header().id();
313
314 // If the queue is full,
315 // Discard the first slot with a lower priority message
316 let (idx, pending_frame) = if queue_is_full {
317 if self.is_available(0, id) {
318 (0, self.abort_pending_fd_mailbox(0))
319 } else if self.is_available(1, id) {
320 (1, self.abort_pending_fd_mailbox(1))
321 } else if self.is_available(2, id) {
322 (2, self.abort_pending_fd_mailbox(2))
323 } else { 213 } else {
324 // For now we bail when there is no lower priority slot available 214 // For now we bail when there is no lower priority slot available
325 // Can this lead to priority inversion? 215 // Can this lead to priority inversion?
@@ -413,7 +303,9 @@ impl Registers {
413 // Framework specific settings are set here 303 // Framework specific settings are set here
414 304
415 // set TxBuffer to Queue Mode 305 // set TxBuffer to Queue Mode
416 self.regs.txbc().write(|w| w.set_tfqm(true)); 306 self.regs
307 .txbc()
308 .write(|w| w.set_tfqm(crate::pac::can::vals::Tfqm::QUEUE));
417 309
418 // set standard filters list size to 28 310 // set standard filters list size to 28
419 // set extended filters list size to 8 311 // set extended filters list size to 8
@@ -557,8 +449,6 @@ impl Registers {
557 /// parameter to this method. 449 /// parameter to this method.
558 #[inline] 450 #[inline]
559 pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) { 451 pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) {
560 //self.control.config.nbtr = btr;
561
562 self.regs.nbtp().write(|w| { 452 self.regs.nbtp().write(|w| {
563 w.set_nbrp(btr.nbrp() - 1); 453 w.set_nbrp(btr.nbrp() - 1);
564 w.set_ntseg1(btr.ntseg1() - 1); 454 w.set_ntseg1(btr.ntseg1() - 1);
@@ -571,8 +461,6 @@ impl Registers {
571 /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS. 461 /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
572 #[inline] 462 #[inline]
573 pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) { 463 pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) {
574 //self.control.config.dbtr = btr;
575
576 self.regs.dbtp().write(|w| { 464 self.regs.dbtp().write(|w| {
577 w.set_dbrp(btr.dbrp() - 1); 465 w.set_dbrp(btr.dbrp() - 1);
578 w.set_dtseg1(btr.dtseg1() - 1); 466 w.set_dtseg1(btr.dtseg1() - 1);
@@ -590,7 +478,6 @@ impl Registers {
590 #[inline] 478 #[inline]
591 pub fn set_automatic_retransmit(&mut self, enabled: bool) { 479 pub fn set_automatic_retransmit(&mut self, enabled: bool) {
592 self.regs.cccr().modify(|w| w.set_dar(!enabled)); 480 self.regs.cccr().modify(|w| w.set_dar(!enabled));
593 //self.control.config.automatic_retransmit = enabled;
594 } 481 }
595 482
596 /// Configures the transmit pause feature. See 483 /// Configures the transmit pause feature. See
@@ -598,21 +485,18 @@ impl Registers {
598 #[inline] 485 #[inline]
599 pub fn set_transmit_pause(&mut self, enabled: bool) { 486 pub fn set_transmit_pause(&mut self, enabled: bool) {
600 self.regs.cccr().modify(|w| w.set_txp(!enabled)); 487 self.regs.cccr().modify(|w| w.set_txp(!enabled));
601 //self.control.config.transmit_pause = enabled;
602 } 488 }
603 489
604 /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`] 490 /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`]
605 #[inline] 491 #[inline]
606 pub fn set_non_iso_mode(&mut self, enabled: bool) { 492 pub fn set_non_iso_mode(&mut self, enabled: bool) {
607 self.regs.cccr().modify(|w| w.set_niso(enabled)); 493 self.regs.cccr().modify(|w| w.set_niso(enabled));
608 //self.control.config.non_iso_mode = enabled;
609 } 494 }
610 495
611 /// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`] 496 /// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`]
612 #[inline] 497 #[inline]
613 pub fn set_edge_filtering(&mut self, enabled: bool) { 498 pub fn set_edge_filtering(&mut self, enabled: bool) {
614 self.regs.cccr().modify(|w| w.set_efbi(enabled)); 499 self.regs.cccr().modify(|w| w.set_efbi(enabled));
615 //self.control.config.edge_filtering = enabled;
616 } 500 }
617 501
618 /// Configures frame transmission mode. See 502 /// Configures frame transmission mode. See
@@ -632,16 +516,12 @@ impl Registers {
632 #[cfg(not(stm32h7))] 516 #[cfg(not(stm32h7))]
633 w.set_brse(brse); 517 w.set_brse(brse);
634 }); 518 });
635
636 //self.control.config.frame_transmit = fts;
637 } 519 }
638 520
639 /// Sets the protocol exception handling on/off 521 /// Sets the protocol exception handling on/off
640 #[inline] 522 #[inline]
641 pub fn set_protocol_exception_handling(&mut self, enabled: bool) { 523 pub fn set_protocol_exception_handling(&mut self, enabled: bool) {
642 self.regs.cccr().modify(|w| w.set_pxhd(!enabled)); 524 self.regs.cccr().modify(|w| w.set_pxhd(!enabled));
643
644 //self.control.config.protocol_exception_handling = enabled;
645 } 525 }
646 526
647 /// Configures and resets the timestamp counter 527 /// Configures and resets the timestamp counter
@@ -665,8 +545,6 @@ impl Registers {
665 w.set_tcp(tcp); 545 w.set_tcp(tcp);
666 w.set_tss(tss); 546 w.set_tss(tss);
667 }); 547 });
668
669 //self.control.config.timestamp_source = select;
670 } 548 }
671 549
672 #[cfg(not(stm32h7))] 550 #[cfg(not(stm32h7))]
@@ -721,13 +599,15 @@ fn make_id(id: u32, extended: bool) -> embedded_can::Id {
721 if extended { 599 if extended {
722 embedded_can::Id::from(unsafe { embedded_can::ExtendedId::new_unchecked(id & 0x1FFFFFFF) }) 600 embedded_can::Id::from(unsafe { embedded_can::ExtendedId::new_unchecked(id & 0x1FFFFFFF) })
723 } else { 601 } else {
724 embedded_can::Id::from(unsafe { embedded_can::StandardId::new_unchecked((id & 0x000007FF) as u16) }) 602 // A standard identifier is stored into ID[28:18].
603 embedded_can::Id::from(unsafe { embedded_can::StandardId::new_unchecked(((id >> 18) & 0x000007FF) as u16) })
725 } 604 }
726} 605}
727 606
728fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) { 607fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) {
729 let (id, id_type) = match header.id() { 608 let (id, id_type) = match header.id() {
730 embedded_can::Id::Standard(id) => (id.as_raw() as u32, IdType::StandardId), 609 // A standard identifier has to be written to ID[28:18].
610 embedded_can::Id::Standard(id) => ((id.as_raw() as u32) << 18, IdType::StandardId),
731 embedded_can::Id::Extended(id) => (id.as_raw() as u32, IdType::ExtendedId), 611 embedded_can::Id::Extended(id) => (id.as_raw() as u32, IdType::ExtendedId),
732 }; 612 };
733 613
@@ -737,7 +617,7 @@ fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) {
737 } else { 617 } else {
738 FrameFormat::Classic 618 FrameFormat::Classic
739 }; 619 };
740 let brs = header.len() > 8 || header.bit_rate_switching(); 620 let brs = (frame_format == FrameFormat::Fdcan) && header.bit_rate_switching();
741 621
742 mailbox.header.write(|w| { 622 mailbox.header.write(|w| {
743 unsafe { w.id().bits(id) } 623 unsafe { w.id().bits(id) }
@@ -792,22 +672,6 @@ fn data_from_tx_buffer(buffer: &mut [u8], mailbox: &TxBufferElement, len: usize)
792 } 672 }
793} 673}
794 674
795impl From<&RxFifoElement> for ClassicFrame {
796 fn from(mailbox: &RxFifoElement) -> Self {
797 let header_reg = mailbox.header.read();
798
799 let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
800 let dlc = header_reg.to_data_length().len();
801 let len = dlc as usize;
802
803 let mut buffer: [u8; 64] = [0; 64];
804 data_from_fifo(&mut buffer, mailbox, len);
805 let data = ClassicData::new(&buffer[0..len]);
806 let header = Header::new(id, dlc, header_reg.rtr().bits());
807 ClassicFrame::new(header, data.unwrap())
808 }
809}
810
811fn extract_frame(mailbox: &RxFifoElement, buffer: &mut [u8]) -> Option<(Header, u16)> { 675fn extract_frame(mailbox: &RxFifoElement, buffer: &mut [u8]) -> Option<(Header, u16)> {
812 let header_reg = mailbox.header.read(); 676 let header_reg = mailbox.header.read();
813 677
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 744d756f5..6a4a25cb7 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -58,7 +58,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
58 if !T::registers().tx_queue_is_full() { 58 if !T::registers().tx_queue_is_full() {
59 match buf.tx_receiver.try_receive() { 59 match buf.tx_receiver.try_receive() {
60 Ok(frame) => { 60 Ok(frame) => {
61 _ = T::registers().write_classic(&frame); 61 _ = T::registers().write(&frame);
62 } 62 }
63 Err(_) => {} 63 Err(_) => {}
64 } 64 }
@@ -68,7 +68,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
68 if !T::registers().tx_queue_is_full() { 68 if !T::registers().tx_queue_is_full() {
69 match buf.tx_receiver.try_receive() { 69 match buf.tx_receiver.try_receive() {
70 Ok(frame) => { 70 Ok(frame) => {
71 _ = T::registers().write_fd(&frame); 71 _ = T::registers().write(&frame);
72 } 72 }
73 Err(_) => {} 73 Err(_) => {}
74 } 74 }
@@ -359,7 +359,7 @@ impl<'d, T: Instance> Fdcan<'d, T> {
359 359
360 /// Returns the next received message frame 360 /// Returns the next received message frame
361 pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { 361 pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
362 T::state().rx_mode.read::<T>().await 362 T::state().rx_mode.read_classic::<T>().await
363 } 363 }
364 364
365 /// Queues the message to be sent but exerts backpressure. If a lower-priority 365 /// Queues the message to be sent but exerts backpressure. If a lower-priority
@@ -633,7 +633,7 @@ impl<'c, 'd, T: Instance> FdcanTx<'d, T> {
633impl<'c, 'd, T: Instance> FdcanRx<'d, T> { 633impl<'c, 'd, T: Instance> FdcanRx<'d, T> {
634 /// Returns the next received message frame 634 /// Returns the next received message frame
635 pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { 635 pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
636 T::state().rx_mode.read::<T>().await 636 T::state().rx_mode.read_classic::<T>().await
637 } 637 }
638 638
639 /// Returns the next received message frame 639 /// Returns the next received message frame
@@ -649,6 +649,7 @@ pub(crate) mod sealed {
649 use embassy_sync::channel::{DynamicReceiver, DynamicSender}; 649 use embassy_sync::channel::{DynamicReceiver, DynamicSender};
650 use embassy_sync::waitqueue::AtomicWaker; 650 use embassy_sync::waitqueue::AtomicWaker;
651 651
652 use super::CanHeader;
652 use crate::can::_version::{BusError, Timestamp}; 653 use crate::can::_version::{BusError, Timestamp};
653 use crate::can::frame::{ClassicFrame, FdFrame}; 654 use crate::can::frame::{ClassicFrame, FdFrame};
654 655
@@ -689,13 +690,13 @@ pub(crate) mod sealed {
689 waker.wake(); 690 waker.wake();
690 } 691 }
691 RxMode::ClassicBuffered(buf) => { 692 RxMode::ClassicBuffered(buf) => {
692 if let Some(r) = T::registers().read_classic(fifonr) { 693 if let Some(r) = T::registers().read(fifonr) {
693 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1); 694 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1);
694 let _ = buf.rx_sender.try_send((r.0, ts)); 695 let _ = buf.rx_sender.try_send((r.0, ts));
695 } 696 }
696 } 697 }
697 RxMode::FdBuffered(buf) => { 698 RxMode::FdBuffered(buf) => {
698 if let Some(r) = T::registers().read_fd(fifonr) { 699 if let Some(r) = T::registers().read(fifonr) {
699 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1); 700 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1);
700 let _ = buf.rx_sender.try_send((r.0, ts)); 701 let _ = buf.rx_sender.try_send((r.0, ts));
701 } 702 }
@@ -703,15 +704,15 @@ pub(crate) mod sealed {
703 } 704 }
704 } 705 }
705 706
706 pub async fn read<T: Instance>(&self) -> Result<(ClassicFrame, Timestamp), BusError> { 707 async fn read<T: Instance, F: CanHeader>(&self) -> Result<(F, Timestamp), BusError> {
707 poll_fn(|cx| { 708 poll_fn(|cx| {
708 T::state().err_waker.register(cx.waker()); 709 T::state().err_waker.register(cx.waker());
709 self.register(cx.waker()); 710 self.register(cx.waker());
710 711
711 if let Some((msg, ts)) = T::registers().read_classic(0) { 712 if let Some((msg, ts)) = T::registers().read(0) {
712 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); 713 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
713 return Poll::Ready(Ok((msg, ts))); 714 return Poll::Ready(Ok((msg, ts)));
714 } else if let Some((msg, ts)) = T::registers().read_classic(1) { 715 } else if let Some((msg, ts)) = T::registers().read(1) {
715 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); 716 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
716 return Poll::Ready(Ok((msg, ts))); 717 return Poll::Ready(Ok((msg, ts)));
717 } else if let Some(err) = T::registers().curr_error() { 718 } else if let Some(err) = T::registers().curr_error() {
@@ -723,24 +724,12 @@ pub(crate) mod sealed {
723 .await 724 .await
724 } 725 }
725 726
726 pub async fn read_fd<T: Instance>(&self) -> Result<(FdFrame, Timestamp), BusError> { 727 pub async fn read_classic<T: Instance>(&self) -> Result<(ClassicFrame, Timestamp), BusError> {
727 poll_fn(|cx| { 728 self.read::<T, _>().await
728 T::state().err_waker.register(cx.waker()); 729 }
729 self.register(cx.waker());
730 730
731 if let Some((msg, ts)) = T::registers().read_fd(0) { 731 pub async fn read_fd<T: Instance>(&self) -> Result<(FdFrame, Timestamp), BusError> {
732 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); 732 self.read::<T, _>().await
733 return Poll::Ready(Ok((msg, ts)));
734 } else if let Some((msg, ts)) = T::registers().read_fd(1) {
735 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
736 return Poll::Ready(Ok((msg, ts)));
737 } else if let Some(err) = T::registers().curr_error() {
738 // TODO: this is probably wrong
739 return Poll::Ready(Err(err));
740 }
741 Poll::Pending
742 })
743 .await
744 } 733 }
745 } 734 }
746 735
@@ -766,11 +755,11 @@ pub(crate) mod sealed {
766 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 755 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
767 /// can be replaced, this call asynchronously waits for a frame to be successfully 756 /// can be replaced, this call asynchronously waits for a frame to be successfully
768 /// transmitted, then tries again. 757 /// transmitted, then tries again.
769 pub async fn write<T: Instance>(&self, frame: &ClassicFrame) -> Option<ClassicFrame> { 758 async fn write_generic<T: Instance, F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> Option<F> {
770 poll_fn(|cx| { 759 poll_fn(|cx| {
771 self.register(cx.waker()); 760 self.register(cx.waker());
772 761
773 if let Ok(dropped) = T::registers().write_classic(frame) { 762 if let Ok(dropped) = T::registers().write(frame) {
774 return Poll::Ready(dropped); 763 return Poll::Ready(dropped);
775 } 764 }
776 765
@@ -785,19 +774,16 @@ pub(crate) mod sealed {
785 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 774 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
786 /// can be replaced, this call asynchronously waits for a frame to be successfully 775 /// can be replaced, this call asynchronously waits for a frame to be successfully
787 /// transmitted, then tries again. 776 /// transmitted, then tries again.
788 pub async fn write_fd<T: Instance>(&self, frame: &FdFrame) -> Option<FdFrame> { 777 pub async fn write<T: Instance>(&self, frame: &ClassicFrame) -> Option<ClassicFrame> {
789 poll_fn(|cx| { 778 self.write_generic::<T, _>(frame).await
790 self.register(cx.waker()); 779 }
791
792 if let Ok(dropped) = T::registers().write_fd(frame) {
793 return Poll::Ready(dropped);
794 }
795 780
796 // Couldn't replace any lower priority frames. Need to wait for some mailboxes 781 /// Queues the message to be sent but exerts backpressure. If a lower-priority
797 // to clear. 782 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
798 Poll::Pending 783 /// can be replaced, this call asynchronously waits for a frame to be successfully
799 }) 784 /// transmitted, then tries again.
800 .await 785 pub async fn write_fd<T: Instance>(&self, frame: &FdFrame) -> Option<FdFrame> {
786 self.write_generic::<T, _>(frame).await
801 } 787 }
802 } 788 }
803 789
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs
index 725a9b1ab..00a441db6 100644
--- a/embassy-stm32/src/can/frame.rs
+++ b/embassy-stm32/src/can/frame.rs
@@ -56,6 +56,16 @@ impl Header {
56 } 56 }
57} 57}
58 58
59/// Trait for FDCAN frame types, providing ability to construct from a Header
60/// and to retrieve the Header from a frame
61pub trait CanHeader: Sized {
62 /// Construct frame from header and payload
63 fn from_header(header: Header, data: &[u8]) -> Option<Self>;
64
65 /// Get this frame's header struct
66 fn header(&self) -> &Header;
67}
68
59/// Payload of a classic CAN data frame. 69/// Payload of a classic CAN data frame.
60/// 70///
61/// Contains 0 to 8 Bytes of data. 71/// Contains 0 to 8 Bytes of data.
@@ -213,6 +223,16 @@ impl embedded_can::Frame for ClassicFrame {
213 } 223 }
214} 224}
215 225
226impl CanHeader for ClassicFrame {
227 fn from_header(header: Header, data: &[u8]) -> Option<Self> {
228 Some(Self::new(header, ClassicData::new(data)?))
229 }
230
231 fn header(&self) -> &Header {
232 self.header()
233 }
234}
235
216/// Payload of a (FD)CAN data frame. 236/// Payload of a (FD)CAN data frame.
217/// 237///
218/// Contains 0 to 64 Bytes of data. 238/// Contains 0 to 64 Bytes of data.
@@ -272,8 +292,6 @@ pub struct FdFrame {
272} 292}
273 293
274impl FdFrame { 294impl FdFrame {
275 pub(crate) const MAX_DATA_LEN: usize = 64;
276
277 /// Create a new CAN classic Frame 295 /// Create a new CAN classic Frame
278 pub fn new(can_header: Header, data: FdData) -> FdFrame { 296 pub fn new(can_header: Header, data: FdData) -> FdFrame {
279 FdFrame { can_header, data } 297 FdFrame { can_header, data }
@@ -368,3 +386,13 @@ impl embedded_can::Frame for FdFrame {
368 &self.data.raw() 386 &self.data.raw()
369 } 387 }
370} 388}
389
390impl CanHeader for FdFrame {
391 fn from_header(header: Header, data: &[u8]) -> Option<Self> {
392 Some(Self::new(header, FdData::new(data)?))
393 }
394
395 fn header(&self) -> &Header {
396 self.header()
397 }
398}
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index ae8b3cacc..cf531e266 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -90,6 +90,7 @@ impl<'d, T: Instance> OpAmp<'d, T> {
90 in_pin.set_as_analog(); 90 in_pin.set_as_analog();
91 out_pin.set_as_analog(); 91 out_pin.set_as_analog();
92 92
93 // PGA_GAIN value may have different meaning in different MCU serials, use with caution.
93 let (vm_sel, pga_gain) = match gain { 94 let (vm_sel, pga_gain) = match gain {
94 OpAmpGain::Mul1 => (0b11, 0b00), 95 OpAmpGain::Mul1 => (0b11, 0b00),
95 OpAmpGain::Mul2 => (0b10, 0b00), 96 OpAmpGain::Mul2 => (0b10, 0b00),
@@ -127,6 +128,7 @@ impl<'d, T: Instance> OpAmp<'d, T> {
127 into_ref!(pin); 128 into_ref!(pin);
128 pin.set_as_analog(); 129 pin.set_as_analog();
129 130
131 // PGA_GAIN value may have different meaning in different MCU serials, use with caution.
130 let (vm_sel, pga_gain) = match gain { 132 let (vm_sel, pga_gain) = match gain {
131 OpAmpGain::Mul1 => (0b11, 0b00), 133 OpAmpGain::Mul1 => (0b11, 0b00),
132 OpAmpGain::Mul2 => (0b10, 0b00), 134 OpAmpGain::Mul2 => (0b10, 0b00),
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index c6da79afb..7b2255cc6 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -557,6 +557,9 @@ pub(crate) unsafe fn init(config: Config) {
557 RCC.d3ccipr().modify(|w| { 557 RCC.d3ccipr().modify(|w| {
558 w.set_adcsel(config.adc_clock_source); 558 w.set_adcsel(config.adc_clock_source);
559 }); 559 });
560 RCC.d2ccip1r().modify(|w| {
561 w.set_fdcansel(config.fdcan_clock_source);
562 });
560 } 563 }
561 #[cfg(stm32h5)] 564 #[cfg(stm32h5)]
562 { 565 {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index a1f54307d..37b2e7526 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -16,6 +16,8 @@ use crate::pac::timer::vals;
16use crate::rcc::sealed::RccPeripheral; 16use crate::rcc::sealed::RccPeripheral;
17#[cfg(feature = "low-power")] 17#[cfg(feature = "low-power")]
18use crate::rtc::Rtc; 18use crate::rtc::Rtc;
19#[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))]
20use crate::timer::sealed::AdvancedControlInstance;
19use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance}; 21use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance};
20use crate::{interrupt, peripherals}; 22use crate::{interrupt, peripherals};
21 23
@@ -38,7 +40,7 @@ cfg_if::cfg_if! {
38 } 40 }
39} 41}
40 42
41#[cfg(time_drvier_tim1)] 43#[cfg(time_driver_tim1)]
42type T = peripherals::TIM1; 44type T = peripherals::TIM1;
43#[cfg(time_driver_tim2)] 45#[cfg(time_driver_tim2)]
44type T = peripherals::TIM2; 46type T = peripherals::TIM2;
@@ -52,8 +54,6 @@ type T = peripherals::TIM5;
52type T = peripherals::TIM8; 54type T = peripherals::TIM8;
53#[cfg(time_driver_tim9)] 55#[cfg(time_driver_tim9)]
54type T = peripherals::TIM9; 56type T = peripherals::TIM9;
55#[cfg(time_driver_tim11)]
56type T = peripherals::TIM11;
57#[cfg(time_driver_tim12)] 57#[cfg(time_driver_tim12)]
58type T = peripherals::TIM12; 58type T = peripherals::TIM12;
59#[cfg(time_driver_tim15)] 59#[cfg(time_driver_tim15)]
@@ -78,6 +78,14 @@ foreach_interrupt! {
78 DRIVER.on_interrupt() 78 DRIVER.on_interrupt()
79 } 79 }
80 }; 80 };
81 (TIM1, timer, $block:ident, CC, $irq:ident) => {
82 #[cfg(time_driver_tim1)]
83 #[cfg(feature = "rt")]
84 #[interrupt]
85 fn $irq() {
86 DRIVER.on_interrupt()
87 }
88 };
81 (TIM2, timer, $block:ident, UP, $irq:ident) => { 89 (TIM2, timer, $block:ident, UP, $irq:ident) => {
82 #[cfg(time_driver_tim2)] 90 #[cfg(time_driver_tim2)]
83 #[cfg(feature = "rt")] 91 #[cfg(feature = "rt")]
@@ -118,6 +126,14 @@ foreach_interrupt! {
118 DRIVER.on_interrupt() 126 DRIVER.on_interrupt()
119 } 127 }
120 }; 128 };
129 (TIM8, timer, $block:ident, CC, $irq:ident) => {
130 #[cfg(time_driver_tim8)]
131 #[cfg(feature = "rt")]
132 #[interrupt]
133 fn $irq() {
134 DRIVER.on_interrupt()
135 }
136 };
121 (TIM9, timer, $block:ident, UP, $irq:ident) => { 137 (TIM9, timer, $block:ident, UP, $irq:ident) => {
122 #[cfg(time_driver_tim9)] 138 #[cfg(time_driver_tim9)]
123 #[cfg(feature = "rt")] 139 #[cfg(feature = "rt")]
@@ -150,6 +166,14 @@ foreach_interrupt! {
150 DRIVER.on_interrupt() 166 DRIVER.on_interrupt()
151 } 167 }
152 }; 168 };
169 (TIM20, timer, $block:ident, CC, $irq:ident) => {
170 #[cfg(time_driver_tim20)]
171 #[cfg(feature = "rt")]
172 #[interrupt]
173 fn $irq() {
174 DRIVER.on_interrupt()
175 }
176 };
153 (TIM21, timer, $block:ident, UP, $irq:ident) => { 177 (TIM21, timer, $block:ident, UP, $irq:ident) => {
154 #[cfg(time_driver_tim21)] 178 #[cfg(time_driver_tim21)]
155 #[cfg(feature = "rt")] 179 #[cfg(feature = "rt")]
@@ -283,6 +307,14 @@ impl RtcDriver {
283 <T as CoreInstance>::Interrupt::unpend(); 307 <T as CoreInstance>::Interrupt::unpend();
284 unsafe { <T as CoreInstance>::Interrupt::enable() }; 308 unsafe { <T as CoreInstance>::Interrupt::enable() };
285 309
310 #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))]
311 {
312 <T as AdvancedControlInstance>::CaptureCompareInterrupt::unpend();
313 unsafe {
314 <T as AdvancedControlInstance>::CaptureCompareInterrupt::enable();
315 }
316 }
317
286 r.cr1().modify(|w| w.set_cen(true)); 318 r.cr1().modify(|w| w.set_cen(true));
287 } 319 }
288 320
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 9397da2a1..8530c5229 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -379,7 +379,7 @@ pub(crate) mod sealed {
379 379
380 let regs = Self::regs_gp32(); 380 let regs = Self::regs_gp32();
381 regs.psc().write(|r| r.set_psc(psc)); 381 regs.psc().write(|r| r.set_psc(psc));
382 regs.arr().write(|r| r.set_arr(arr)); 382 regs.arr().write_value(arr);
383 383
384 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); 384 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
385 regs.egr().write(|r| r.set_ug(true)); 385 regs.egr().write(|r| r.set_ug(true));
@@ -391,7 +391,7 @@ pub(crate) mod sealed {
391 let timer_f = Self::frequency(); 391 let timer_f = Self::frequency();
392 392
393 let regs = Self::regs_gp32(); 393 let regs = Self::regs_gp32();
394 let arr = regs.arr().read().arr(); 394 let arr = regs.arr().read();
395 let psc = regs.psc().read().psc(); 395 let psc = regs.psc().read().psc();
396 396
397 timer_f / arr / (psc + 1) 397 timer_f / arr / (psc + 1)
@@ -399,22 +399,22 @@ pub(crate) mod sealed {
399 399
400 /// Set comapre value for a channel. 400 /// Set comapre value for a channel.
401 fn set_compare_value(&self, channel: Channel, value: u32) { 401 fn set_compare_value(&self, channel: Channel, value: u32) {
402 Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); 402 Self::regs_gp32().ccr(channel.index()).write_value(value);
403 } 403 }
404 404
405 /// Get capture value for a channel. 405 /// Get capture value for a channel.
406 fn get_capture_value(&self, channel: Channel) -> u32 { 406 fn get_capture_value(&self, channel: Channel) -> u32 {
407 Self::regs_gp32().ccr(channel.index()).read().ccr() 407 Self::regs_gp32().ccr(channel.index()).read()
408 } 408 }
409 409
410 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. 410 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
411 fn get_max_compare_value(&self) -> u32 { 411 fn get_max_compare_value(&self) -> u32 {
412 Self::regs_gp32().arr().read().arr() 412 Self::regs_gp32().arr().read()
413 } 413 }
414 414
415 /// Get compare value for a channel. 415 /// Get compare value for a channel.
416 fn get_compare_value(&self, channel: Channel) -> u32 { 416 fn get_compare_value(&self, channel: Channel) -> u32 {
417 Self::regs_gp32().ccr(channel.index()).read().ccr() 417 Self::regs_gp32().ccr(channel.index()).read()
418 } 418 }
419 } 419 }
420 420
@@ -464,6 +464,9 @@ pub(crate) mod sealed {
464 pub trait AdvancedControlInstance: 464 pub trait AdvancedControlInstance:
465 GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance 465 GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance
466 { 466 {
467 /// Capture compare interrupt for this timer.
468 type CaptureCompareInterrupt: interrupt::typelevel::Interrupt;
469
467 /// Get access to the advanced timer registers. 470 /// Get access to the advanced timer registers.
468 fn regs_advanced() -> crate::pac::timer::TimAdv; 471 fn regs_advanced() -> crate::pac::timer::TimAdv;
469 472
@@ -831,8 +834,10 @@ macro_rules! impl_2ch_cmp_timer {
831 834
832#[allow(unused)] 835#[allow(unused)]
833macro_rules! impl_adv_timer { 836macro_rules! impl_adv_timer {
834 ($inst:ident) => { 837 ($inst:ident, $irq:ident) => {
835 impl sealed::AdvancedControlInstance for crate::peripherals::$inst { 838 impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
839 type CaptureCompareInterrupt = crate::interrupt::typelevel::$irq;
840
836 fn regs_advanced() -> crate::pac::timer::TimAdv { 841 fn regs_advanced() -> crate::pac::timer::TimAdv {
837 unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) } 842 unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) }
838 } 843 }
@@ -905,11 +910,13 @@ foreach_interrupt! {
905 impl_gp16_timer!($inst); 910 impl_gp16_timer!($inst);
906 impl_1ch_cmp_timer!($inst); 911 impl_1ch_cmp_timer!($inst);
907 impl_2ch_cmp_timer!($inst); 912 impl_2ch_cmp_timer!($inst);
908 impl_adv_timer!($inst);
909 impl BasicInstance for crate::peripherals::$inst {} 913 impl BasicInstance for crate::peripherals::$inst {}
910 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 914 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
911 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} 915 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
912 }; 916 };
917 ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => {
918 impl_adv_timer!($inst, $irq);
919 };
913 920
914 921
915 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { 922 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => {
@@ -921,11 +928,13 @@ foreach_interrupt! {
921 impl_gp16_timer!($inst); 928 impl_gp16_timer!($inst);
922 impl_1ch_cmp_timer!($inst); 929 impl_1ch_cmp_timer!($inst);
923 impl_2ch_cmp_timer!($inst); 930 impl_2ch_cmp_timer!($inst);
924 impl_adv_timer!($inst);
925 impl BasicInstance for crate::peripherals::$inst {} 931 impl BasicInstance for crate::peripherals::$inst {}
926 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 932 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
927 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} 933 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
928 }; 934 };
935 ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => {
936 impl_adv_timer!($inst, $irq);
937 };
929 938
930 939
931 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { 940 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
@@ -937,11 +946,13 @@ foreach_interrupt! {
937 impl_gp16_timer!($inst); 946 impl_gp16_timer!($inst);
938 impl_1ch_cmp_timer!($inst); 947 impl_1ch_cmp_timer!($inst);
939 impl_2ch_cmp_timer!($inst); 948 impl_2ch_cmp_timer!($inst);
940 impl_adv_timer!($inst);
941 impl BasicInstance for crate::peripherals::$inst {} 949 impl BasicInstance for crate::peripherals::$inst {}
942 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 950 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
943 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} 951 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
944 }; 952 };
953 ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => {
954 impl_adv_timer!($inst, $irq);
955 };
945} 956}
946 957
947// Update Event trigger DMA for every timer 958// Update Event trigger DMA for every timer
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index dc701ef64..2ff0db09e 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -42,9 +42,13 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
42 // Prescaler value 42 // Prescaler value
43 let psc = 2u16.pow(psc_power); 43 let psc = 2u16.pow(psc_power);
44 44
45 #[cfg(not(iwdg_v3))]
46 assert!(psc <= 256, "IWDG prescaler should be no more than 256");
47 #[cfg(iwdg_v3)] // H5, U5, WBA
48 assert!(psc <= 1024, "IWDG prescaler should be no more than 1024");
49
45 // Convert prescaler power to PR register value 50 // Convert prescaler power to PR register value
46 let pr = psc_power as u8 - 2; 51 let pr = psc_power as u8 - 2;
47 assert!(pr <= 0b110);
48 52
49 // Reload value 53 // Reload value
50 let rl = reload_value(psc, timeout_us); 54 let rl = reload_value(psc, timeout_us);
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 1b31b6145..fe5e36b32 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -56,5 +56,5 @@ log = { version = "0.4.14", optional = true }
56heapless = "0.8" 56heapless = "0.8"
57 57
58# for HID 58# for HID
59usbd-hid = { version = "0.6.0", optional = true } 59usbd-hid = { version = "0.7.0", optional = true }
60ssmarshal = { version = "1.0", default-features = false, optional = true } 60ssmarshal = { version = "1.0", default-features = false, optional = true }
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index abb995be6..4ab5c7b7c 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -28,7 +28,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
28futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 28futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
29rand = { version = "0.8.4", default-features = false } 29rand = { version = "0.8.4", default-features = false }
30embedded-storage = "0.3.1" 30embedded-storage = "0.3.1"
31usbd-hid = "0.6.0" 31usbd-hid = "0.7.0"
32serde = { version = "1.0.136", default-features = false } 32serde = { version = "1.0.136", default-features = false }
33embedded-hal = { version = "1.0" } 33embedded-hal = { version = "1.0" }
34embedded-hal-async = { version = "1.0" } 34embedded-hal-async = { version = "1.0" }
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 56b9c8018..24aa560d5 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -24,7 +24,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 24futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25rand = { version = "0.8.4", default-features = false } 25rand = { version = "0.8.4", default-features = false }
26embedded-storage = "0.3.1" 26embedded-storage = "0.3.1"
27usbd-hid = "0.6.0" 27usbd-hid = "0.7.0"
28serde = { version = "1.0.136", default-features = false } 28serde = { version = "1.0.136", default-features = false }
29 29
30[profile.release] 30[profile.release]
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index e1092dba4..585349506 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -36,7 +36,7 @@ display-interface = "0.4.1"
36byte-slice-cast = { version = "1.2.0", default-features = false } 36byte-slice-cast = { version = "1.2.0", default-features = false }
37smart-leds = "0.3.0" 37smart-leds = "0.3.0"
38heapless = "0.8" 38heapless = "0.8"
39usbd-hid = "0.6.1" 39usbd-hid = "0.7.0"
40 40
41embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 41embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
42embedded-hal-async = "1.0" 42embedded-hal-async = "1.0"
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 74ccfa3b0..64c749b9b 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -12,7 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature
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", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15usbd-hid = "0.6.0" 15usbd-hid = "0.7.0"
16 16
17defmt = "0.3" 17defmt = "0.3"
18defmt-rtt = "0.4" 18defmt-rtt = "0.4"
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index cc508c3cf..049d9967d 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -113,11 +113,11 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
113 } 113 }
114 114
115 pub fn get_max_duty(&self) -> u32 { 115 pub fn get_max_duty(&self) -> u32 {
116 T::regs_gp32().arr().read().arr() 116 T::regs_gp32().arr().read()
117 } 117 }
118 118
119 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 119 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
120 defmt::assert!(duty < self.get_max_duty()); 120 defmt::assert!(duty < self.get_max_duty());
121 T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty)) 121 T::regs_gp32().ccr(channel.index()).write_value(duty)
122 } 122 }
123} 123}
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 0c6beb72c..5bcee178f 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -13,7 +13,7 @@ embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["de
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16usbd-hid = "0.6.0" 16usbd-hid = "0.7.0"
17 17
18defmt = "0.3" 18defmt = "0.3"
19defmt-rtt = "0.4" 19defmt-rtt = "0.4"