aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci.sh25
-rw-r--r--embassy-executor/CHANGELOG.md4
-rw-r--r--embassy-executor/Cargo.toml16
-rw-r--r--embassy-mspm0/CHANGELOG.md3
-rw-r--r--embassy-mspm0/Cargo.toml22
-rw-r--r--embassy-mspm0/build.rs8
-rw-r--r--embassy-mspm0/src/gpio.rs14
-rw-r--r--embassy-mspm0/src/i2c.rs2
-rw-r--r--embassy-stm32/CHANGELOG.md3
-rw-r--r--embassy-stm32/src/i2c/v2.rs15
-rw-r--r--embassy-stm32/src/qspi/mod.rs2
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs10
-rw-r--r--examples/nrf52840/src/bin/nfct.rs274
13 files changed, 340 insertions, 58 deletions
diff --git a/ci.sh b/ci.sh
index a585a3ab8..e1197f397 100755
--- a/ci.sh
+++ b/ci.sh
@@ -193,18 +193,19 @@ cargo batch \
193 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf --features lpc55,defmt \ 193 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf --features lpc55,defmt \
194 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1011,rt,defmt,time-driver-pit \ 194 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1011,rt,defmt,time-driver-pit \
195 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1062,rt,defmt,time-driver-pit \ 195 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1062,rt,defmt,time-driver-pit \
196 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1104dgs20,defmt,time-driver-any \ 196 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1104dgs20,rt,defmt,time-driver-any \
197 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507pm,defmt,time-driver-any \ 197 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1106rgz,rt,defmt,time-driver-any \
198 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3519pz,defmt,time-driver-any \ 198 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507pm,rt,defmt,time-driver-any \
199 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1306rhb,defmt,time-driver-any \ 199 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3519pz,rt,defmt,time-driver-any \
200 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l2228pn,defmt,time-driver-any \ 200 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1306rhb,rt,defmt,time-driver-any \
201 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1345dgs28,defmt,time-driver-any \ 201 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l2228pn,rt,defmt,time-driver-any \
202 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1106dgs28,defmt,time-driver-any \ 202 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1345dgs28,rt,defmt,time-driver-any \
203 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1228pm,defmt,time-driver-any \ 203 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1106dgs28,rt,defmt,time-driver-any \
204 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1107ycj,defmt,time-driver-any \ 204 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1228pm,rt,defmt,time-driver-any \
205 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3105rhb,defmt,time-driver-any \ 205 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1107ycj,rt,defmt,time-driver-any \
206 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1505pt,defmt,time-driver-any \ 206 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3105rhb,rt,defmt,time-driver-any \
207 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1519rhb,defmt,time-driver-any \ 207 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1505pt,rt,defmt,time-driver-any \
208 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1519rhb,rt,defmt,time-driver-any \
208 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\ 209 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
209 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \ 210 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
210 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ 211 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md
index 3e6c180c6..a36d270ba 100644
--- a/embassy-executor/CHANGELOG.md
+++ b/embassy-executor/CHANGELOG.md
@@ -20,8 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
20 20
21- Added `extern "Rust" fn __embassy_time_queue_item_from_waker` 21- Added `extern "Rust" fn __embassy_time_queue_item_from_waker`
22- Removed `TaskRef::dangling` 22- Removed `TaskRef::dangling`
23- Added `embassy_time_queue_utils` as a dependency 23- Added `embassy-executor-timer-queue` as a dependency
24- Moved the `TimeQueueItem` struct and `timer-item-payload-size-*` features into embassy-time-queue-utils 24- Moved the `TimeQueueItem` struct and `timer-item-payload-size-*` features (as `timer-item-size-X-words`) into `embassy-executor-timer-queue`
25 25
26## 0.8.0 - 2025-07-31 26## 0.8.0 - 2025-07-31
27 27
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index dc423aba2..ed72a585f 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -125,19 +125,3 @@ trace = ["_any_trace"]
125## Enable support for rtos-trace framework 125## Enable support for rtos-trace framework
126rtos-trace = ["_any_trace", "metadata-name", "dep:rtos-trace", "dep:embassy-time-driver"] 126rtos-trace = ["_any_trace", "metadata-name", "dep:rtos-trace", "dep:embassy-time-driver"]
127_any_trace = [] 127_any_trace = []
128
129#! ### Timer Item Payload Size
130#! Sets the size of the payload for timer items, allowing integrated timer implementors to store
131#! additional data in the timer item. The payload field will be aligned to this value as well.
132#! If these features are not defined, the timer item will contain no payload field.
133
134_timer-item-payload = [] # A size was picked
135
136## 1 bytes
137timer-item-payload-size-1 = ["_timer-item-payload"]
138## 2 bytes
139timer-item-payload-size-2 = ["_timer-item-payload"]
140## 4 bytes
141timer-item-payload-size-4 = ["_timer-item-payload"]
142## 8 bytes
143timer-item-payload-size-8 = ["_timer-item-payload"]
diff --git a/embassy-mspm0/CHANGELOG.md b/embassy-mspm0/CHANGELOG.md
index eca0defd7..c7da4eb33 100644
--- a/embassy-mspm0/CHANGELOG.md
+++ b/embassy-mspm0/CHANGELOG.md
@@ -7,7 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11- feat: Add I2C Controller (blocking & async) + examples for mspm0l1306, mspm0g3507 (tested MCUs) (#4435) 11- feat: Add I2C Controller (blocking & async) + examples for mspm0l1306, mspm0g3507 (tested MCUs) (#4435)
12- fix gpio interrupt not being set for mspm0l110x 12- fix gpio interrupt not being set for mspm0l110x
13- feat: Add window watchdog implementation based on WWDT0, WWDT1 peripherals (#4574) 13- feat: Add window watchdog implementation based on WWDT0, WWDT1 peripherals (#4574)
14- feat: Add MSPM0C1105/C1106 support
diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml
index 92f7a2655..1b32c4d43 100644
--- a/embassy-mspm0/Cargo.toml
+++ b/embassy-mspm0/Cargo.toml
@@ -69,7 +69,7 @@ cortex-m = "0.7.6"
69critical-section = "1.2.0" 69critical-section = "1.2.0"
70 70
71# mspm0-metapac = { version = "" } 71# mspm0-metapac = { version = "" }
72mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-fe17d879548757ca29821da66a1bebf2debd4846" } 72mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-d7bf3d01ac0780e716a45b0474234d39443dc5cf" }
73 73
74[build-dependencies] 74[build-dependencies]
75proc-macro2 = "1.0.94" 75proc-macro2 = "1.0.94"
@@ -77,7 +77,7 @@ quote = "1.0.40"
77cfg_aliases = "0.2.1" 77cfg_aliases = "0.2.1"
78 78
79# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } 79# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] }
80mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-fe17d879548757ca29821da66a1bebf2debd4846", default-features = false, features = ["metadata"] } 80mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-d7bf3d01ac0780e716a45b0474234d39443dc5cf", default-features = false, features = ["metadata"] }
81 81
82[features] 82[features]
83default = ["rt"] 83default = ["rt"]
@@ -159,6 +159,24 @@ mspm0c1104dsg = ["mspm0-metapac/mspm0c1104dsg"]
159mspm0c1104dyy = ["mspm0-metapac/mspm0c1104dyy"] 159mspm0c1104dyy = ["mspm0-metapac/mspm0c1104dyy"]
160mspm0c1104ruk = ["mspm0-metapac/mspm0c1104ruk"] 160mspm0c1104ruk = ["mspm0-metapac/mspm0c1104ruk"]
161mspm0c1104ycj = ["mspm0-metapac/mspm0c1104ycj"] 161mspm0c1104ycj = ["mspm0-metapac/mspm0c1104ycj"]
162mspm0c1105pt = ["mspm0-metapac/mspm0c1105pt"]
163mspm0c1105rgz = ["mspm0-metapac/mspm0c1105rgz"]
164mspm0c1105rhb = ["mspm0-metapac/mspm0c1105rhb"]
165mspm0c1105dgs32 = ["mspm0-metapac/mspm0c1105dgs32"]
166mspm0c1105dgs28 = ["mspm0-metapac/mspm0c1105dgs28"]
167mspm0c1105rge = ["mspm0-metapac/mspm0c1105rge"]
168mspm0c1105dgs20 = ["mspm0-metapac/mspm0c1105dgs20"]
169mspm0c1105ruk = ["mspm0-metapac/mspm0c1105ruk"]
170mspm0c1105zcm = ["mspm0-metapac/mspm0c1105zcm"]
171mspm0c1106pt = ["mspm0-metapac/mspm0c1106pt"]
172mspm0c1106rgz = ["mspm0-metapac/mspm0c1106rgz"]
173mspm0c1106rhb = ["mspm0-metapac/mspm0c1106rhb"]
174mspm0c1106dgs32 = ["mspm0-metapac/mspm0c1106dgs32"]
175mspm0c1106dgs28 = ["mspm0-metapac/mspm0c1106dgs28"]
176mspm0c1106rge = ["mspm0-metapac/mspm0c1106rge"]
177mspm0c1106dgs20 = ["mspm0-metapac/mspm0c1106dgs20"]
178mspm0c1106ruk = ["mspm0-metapac/mspm0c1106ruk"]
179mspm0c1106zcm = ["mspm0-metapac/mspm0c1106zcm"]
162mspm0g1105dgs28 = ["mspm0-metapac/mspm0g1105dgs28"] 180mspm0g1105dgs28 = ["mspm0-metapac/mspm0g1105dgs28"]
163mspm0g1105pm = ["mspm0-metapac/mspm0g1105pm"] 181mspm0g1105pm = ["mspm0-metapac/mspm0g1105pm"]
164mspm0g1105pt = ["mspm0-metapac/mspm0g1105pt"] 182mspm0g1105pt = ["mspm0-metapac/mspm0g1105pt"]
diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs
index 256192f8b..e8364e31a 100644
--- a/embassy-mspm0/build.rs
+++ b/embassy-mspm0/build.rs
@@ -79,10 +79,14 @@ fn get_chip_cfgs(chip_name: &str) -> Vec<String> {
79 let mut cfgs = Vec::new(); 79 let mut cfgs = Vec::new();
80 80
81 // GPIO on C110x is special as it does not belong to an interrupt group. 81 // GPIO on C110x is special as it does not belong to an interrupt group.
82 if chip_name.starts_with("mspm0c110") || chip_name.starts_with("msps003f") { 82 if chip_name.starts_with("mspm0c1103") || chip_name.starts_with("mspm0c1104") || chip_name.starts_with("msps003f") {
83 cfgs.push("mspm0c110x".to_string()); 83 cfgs.push("mspm0c110x".to_string());
84 } 84 }
85 85
86 if chip_name.starts_with("mspm0c1105") || chip_name.starts_with("mspm0c1106") {
87 cfgs.push("mspm0c1105_c1106".to_string());
88 }
89
86 // Family ranges (temporary until int groups are generated) 90 // Family ranges (temporary until int groups are generated)
87 // 91 //
88 // TODO: Remove this once int group stuff is generated. 92 // TODO: Remove this once int group stuff is generated.
@@ -537,6 +541,8 @@ fn generate_interrupts() -> TokenStream {
537 pub fn enable_group_interrupts(_cs: critical_section::CriticalSection) { 541 pub fn enable_group_interrupts(_cs: critical_section::CriticalSection) {
538 use crate::interrupt::typelevel::Interrupt; 542 use crate::interrupt::typelevel::Interrupt;
539 543
544 // This is empty for C1105/6
545 #[allow(unused_unsafe)]
540 unsafe { 546 unsafe {
541 #(#group_interrupt_enables)* 547 #(#group_interrupt_enables)*
542 } 548 }
diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs
index f77848888..d5fd36dbf 100644
--- a/embassy-mspm0/src/gpio.rs
+++ b/embassy-mspm0/src/gpio.rs
@@ -10,7 +10,7 @@ use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::pac::gpio::vals::*; 11use crate::pac::gpio::vals::*;
12use crate::pac::gpio::{self}; 12use crate::pac::gpio::{self};
13#[cfg(all(feature = "rt", any(mspm0c110x, mspm0l110x)))] 13#[cfg(all(feature = "rt", any(mspm0c110x, mspm0c1105_c1106, mspm0l110x)))]
14use crate::pac::interrupt; 14use crate::pac::interrupt;
15use crate::pac::{self}; 15use crate::pac::{self};
16 16
@@ -1108,24 +1108,30 @@ fn irq_handler(gpio: gpio::Gpio, wakers: &[AtomicWaker; 32]) {
1108// C110x and L110x have a dedicated interrupts just for GPIOA. 1108// C110x and L110x have a dedicated interrupts just for GPIOA.
1109// 1109//
1110// These chips do not have a GROUP1 interrupt. 1110// These chips do not have a GROUP1 interrupt.
1111#[cfg(all(feature = "rt", any(mspm0c110x, mspm0l110x)))] 1111#[cfg(all(feature = "rt", any(mspm0c110x, mspm0c1105_c1106, mspm0l110x)))]
1112#[interrupt] 1112#[interrupt]
1113fn GPIOA() { 1113fn GPIOA() {
1114 irq_handler(pac::GPIOA, &PORTA_WAKERS); 1114 irq_handler(pac::GPIOA, &PORTA_WAKERS);
1115} 1115}
1116 1116
1117#[cfg(all(feature = "rt", mspm0c1105_c1106))]
1118#[interrupt]
1119fn GPIOB() {
1120 irq_handler(pac::GPIOB, &PORTB_WAKERS);
1121}
1122
1117// These symbols are weakly defined as DefaultHandler and are called by the interrupt group implementation. 1123// These symbols are weakly defined as DefaultHandler and are called by the interrupt group implementation.
1118// 1124//
1119// Defining these as no_mangle is required so that the linker will pick these over the default handler. 1125// Defining these as no_mangle is required so that the linker will pick these over the default handler.
1120 1126
1121#[cfg(all(feature = "rt", not(any(mspm0c110x, mspm0l110x))))] 1127#[cfg(all(feature = "rt", not(any(mspm0c110x, mspm0c1105_c1106, mspm0l110x))))]
1122#[no_mangle] 1128#[no_mangle]
1123#[allow(non_snake_case)] 1129#[allow(non_snake_case)]
1124fn GPIOA() { 1130fn GPIOA() {
1125 irq_handler(pac::GPIOA, &PORTA_WAKERS); 1131 irq_handler(pac::GPIOA, &PORTA_WAKERS);
1126} 1132}
1127 1133
1128#[cfg(all(feature = "rt", gpio_pb))] 1134#[cfg(all(feature = "rt", gpio_pb, not(mspm0c1105_c1106)))]
1129#[no_mangle] 1135#[no_mangle]
1130#[allow(non_snake_case)] 1136#[allow(non_snake_case)]
1131fn GPIOB() { 1137fn GPIOB() {
diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs
index 7e22bb724..1906e37ba 100644
--- a/embassy-mspm0/src/i2c.rs
+++ b/embassy-mspm0/src/i2c.rs
@@ -195,7 +195,7 @@ impl Config {
195 .unwrap(); 195 .unwrap();
196 } 196 }
197 197
198 #[cfg(any(mspm0c110x))] 198 #[cfg(any(mspm0c110x, mspm0c1105_c1106))]
199 fn calculate_clock_source(&self) -> u32 { 199 fn calculate_clock_source(&self) -> u32 {
200 // Assume that BusClk has default value. 200 // Assume that BusClk has default value.
201 // TODO: calculate BusClk more precisely. 201 // TODO: calculate BusClk more precisely.
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index dfb8ca066..4cc48ed97 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11- fix: Fixed STM32H5 builds requiring time feature 11- fix: Fixed STM32H5 builds requiring time feature
12- feat: Derive Clone, Copy for QSPI Config
13- fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received
14- feat: stm32/timer: add set_polarity functions for main and complementary outputs in complementary_pwm
12 15
13## 0.4.0 - 2025-08-26 16## 0.4.0 - 2025-08-26
14 17
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 3b09f1b34..6b20a601b 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -454,7 +454,8 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
454 // (START has been ACKed or last byte when 454 // (START has been ACKed or last byte when
455 // through) 455 // through)
456 if let Err(err) = self.wait_txis(timeout) { 456 if let Err(err) = self.wait_txis(timeout) {
457 if send_stop { 457 if send_stop && err != Error::Nack {
458 // STOP is sent automatically if a NACK was received
458 self.master_stop(); 459 self.master_stop();
459 } 460 }
460 return Err(err); 461 return Err(err);
@@ -548,7 +549,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
548 (idx != last_slice_index) || (slice_len > 255), 549 (idx != last_slice_index) || (slice_len > 255),
549 timeout, 550 timeout,
550 ) { 551 ) {
551 self.master_stop(); 552 if err != Error::Nack {
553 self.master_stop();
554 }
552 return Err(err); 555 return Err(err);
553 } 556 }
554 } 557 }
@@ -561,7 +564,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
561 (number != last_chunk_idx) || (idx != last_slice_index), 564 (number != last_chunk_idx) || (idx != last_slice_index),
562 timeout, 565 timeout,
563 ) { 566 ) {
564 self.master_stop(); 567 if err != Error::Nack {
568 self.master_stop();
569 }
565 return Err(err); 570 return Err(err);
566 } 571 }
567 } 572 }
@@ -571,7 +576,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
571 // (START has been ACKed or last byte when 576 // (START has been ACKed or last byte when
572 // through) 577 // through)
573 if let Err(err) = self.wait_txis(timeout) { 578 if let Err(err) = self.wait_txis(timeout) {
574 self.master_stop(); 579 if err != Error::Nack {
580 self.master_stop();
581 }
575 return Err(err); 582 return Err(err);
576 } 583 }
577 584
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index 1e20d7cd3..c0cd216f0 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -17,6 +17,7 @@ use crate::rcc::{self, RccPeripheral};
17use crate::{peripherals, Peri}; 17use crate::{peripherals, Peri};
18 18
19/// QSPI transfer configuration. 19/// QSPI transfer configuration.
20#[derive(Clone, Copy)]
20pub struct TransferConfig { 21pub struct TransferConfig {
21 /// Instruction width (IMODE) 22 /// Instruction width (IMODE)
22 pub iwidth: QspiWidth, 23 pub iwidth: QspiWidth,
@@ -46,6 +47,7 @@ impl Default for TransferConfig {
46} 47}
47 48
48/// QSPI driver configuration. 49/// QSPI driver configuration.
50#[derive(Clone, Copy)]
49pub struct Config { 51pub struct Config {
50 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. 52 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
51 /// If you need other value the whose predefined use `Other` variant. 53 /// If you need other value the whose predefined use `Other` variant.
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index b291fc155..7d6c2273e 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -185,6 +185,16 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
185 self.inner.set_complementary_output_polarity(channel, polarity); 185 self.inner.set_complementary_output_polarity(channel, polarity);
186 } 186 }
187 187
188 /// Set the main output polarity for a given channel.
189 pub fn set_main_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
190 self.inner.set_output_polarity(channel, polarity);
191 }
192
193 /// Set the complementary output polarity for a given channel.
194 pub fn set_complementary_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
195 self.inner.set_complementary_output_polarity(channel, polarity);
196 }
197
188 /// Set the dead time as a proportion of max_duty 198 /// Set the dead time as a proportion of max_duty
189 pub fn set_dead_time(&mut self, value: u16) { 199 pub fn set_dead_time(&mut self, value: u16) {
190 let (ckd, value) = compute_dead_time_value(value); 200 let (ckd, value) = compute_dead_time_value(value);
diff --git a/examples/nrf52840/src/bin/nfct.rs b/examples/nrf52840/src/bin/nfct.rs
index d559d006a..fafa37f48 100644
--- a/examples/nrf52840/src/bin/nfct.rs
+++ b/examples/nrf52840/src/bin/nfct.rs
@@ -1,11 +1,12 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::{todo, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::config::HfclkSource; 6use embassy_nrf::config::HfclkSource;
7use embassy_nrf::nfct::{Config as NfcConfig, NfcId, NfcT}; 7use embassy_nrf::nfct::{Config as NfcConfig, NfcId, NfcT};
8use embassy_nrf::{bind_interrupts, nfct}; 8use embassy_nrf::{bind_interrupts, nfct};
9use iso14443_4::{Card, IsoDep};
9use {defmt_rtt as _, embassy_nrf as _, panic_probe as _}; 10use {defmt_rtt as _, embassy_nrf as _, panic_probe as _};
10 11
11bind_interrupts!(struct Irqs { 12bind_interrupts!(struct Irqs {
@@ -30,12 +31,28 @@ async fn main(_spawner: Spawner) {
30 31
31 let mut buf = [0u8; 256]; 32 let mut buf = [0u8; 256];
32 33
34 let cc = &[
35 0x00, 0x0f, /* CCEN_HI, CCEN_LOW */
36 0x20, /* VERSION */
37 0x00, 0x7f, /* MLe_HI, MLe_LOW */
38 0x00, 0x7f, /* MLc_HI, MLc_LOW */
39 /* TLV */
40 0x04, 0x06, 0xe1, 0x04, 0x00, 0x7f, 0x00, 0x00,
41 ];
42
43 let ndef = &[
44 0x00, 0x10, 0xd1, 0x1, 0xc, 0x55, 0x4, 0x65, 0x6d, 0x62, 0x61, 0x73, 0x73, 0x79, 0x2e, 0x64, 0x65, 0x76,
45 ];
46 let mut selected: &[u8] = cc;
47
33 loop { 48 loop {
34 info!("activating"); 49 info!("activating");
35 nfc.activate().await; 50 nfc.activate().await;
51 info!("activated!");
52
53 let mut nfc = IsoDep::new(iso14443_3::Logger(&mut nfc));
36 54
37 loop { 55 loop {
38 info!("rxing");
39 let n = match nfc.receive(&mut buf).await { 56 let n = match nfc.receive(&mut buf).await {
40 Ok(n) => n, 57 Ok(n) => n,
41 Err(e) => { 58 Err(e) => {
@@ -44,25 +61,51 @@ async fn main(_spawner: Spawner) {
44 } 61 }
45 }; 62 };
46 let req = &buf[..n]; 63 let req = &buf[..n];
47 info!("received frame {:02x}", req); 64 info!("iso-dep rx {:02x}", req);
48 65
49 let mut deselect = false; 66 let Ok(apdu) = Apdu::parse(req) else {
50 let resp = match req { 67 error!("apdu parse error");
51 [0xe0, ..] => { 68 break;
52 info!("Got RATS, tx'ing ATS"); 69 };
53 &[0x06, 0x77, 0x77, 0x81, 0x02, 0x80][..] 70
71 info!("apdu: {:?}", apdu);
72
73 let resp = match (apdu.cla, apdu.ins, apdu.p1, apdu.p2) {
74 (0, 0xa4, 4, 0) => {
75 info!("select app");
76 &[0x90, 0x00][..]
54 } 77 }
55 [0xc2] => { 78 (0, 0xa4, 0, 12) => {
56 info!("Got deselect!"); 79 info!("select df");
57 deselect = true; 80 match apdu.data {
58 &[0xc2] 81 [0xe1, 0x03] => {
82 selected = cc;
83 &[0x90, 0x00][..]
84 }
85 [0xe1, 0x04] => {
86 selected = ndef;
87 &[0x90, 0x00][..]
88 }
89 _ => todo!(), // return NOT FOUND
90 }
91 }
92 (0, 0xb0, p1, p2) => {
93 info!("read");
94 let offs = u16::from_be_bytes([p1 & 0x7f, p2]) as usize;
95 let len = if apdu.le == 0 { usize::MAX } else { apdu.le as usize };
96 let n = len.min(selected.len() - offs);
97 buf[..n].copy_from_slice(&selected[offs..][..n]);
98 buf[n..][..2].copy_from_slice(&[0x90, 0x00]);
99 &buf[..n + 2]
59 } 100 }
60 _ => { 101 _ => {
61 info!("Got unknown command!"); 102 info!("Got unknown command!");
62 &[0xFF] 103 &[0xFF, 0xFF]
63 } 104 }
64 }; 105 };
65 106
107 info!("iso-dep tx {:02x}", resp);
108
66 match nfc.transmit(resp).await { 109 match nfc.transmit(resp).await {
67 Ok(()) => {} 110 Ok(()) => {}
68 Err(e) => { 111 Err(e) => {
@@ -70,10 +113,211 @@ async fn main(_spawner: Spawner) {
70 break; 113 break;
71 } 114 }
72 } 115 }
116 }
117 }
118}
73 119
74 if deselect { 120#[derive(Debug, Clone, defmt::Format)]
75 break; 121struct Apdu<'a> {
122 pub cla: u8,
123 pub ins: u8,
124 pub p1: u8,
125 pub p2: u8,
126 pub data: &'a [u8],
127 pub le: u16,
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
131struct ApduParseError;
132
133impl<'a> Apdu<'a> {
134 pub fn parse(apdu: &'a [u8]) -> Result<Self, ApduParseError> {
135 if apdu.len() < 4 {
136 return Err(ApduParseError);
137 }
138
139 let (data, le) = match apdu.len() - 4 {
140 0 => (&[][..], 0),
141 1 => (&[][..], apdu[4]),
142 n if n == 1 + apdu[4] as usize && apdu[4] != 0 => (&apdu[5..][..apdu[4] as usize], 0),
143 n if n == 2 + apdu[4] as usize && apdu[4] != 0 => (&apdu[5..][..apdu[4] as usize], apdu[apdu.len() - 1]),
144 _ => return Err(ApduParseError),
145 };
146
147 Ok(Apdu {
148 cla: apdu[0],
149 ins: apdu[1],
150 p1: apdu[2],
151 p2: apdu[3],
152 data,
153 le: le as _,
154 })
155 }
156}
157
158mod iso14443_3 {
159 use core::future::Future;
160
161 use defmt::info;
162 use embassy_nrf::nfct::{Error, NfcT};
163
164 pub trait Card {
165 type Error;
166 async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
167 async fn transmit(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
168 }
169
170 impl<'a, T: Card> Card for &'a mut T {
171 type Error = T::Error;
172
173 fn receive(&mut self, buf: &mut [u8]) -> impl Future<Output = Result<usize, Self::Error>> {
174 T::receive(self, buf)
175 }
176
177 fn transmit(&mut self, buf: &[u8]) -> impl Future<Output = Result<(), Self::Error>> {
178 T::transmit(self, buf)
179 }
180 }
181
182 impl<'a> Card for NfcT<'a> {
183 type Error = Error;
184
185 fn receive(&mut self, buf: &mut [u8]) -> impl Future<Output = Result<usize, Self::Error>> {
186 self.receive(buf)
187 }
188
189 fn transmit(&mut self, buf: &[u8]) -> impl Future<Output = Result<(), Self::Error>> {
190 self.transmit(buf)
191 }
192 }
193
194 pub struct Logger<T: Card>(pub T);
195
196 impl<T: Card> Card for Logger<T> {
197 type Error = T::Error;
198
199 async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
200 let n = T::receive(&mut self.0, buf).await?;
201 info!("<- {:02x}", &buf[..n]);
202 Ok(n)
203 }
204
205 fn transmit(&mut self, buf: &[u8]) -> impl Future<Output = Result<(), Self::Error>> {
206 info!("-> {:02x}", buf);
207 T::transmit(&mut self.0, buf)
208 }
209 }
210}
211
212mod iso14443_4 {
213 use defmt::info;
214
215 use crate::iso14443_3;
216
217 #[derive(defmt::Format)]
218 pub enum Error<T> {
219 Deselected,
220 Protocol,
221 Lower(T),
222 }
223
224 pub trait Card {
225 type Error;
226 async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
227 async fn transmit(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
228 }
229
230 pub struct IsoDep<T: iso14443_3::Card> {
231 nfc: T,
232
233 /// Block count spin bit: 0 or 1
234 block_num: u8,
235
236 /// true if deselected. This is permanent, you must create another IsoDep
237 /// instance if we get selected again.
238 deselected: bool,
239
240 /// last response, in case we need to retransmit.
241 resp: [u8; 256],
242 resp_len: usize,
243 }
244
245 impl<T: iso14443_3::Card> IsoDep<T> {
246 pub fn new(nfc: T) -> Self {
247 Self {
248 nfc,
249 block_num: 1,
250 deselected: false,
251 resp: [0u8; 256],
252 resp_len: 0,
76 } 253 }
77 } 254 }
78 } 255 }
256
257 impl<T: iso14443_3::Card> Card for IsoDep<T> {
258 type Error = Error<T::Error>;
259
260 async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
261 if self.deselected {
262 return Err(Error::Deselected);
263 }
264
265 let mut temp = [0u8; 256];
266
267 loop {
268 let n = self.nfc.receive(&mut temp).await.map_err(Error::Lower)?;
269 assert!(n != 0);
270 match temp[0] {
271 0x02 | 0x03 => {
272 self.block_num ^= 0x01;
273 assert!(temp[0] == 0x02 | self.block_num);
274 buf[..n - 1].copy_from_slice(&temp[1..n]);
275 return Ok(n - 1);
276 }
277 0xb2 | 0xb3 => {
278 if temp[0] & 0x01 != self.block_num {
279 info!("Got NAK, transmitting ACK.");
280 let resp = &[0xA2 | self.block_num];
281 self.nfc.transmit(resp).await.map_err(Error::Lower)?;
282 } else {
283 info!("Got NAK, retransmitting.");
284 let resp: &[u8] = &self.resp[..self.resp_len];
285 self.nfc.transmit(resp).await.map_err(Error::Lower)?;
286 }
287 }
288 0xe0 => {
289 info!("Got RATS, tx'ing ATS");
290 let resp = &[0x06, 0x77, 0x77, 0x81, 0x02, 0x80];
291 self.nfc.transmit(resp).await.map_err(Error::Lower)?;
292 }
293 0xc2 => {
294 info!("Got deselect!");
295 self.deselected = true;
296 let resp = &[0xC2];
297 self.nfc.transmit(resp).await.map_err(Error::Lower)?;
298 return Err(Error::Deselected);
299 }
300 _ => {
301 info!("Got unknown command {:02x}!", temp[0]);
302 return Err(Error::Protocol);
303 }
304 };
305 }
306 }
307
308 async fn transmit(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
309 if self.deselected {
310 return Err(Error::Deselected);
311 }
312
313 self.resp[0] = 0x02 | self.block_num;
314 self.resp[1..][..buf.len()].copy_from_slice(buf);
315 self.resp_len = 1 + buf.len();
316
317 let resp: &[u8] = &self.resp[..self.resp_len];
318 self.nfc.transmit(resp).await.map_err(Error::Lower)?;
319
320 Ok(())
321 }
322 }
79} 323}