diff options
| -rwxr-xr-x | ci.sh | 25 | ||||
| -rw-r--r-- | embassy-executor/CHANGELOG.md | 4 | ||||
| -rw-r--r-- | embassy-executor/Cargo.toml | 16 | ||||
| -rw-r--r-- | embassy-mspm0/CHANGELOG.md | 3 | ||||
| -rw-r--r-- | embassy-mspm0/Cargo.toml | 22 | ||||
| -rw-r--r-- | embassy-mspm0/build.rs | 8 | ||||
| -rw-r--r-- | embassy-mspm0/src/gpio.rs | 14 | ||||
| -rw-r--r-- | embassy-mspm0/src/i2c.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 3 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 15 | ||||
| -rw-r--r-- | embassy-stm32/src/qspi/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 10 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/nfct.rs | 274 |
13 files changed, 340 insertions, 58 deletions
| @@ -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 |
| 126 | rtos-trace = ["_any_trace", "metadata-name", "dep:rtos-trace", "dep:embassy-time-driver"] | 126 | rtos-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 | ||
| 137 | timer-item-payload-size-1 = ["_timer-item-payload"] | ||
| 138 | ## 2 bytes | ||
| 139 | timer-item-payload-size-2 = ["_timer-item-payload"] | ||
| 140 | ## 4 bytes | ||
| 141 | timer-item-payload-size-4 = ["_timer-item-payload"] | ||
| 142 | ## 8 bytes | ||
| 143 | timer-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" | |||
| 69 | critical-section = "1.2.0" | 69 | critical-section = "1.2.0" |
| 70 | 70 | ||
| 71 | # mspm0-metapac = { version = "" } | 71 | # mspm0-metapac = { version = "" } |
| 72 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-fe17d879548757ca29821da66a1bebf2debd4846" } | 72 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-d7bf3d01ac0780e716a45b0474234d39443dc5cf" } |
| 73 | 73 | ||
| 74 | [build-dependencies] | 74 | [build-dependencies] |
| 75 | proc-macro2 = "1.0.94" | 75 | proc-macro2 = "1.0.94" |
| @@ -77,7 +77,7 @@ quote = "1.0.40" | |||
| 77 | cfg_aliases = "0.2.1" | 77 | cfg_aliases = "0.2.1" |
| 78 | 78 | ||
| 79 | # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } | 79 | # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } |
| 80 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-fe17d879548757ca29821da66a1bebf2debd4846", default-features = false, features = ["metadata"] } | 80 | mspm0-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] |
| 83 | default = ["rt"] | 83 | default = ["rt"] |
| @@ -159,6 +159,24 @@ mspm0c1104dsg = ["mspm0-metapac/mspm0c1104dsg"] | |||
| 159 | mspm0c1104dyy = ["mspm0-metapac/mspm0c1104dyy"] | 159 | mspm0c1104dyy = ["mspm0-metapac/mspm0c1104dyy"] |
| 160 | mspm0c1104ruk = ["mspm0-metapac/mspm0c1104ruk"] | 160 | mspm0c1104ruk = ["mspm0-metapac/mspm0c1104ruk"] |
| 161 | mspm0c1104ycj = ["mspm0-metapac/mspm0c1104ycj"] | 161 | mspm0c1104ycj = ["mspm0-metapac/mspm0c1104ycj"] |
| 162 | mspm0c1105pt = ["mspm0-metapac/mspm0c1105pt"] | ||
| 163 | mspm0c1105rgz = ["mspm0-metapac/mspm0c1105rgz"] | ||
| 164 | mspm0c1105rhb = ["mspm0-metapac/mspm0c1105rhb"] | ||
| 165 | mspm0c1105dgs32 = ["mspm0-metapac/mspm0c1105dgs32"] | ||
| 166 | mspm0c1105dgs28 = ["mspm0-metapac/mspm0c1105dgs28"] | ||
| 167 | mspm0c1105rge = ["mspm0-metapac/mspm0c1105rge"] | ||
| 168 | mspm0c1105dgs20 = ["mspm0-metapac/mspm0c1105dgs20"] | ||
| 169 | mspm0c1105ruk = ["mspm0-metapac/mspm0c1105ruk"] | ||
| 170 | mspm0c1105zcm = ["mspm0-metapac/mspm0c1105zcm"] | ||
| 171 | mspm0c1106pt = ["mspm0-metapac/mspm0c1106pt"] | ||
| 172 | mspm0c1106rgz = ["mspm0-metapac/mspm0c1106rgz"] | ||
| 173 | mspm0c1106rhb = ["mspm0-metapac/mspm0c1106rhb"] | ||
| 174 | mspm0c1106dgs32 = ["mspm0-metapac/mspm0c1106dgs32"] | ||
| 175 | mspm0c1106dgs28 = ["mspm0-metapac/mspm0c1106dgs28"] | ||
| 176 | mspm0c1106rge = ["mspm0-metapac/mspm0c1106rge"] | ||
| 177 | mspm0c1106dgs20 = ["mspm0-metapac/mspm0c1106dgs20"] | ||
| 178 | mspm0c1106ruk = ["mspm0-metapac/mspm0c1106ruk"] | ||
| 179 | mspm0c1106zcm = ["mspm0-metapac/mspm0c1106zcm"] | ||
| 162 | mspm0g1105dgs28 = ["mspm0-metapac/mspm0g1105dgs28"] | 180 | mspm0g1105dgs28 = ["mspm0-metapac/mspm0g1105dgs28"] |
| 163 | mspm0g1105pm = ["mspm0-metapac/mspm0g1105pm"] | 181 | mspm0g1105pm = ["mspm0-metapac/mspm0g1105pm"] |
| 164 | mspm0g1105pt = ["mspm0-metapac/mspm0g1105pt"] | 182 | mspm0g1105pt = ["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 | ||
| 11 | use crate::pac::gpio::vals::*; | 11 | use crate::pac::gpio::vals::*; |
| 12 | use crate::pac::gpio::{self}; | 12 | use crate::pac::gpio::{self}; |
| 13 | #[cfg(all(feature = "rt", any(mspm0c110x, mspm0l110x)))] | 13 | #[cfg(all(feature = "rt", any(mspm0c110x, mspm0c1105_c1106, mspm0l110x)))] |
| 14 | use crate::pac::interrupt; | 14 | use crate::pac::interrupt; |
| 15 | use crate::pac::{self}; | 15 | use 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] |
| 1113 | fn GPIOA() { | 1113 | fn 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] | ||
| 1119 | fn 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)] |
| 1124 | fn GPIOA() { | 1130 | fn 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)] |
| 1131 | fn GPIOB() { | 1137 | fn 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}; | |||
| 17 | use crate::{peripherals, Peri}; | 17 | use crate::{peripherals, Peri}; |
| 18 | 18 | ||
| 19 | /// QSPI transfer configuration. | 19 | /// QSPI transfer configuration. |
| 20 | #[derive(Clone, Copy)] | ||
| 20 | pub struct TransferConfig { | 21 | pub 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)] | ||
| 49 | pub struct Config { | 51 | pub 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 | ||
| 4 | use defmt::*; | 4 | use defmt::{todo, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::config::HfclkSource; | 6 | use embassy_nrf::config::HfclkSource; |
| 7 | use embassy_nrf::nfct::{Config as NfcConfig, NfcId, NfcT}; | 7 | use embassy_nrf::nfct::{Config as NfcConfig, NfcId, NfcT}; |
| 8 | use embassy_nrf::{bind_interrupts, nfct}; | 8 | use embassy_nrf::{bind_interrupts, nfct}; |
| 9 | use iso14443_4::{Card, IsoDep}; | ||
| 9 | use {defmt_rtt as _, embassy_nrf as _, panic_probe as _}; | 10 | use {defmt_rtt as _, embassy_nrf as _, panic_probe as _}; |
| 10 | 11 | ||
| 11 | bind_interrupts!(struct Irqs { | 12 | bind_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; | 121 | struct 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)] | ||
| 131 | struct ApduParseError; | ||
| 132 | |||
| 133 | impl<'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 | |||
| 158 | mod 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 | |||
| 212 | mod 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 | } |
