diff options
| author | benjaminschlegel87 <[email protected]> | 2025-07-25 20:39:40 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-25 20:39:40 +0200 |
| commit | dbc1818acd69e2e15ac574356c9b07cb717df441 (patch) | |
| tree | 05e6360c1946183b524a1ce82268547fe4bbcfd0 /embassy-stm32 | |
| parent | adb728009ceba095d2190038ff698aaee08907a9 (diff) | |
| parent | 996974e313fa5ec2c7c2d9dd0998fab244c0a180 (diff) | |
Merge branch 'embassy-rs:main' into stm32_adc_v3_hw_oversampling_support
Diffstat (limited to 'embassy-stm32')
64 files changed, 2829 insertions, 1101 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index b6781905e..c4c2cd013 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | ## Unreleased | 8 | ## Unreleased |
| 9 | - Modify BufferedUart initialization to take pins before interrupts ([#3983](https://github.com/embassy-rs/embassy/pull/3983)) | 9 | - Modify BufferedUart initialization to take pins before interrupts ([#3983](https://github.com/embassy-rs/embassy/pull/3983)) |
| 10 | - Added a 'single-bank' and a 'dual-bank' feature so chips with configurable flash bank setups are be supported in embassy ([#4125](https://github.com/embassy-rs/embassy/pull/4125)) | 10 | - Added a 'single-bank' and a 'dual-bank' feature so chips with configurable flash bank setups are be supported in embassy ([#4125](https://github.com/embassy-rs/embassy/pull/4125)) |
| 11 | - Add automatic setting of remap bits when using alternate DMA channels on STM32F0 and STM32F3 devices ([#3653](https://github.com/embassy-rs/embassy/pull/3653)) | ||
| 11 | 12 | ||
| 12 | ## 0.2.0 - 2025-01-10 | 13 | ## 0.2.0 - 2025-01-10 |
| 13 | 14 | ||
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 034f51df9..02e75733e 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -53,11 +53,11 @@ embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } | |||
| 53 | embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } | 53 | embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } |
| 54 | embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } | 54 | embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } |
| 55 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | 55 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } |
| 56 | embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } | 56 | embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } |
| 57 | embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } | 57 | embassy-embedded-hal = { version = "0.3.1", path = "../embassy-embedded-hal", default-features = false } |
| 58 | embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } | 58 | embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } |
| 59 | embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } | 59 | embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" } |
| 60 | embassy-usb-synopsys-otg = { version = "0.2.0", path = "../embassy-usb-synopsys-otg" } | 60 | embassy-usb-synopsys-otg = { version = "0.3.0", path = "../embassy-usb-synopsys-otg" } |
| 61 | embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true } | 61 | embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true } |
| 62 | 62 | ||
| 63 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 63 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| @@ -81,7 +81,7 @@ futures-util = { version = "0.3.30", default-features = false } | |||
| 81 | sdio-host = "0.9.0" | 81 | sdio-host = "0.9.0" |
| 82 | critical-section = "1.1" | 82 | critical-section = "1.1" |
| 83 | #stm32-metapac = { version = "16" } | 83 | #stm32-metapac = { version = "16" } |
| 84 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-27ef8fba3483187e852eaf3796d827259f61e8ec" } | 84 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9fc86ca7b3a8bc05182bf1ce3045602df1f5dce3" } |
| 85 | 85 | ||
| 86 | vcell = "0.1.3" | 86 | vcell = "0.1.3" |
| 87 | nb = "1.0.0" | 87 | nb = "1.0.0" |
| @@ -110,7 +110,7 @@ proc-macro2 = "1.0.36" | |||
| 110 | quote = "1.0.15" | 110 | quote = "1.0.15" |
| 111 | 111 | ||
| 112 | #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} | 112 | #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} |
| 113 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-27ef8fba3483187e852eaf3796d827259f61e8ec", default-features = false, features = ["metadata"] } | 113 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9fc86ca7b3a8bc05182bf1ce3045602df1f5dce3", default-features = false, features = ["metadata"] } |
| 114 | 114 | ||
| 115 | [features] | 115 | [features] |
| 116 | default = ["rt"] | 116 | default = ["rt"] |
| @@ -129,6 +129,7 @@ defmt = [ | |||
| 129 | "embassy-net-driver/defmt", | 129 | "embassy-net-driver/defmt", |
| 130 | "embassy-time?/defmt", | 130 | "embassy-time?/defmt", |
| 131 | "embassy-usb-synopsys-otg/defmt", | 131 | "embassy-usb-synopsys-otg/defmt", |
| 132 | "stm32-metapac/defmt" | ||
| 132 | ] | 133 | ] |
| 133 | 134 | ||
| 134 | exti = [] | 135 | exti = [] |
| @@ -237,6 +238,47 @@ stm32c031g4 = [ "stm32-metapac/stm32c031g4" ] | |||
| 237 | stm32c031g6 = [ "stm32-metapac/stm32c031g6" ] | 238 | stm32c031g6 = [ "stm32-metapac/stm32c031g6" ] |
| 238 | stm32c031k4 = [ "stm32-metapac/stm32c031k4" ] | 239 | stm32c031k4 = [ "stm32-metapac/stm32c031k4" ] |
| 239 | stm32c031k6 = [ "stm32-metapac/stm32c031k6" ] | 240 | stm32c031k6 = [ "stm32-metapac/stm32c031k6" ] |
| 241 | stm32c051c6 = [ "stm32-metapac/stm32c051c6" ] | ||
| 242 | stm32c051c8 = [ "stm32-metapac/stm32c051c8" ] | ||
| 243 | stm32c051d8 = [ "stm32-metapac/stm32c051d8" ] | ||
| 244 | stm32c051f6 = [ "stm32-metapac/stm32c051f6" ] | ||
| 245 | stm32c051f8 = [ "stm32-metapac/stm32c051f8" ] | ||
| 246 | stm32c051g6 = [ "stm32-metapac/stm32c051g6" ] | ||
| 247 | stm32c051g8 = [ "stm32-metapac/stm32c051g8" ] | ||
| 248 | stm32c051k6 = [ "stm32-metapac/stm32c051k6" ] | ||
| 249 | stm32c051k8 = [ "stm32-metapac/stm32c051k8" ] | ||
| 250 | stm32c071c8 = [ "stm32-metapac/stm32c071c8" ] | ||
| 251 | stm32c071cb = [ "stm32-metapac/stm32c071cb" ] | ||
| 252 | stm32c071f8 = [ "stm32-metapac/stm32c071f8" ] | ||
| 253 | stm32c071fb = [ "stm32-metapac/stm32c071fb" ] | ||
| 254 | stm32c071g8 = [ "stm32-metapac/stm32c071g8" ] | ||
| 255 | stm32c071gb = [ "stm32-metapac/stm32c071gb" ] | ||
| 256 | stm32c071k8 = [ "stm32-metapac/stm32c071k8" ] | ||
| 257 | stm32c071kb = [ "stm32-metapac/stm32c071kb" ] | ||
| 258 | stm32c071r8 = [ "stm32-metapac/stm32c071r8" ] | ||
| 259 | stm32c071rb = [ "stm32-metapac/stm32c071rb" ] | ||
| 260 | stm32c091cb = [ "stm32-metapac/stm32c091cb" ] | ||
| 261 | stm32c091cc = [ "stm32-metapac/stm32c091cc" ] | ||
| 262 | stm32c091ec = [ "stm32-metapac/stm32c091ec" ] | ||
| 263 | stm32c091fb = [ "stm32-metapac/stm32c091fb" ] | ||
| 264 | stm32c091fc = [ "stm32-metapac/stm32c091fc" ] | ||
| 265 | stm32c091gb = [ "stm32-metapac/stm32c091gb" ] | ||
| 266 | stm32c091gc = [ "stm32-metapac/stm32c091gc" ] | ||
| 267 | stm32c091kb = [ "stm32-metapac/stm32c091kb" ] | ||
| 268 | stm32c091kc = [ "stm32-metapac/stm32c091kc" ] | ||
| 269 | stm32c091rb = [ "stm32-metapac/stm32c091rb" ] | ||
| 270 | stm32c091rc = [ "stm32-metapac/stm32c091rc" ] | ||
| 271 | stm32c092cb = [ "stm32-metapac/stm32c092cb" ] | ||
| 272 | stm32c092cc = [ "stm32-metapac/stm32c092cc" ] | ||
| 273 | stm32c092ec = [ "stm32-metapac/stm32c092ec" ] | ||
| 274 | stm32c092fb = [ "stm32-metapac/stm32c092fb" ] | ||
| 275 | stm32c092fc = [ "stm32-metapac/stm32c092fc" ] | ||
| 276 | stm32c092gb = [ "stm32-metapac/stm32c092gb" ] | ||
| 277 | stm32c092gc = [ "stm32-metapac/stm32c092gc" ] | ||
| 278 | stm32c092kb = [ "stm32-metapac/stm32c092kb" ] | ||
| 279 | stm32c092kc = [ "stm32-metapac/stm32c092kc" ] | ||
| 280 | stm32c092rb = [ "stm32-metapac/stm32c092rb" ] | ||
| 281 | stm32c092rc = [ "stm32-metapac/stm32c092rc" ] | ||
| 240 | stm32f030c6 = [ "stm32-metapac/stm32f030c6" ] | 282 | stm32f030c6 = [ "stm32-metapac/stm32f030c6" ] |
| 241 | stm32f030c8 = [ "stm32-metapac/stm32f030c8" ] | 283 | stm32f030c8 = [ "stm32-metapac/stm32f030c8" ] |
| 242 | stm32f030cc = [ "stm32-metapac/stm32f030cc" ] | 284 | stm32f030cc = [ "stm32-metapac/stm32f030cc" ] |
| @@ -1634,6 +1676,24 @@ stm32wba55he = [ "stm32-metapac/stm32wba55he" ] | |||
| 1634 | stm32wba55hg = [ "stm32-metapac/stm32wba55hg" ] | 1676 | stm32wba55hg = [ "stm32-metapac/stm32wba55hg" ] |
| 1635 | stm32wba55ue = [ "stm32-metapac/stm32wba55ue" ] | 1677 | stm32wba55ue = [ "stm32-metapac/stm32wba55ue" ] |
| 1636 | stm32wba55ug = [ "stm32-metapac/stm32wba55ug" ] | 1678 | stm32wba55ug = [ "stm32-metapac/stm32wba55ug" ] |
| 1679 | stm32wba62cg = [ "stm32-metapac/stm32wba62cg" ] | ||
| 1680 | stm32wba62ci = [ "stm32-metapac/stm32wba62ci" ] | ||
| 1681 | stm32wba62mg = [ "stm32-metapac/stm32wba62mg" ] | ||
| 1682 | stm32wba62mi = [ "stm32-metapac/stm32wba62mi" ] | ||
| 1683 | stm32wba62pg = [ "stm32-metapac/stm32wba62pg" ] | ||
| 1684 | stm32wba62pi = [ "stm32-metapac/stm32wba62pi" ] | ||
| 1685 | stm32wba63cg = [ "stm32-metapac/stm32wba63cg" ] | ||
| 1686 | stm32wba63ci = [ "stm32-metapac/stm32wba63ci" ] | ||
| 1687 | stm32wba64cg = [ "stm32-metapac/stm32wba64cg" ] | ||
| 1688 | stm32wba64ci = [ "stm32-metapac/stm32wba64ci" ] | ||
| 1689 | stm32wba65cg = [ "stm32-metapac/stm32wba65cg" ] | ||
| 1690 | stm32wba65ci = [ "stm32-metapac/stm32wba65ci" ] | ||
| 1691 | stm32wba65mg = [ "stm32-metapac/stm32wba65mg" ] | ||
| 1692 | stm32wba65mi = [ "stm32-metapac/stm32wba65mi" ] | ||
| 1693 | stm32wba65pg = [ "stm32-metapac/stm32wba65pg" ] | ||
| 1694 | stm32wba65pi = [ "stm32-metapac/stm32wba65pi" ] | ||
| 1695 | stm32wba65rg = [ "stm32-metapac/stm32wba65rg" ] | ||
| 1696 | stm32wba65ri = [ "stm32-metapac/stm32wba65ri" ] | ||
| 1637 | stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4", "_dual-core", "_core-cm4" ] | 1697 | stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4", "_dual-core", "_core-cm4" ] |
| 1638 | stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p", "_dual-core", "_core-cm0p" ] | 1698 | stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p", "_dual-core", "_core-cm0p" ] |
| 1639 | stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4", "_dual-core", "_core-cm4" ] | 1699 | stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4", "_dual-core", "_core-cm4" ] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index bb5ef53d7..73860c64a 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -505,6 +505,13 @@ fn main() { | |||
| 505 | field: "CLK48SEL", | 505 | field: "CLK48SEL", |
| 506 | }, | 506 | }, |
| 507 | ); | 507 | ); |
| 508 | clock_gen.chained_muxes.insert( | ||
| 509 | "RFWKP", | ||
| 510 | &PeripheralRccRegister { | ||
| 511 | register: "CSR", | ||
| 512 | field: "RFWKPSEL", | ||
| 513 | }, | ||
| 514 | ); | ||
| 508 | } | 515 | } |
| 509 | if chip_name.starts_with("stm32f7") { | 516 | if chip_name.starts_with("stm32f7") { |
| 510 | clock_gen.chained_muxes.insert( | 517 | clock_gen.chained_muxes.insert( |
| @@ -1090,21 +1097,21 @@ fn main() { | |||
| 1090 | (("fmc", "CLK"), quote!(crate::fmc::ClkPin)), | 1097 | (("fmc", "CLK"), quote!(crate::fmc::ClkPin)), |
| 1091 | (("fmc", "BA0"), quote!(crate::fmc::BA0Pin)), | 1098 | (("fmc", "BA0"), quote!(crate::fmc::BA0Pin)), |
| 1092 | (("fmc", "BA1"), quote!(crate::fmc::BA1Pin)), | 1099 | (("fmc", "BA1"), quote!(crate::fmc::BA1Pin)), |
| 1093 | (("timer", "CH1"), quote!(crate::timer::Channel1Pin)), | 1100 | (("timer", "CH1"), quote!(crate::timer::TimerPin<Ch1>)), |
| 1094 | (("timer", "CH1N"), quote!(crate::timer::Channel1ComplementaryPin)), | 1101 | (("timer", "CH1N"), quote!(crate::timer::TimerComplementaryPin<Ch1>)), |
| 1095 | (("timer", "CH2"), quote!(crate::timer::Channel2Pin)), | 1102 | (("timer", "CH2"), quote!(crate::timer::TimerPin<Ch2>)), |
| 1096 | (("timer", "CH2N"), quote!(crate::timer::Channel2ComplementaryPin)), | 1103 | (("timer", "CH2N"), quote!(crate::timer::TimerComplementaryPin<Ch2>)), |
| 1097 | (("timer", "CH3"), quote!(crate::timer::Channel3Pin)), | 1104 | (("timer", "CH3"), quote!(crate::timer::TimerPin<Ch3>)), |
| 1098 | (("timer", "CH3N"), quote!(crate::timer::Channel3ComplementaryPin)), | 1105 | (("timer", "CH3N"), quote!(crate::timer::TimerComplementaryPin<Ch3>)), |
| 1099 | (("timer", "CH4"), quote!(crate::timer::Channel4Pin)), | 1106 | (("timer", "CH4"), quote!(crate::timer::TimerPin<Ch4>)), |
| 1100 | (("timer", "CH4N"), quote!(crate::timer::Channel4ComplementaryPin)), | 1107 | (("timer", "CH4N"), quote!(crate::timer::TimerComplementaryPin<Ch4>)), |
| 1101 | (("timer", "ETR"), quote!(crate::timer::ExternalTriggerPin)), | 1108 | (("timer", "ETR"), quote!(crate::timer::ExternalTriggerPin)), |
| 1102 | (("timer", "BKIN"), quote!(crate::timer::BreakInputPin)), | 1109 | (("timer", "BKIN"), quote!(crate::timer::BreakInputPin<BkIn1>)), |
| 1103 | (("timer", "BKIN_COMP1"), quote!(crate::timer::BreakInputComparator1Pin)), | 1110 | (("timer", "BKIN_COMP1"), quote!(crate::timer::BreakInputComparator1Pin<BkIn1>)), |
| 1104 | (("timer", "BKIN_COMP2"), quote!(crate::timer::BreakInputComparator2Pin)), | 1111 | (("timer", "BKIN_COMP2"), quote!(crate::timer::BreakInputComparator2Pin<BkIn1>)), |
| 1105 | (("timer", "BKIN2"), quote!(crate::timer::BreakInput2Pin)), | 1112 | (("timer", "BKIN2"), quote!(crate::timer::BreakInputPin<BkIn2>)), |
| 1106 | (("timer", "BKIN2_COMP1"), quote!(crate::timer::BreakInput2Comparator1Pin)), | 1113 | (("timer", "BKIN2_COMP1"), quote!(crate::timer::BreakInputComparator1Pin<BkIn2>)), |
| 1107 | (("timer", "BKIN2_COMP2"), quote!(crate::timer::BreakInput2Comparator2Pin)), | 1114 | (("timer", "BKIN2_COMP2"), quote!(crate::timer::BreakInputComparator2Pin<BkIn2>)), |
| 1108 | (("hrtim", "CHA1"), quote!(crate::hrtim::ChannelAPin)), | 1115 | (("hrtim", "CHA1"), quote!(crate::hrtim::ChannelAPin)), |
| 1109 | (("hrtim", "CHA2"), quote!(crate::hrtim::ChannelAComplementaryPin)), | 1116 | (("hrtim", "CHA2"), quote!(crate::hrtim::ChannelAComplementaryPin)), |
| 1110 | (("hrtim", "CHB1"), quote!(crate::hrtim::ChannelBPin)), | 1117 | (("hrtim", "CHB1"), quote!(crate::hrtim::ChannelBPin)), |
| @@ -1402,31 +1409,24 @@ fn main() { | |||
| 1402 | } | 1409 | } |
| 1403 | 1410 | ||
| 1404 | if regs.kind == "opamp" { | 1411 | if regs.kind == "opamp" { |
| 1405 | if pin.signal.starts_with("VP") { | 1412 | let peri = format_ident!("{}", p.name); |
| 1406 | // Impl NonInvertingPin for the VP* signals (VP0, VP1, VP2, etc) | 1413 | let pin_name = format_ident!("{}", pin.pin); |
| 1407 | let peri = format_ident!("{}", p.name); | 1414 | if let Some(ch_str) = pin.signal.strip_prefix("VINP") { |
| 1408 | let pin_name = format_ident!("{}", pin.pin); | 1415 | // Impl NonInvertingPin for VINP0, VINP1 etc. |
| 1409 | let ch: u8 = pin.signal.strip_prefix("VP").unwrap().parse().unwrap(); | 1416 | if let Ok(ch) = ch_str.parse::<u8>() { |
| 1410 | 1417 | g.extend(quote! { | |
| 1411 | g.extend(quote! { | 1418 | impl_opamp_vp_pin!( #peri, #pin_name, #ch ); |
| 1412 | impl_opamp_vp_pin!( #peri, #pin_name, #ch); | 1419 | }); |
| 1413 | }) | 1420 | } |
| 1414 | } else if pin.signal.starts_with("VINM") { | 1421 | } else if let Some(ch_str) = pin.signal.strip_prefix("VINM") { |
| 1415 | // Impl NonInvertingPin for the VINM* signals ( VINM0, VINM1, etc) | 1422 | // Impl InvertingPin for VINM0, VINM1 etc. |
| 1416 | // STM32G4 | 1423 | if let Ok(ch) = ch_str.parse::<u8>() { |
| 1417 | let peri = format_ident!("{}", p.name); | ||
| 1418 | let pin_name = format_ident!("{}", pin.pin); | ||
| 1419 | let ch: Result<u8, _> = pin.signal.strip_prefix("VINM").unwrap().parse(); | ||
| 1420 | |||
| 1421 | if let Ok(ch) = ch { | ||
| 1422 | g.extend(quote! { | 1424 | g.extend(quote! { |
| 1423 | impl_opamp_vn_pin!( #peri, #pin_name, #ch); | 1425 | impl_opamp_vn_pin!( #peri, #pin_name, #ch); |
| 1424 | }) | 1426 | }); |
| 1425 | } | 1427 | } |
| 1426 | } else if pin.signal == "VOUT" { | 1428 | } else if pin.signal == "VOUT" { |
| 1427 | // Impl OutputPin for the VOUT pin | 1429 | // Impl OutputPin for the VOUT pin |
| 1428 | let peri = format_ident!("{}", p.name); | ||
| 1429 | let pin_name = format_ident!("{}", pin.pin); | ||
| 1430 | g.extend(quote! { | 1430 | g.extend(quote! { |
| 1431 | impl_opamp_vout_pin!( #peri, #pin_name ); | 1431 | impl_opamp_vout_pin!( #peri, #pin_name ); |
| 1432 | }) | 1432 | }) |
| @@ -1482,10 +1482,10 @@ fn main() { | |||
| 1482 | (("hash", "IN"), quote!(crate::hash::Dma)), | 1482 | (("hash", "IN"), quote!(crate::hash::Dma)), |
| 1483 | (("cryp", "IN"), quote!(crate::cryp::DmaIn)), | 1483 | (("cryp", "IN"), quote!(crate::cryp::DmaIn)), |
| 1484 | (("cryp", "OUT"), quote!(crate::cryp::DmaOut)), | 1484 | (("cryp", "OUT"), quote!(crate::cryp::DmaOut)), |
| 1485 | (("timer", "CH1"), quote!(crate::timer::Ch1Dma)), | 1485 | (("timer", "CH1"), quote!(crate::timer::Dma<Ch1>)), |
| 1486 | (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), | 1486 | (("timer", "CH2"), quote!(crate::timer::Dma<Ch2>)), |
| 1487 | (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), | 1487 | (("timer", "CH3"), quote!(crate::timer::Dma<Ch3>)), |
| 1488 | (("timer", "CH4"), quote!(crate::timer::Ch4Dma)), | 1488 | (("timer", "CH4"), quote!(crate::timer::Dma<Ch4>)), |
| 1489 | (("cordic", "WRITE"), quote!(crate::cordic::WriteDma)), // FIXME: stm32u5a crash on Cordic driver | 1489 | (("cordic", "WRITE"), quote!(crate::cordic::WriteDma)), // FIXME: stm32u5a crash on Cordic driver |
| 1490 | (("cordic", "READ"), quote!(crate::cordic::ReadDma)), // FIXME: stm32u5a crash on Cordic driver | 1490 | (("cordic", "READ"), quote!(crate::cordic::ReadDma)), // FIXME: stm32u5a crash on Cordic driver |
| 1491 | ] | 1491 | ] |
| @@ -1497,6 +1497,10 @@ fn main() { | |||
| 1497 | signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); | 1497 | signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); |
| 1498 | } | 1498 | } |
| 1499 | 1499 | ||
| 1500 | if chip_name.starts_with("stm32wba") { | ||
| 1501 | signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma4)); | ||
| 1502 | } | ||
| 1503 | |||
| 1500 | if chip_name.starts_with("stm32g4") { | 1504 | if chip_name.starts_with("stm32g4") { |
| 1501 | let line_number = chip_name.chars().skip(8).next().unwrap(); | 1505 | let line_number = chip_name.chars().skip(8).next().unwrap(); |
| 1502 | if line_number == '3' || line_number == '4' { | 1506 | if line_number == '3' || line_number == '4' { |
| @@ -1554,9 +1558,35 @@ fn main() { | |||
| 1554 | quote!(()) | 1558 | quote!(()) |
| 1555 | }; | 1559 | }; |
| 1556 | 1560 | ||
| 1561 | let mut remap = quote!(); | ||
| 1562 | for remap_info in ch.remap { | ||
| 1563 | let register = format_ident!("{}", remap_info.register.to_lowercase()); | ||
| 1564 | let setter = format_ident!("set_{}", remap_info.field.to_lowercase()); | ||
| 1565 | |||
| 1566 | let field_metadata = METADATA | ||
| 1567 | .peripherals | ||
| 1568 | .iter() | ||
| 1569 | .filter(|p| p.name == "SYSCFG") | ||
| 1570 | .flat_map(|p| p.registers.as_ref().unwrap().ir.fieldsets.iter()) | ||
| 1571 | .filter(|f| f.name.eq_ignore_ascii_case(remap_info.register)) | ||
| 1572 | .flat_map(|f| f.fields.iter()) | ||
| 1573 | .find(|f| f.name.eq_ignore_ascii_case(remap_info.field)) | ||
| 1574 | .unwrap(); | ||
| 1575 | |||
| 1576 | let value = if field_metadata.bit_size == 1 { | ||
| 1577 | let bool_value = format_ident!("{}", remap_info.value > 0); | ||
| 1578 | quote!(#bool_value) | ||
| 1579 | } else { | ||
| 1580 | let value = remap_info.value; | ||
| 1581 | quote!(#value.into()) | ||
| 1582 | }; | ||
| 1583 | |||
| 1584 | remap.extend(quote!(crate::pac::SYSCFG.#register().modify(|w| w.#setter(#value));)); | ||
| 1585 | } | ||
| 1586 | |||
| 1557 | let channel = format_ident!("{}", channel); | 1587 | let channel = format_ident!("{}", channel); |
| 1558 | g.extend(quote! { | 1588 | g.extend(quote! { |
| 1559 | dma_trait_impl!(#tr, #peri, #channel, #request); | 1589 | dma_trait_impl!(#tr, #peri, #channel, #request, {#remap}); |
| 1560 | }); | 1590 | }); |
| 1561 | } | 1591 | } |
| 1562 | } | 1592 | } |
| @@ -1888,9 +1918,9 @@ fn main() { | |||
| 1888 | } | 1918 | } |
| 1889 | 1919 | ||
| 1890 | g.extend(quote!( | 1920 | g.extend(quote!( |
| 1891 | pub fn gpio_block(n: usize) -> crate::pac::gpio::Gpio {{ | 1921 | pub fn gpio_block(n: usize) -> crate::pac::gpio::Gpio { |
| 1892 | unsafe {{ crate::pac::gpio::Gpio::from_ptr((#gpio_base + #gpio_stride*n) as _) }} | 1922 | unsafe { crate::pac::gpio::Gpio::from_ptr((#gpio_base + #gpio_stride*n) as _) } |
| 1893 | }} | 1923 | } |
| 1894 | )); | 1924 | )); |
| 1895 | 1925 | ||
| 1896 | // ======== | 1926 | // ======== |
diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/adc4.rs index 1dd664366..31cbdc0d7 100644 --- a/embassy-stm32/src/adc/u5_adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs | |||
| @@ -1,10 +1,19 @@ | |||
| 1 | #[cfg(stm32u5)] | ||
| 2 | use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingRatio as OversamplingRatio}; | ||
| 1 | #[allow(unused)] | 3 | #[allow(unused)] |
| 2 | use pac::adc::vals::{Adc4Dmacfg, Adc4Exten, Adc4OversamplingRatio}; | 4 | #[cfg(stm32wba)] |
| 5 | use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; | ||
| 3 | 6 | ||
| 4 | use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel}; | 7 | use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel}; |
| 5 | use crate::dma::Transfer; | 8 | use crate::dma::Transfer; |
| 6 | pub use crate::pac::adc::regs::Adc4Chselrmod0; | 9 | #[cfg(stm32u5)] |
| 10 | pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; | ||
| 11 | #[cfg(stm32wba)] | ||
| 12 | pub use crate::pac::adc::regs::Chselr; | ||
| 13 | #[cfg(stm32u5)] | ||
| 7 | pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4SampleTime as SampleTime}; | 14 | pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4SampleTime as SampleTime}; |
| 15 | #[cfg(stm32wba)] | ||
| 16 | pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime}; | ||
| 8 | use crate::time::Hertz; | 17 | use crate::time::Hertz; |
| 9 | use crate::{pac, rcc, Peri}; | 18 | use crate::{pac, rcc, Peri}; |
| 10 | 19 | ||
| @@ -67,12 +76,14 @@ impl<T: Instance> SealedAdcChannel<T> for Vcore { | |||
| 67 | } | 76 | } |
| 68 | } | 77 | } |
| 69 | 78 | ||
| 79 | #[derive(Copy, Clone)] | ||
| 70 | pub enum DacChannel { | 80 | pub enum DacChannel { |
| 71 | OUT1, | 81 | OUT1, |
| 72 | OUT2, | 82 | OUT2, |
| 73 | } | 83 | } |
| 74 | 84 | ||
| 75 | /// Number of samples used for averaging. | 85 | /// Number of samples used for averaging. |
| 86 | #[derive(Copy, Clone)] | ||
| 76 | pub enum Averaging { | 87 | pub enum Averaging { |
| 77 | Disabled, | 88 | Disabled, |
| 78 | Samples2, | 89 | Samples2, |
| @@ -178,7 +189,7 @@ pub struct Adc4<'d, T: Instance> { | |||
| 178 | adc: crate::Peri<'d, T>, | 189 | adc: crate::Peri<'d, T>, |
| 179 | } | 190 | } |
| 180 | 191 | ||
| 181 | #[derive(Debug)] | 192 | #[derive(Copy, Clone, Debug)] |
| 182 | pub enum Adc4Error { | 193 | pub enum Adc4Error { |
| 183 | InvalidSequence, | 194 | InvalidSequence, |
| 184 | DMAError, | 195 | DMAError, |
| @@ -242,17 +253,28 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 242 | fn configure(&mut self) { | 253 | fn configure(&mut self) { |
| 243 | // single conversion mode, software trigger | 254 | // single conversion mode, software trigger |
| 244 | T::regs().cfgr1().modify(|w| { | 255 | T::regs().cfgr1().modify(|w| { |
| 256 | #[cfg(stm32u5)] | ||
| 245 | w.set_cont(false); | 257 | w.set_cont(false); |
| 258 | #[cfg(stm32wba)] | ||
| 259 | w.set_cont(Cont::SINGLE); | ||
| 246 | w.set_discen(false); | 260 | w.set_discen(false); |
| 247 | w.set_exten(Adc4Exten::DISABLED); | 261 | w.set_exten(Exten::DISABLED); |
| 262 | #[cfg(stm32u5)] | ||
| 248 | w.set_chselrmod(false); | 263 | w.set_chselrmod(false); |
| 264 | #[cfg(stm32wba)] | ||
| 265 | w.set_chselrmod(Chselrmod::ENABLE_INPUT); | ||
| 249 | }); | 266 | }); |
| 250 | 267 | ||
| 251 | // only use one channel at the moment | 268 | // only use one channel at the moment |
| 252 | T::regs().smpr().modify(|w| { | 269 | T::regs().smpr().modify(|w| { |
| 270 | #[cfg(stm32u5)] | ||
| 253 | for i in 0..24 { | 271 | for i in 0..24 { |
| 254 | w.set_smpsel(i, false); | 272 | w.set_smpsel(i, false); |
| 255 | } | 273 | } |
| 274 | #[cfg(stm32wba)] | ||
| 275 | for i in 0..14 { | ||
| 276 | w.set_smpsel(i, Smpsel::SMP1); | ||
| 277 | } | ||
| 256 | }); | 278 | }); |
| 257 | } | 279 | } |
| 258 | 280 | ||
| @@ -275,6 +297,7 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 275 | } | 297 | } |
| 276 | 298 | ||
| 277 | /// Enable reading the vbat internal channel. | 299 | /// Enable reading the vbat internal channel. |
| 300 | #[cfg(stm32u5)] | ||
| 278 | pub fn enable_vbat(&self) -> Vbat { | 301 | pub fn enable_vbat(&self) -> Vbat { |
| 279 | T::regs().ccr().modify(|w| { | 302 | T::regs().ccr().modify(|w| { |
| 280 | w.set_vbaten(true); | 303 | w.set_vbaten(true); |
| @@ -289,6 +312,7 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 289 | } | 312 | } |
| 290 | 313 | ||
| 291 | /// Enable reading the vbat internal channel. | 314 | /// Enable reading the vbat internal channel. |
| 315 | #[cfg(stm32u5)] | ||
| 292 | pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { | 316 | pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { |
| 293 | let mux; | 317 | let mux; |
| 294 | match dac { | 318 | match dac { |
| @@ -317,17 +341,38 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 317 | } | 341 | } |
| 318 | 342 | ||
| 319 | /// Set hardware averaging. | 343 | /// Set hardware averaging. |
| 344 | #[cfg(stm32u5)] | ||
| 345 | pub fn set_averaging(&mut self, averaging: Averaging) { | ||
| 346 | let (enable, samples, right_shift) = match averaging { | ||
| 347 | Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0), | ||
| 348 | Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1), | ||
| 349 | Averaging::Samples4 => (true, OversamplingRatio::OVERSAMPLE4X, 2), | ||
| 350 | Averaging::Samples8 => (true, OversamplingRatio::OVERSAMPLE8X, 3), | ||
| 351 | Averaging::Samples16 => (true, OversamplingRatio::OVERSAMPLE16X, 4), | ||
| 352 | Averaging::Samples32 => (true, OversamplingRatio::OVERSAMPLE32X, 5), | ||
| 353 | Averaging::Samples64 => (true, OversamplingRatio::OVERSAMPLE64X, 6), | ||
| 354 | Averaging::Samples128 => (true, OversamplingRatio::OVERSAMPLE128X, 7), | ||
| 355 | Averaging::Samples256 => (true, OversamplingRatio::OVERSAMPLE256X, 8), | ||
| 356 | }; | ||
| 357 | |||
| 358 | T::regs().cfgr2().modify(|w| { | ||
| 359 | w.set_ovsr(samples); | ||
| 360 | w.set_ovss(right_shift); | ||
| 361 | w.set_ovse(enable) | ||
| 362 | }) | ||
| 363 | } | ||
| 364 | #[cfg(stm32wba)] | ||
| 320 | pub fn set_averaging(&mut self, averaging: Averaging) { | 365 | pub fn set_averaging(&mut self, averaging: Averaging) { |
| 321 | let (enable, samples, right_shift) = match averaging { | 366 | let (enable, samples, right_shift) = match averaging { |
| 322 | Averaging::Disabled => (false, Adc4OversamplingRatio::OVERSAMPLE2X, 0), | 367 | Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0), |
| 323 | Averaging::Samples2 => (true, Adc4OversamplingRatio::OVERSAMPLE2X, 1), | 368 | Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1), |
| 324 | Averaging::Samples4 => (true, Adc4OversamplingRatio::OVERSAMPLE4X, 2), | 369 | Averaging::Samples4 => (true, OversamplingRatio::OVERSAMPLE4X, Ovss::SHIFT2), |
| 325 | Averaging::Samples8 => (true, Adc4OversamplingRatio::OVERSAMPLE8X, 3), | 370 | Averaging::Samples8 => (true, OversamplingRatio::OVERSAMPLE8X, Ovss::SHIFT3), |
| 326 | Averaging::Samples16 => (true, Adc4OversamplingRatio::OVERSAMPLE16X, 4), | 371 | Averaging::Samples16 => (true, OversamplingRatio::OVERSAMPLE16X, Ovss::SHIFT4), |
| 327 | Averaging::Samples32 => (true, Adc4OversamplingRatio::OVERSAMPLE32X, 5), | 372 | Averaging::Samples32 => (true, OversamplingRatio::OVERSAMPLE32X, Ovss::SHIFT5), |
| 328 | Averaging::Samples64 => (true, Adc4OversamplingRatio::OVERSAMPLE64X, 6), | 373 | Averaging::Samples64 => (true, OversamplingRatio::OVERSAMPLE64X, Ovss::SHIFT6), |
| 329 | Averaging::Samples128 => (true, Adc4OversamplingRatio::OVERSAMPLE128X, 7), | 374 | Averaging::Samples128 => (true, OversamplingRatio::OVERSAMPLE128X, Ovss::SHIFT7), |
| 330 | Averaging::Samples256 => (true, Adc4OversamplingRatio::OVERSAMPLE256X, 8), | 375 | Averaging::Samples256 => (true, OversamplingRatio::OVERSAMPLE256X, Ovss::SHIFT8), |
| 331 | }; | 376 | }; |
| 332 | 377 | ||
| 333 | T::regs().cfgr2().modify(|w| { | 378 | T::regs().cfgr2().modify(|w| { |
| @@ -342,10 +387,20 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 342 | channel.setup(); | 387 | channel.setup(); |
| 343 | 388 | ||
| 344 | // Select channel | 389 | // Select channel |
| 345 | T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); | 390 | #[cfg(stm32wba)] |
| 346 | T::regs().chselrmod0().modify(|w| { | 391 | { |
| 347 | w.set_chsel(channel.channel() as usize, true); | 392 | T::regs().chselr().write_value(Chselr(0_u32)); |
| 348 | }); | 393 | T::regs().chselr().modify(|w| { |
| 394 | w.set_chsel0(channel.channel() as usize, true); | ||
| 395 | }); | ||
| 396 | } | ||
| 397 | #[cfg(stm32u5)] | ||
| 398 | { | ||
| 399 | T::regs().chselrmod0().write_value(Chselr(0_u32)); | ||
| 400 | T::regs().chselrmod0().modify(|w| { | ||
| 401 | w.set_chsel(channel.channel() as usize, true); | ||
| 402 | }); | ||
| 403 | } | ||
| 349 | 404 | ||
| 350 | // Reset interrupts | 405 | // Reset interrupts |
| 351 | T::regs().isr().modify(|reg| { | 406 | T::regs().isr().modify(|reg| { |
| @@ -415,13 +470,19 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 415 | 470 | ||
| 416 | T::regs().cfgr1().modify(|reg| { | 471 | T::regs().cfgr1().modify(|reg| { |
| 417 | reg.set_dmaen(true); | 472 | reg.set_dmaen(true); |
| 418 | reg.set_dmacfg(Adc4Dmacfg::ONE_SHOT); | 473 | reg.set_dmacfg(Dmacfg::ONE_SHOT); |
| 474 | #[cfg(stm32u5)] | ||
| 419 | reg.set_chselrmod(false); | 475 | reg.set_chselrmod(false); |
| 476 | #[cfg(stm32wba)] | ||
| 477 | reg.set_chselrmod(Chselrmod::ENABLE_INPUT) | ||
| 420 | }); | 478 | }); |
| 421 | 479 | ||
| 422 | // Verify and activate sequence | 480 | // Verify and activate sequence |
| 423 | let mut prev_channel: i16 = -1; | 481 | let mut prev_channel: i16 = -1; |
| 424 | T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); | 482 | #[cfg(stm32wba)] |
| 483 | T::regs().chselr().write_value(Chselr(0_u32)); | ||
| 484 | #[cfg(stm32u5)] | ||
| 485 | T::regs().chselrmod0().write_value(Chselr(0_u32)); | ||
| 425 | for channel in sequence { | 486 | for channel in sequence { |
| 426 | let channel_num = channel.channel; | 487 | let channel_num = channel.channel; |
| 427 | if channel_num as i16 <= prev_channel { | 488 | if channel_num as i16 <= prev_channel { |
| @@ -429,6 +490,11 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 429 | }; | 490 | }; |
| 430 | prev_channel = channel_num as i16; | 491 | prev_channel = channel_num as i16; |
| 431 | 492 | ||
| 493 | #[cfg(stm32wba)] | ||
| 494 | T::regs().chselr().modify(|w| { | ||
| 495 | w.set_chsel0(channel.channel as usize, true); | ||
| 496 | }); | ||
| 497 | #[cfg(stm32u5)] | ||
| 432 | T::regs().chselrmod0().modify(|w| { | 498 | T::regs().chselrmod0().modify(|w| { |
| 433 | w.set_chsel(channel.channel as usize, true); | 499 | w.set_chsel(channel.channel as usize, true); |
| 434 | }); | 500 | }); |
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index 936ad7413..f5870801e 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs | |||
| @@ -48,7 +48,7 @@ impl<T: Instance> SealedAdcChannel<T> for Temperature { | |||
| 48 | } | 48 | } |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | #[derive(Debug)] | 51 | #[derive(Copy, Clone, Debug)] |
| 52 | pub enum Prescaler { | 52 | pub enum Prescaler { |
| 53 | NotDivided, | 53 | NotDivided, |
| 54 | DividedBy2, | 54 | DividedBy2, |
| @@ -138,6 +138,7 @@ impl<'a> defmt::Format for Prescaler { | |||
| 138 | /// Number of samples used for averaging. | 138 | /// Number of samples used for averaging. |
| 139 | /// TODO: Implement hardware averaging setting. | 139 | /// TODO: Implement hardware averaging setting. |
| 140 | #[allow(unused)] | 140 | #[allow(unused)] |
| 141 | #[derive(Copy, Clone)] | ||
| 141 | pub enum Averaging { | 142 | pub enum Averaging { |
| 142 | Disabled, | 143 | Disabled, |
| 143 | Samples2, | 144 | Samples2, |
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index 944e971bb..84613078c 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs | |||
| @@ -17,6 +17,7 @@ pub const VDDA_CALIB_MV: u32 = 3300; | |||
| 17 | pub const ADC_MAX: u32 = (1 << 12) - 1; | 17 | pub const ADC_MAX: u32 = (1 << 12) - 1; |
| 18 | pub const VREF_INT: u32 = 1230; | 18 | pub const VREF_INT: u32 = 1230; |
| 19 | 19 | ||
| 20 | #[derive(Copy, Clone)] | ||
| 20 | pub enum AdcPowerMode { | 21 | pub enum AdcPowerMode { |
| 21 | AlwaysOn, | 22 | AlwaysOn, |
| 22 | DelayOff, | 23 | DelayOff, |
| @@ -24,6 +25,7 @@ pub enum AdcPowerMode { | |||
| 24 | DelayIdleOff, | 25 | DelayIdleOff, |
| 25 | } | 26 | } |
| 26 | 27 | ||
| 28 | #[derive(Copy, Clone)] | ||
| 27 | pub enum Prescaler { | 29 | pub enum Prescaler { |
| 28 | Div1, | 30 | Div1, |
| 29 | Div2, | 31 | Div2, |
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 1fce3085a..43498966f 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs | |||
| @@ -24,44 +24,31 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); | |||
| 24 | #[cfg(stm32h7)] | 24 | #[cfg(stm32h7)] |
| 25 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); | 25 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); |
| 26 | 26 | ||
| 27 | #[cfg(stm32g4)] | ||
| 28 | const VREF_CHANNEL: u8 = 18; | ||
| 29 | #[cfg(stm32g4)] | ||
| 30 | const TEMP_CHANNEL: u8 = 16; | ||
| 31 | |||
| 32 | #[cfg(stm32h7)] | ||
| 33 | const VREF_CHANNEL: u8 = 19; | ||
| 34 | #[cfg(stm32h7)] | ||
| 35 | const TEMP_CHANNEL: u8 = 18; | ||
| 36 | |||
| 37 | // TODO this should be 14 for H7a/b/35 | ||
| 38 | const VBAT_CHANNEL: u8 = 17; | ||
| 39 | |||
| 40 | // NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs | 27 | // NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs |
| 41 | /// Internal voltage reference channel. | 28 | /// Internal voltage reference channel. |
| 42 | pub struct VrefInt; | 29 | pub struct VrefInt; |
| 43 | impl<T: Instance> AdcChannel<T> for VrefInt {} | 30 | impl<T: Instance + VrefChannel> AdcChannel<T> for VrefInt {} |
| 44 | impl<T: Instance> super::SealedAdcChannel<T> for VrefInt { | 31 | impl<T: Instance + VrefChannel> super::SealedAdcChannel<T> for VrefInt { |
| 45 | fn channel(&self) -> u8 { | 32 | fn channel(&self) -> u8 { |
| 46 | VREF_CHANNEL | 33 | T::CHANNEL |
| 47 | } | 34 | } |
| 48 | } | 35 | } |
| 49 | 36 | ||
| 50 | /// Internal temperature channel. | 37 | /// Internal temperature channel. |
| 51 | pub struct Temperature; | 38 | pub struct Temperature; |
| 52 | impl<T: Instance> AdcChannel<T> for Temperature {} | 39 | impl<T: Instance + TemperatureChannel> AdcChannel<T> for Temperature {} |
| 53 | impl<T: Instance> super::SealedAdcChannel<T> for Temperature { | 40 | impl<T: Instance + TemperatureChannel> super::SealedAdcChannel<T> for Temperature { |
| 54 | fn channel(&self) -> u8 { | 41 | fn channel(&self) -> u8 { |
| 55 | TEMP_CHANNEL | 42 | T::CHANNEL |
| 56 | } | 43 | } |
| 57 | } | 44 | } |
| 58 | 45 | ||
| 59 | /// Internal battery voltage channel. | 46 | /// Internal battery voltage channel. |
| 60 | pub struct Vbat; | 47 | pub struct Vbat; |
| 61 | impl<T: Instance> AdcChannel<T> for Vbat {} | 48 | impl<T: Instance + VBatChannel> AdcChannel<T> for Vbat {} |
| 62 | impl<T: Instance> super::SealedAdcChannel<T> for Vbat { | 49 | impl<T: Instance + VBatChannel> super::SealedAdcChannel<T> for Vbat { |
| 63 | fn channel(&self) -> u8 { | 50 | fn channel(&self) -> u8 { |
| 64 | VBAT_CHANNEL | 51 | T::CHANNEL |
| 65 | } | 52 | } |
| 66 | } | 53 | } |
| 67 | 54 | ||
| @@ -234,7 +221,10 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 234 | } | 221 | } |
| 235 | 222 | ||
| 236 | /// Enable reading the voltage reference internal channel. | 223 | /// Enable reading the voltage reference internal channel. |
| 237 | pub fn enable_vrefint(&self) -> VrefInt { | 224 | pub fn enable_vrefint(&self) -> VrefInt |
| 225 | where | ||
| 226 | T: VrefChannel, | ||
| 227 | { | ||
| 238 | T::common_regs().ccr().modify(|reg| { | 228 | T::common_regs().ccr().modify(|reg| { |
| 239 | reg.set_vrefen(true); | 229 | reg.set_vrefen(true); |
| 240 | }); | 230 | }); |
| @@ -243,7 +233,10 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 243 | } | 233 | } |
| 244 | 234 | ||
| 245 | /// Enable reading the temperature internal channel. | 235 | /// Enable reading the temperature internal channel. |
| 246 | pub fn enable_temperature(&self) -> Temperature { | 236 | pub fn enable_temperature(&self) -> Temperature |
| 237 | where | ||
| 238 | T: TemperatureChannel, | ||
| 239 | { | ||
| 247 | T::common_regs().ccr().modify(|reg| { | 240 | T::common_regs().ccr().modify(|reg| { |
| 248 | reg.set_vsenseen(true); | 241 | reg.set_vsenseen(true); |
| 249 | }); | 242 | }); |
| @@ -252,7 +245,10 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 252 | } | 245 | } |
| 253 | 246 | ||
| 254 | /// Enable reading the vbat internal channel. | 247 | /// Enable reading the vbat internal channel. |
| 255 | pub fn enable_vbat(&self) -> Vbat { | 248 | pub fn enable_vbat(&self) -> Vbat |
| 249 | where | ||
| 250 | T: VBatChannel, | ||
| 251 | { | ||
| 256 | T::common_regs().ccr().modify(|reg| { | 252 | T::common_regs().ccr().modify(|reg| { |
| 257 | reg.set_vbaten(true); | 253 | reg.set_vbaten(true); |
| 258 | }); | 254 | }); |
| @@ -519,3 +515,78 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 519 | } | 515 | } |
| 520 | } | 516 | } |
| 521 | } | 517 | } |
| 518 | |||
| 519 | /// Implemented for ADCs that have a Temperature channel | ||
| 520 | pub trait TemperatureChannel { | ||
| 521 | const CHANNEL: u8; | ||
| 522 | } | ||
| 523 | /// Implemented for ADCs that have a Vref channel | ||
| 524 | pub trait VrefChannel { | ||
| 525 | const CHANNEL: u8; | ||
| 526 | } | ||
| 527 | /// Implemented for ADCs that have a VBat channel | ||
| 528 | pub trait VBatChannel { | ||
| 529 | const CHANNEL: u8; | ||
| 530 | } | ||
| 531 | |||
| 532 | #[cfg(stm32g4)] | ||
| 533 | mod g4 { | ||
| 534 | pub use super::*; | ||
| 535 | |||
| 536 | impl TemperatureChannel for crate::peripherals::ADC1 { | ||
| 537 | const CHANNEL: u8 = 16; | ||
| 538 | } | ||
| 539 | |||
| 540 | impl VrefChannel for crate::peripherals::ADC1 { | ||
| 541 | const CHANNEL: u8 = 18; | ||
| 542 | } | ||
| 543 | |||
| 544 | impl VBatChannel for crate::peripherals::ADC1 { | ||
| 545 | const CHANNEL: u8 = 17; | ||
| 546 | } | ||
| 547 | |||
| 548 | #[cfg(peri_adc3_common)] | ||
| 549 | impl VrefChannel for crate::peripherals::ADC3 { | ||
| 550 | const CHANNEL: u8 = 18; | ||
| 551 | } | ||
| 552 | |||
| 553 | #[cfg(peri_adc3_common)] | ||
| 554 | impl VBatChannel for crate::peripherals::ADC3 { | ||
| 555 | const CHANNEL: u8 = 17; | ||
| 556 | } | ||
| 557 | |||
| 558 | #[cfg(not(stm32g4x1))] | ||
| 559 | impl VrefChannel for crate::peripherals::ADC4 { | ||
| 560 | const CHANNEL: u8 = 18; | ||
| 561 | } | ||
| 562 | |||
| 563 | #[cfg(not(stm32g4x1))] | ||
| 564 | impl TemperatureChannel for crate::peripherals::ADC5 { | ||
| 565 | const CHANNEL: u8 = 4; | ||
| 566 | } | ||
| 567 | |||
| 568 | #[cfg(not(stm32g4x1))] | ||
| 569 | impl VrefChannel for crate::peripherals::ADC5 { | ||
| 570 | const CHANNEL: u8 = 18; | ||
| 571 | } | ||
| 572 | |||
| 573 | #[cfg(not(stm32g4x1))] | ||
| 574 | impl VBatChannel for crate::peripherals::ADC5 { | ||
| 575 | const CHANNEL: u8 = 17; | ||
| 576 | } | ||
| 577 | } | ||
| 578 | |||
| 579 | // TODO this should look at each ADC individually and impl the correct channels | ||
| 580 | #[cfg(stm32h7)] | ||
| 581 | mod h7 { | ||
| 582 | impl<T: Instance> TemperatureChannel for T { | ||
| 583 | const CHANNEL: u8 = 18; | ||
| 584 | } | ||
| 585 | impl<T: Instance> VrefChannel for T { | ||
| 586 | const CHANNEL: u8 = 19; | ||
| 587 | } | ||
| 588 | impl<T: Instance> VBatChannel for T { | ||
| 589 | // TODO this should be 14 for H7a/b/35 | ||
| 590 | const CHANNEL: u8 = 17; | ||
| 591 | } | ||
| 592 | } | ||
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index f46e87f38..778edc6f6 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | #![allow(missing_docs)] // TODO | 4 | #![allow(missing_docs)] // TODO |
| 5 | #![cfg_attr(adc_f3_v2, allow(unused))] | 5 | #![cfg_attr(adc_f3_v2, allow(unused))] |
| 6 | 6 | ||
| 7 | #[cfg(not(any(adc_f3_v2)))] | 7 | #[cfg(not(any(adc_f3_v2, adc_wba)))] |
| 8 | #[cfg_attr(adc_f1, path = "f1.rs")] | 8 | #[cfg_attr(adc_f1, path = "f1.rs")] |
| 9 | #[cfg_attr(adc_f3, path = "f3.rs")] | 9 | #[cfg_attr(adc_f3, path = "f3.rs")] |
| 10 | #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] | 10 | #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] |
| @@ -20,14 +20,14 @@ mod _version; | |||
| 20 | use core::marker::PhantomData; | 20 | use core::marker::PhantomData; |
| 21 | 21 | ||
| 22 | #[allow(unused)] | 22 | #[allow(unused)] |
| 23 | #[cfg(not(any(adc_f3_v2)))] | 23 | #[cfg(not(any(adc_f3_v2, adc_wba)))] |
| 24 | pub use _version::*; | 24 | pub use _version::*; |
| 25 | use embassy_hal_internal::{impl_peripheral, PeripheralType}; | 25 | use embassy_hal_internal::{impl_peripheral, PeripheralType}; |
| 26 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | 26 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] |
| 27 | use embassy_sync::waitqueue::AtomicWaker; | 27 | use embassy_sync::waitqueue::AtomicWaker; |
| 28 | 28 | ||
| 29 | #[cfg(adc_u5)] | 29 | #[cfg(any(adc_u5, adc_wba))] |
| 30 | #[path = "u5_adc4.rs"] | 30 | #[path = "adc4.rs"] |
| 31 | pub mod adc4; | 31 | pub mod adc4; |
| 32 | 32 | ||
| 33 | pub use crate::pac::adc::vals; | 33 | pub use crate::pac::adc::vals; |
| @@ -36,15 +36,18 @@ pub use crate::pac::adc::vals::Res as Resolution; | |||
| 36 | pub use crate::pac::adc::vals::SampleTime; | 36 | pub use crate::pac::adc::vals::SampleTime; |
| 37 | use crate::peripherals; | 37 | use crate::peripherals; |
| 38 | 38 | ||
| 39 | #[cfg(not(adc_wba))] | ||
| 39 | dma_trait!(RxDma, Instance); | 40 | dma_trait!(RxDma, Instance); |
| 40 | #[cfg(adc_u5)] | 41 | #[cfg(adc_u5)] |
| 41 | dma_trait!(RxDma4, adc4::Instance); | 42 | dma_trait!(RxDma4, adc4::Instance); |
| 43 | #[cfg(adc_wba)] | ||
| 44 | dma_trait!(RxDma4, adc4::Instance); | ||
| 42 | 45 | ||
| 43 | /// Analog to Digital driver. | 46 | /// Analog to Digital driver. |
| 44 | pub struct Adc<'d, T: Instance> { | 47 | pub struct Adc<'d, T: Instance> { |
| 45 | #[allow(unused)] | 48 | #[allow(unused)] |
| 46 | adc: crate::Peri<'d, T>, | 49 | adc: crate::Peri<'d, T>, |
| 47 | #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))] | 50 | #[cfg(not(any(adc_f3_v2, adc_f3_v1_1, adc_wba)))] |
| 48 | sample_time: SampleTime, | 51 | sample_time: SampleTime, |
| 49 | } | 52 | } |
| 50 | 53 | ||
| @@ -63,6 +66,7 @@ impl State { | |||
| 63 | } | 66 | } |
| 64 | 67 | ||
| 65 | trait SealedInstance { | 68 | trait SealedInstance { |
| 69 | #[cfg(not(adc_wba))] | ||
| 66 | #[allow(unused)] | 70 | #[allow(unused)] |
| 67 | fn regs() -> crate::pac::adc::Adc; | 71 | fn regs() -> crate::pac::adc::Adc; |
| 68 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] | 72 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] |
| @@ -73,7 +77,7 @@ trait SealedInstance { | |||
| 73 | } | 77 | } |
| 74 | 78 | ||
| 75 | pub(crate) trait SealedAdcChannel<T> { | 79 | pub(crate) trait SealedAdcChannel<T> { |
| 76 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] | 80 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] |
| 77 | fn setup(&mut self) {} | 81 | fn setup(&mut self) {} |
| 78 | 82 | ||
| 79 | #[allow(unused)] | 83 | #[allow(unused)] |
| @@ -110,7 +114,8 @@ pub(crate) fn blocking_delay_us(us: u32) { | |||
| 110 | adc_h5, | 114 | adc_h5, |
| 111 | adc_h7rs, | 115 | adc_h7rs, |
| 112 | adc_u5, | 116 | adc_u5, |
| 113 | adc_c0 | 117 | adc_c0, |
| 118 | adc_wba, | ||
| 114 | )))] | 119 | )))] |
| 115 | #[allow(private_bounds)] | 120 | #[allow(private_bounds)] |
| 116 | pub trait Instance: SealedInstance + crate::PeripheralType { | 121 | pub trait Instance: SealedInstance + crate::PeripheralType { |
| @@ -132,7 +137,8 @@ pub trait Instance: SealedInstance + crate::PeripheralType { | |||
| 132 | adc_h5, | 137 | adc_h5, |
| 133 | adc_h7rs, | 138 | adc_h7rs, |
| 134 | adc_u5, | 139 | adc_u5, |
| 135 | adc_c0 | 140 | adc_c0, |
| 141 | adc_wba, | ||
| 136 | ))] | 142 | ))] |
| 137 | #[allow(private_bounds)] | 143 | #[allow(private_bounds)] |
| 138 | pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { | 144 | pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { |
| @@ -144,7 +150,7 @@ pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeri | |||
| 144 | pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { | 150 | pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { |
| 145 | #[allow(unused_mut)] | 151 | #[allow(unused_mut)] |
| 146 | fn degrade_adc(mut self) -> AnyAdcChannel<T> { | 152 | fn degrade_adc(mut self) -> AnyAdcChannel<T> { |
| 147 | #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] | 153 | #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] |
| 148 | self.setup(); | 154 | self.setup(); |
| 149 | 155 | ||
| 150 | AnyAdcChannel { | 156 | AnyAdcChannel { |
| @@ -176,6 +182,36 @@ impl<T> AnyAdcChannel<T> { | |||
| 176 | self.channel | 182 | self.channel |
| 177 | } | 183 | } |
| 178 | } | 184 | } |
| 185 | #[cfg(adc_wba)] | ||
| 186 | foreach_adc!( | ||
| 187 | (ADC4, $common_inst:ident, $clock:ident) => { | ||
| 188 | impl crate::adc::adc4::SealedInstance for peripherals::ADC4 { | ||
| 189 | fn regs() -> crate::pac::adc::Adc4 { | ||
| 190 | crate::pac::ADC4 | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | impl crate::adc::adc4::Instance for peripherals::ADC4 { | ||
| 195 | type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; | ||
| 196 | } | ||
| 197 | }; | ||
| 198 | |||
| 199 | ($inst:ident, $common_inst:ident, $clock:ident) => { | ||
| 200 | impl crate::adc::SealedInstance for peripherals::$inst { | ||
| 201 | fn regs() -> crate::pac::adc::Adc { | ||
| 202 | crate::pac::$inst | ||
| 203 | } | ||
| 204 | |||
| 205 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | ||
| 206 | return crate::pac::$common_inst | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | impl crate::adc::Instance for peripherals::$inst { | ||
| 211 | type Interrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL; | ||
| 212 | } | ||
| 213 | }; | ||
| 214 | ); | ||
| 179 | 215 | ||
| 180 | #[cfg(adc_u5)] | 216 | #[cfg(adc_u5)] |
| 181 | foreach_adc!( | 217 | foreach_adc!( |
| @@ -208,15 +244,21 @@ foreach_adc!( | |||
| 208 | }; | 244 | }; |
| 209 | ); | 245 | ); |
| 210 | 246 | ||
| 211 | #[cfg(not(adc_u5))] | 247 | #[cfg(not(any(adc_u5, adc_wba)))] |
| 212 | foreach_adc!( | 248 | foreach_adc!( |
| 213 | ($inst:ident, $common_inst:ident, $clock:ident) => { | 249 | ($inst:ident, $common_inst:ident, $clock:ident) => { |
| 214 | impl crate::adc::SealedInstance for peripherals::$inst { | 250 | impl crate::adc::SealedInstance for peripherals::$inst { |
| 251 | #[cfg(not(adc_wba))] | ||
| 215 | fn regs() -> crate::pac::adc::Adc { | 252 | fn regs() -> crate::pac::adc::Adc { |
| 216 | crate::pac::$inst | 253 | crate::pac::$inst |
| 217 | } | 254 | } |
| 218 | 255 | ||
| 219 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] | 256 | #[cfg(adc_wba)] |
| 257 | fn regs() -> crate::pac::adc::Adc4 { | ||
| 258 | crate::pac::$inst | ||
| 259 | } | ||
| 260 | |||
| 261 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5, adc_wba)))] | ||
| 220 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | 262 | fn common_regs() -> crate::pac::adccommon::AdcCommon { |
| 221 | return crate::pac::$common_inst | 263 | return crate::pac::$common_inst |
| 222 | } | 264 | } |
| @@ -238,7 +280,7 @@ macro_rules! impl_adc_pin { | |||
| 238 | ($inst:ident, $pin:ident, $ch:expr) => { | 280 | ($inst:ident, $pin:ident, $ch:expr) => { |
| 239 | impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {} | 281 | impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {} |
| 240 | impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> { | 282 | impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> { |
| 241 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] | 283 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] |
| 242 | fn setup(&mut self) { | 284 | fn setup(&mut self) { |
| 243 | <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self); | 285 | <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self); |
| 244 | } | 286 | } |
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index fb6f5b7d0..7fe502da0 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs | |||
| @@ -11,6 +11,9 @@ use crate::interrupt::typelevel::Interrupt; | |||
| 11 | use crate::peripherals::ADC1; | 11 | use crate::peripherals::ADC1; |
| 12 | use crate::{interrupt, rcc, Peri}; | 12 | use crate::{interrupt, rcc, Peri}; |
| 13 | 13 | ||
| 14 | mod watchdog_v1; | ||
| 15 | pub use watchdog_v1::WatchdogChannels; | ||
| 16 | |||
| 14 | pub const VDDA_CALIB_MV: u32 = 3300; | 17 | pub const VDDA_CALIB_MV: u32 = 3300; |
| 15 | pub const VREF_INT: u32 = 1230; | 18 | pub const VREF_INT: u32 = 1230; |
| 16 | 19 | ||
| @@ -21,8 +24,15 @@ pub struct InterruptHandler<T: Instance> { | |||
| 21 | 24 | ||
| 22 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | 25 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 23 | unsafe fn on_interrupt() { | 26 | unsafe fn on_interrupt() { |
| 24 | if T::regs().isr().read().eoc() { | 27 | let isr = T::regs().isr().read(); |
| 28 | let ier = T::regs().ier().read(); | ||
| 29 | if ier.eocie() && isr.eoc() { | ||
| 30 | // eocie is set during adc.read() | ||
| 25 | T::regs().ier().modify(|w| w.set_eocie(false)); | 31 | T::regs().ier().modify(|w| w.set_eocie(false)); |
| 32 | } else if ier.awdie() && isr.awd() { | ||
| 33 | // awdie is set during adc.monitor_watchdog() | ||
| 34 | T::regs().cr().read().set_adstp(true); | ||
| 35 | T::regs().ier().modify(|w| w.set_awdie(false)); | ||
| 26 | } else { | 36 | } else { |
| 27 | return; | 37 | return; |
| 28 | } | 38 | } |
| @@ -186,16 +196,21 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 186 | 196 | ||
| 187 | T::regs().dr().read().data() | 197 | T::regs().dr().read().data() |
| 188 | } | 198 | } |
| 189 | } | ||
| 190 | 199 | ||
| 191 | impl<'d, T: Instance> Drop for Adc<'d, T> { | 200 | fn teardown_adc() { |
| 192 | fn drop(&mut self) { | ||
| 193 | // A.7.3 ADC disable code example | 201 | // A.7.3 ADC disable code example |
| 194 | T::regs().cr().modify(|reg| reg.set_adstp(true)); | 202 | T::regs().cr().modify(|reg| reg.set_adstp(true)); |
| 195 | while T::regs().cr().read().adstp() {} | 203 | while T::regs().cr().read().adstp() {} |
| 196 | 204 | ||
| 197 | T::regs().cr().modify(|reg| reg.set_addis(true)); | 205 | T::regs().cr().modify(|reg| reg.set_addis(true)); |
| 198 | while T::regs().cr().read().aden() {} | 206 | while T::regs().cr().read().aden() {} |
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | impl<'d, T: Instance> Drop for Adc<'d, T> { | ||
| 211 | fn drop(&mut self) { | ||
| 212 | Self::teardown_adc(); | ||
| 213 | Self::teardown_awd(); | ||
| 199 | 214 | ||
| 200 | rcc::disable::<T>(); | 215 | rcc::disable::<T>(); |
| 201 | } | 216 | } |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 7b5df80b8..805dae564 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | use cfg_if::cfg_if; | 1 | use cfg_if::cfg_if; |
| 2 | use pac::adc::vals::Dmacfg; | 2 | use pac::adc::vals::Dmacfg; |
| 3 | #[cfg(adc_v3)] | ||
| 4 | use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; | ||
| 3 | 5 | ||
| 4 | use super::{ | 6 | use super::{ |
| 5 | blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, | 7 | blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, |
| @@ -506,6 +508,23 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 506 | T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); | 508 | T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); |
| 507 | } | 509 | } |
| 508 | 510 | ||
| 511 | #[cfg(adc_v3)] | ||
| 512 | pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) { | ||
| 513 | T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); | ||
| 514 | T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); | ||
| 515 | T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); | ||
| 516 | } | ||
| 517 | |||
| 518 | #[cfg(adc_v3)] | ||
| 519 | pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) { | ||
| 520 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | ||
| 521 | } | ||
| 522 | |||
| 523 | #[cfg(adc_v3)] | ||
| 524 | pub fn set_oversampling_shift(&mut self, shift: OversamplingShift) { | ||
| 525 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | ||
| 526 | } | ||
| 527 | |||
| 509 | fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { | 528 | fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { |
| 510 | cfg_if! { | 529 | cfg_if! { |
| 511 | if #[cfg(any(adc_g0, adc_u0))] { | 530 | if #[cfg(any(adc_g0, adc_u0))] { |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 39e0d51b9..b0871019a 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -142,6 +142,7 @@ impl Prescaler { | |||
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | /// Number of samples used for averaging. | 144 | /// Number of samples used for averaging. |
| 145 | #[derive(Copy, Clone)] | ||
| 145 | pub enum Averaging { | 146 | pub enum Averaging { |
| 146 | Disabled, | 147 | Disabled, |
| 147 | Samples2, | 148 | Samples2, |
diff --git a/embassy-stm32/src/adc/watchdog_v1.rs b/embassy-stm32/src/adc/watchdog_v1.rs new file mode 100644 index 000000000..bbe8e1971 --- /dev/null +++ b/embassy-stm32/src/adc/watchdog_v1.rs | |||
| @@ -0,0 +1,188 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::task::Poll; | ||
| 3 | |||
| 4 | use stm32_metapac::adc::vals::{Align, Awdsgl, Res}; | ||
| 5 | |||
| 6 | use crate::adc::{Adc, AdcChannel, Instance}; | ||
| 7 | |||
| 8 | /// This enum is passed into `Adc::init_watchdog` to specify the channels for the watchdog to monitor | ||
| 9 | pub enum WatchdogChannels { | ||
| 10 | // Single channel identified by index | ||
| 11 | Single(u8), | ||
| 12 | // Multiple channels identified by mask | ||
| 13 | Multiple(u16), | ||
| 14 | } | ||
| 15 | |||
| 16 | impl WatchdogChannels { | ||
| 17 | pub fn from_channel<T>(channel: &impl AdcChannel<T>) -> Self { | ||
| 18 | Self::Single(channel.channel()) | ||
| 19 | } | ||
| 20 | |||
| 21 | pub fn add_channel<T>(self, channel: &impl AdcChannel<T>) -> Self { | ||
| 22 | WatchdogChannels::Multiple( | ||
| 23 | (match self { | ||
| 24 | WatchdogChannels::Single(ch) => 1 << ch, | ||
| 25 | WatchdogChannels::Multiple(ch) => ch, | ||
| 26 | }) | 1 << channel.channel(), | ||
| 27 | ) | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | impl<'d, T: Instance> Adc<'d, T> { | ||
| 32 | /// Configure the analog window watchdog to monitor one or more ADC channels | ||
| 33 | /// | ||
| 34 | /// `high_threshold` and `low_threshold` are expressed in the same way as ADC results. The format | ||
| 35 | /// depends on the values of CFGR1.ALIGN and CFGR1.RES. | ||
| 36 | pub fn init_watchdog(&mut self, channels: WatchdogChannels, low_threshold: u16, high_threshold: u16) { | ||
| 37 | Self::stop_awd(); | ||
| 38 | |||
| 39 | match channels { | ||
| 40 | WatchdogChannels::Single(ch) => { | ||
| 41 | T::regs().chselr().modify(|w| { | ||
| 42 | w.set_chsel_x(ch.into(), true); | ||
| 43 | }); | ||
| 44 | T::regs().cfgr1().modify(|w| { | ||
| 45 | w.set_awdch(ch); | ||
| 46 | w.set_awdsgl(Awdsgl::SINGLE_CHANNEL) | ||
| 47 | }); | ||
| 48 | } | ||
| 49 | WatchdogChannels::Multiple(ch) => { | ||
| 50 | T::regs().chselr().modify(|w| w.0 = ch.into()); | ||
| 51 | T::regs().cfgr1().modify(|w| { | ||
| 52 | w.set_awdch(0); | ||
| 53 | w.set_awdsgl(Awdsgl::ALL_CHANNELS) | ||
| 54 | }); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | Self::set_watchdog_thresholds(low_threshold, high_threshold); | ||
| 59 | Self::setup_awd(); | ||
| 60 | } | ||
| 61 | |||
| 62 | /// Monitor the voltage on the selected channels; return when it crosses the thresholds. | ||
| 63 | /// | ||
| 64 | /// ```rust,ignore | ||
| 65 | /// // Wait for pin to go high | ||
| 66 | /// adc.init_watchdog(WatchdogChannels::from_channel(&pin), 0, 0x07F); | ||
| 67 | /// let v_high = adc.monitor_watchdog().await; | ||
| 68 | /// info!("ADC sample is high {}", v_high); | ||
| 69 | /// ``` | ||
| 70 | pub async fn monitor_watchdog(&mut self) -> u16 { | ||
| 71 | assert!( | ||
| 72 | match T::regs().cfgr1().read().awdsgl() { | ||
| 73 | Awdsgl::SINGLE_CHANNEL => T::regs().cfgr1().read().awdch() != 0, | ||
| 74 | Awdsgl::ALL_CHANNELS => T::regs().cfgr1().read().awdch() == 0, | ||
| 75 | }, | ||
| 76 | "`set_channel` should be called before `monitor`", | ||
| 77 | ); | ||
| 78 | assert!(T::regs().chselr().read().0 != 0); | ||
| 79 | T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); | ||
| 80 | Self::start_awd(); | ||
| 81 | |||
| 82 | let sample = poll_fn(|cx| { | ||
| 83 | T::state().waker.register(cx.waker()); | ||
| 84 | |||
| 85 | if T::regs().isr().read().awd() { | ||
| 86 | Poll::Ready(T::regs().dr().read().data()) | ||
| 87 | } else { | ||
| 88 | Poll::Pending | ||
| 89 | } | ||
| 90 | }) | ||
| 91 | .await; | ||
| 92 | |||
| 93 | self.stop_watchdog(); | ||
| 94 | sample | ||
| 95 | } | ||
| 96 | |||
| 97 | /// Stop monitoring the selected channels | ||
| 98 | pub fn stop_watchdog(&mut self) { | ||
| 99 | Self::stop_awd(); | ||
| 100 | } | ||
| 101 | |||
| 102 | fn set_watchdog_thresholds(low_threshold: u16, high_threshold: u16) { | ||
| 103 | // This function takes `high_threshold` and `low_threshold` in the same alignment and resolution | ||
| 104 | // as ADC results, and programs them into ADC_DR. Because ADC_DR is always right-aligned on 12 bits, | ||
| 105 | // some bit-shifting may be necessary. See more in table 47 §13.7.1 Analog Watchdog Comparison | ||
| 106 | |||
| 107 | // Verify that the thresholds are in the correct bit positions according to alignment and resolution | ||
| 108 | let threshold_mask = match (T::regs().cfgr1().read().align(), T::regs().cfgr1().read().res()) { | ||
| 109 | (Align::LEFT, Res::BITS6) => 0x00FC, | ||
| 110 | (Align::LEFT, Res::BITS8) => 0xFF00, | ||
| 111 | (Align::LEFT, Res::BITS10) => 0xFFC0, | ||
| 112 | (Align::LEFT, Res::BITS12) => 0xFFF0, | ||
| 113 | (Align::RIGHT, Res::BITS6) => 0x003F, | ||
| 114 | (Align::RIGHT, Res::BITS8) => 0x00FF, | ||
| 115 | (Align::RIGHT, Res::BITS10) => 0x03FF, | ||
| 116 | (Align::RIGHT, Res::BITS12) => 0x0FFF, | ||
| 117 | }; | ||
| 118 | assert!( | ||
| 119 | high_threshold & !threshold_mask == 0, | ||
| 120 | "High threshold {:x} is invalid — only bits {:x} are allowed", | ||
| 121 | high_threshold, | ||
| 122 | threshold_mask | ||
| 123 | ); | ||
| 124 | assert!( | ||
| 125 | low_threshold & !threshold_mask == 0, | ||
| 126 | "Low threshold {:x} is invalid — only bits {:x} are allowed", | ||
| 127 | low_threshold, | ||
| 128 | threshold_mask | ||
| 129 | ); | ||
| 130 | |||
| 131 | T::regs().tr().modify(|w| { | ||
| 132 | w.set_lt(low_threshold << threshold_mask.leading_zeros() >> 4); | ||
| 133 | w.set_ht(high_threshold << threshold_mask.leading_zeros() >> 4); | ||
| 134 | }) | ||
| 135 | } | ||
| 136 | |||
| 137 | fn setup_awd() { | ||
| 138 | // Configure AWD | ||
| 139 | assert!(!T::regs().cr().read().adstart()); | ||
| 140 | T::regs().cfgr1().modify(|w| w.set_awden(true)); | ||
| 141 | } | ||
| 142 | |||
| 143 | fn start_awd() { | ||
| 144 | // Clear AWD interrupt flag | ||
| 145 | while T::regs().isr().read().awd() { | ||
| 146 | T::regs().isr().modify(|regs| { | ||
| 147 | regs.set_awd(true); | ||
| 148 | }) | ||
| 149 | } | ||
| 150 | |||
| 151 | // Enable AWD interrupt | ||
| 152 | assert!(!T::regs().cr().read().adstart()); | ||
| 153 | T::regs().ier().modify(|w| { | ||
| 154 | w.set_eocie(false); | ||
| 155 | w.set_awdie(true) | ||
| 156 | }); | ||
| 157 | |||
| 158 | // Start conversion | ||
| 159 | T::regs().cfgr1().modify(|w| w.set_cont(true)); | ||
| 160 | T::regs().cr().modify(|w| w.set_adstart(true)); | ||
| 161 | } | ||
| 162 | |||
| 163 | fn stop_awd() { | ||
| 164 | // Stop conversion | ||
| 165 | while T::regs().cr().read().addis() {} | ||
| 166 | if T::regs().cr().read().adstart() { | ||
| 167 | T::regs().cr().write(|x| x.set_adstp(true)); | ||
| 168 | while T::regs().cr().read().adstp() {} | ||
| 169 | } | ||
| 170 | T::regs().cfgr1().modify(|w| w.set_cont(false)); | ||
| 171 | |||
| 172 | // Disable AWD interrupt | ||
| 173 | assert!(!T::regs().cr().read().adstart()); | ||
| 174 | T::regs().ier().modify(|w| w.set_awdie(false)); | ||
| 175 | |||
| 176 | // Clear AWD interrupt flag | ||
| 177 | while T::regs().isr().read().awd() { | ||
| 178 | T::regs().isr().modify(|regs| { | ||
| 179 | regs.set_awd(true); | ||
| 180 | }) | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | pub(crate) fn teardown_awd() { | ||
| 185 | Self::stop_awd(); | ||
| 186 | T::regs().cfgr1().modify(|w| w.set_awden(false)); | ||
| 187 | } | ||
| 188 | } | ||
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 305666d5b..4c0795a2a 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs | |||
| @@ -15,9 +15,10 @@ pub use embedded_can::{ExtendedId, Id, StandardId}; | |||
| 15 | use self::filter::MasterFilters; | 15 | use self::filter::MasterFilters; |
| 16 | use self::registers::{Registers, RxFifo}; | 16 | use self::registers::{Registers, RxFifo}; |
| 17 | pub use super::common::{BufferedCanReceiver, BufferedCanSender}; | 17 | pub use super::common::{BufferedCanReceiver, BufferedCanSender}; |
| 18 | use super::common::{InfoRef, RxInfoRef, TxInfoRef}; | ||
| 18 | use super::frame::{Envelope, Frame}; | 19 | use super::frame::{Envelope, Frame}; |
| 19 | use super::util; | 20 | use super::util; |
| 20 | use crate::can::enums::{BusError, InternalOperation, TryReadError}; | 21 | use crate::can::enums::{BusError, RefCountOp, TryReadError}; |
| 21 | use crate::gpio::{AfType, OutputType, Pull, Speed}; | 22 | use crate::gpio::{AfType, OutputType, Pull, Speed}; |
| 22 | use crate::interrupt::typelevel::Interrupt; | 23 | use crate::interrupt::typelevel::Interrupt; |
| 23 | use crate::rcc::{self, RccPeripheral}; | 24 | use crate::rcc::{self, RccPeripheral}; |
| @@ -35,7 +36,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptH | |||
| 35 | v.set_rqcp(1, true); | 36 | v.set_rqcp(1, true); |
| 36 | v.set_rqcp(2, true); | 37 | v.set_rqcp(2, true); |
| 37 | }); | 38 | }); |
| 38 | T::state().tx_mode.on_interrupt::<T>(); | 39 | T::info().state.lock(|state| { |
| 40 | state.borrow().tx_mode.on_interrupt::<T>(); | ||
| 41 | }); | ||
| 39 | } | 42 | } |
| 40 | } | 43 | } |
| 41 | 44 | ||
| @@ -46,7 +49,9 @@ pub struct Rx0InterruptHandler<T: Instance> { | |||
| 46 | 49 | ||
| 47 | impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { | 50 | impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { |
| 48 | unsafe fn on_interrupt() { | 51 | unsafe fn on_interrupt() { |
| 49 | T::state().rx_mode.on_interrupt::<T>(RxFifo::Fifo0); | 52 | T::info().state.lock(|state| { |
| 53 | state.borrow().rx_mode.on_interrupt::<T>(RxFifo::Fifo0); | ||
| 54 | }); | ||
| 50 | } | 55 | } |
| 51 | } | 56 | } |
| 52 | 57 | ||
| @@ -57,7 +62,9 @@ pub struct Rx1InterruptHandler<T: Instance> { | |||
| 57 | 62 | ||
| 58 | impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { | 63 | impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { |
| 59 | unsafe fn on_interrupt() { | 64 | unsafe fn on_interrupt() { |
| 60 | T::state().rx_mode.on_interrupt::<T>(RxFifo::Fifo1); | 65 | T::info().state.lock(|state| { |
| 66 | state.borrow().rx_mode.on_interrupt::<T>(RxFifo::Fifo1); | ||
| 67 | }); | ||
| 61 | } | 68 | } |
| 62 | } | 69 | } |
| 63 | 70 | ||
| @@ -73,7 +80,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup | |||
| 73 | 80 | ||
| 74 | if msr_val.slaki() { | 81 | if msr_val.slaki() { |
| 75 | msr.modify(|m| m.set_slaki(true)); | 82 | msr.modify(|m| m.set_slaki(true)); |
| 76 | T::state().err_waker.wake(); | 83 | T::info().state.lock(|state| { |
| 84 | state.borrow().err_waker.wake(); | ||
| 85 | }); | ||
| 77 | } else if msr_val.erri() { | 86 | } else if msr_val.erri() { |
| 78 | // Disable the interrupt, but don't acknowledge the error, so that it can be | 87 | // Disable the interrupt, but don't acknowledge the error, so that it can be |
| 79 | // forwarded off the bus message consumer. If we don't provide some way for | 88 | // forwarded off the bus message consumer. If we don't provide some way for |
| @@ -82,8 +91,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup | |||
| 82 | // an indefinite amount of time. | 91 | // an indefinite amount of time. |
| 83 | let ier = T::regs().ier(); | 92 | let ier = T::regs().ier(); |
| 84 | ier.modify(|i| i.set_errie(false)); | 93 | ier.modify(|i| i.set_errie(false)); |
| 85 | 94 | T::info().state.lock(|state| { | |
| 86 | T::state().err_waker.wake(); | 95 | state.borrow().err_waker.wake(); |
| 96 | }); | ||
| 87 | } | 97 | } |
| 88 | } | 98 | } |
| 89 | } | 99 | } |
| @@ -91,7 +101,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup | |||
| 91 | /// Configuration proxy returned by [`Can::modify_config`]. | 101 | /// Configuration proxy returned by [`Can::modify_config`]. |
| 92 | pub struct CanConfig<'a> { | 102 | pub struct CanConfig<'a> { |
| 93 | phantom: PhantomData<&'a ()>, | 103 | phantom: PhantomData<&'a ()>, |
| 94 | info: &'static Info, | 104 | info: InfoRef, |
| 95 | periph_clock: crate::time::Hertz, | 105 | periph_clock: crate::time::Hertz, |
| 96 | } | 106 | } |
| 97 | 107 | ||
| @@ -156,8 +166,7 @@ impl Drop for CanConfig<'_> { | |||
| 156 | /// CAN driver | 166 | /// CAN driver |
| 157 | pub struct Can<'d> { | 167 | pub struct Can<'d> { |
| 158 | phantom: PhantomData<&'d ()>, | 168 | phantom: PhantomData<&'d ()>, |
| 159 | info: &'static Info, | 169 | info: InfoRef, |
| 160 | state: &'static State, | ||
| 161 | periph_clock: crate::time::Hertz, | 170 | periph_clock: crate::time::Hertz, |
| 162 | } | 171 | } |
| 163 | 172 | ||
| @@ -227,8 +236,7 @@ impl<'d> Can<'d> { | |||
| 227 | 236 | ||
| 228 | Self { | 237 | Self { |
| 229 | phantom: PhantomData, | 238 | phantom: PhantomData, |
| 230 | info: T::info(), | 239 | info: InfoRef::new(T::info()), |
| 231 | state: T::state(), | ||
| 232 | periph_clock: T::frequency(), | 240 | periph_clock: T::frequency(), |
| 233 | } | 241 | } |
| 234 | } | 242 | } |
| @@ -248,7 +256,7 @@ impl<'d> Can<'d> { | |||
| 248 | 256 | ||
| 249 | CanConfig { | 257 | CanConfig { |
| 250 | phantom: self.phantom, | 258 | phantom: self.phantom, |
| 251 | info: self.info, | 259 | info: InfoRef::new(&self.info), |
| 252 | periph_clock: self.periph_clock, | 260 | periph_clock: self.periph_clock, |
| 253 | } | 261 | } |
| 254 | } | 262 | } |
| @@ -297,7 +305,9 @@ impl<'d> Can<'d> { | |||
| 297 | self.info.regs.0.mcr().modify(|m| m.set_sleep(true)); | 305 | self.info.regs.0.mcr().modify(|m| m.set_sleep(true)); |
| 298 | 306 | ||
| 299 | poll_fn(|cx| { | 307 | poll_fn(|cx| { |
| 300 | self.state.err_waker.register(cx.waker()); | 308 | self.info.state.lock(|s| { |
| 309 | s.borrow().err_waker.register(cx.waker()); | ||
| 310 | }); | ||
| 301 | if self.is_sleeping() { | 311 | if self.is_sleeping() { |
| 302 | Poll::Ready(()) | 312 | Poll::Ready(()) |
| 303 | } else { | 313 | } else { |
| @@ -350,8 +360,7 @@ impl<'d> Can<'d> { | |||
| 350 | pub async fn flush(&self, mb: Mailbox) { | 360 | pub async fn flush(&self, mb: Mailbox) { |
| 351 | CanTx { | 361 | CanTx { |
| 352 | _phantom: PhantomData, | 362 | _phantom: PhantomData, |
| 353 | info: self.info, | 363 | info: TxInfoRef::new(&self.info), |
| 354 | state: self.state, | ||
| 355 | } | 364 | } |
| 356 | .flush_inner(mb) | 365 | .flush_inner(mb) |
| 357 | .await; | 366 | .await; |
| @@ -366,8 +375,7 @@ impl<'d> Can<'d> { | |||
| 366 | pub async fn flush_any(&self) { | 375 | pub async fn flush_any(&self) { |
| 367 | CanTx { | 376 | CanTx { |
| 368 | _phantom: PhantomData, | 377 | _phantom: PhantomData, |
| 369 | info: self.info, | 378 | info: TxInfoRef::new(&self.info), |
| 370 | state: self.state, | ||
| 371 | } | 379 | } |
| 372 | .flush_any_inner() | 380 | .flush_any_inner() |
| 373 | .await | 381 | .await |
| @@ -377,8 +385,7 @@ impl<'d> Can<'d> { | |||
| 377 | pub async fn flush_all(&self) { | 385 | pub async fn flush_all(&self) { |
| 378 | CanTx { | 386 | CanTx { |
| 379 | _phantom: PhantomData, | 387 | _phantom: PhantomData, |
| 380 | info: self.info, | 388 | info: TxInfoRef::new(&self.info), |
| 381 | state: self.state, | ||
| 382 | } | 389 | } |
| 383 | .flush_all_inner() | 390 | .flush_all_inner() |
| 384 | .await | 391 | .await |
| @@ -406,19 +413,19 @@ impl<'d> Can<'d> { | |||
| 406 | /// | 413 | /// |
| 407 | /// Returns a tuple of the time the message was received and the message frame | 414 | /// Returns a tuple of the time the message was received and the message frame |
| 408 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | 415 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 409 | self.state.rx_mode.read(self.info, self.state).await | 416 | RxMode::read(&self.info).await |
| 410 | } | 417 | } |
| 411 | 418 | ||
| 412 | /// Attempts to read a CAN frame without blocking. | 419 | /// Attempts to read a CAN frame without blocking. |
| 413 | /// | 420 | /// |
| 414 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | 421 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. |
| 415 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | 422 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { |
| 416 | self.state.rx_mode.try_read(self.info) | 423 | RxMode::try_read(&self.info) |
| 417 | } | 424 | } |
| 418 | 425 | ||
| 419 | /// Waits while receive queue is empty. | 426 | /// Waits while receive queue is empty. |
| 420 | pub async fn wait_not_empty(&mut self) { | 427 | pub async fn wait_not_empty(&mut self) { |
| 421 | self.state.rx_mode.wait_not_empty(self.info, self.state).await | 428 | RxMode::wait_not_empty(&self.info).await |
| 422 | } | 429 | } |
| 423 | 430 | ||
| 424 | /// Split the CAN driver into transmit and receive halves. | 431 | /// Split the CAN driver into transmit and receive halves. |
| @@ -428,13 +435,11 @@ impl<'d> Can<'d> { | |||
| 428 | ( | 435 | ( |
| 429 | CanTx { | 436 | CanTx { |
| 430 | _phantom: PhantomData, | 437 | _phantom: PhantomData, |
| 431 | info: self.info, | 438 | info: TxInfoRef::new(&self.info), |
| 432 | state: self.state, | ||
| 433 | }, | 439 | }, |
| 434 | CanRx { | 440 | CanRx { |
| 435 | _phantom: PhantomData, | 441 | _phantom: PhantomData, |
| 436 | info: self.info, | 442 | info: RxInfoRef::new(&self.info), |
| 437 | state: self.state, | ||
| 438 | }, | 443 | }, |
| 439 | ) | 444 | ) |
| 440 | } | 445 | } |
| @@ -459,7 +464,7 @@ impl<'d> Can<'d> { | |||
| 459 | /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master | 464 | /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master |
| 460 | /// peripheral instead. | 465 | /// peripheral instead. |
| 461 | pub fn modify_filters(&mut self) -> MasterFilters<'_> { | 466 | pub fn modify_filters(&mut self) -> MasterFilters<'_> { |
| 462 | unsafe { MasterFilters::new(self.info) } | 467 | unsafe { MasterFilters::new(&self.info) } |
| 463 | } | 468 | } |
| 464 | } | 469 | } |
| 465 | 470 | ||
| @@ -514,8 +519,7 @@ impl<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_ | |||
| 514 | /// CAN driver, transmit half. | 519 | /// CAN driver, transmit half. |
| 515 | pub struct CanTx<'d> { | 520 | pub struct CanTx<'d> { |
| 516 | _phantom: PhantomData<&'d ()>, | 521 | _phantom: PhantomData<&'d ()>, |
| 517 | info: &'static Info, | 522 | info: TxInfoRef, |
| 518 | state: &'static State, | ||
| 519 | } | 523 | } |
| 520 | 524 | ||
| 521 | impl<'d> CanTx<'d> { | 525 | impl<'d> CanTx<'d> { |
| @@ -524,7 +528,9 @@ impl<'d> CanTx<'d> { | |||
| 524 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | 528 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. |
| 525 | pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { | 529 | pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { |
| 526 | poll_fn(|cx| { | 530 | poll_fn(|cx| { |
| 527 | self.state.tx_mode.register(cx.waker()); | 531 | self.info.state.lock(|s| { |
| 532 | s.borrow().tx_mode.register(cx.waker()); | ||
| 533 | }); | ||
| 528 | if let Ok(status) = self.info.regs.transmit(frame) { | 534 | if let Ok(status) = self.info.regs.transmit(frame) { |
| 529 | return Poll::Ready(status); | 535 | return Poll::Ready(status); |
| 530 | } | 536 | } |
| @@ -549,7 +555,9 @@ impl<'d> CanTx<'d> { | |||
| 549 | 555 | ||
| 550 | async fn flush_inner(&self, mb: Mailbox) { | 556 | async fn flush_inner(&self, mb: Mailbox) { |
| 551 | poll_fn(|cx| { | 557 | poll_fn(|cx| { |
| 552 | self.state.tx_mode.register(cx.waker()); | 558 | self.info.state.lock(|s| { |
| 559 | s.borrow().tx_mode.register(cx.waker()); | ||
| 560 | }); | ||
| 553 | if self.info.regs.0.tsr().read().tme(mb.index()) { | 561 | if self.info.regs.0.tsr().read().tme(mb.index()) { |
| 554 | return Poll::Ready(()); | 562 | return Poll::Ready(()); |
| 555 | } | 563 | } |
| @@ -566,7 +574,9 @@ impl<'d> CanTx<'d> { | |||
| 566 | 574 | ||
| 567 | async fn flush_any_inner(&self) { | 575 | async fn flush_any_inner(&self) { |
| 568 | poll_fn(|cx| { | 576 | poll_fn(|cx| { |
| 569 | self.state.tx_mode.register(cx.waker()); | 577 | self.info.state.lock(|s| { |
| 578 | s.borrow().tx_mode.register(cx.waker()); | ||
| 579 | }); | ||
| 570 | 580 | ||
| 571 | let tsr = self.info.regs.0.tsr().read(); | 581 | let tsr = self.info.regs.0.tsr().read(); |
| 572 | if tsr.tme(Mailbox::Mailbox0.index()) | 582 | if tsr.tme(Mailbox::Mailbox0.index()) |
| @@ -593,7 +603,9 @@ impl<'d> CanTx<'d> { | |||
| 593 | 603 | ||
| 594 | async fn flush_all_inner(&self) { | 604 | async fn flush_all_inner(&self) { |
| 595 | poll_fn(|cx| { | 605 | poll_fn(|cx| { |
| 596 | self.state.tx_mode.register(cx.waker()); | 606 | self.info.state.lock(|s| { |
| 607 | s.borrow().tx_mode.register(cx.waker()); | ||
| 608 | }); | ||
| 597 | 609 | ||
| 598 | let tsr = self.info.regs.0.tsr().read(); | 610 | let tsr = self.info.regs.0.tsr().read(); |
| 599 | if tsr.tme(Mailbox::Mailbox0.index()) | 611 | if tsr.tme(Mailbox::Mailbox0.index()) |
| @@ -634,7 +646,7 @@ impl<'d> CanTx<'d> { | |||
| 634 | self, | 646 | self, |
| 635 | txb: &'static mut TxBuf<TX_BUF_SIZE>, | 647 | txb: &'static mut TxBuf<TX_BUF_SIZE>, |
| 636 | ) -> BufferedCanTx<'d, TX_BUF_SIZE> { | 648 | ) -> BufferedCanTx<'d, TX_BUF_SIZE> { |
| 637 | BufferedCanTx::new(self.info, self.state, self, txb) | 649 | BufferedCanTx::new(&self.info, self, txb) |
| 638 | } | 650 | } |
| 639 | } | 651 | } |
| 640 | 652 | ||
| @@ -643,17 +655,15 @@ pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, | |||
| 643 | 655 | ||
| 644 | /// Buffered CAN driver, transmit half. | 656 | /// Buffered CAN driver, transmit half. |
| 645 | pub struct BufferedCanTx<'d, const TX_BUF_SIZE: usize> { | 657 | pub struct BufferedCanTx<'d, const TX_BUF_SIZE: usize> { |
| 646 | info: &'static Info, | 658 | info: TxInfoRef, |
| 647 | state: &'static State, | ||
| 648 | _tx: CanTx<'d>, | 659 | _tx: CanTx<'d>, |
| 649 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | 660 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, |
| 650 | } | 661 | } |
| 651 | 662 | ||
| 652 | impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> { | 663 | impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> { |
| 653 | fn new(info: &'static Info, state: &'static State, _tx: CanTx<'d>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self { | 664 | fn new(info: &'static Info, _tx: CanTx<'d>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self { |
| 654 | Self { | 665 | Self { |
| 655 | info, | 666 | info: TxInfoRef::new(info), |
| 656 | state, | ||
| 657 | _tx, | 667 | _tx, |
| 658 | tx_buf, | 668 | tx_buf, |
| 659 | } | 669 | } |
| @@ -666,11 +676,9 @@ impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> { | |||
| 666 | let tx_inner = super::common::ClassicBufferedTxInner { | 676 | let tx_inner = super::common::ClassicBufferedTxInner { |
| 667 | tx_receiver: self.tx_buf.receiver().into(), | 677 | tx_receiver: self.tx_buf.receiver().into(), |
| 668 | }; | 678 | }; |
| 669 | let state = self.state as *const State; | 679 | self.info.state.lock(|s| { |
| 670 | unsafe { | 680 | s.borrow_mut().tx_mode = TxMode::Buffered(tx_inner); |
| 671 | let mut_state = state as *mut State; | 681 | }); |
| 672 | (*mut_state).tx_mode = TxMode::Buffered(tx_inner); | ||
| 673 | } | ||
| 674 | }); | 682 | }); |
| 675 | self | 683 | self |
| 676 | } | 684 | } |
| @@ -684,27 +692,18 @@ impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> { | |||
| 684 | 692 | ||
| 685 | /// Returns a sender that can be used for sending CAN frames. | 693 | /// Returns a sender that can be used for sending CAN frames. |
| 686 | pub fn writer(&self) -> BufferedCanSender { | 694 | pub fn writer(&self) -> BufferedCanSender { |
| 687 | (self.info.internal_operation)(InternalOperation::NotifySenderCreated); | ||
| 688 | BufferedCanSender { | 695 | BufferedCanSender { |
| 689 | tx_buf: self.tx_buf.sender().into(), | 696 | tx_buf: self.tx_buf.sender().into(), |
| 690 | waker: self.info.tx_waker, | 697 | info: TxInfoRef::new(&self.info), |
| 691 | internal_operation: self.info.internal_operation, | ||
| 692 | } | 698 | } |
| 693 | } | 699 | } |
| 694 | } | 700 | } |
| 695 | 701 | ||
| 696 | impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> { | ||
| 697 | fn drop(&mut self) { | ||
| 698 | (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); | ||
| 699 | } | ||
| 700 | } | ||
| 701 | |||
| 702 | /// CAN driver, receive half. | 702 | /// CAN driver, receive half. |
| 703 | #[allow(dead_code)] | 703 | #[allow(dead_code)] |
| 704 | pub struct CanRx<'d> { | 704 | pub struct CanRx<'d> { |
| 705 | _phantom: PhantomData<&'d ()>, | 705 | _phantom: PhantomData<&'d ()>, |
| 706 | info: &'static Info, | 706 | info: RxInfoRef, |
| 707 | state: &'static State, | ||
| 708 | } | 707 | } |
| 709 | 708 | ||
| 710 | impl<'d> CanRx<'d> { | 709 | impl<'d> CanRx<'d> { |
| @@ -714,19 +713,19 @@ impl<'d> CanRx<'d> { | |||
| 714 | /// | 713 | /// |
| 715 | /// Returns a tuple of the time the message was received and the message frame | 714 | /// Returns a tuple of the time the message was received and the message frame |
| 716 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | 715 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 717 | self.state.rx_mode.read(self.info, self.state).await | 716 | RxMode::read(&self.info).await |
| 718 | } | 717 | } |
| 719 | 718 | ||
| 720 | /// Attempts to read a CAN frame without blocking. | 719 | /// Attempts to read a CAN frame without blocking. |
| 721 | /// | 720 | /// |
| 722 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | 721 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. |
| 723 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | 722 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { |
| 724 | self.state.rx_mode.try_read(self.info) | 723 | RxMode::try_read(&self.info) |
| 725 | } | 724 | } |
| 726 | 725 | ||
| 727 | /// Waits while receive queue is empty. | 726 | /// Waits while receive queue is empty. |
| 728 | pub async fn wait_not_empty(&mut self) { | 727 | pub async fn wait_not_empty(&mut self) { |
| 729 | self.state.rx_mode.wait_not_empty(self.info, self.state).await | 728 | RxMode::wait_not_empty(&self.info).await |
| 730 | } | 729 | } |
| 731 | 730 | ||
| 732 | /// Return a buffered instance of driver. User must supply Buffers | 731 | /// Return a buffered instance of driver. User must supply Buffers |
| @@ -734,7 +733,7 @@ impl<'d> CanRx<'d> { | |||
| 734 | self, | 733 | self, |
| 735 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, | 734 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, |
| 736 | ) -> BufferedCanRx<'d, RX_BUF_SIZE> { | 735 | ) -> BufferedCanRx<'d, RX_BUF_SIZE> { |
| 737 | BufferedCanRx::new(self.info, self.state, self, rxb) | 736 | BufferedCanRx::new(&self.info, self, rxb) |
| 738 | } | 737 | } |
| 739 | 738 | ||
| 740 | /// Accesses the filter banks owned by this CAN peripheral. | 739 | /// Accesses the filter banks owned by this CAN peripheral. |
| @@ -742,7 +741,7 @@ impl<'d> CanRx<'d> { | |||
| 742 | /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master | 741 | /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master |
| 743 | /// peripheral instead. | 742 | /// peripheral instead. |
| 744 | pub fn modify_filters(&mut self) -> MasterFilters<'_> { | 743 | pub fn modify_filters(&mut self) -> MasterFilters<'_> { |
| 745 | unsafe { MasterFilters::new(self.info) } | 744 | unsafe { MasterFilters::new(&self.info) } |
| 746 | } | 745 | } |
| 747 | } | 746 | } |
| 748 | 747 | ||
| @@ -751,17 +750,15 @@ pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result< | |||
| 751 | 750 | ||
| 752 | /// CAN driver, receive half in Buffered mode. | 751 | /// CAN driver, receive half in Buffered mode. |
| 753 | pub struct BufferedCanRx<'d, const RX_BUF_SIZE: usize> { | 752 | pub struct BufferedCanRx<'d, const RX_BUF_SIZE: usize> { |
| 754 | info: &'static Info, | 753 | info: RxInfoRef, |
| 755 | state: &'static State, | ||
| 756 | rx: CanRx<'d>, | 754 | rx: CanRx<'d>, |
| 757 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | 755 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, |
| 758 | } | 756 | } |
| 759 | 757 | ||
| 760 | impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { | 758 | impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { |
| 761 | fn new(info: &'static Info, state: &'static State, rx: CanRx<'d>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self { | 759 | fn new(info: &'static Info, rx: CanRx<'d>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self { |
| 762 | BufferedCanRx { | 760 | BufferedCanRx { |
| 763 | info, | 761 | info: RxInfoRef::new(info), |
| 764 | state, | ||
| 765 | rx, | 762 | rx, |
| 766 | rx_buf, | 763 | rx_buf, |
| 767 | } | 764 | } |
| @@ -774,11 +771,9 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { | |||
| 774 | let rx_inner = super::common::ClassicBufferedRxInner { | 771 | let rx_inner = super::common::ClassicBufferedRxInner { |
| 775 | rx_sender: self.rx_buf.sender().into(), | 772 | rx_sender: self.rx_buf.sender().into(), |
| 776 | }; | 773 | }; |
| 777 | let state = self.state as *const State; | 774 | self.info.state.lock(|s| { |
| 778 | unsafe { | 775 | s.borrow_mut().rx_mode = RxMode::Buffered(rx_inner); |
| 779 | let mut_state = state as *mut State; | 776 | }); |
| 780 | (*mut_state).rx_mode = RxMode::Buffered(rx_inner); | ||
| 781 | } | ||
| 782 | }); | 777 | }); |
| 783 | self | 778 | self |
| 784 | } | 779 | } |
| @@ -792,7 +787,7 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { | |||
| 792 | /// | 787 | /// |
| 793 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | 788 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. |
| 794 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | 789 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { |
| 795 | match &self.state.rx_mode { | 790 | self.info.state.lock(|s| match &s.borrow().rx_mode { |
| 796 | RxMode::Buffered(_) => { | 791 | RxMode::Buffered(_) => { |
| 797 | if let Ok(result) = self.rx_buf.try_receive() { | 792 | if let Ok(result) = self.rx_buf.try_receive() { |
| 798 | match result { | 793 | match result { |
| @@ -810,7 +805,7 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { | |||
| 810 | _ => { | 805 | _ => { |
| 811 | panic!("Bad Mode") | 806 | panic!("Bad Mode") |
| 812 | } | 807 | } |
| 813 | } | 808 | }) |
| 814 | } | 809 | } |
| 815 | 810 | ||
| 816 | /// Waits while receive queue is empty. | 811 | /// Waits while receive queue is empty. |
| @@ -820,10 +815,9 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { | |||
| 820 | 815 | ||
| 821 | /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | 816 | /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. |
| 822 | pub fn reader(&self) -> BufferedCanReceiver { | 817 | pub fn reader(&self) -> BufferedCanReceiver { |
| 823 | (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); | ||
| 824 | BufferedCanReceiver { | 818 | BufferedCanReceiver { |
| 825 | rx_buf: self.rx_buf.receiver().into(), | 819 | rx_buf: self.rx_buf.receiver().into(), |
| 826 | internal_operation: self.info.internal_operation, | 820 | info: RxInfoRef::new(&self.info), |
| 827 | } | 821 | } |
| 828 | } | 822 | } |
| 829 | 823 | ||
| @@ -836,12 +830,6 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { | |||
| 836 | } | 830 | } |
| 837 | } | 831 | } |
| 838 | 832 | ||
| 839 | impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> { | ||
| 840 | fn drop(&mut self) { | ||
| 841 | (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); | ||
| 842 | } | ||
| 843 | } | ||
| 844 | |||
| 845 | impl Drop for Can<'_> { | 833 | impl Drop for Can<'_> { |
| 846 | fn drop(&mut self) { | 834 | fn drop(&mut self) { |
| 847 | // Cannot call `free()` because it moves the instance. | 835 | // Cannot call `free()` because it moves the instance. |
| @@ -929,27 +917,30 @@ impl RxMode { | |||
| 929 | } | 917 | } |
| 930 | } | 918 | } |
| 931 | 919 | ||
| 932 | pub(crate) async fn read(&self, info: &Info, state: &State) -> Result<Envelope, BusError> { | 920 | pub(crate) async fn read(info: &Info) -> Result<Envelope, BusError> { |
| 933 | match self { | 921 | poll_fn(|cx| { |
| 934 | Self::NonBuffered(waker) => { | 922 | info.state.lock(|state| { |
| 935 | poll_fn(|cx| { | 923 | let state = state.borrow(); |
| 936 | state.err_waker.register(cx.waker()); | 924 | state.err_waker.register(cx.waker()); |
| 937 | waker.register(cx.waker()); | 925 | match &state.rx_mode { |
| 938 | match self.try_read(info) { | 926 | Self::NonBuffered(waker) => { |
| 939 | Ok(result) => Poll::Ready(Ok(result)), | 927 | waker.register(cx.waker()); |
| 940 | Err(TryReadError::Empty) => Poll::Pending, | ||
| 941 | Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), | ||
| 942 | } | 928 | } |
| 943 | }) | 929 | _ => { |
| 944 | .await | 930 | panic!("Bad Mode") |
| 945 | } | 931 | } |
| 946 | _ => { | 932 | } |
| 947 | panic!("Bad Mode") | 933 | }); |
| 934 | match RxMode::try_read(info) { | ||
| 935 | Ok(result) => Poll::Ready(Ok(result)), | ||
| 936 | Err(TryReadError::Empty) => Poll::Pending, | ||
| 937 | Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), | ||
| 948 | } | 938 | } |
| 949 | } | 939 | }) |
| 940 | .await | ||
| 950 | } | 941 | } |
| 951 | pub(crate) fn try_read(&self, info: &Info) -> Result<Envelope, TryReadError> { | 942 | pub(crate) fn try_read(info: &Info) -> Result<Envelope, TryReadError> { |
| 952 | match self { | 943 | info.state.lock(|state| match state.borrow().rx_mode { |
| 953 | Self::NonBuffered(_) => { | 944 | Self::NonBuffered(_) => { |
| 954 | let registers = &info.regs; | 945 | let registers = &info.regs; |
| 955 | if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) { | 946 | if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) { |
| @@ -975,25 +966,28 @@ impl RxMode { | |||
| 975 | _ => { | 966 | _ => { |
| 976 | panic!("Bad Mode") | 967 | panic!("Bad Mode") |
| 977 | } | 968 | } |
| 978 | } | 969 | }) |
| 979 | } | 970 | } |
| 980 | pub(crate) async fn wait_not_empty(&self, info: &Info, state: &State) { | 971 | pub(crate) async fn wait_not_empty(info: &Info) { |
| 981 | match &state.rx_mode { | 972 | poll_fn(|cx| { |
| 982 | Self::NonBuffered(waker) => { | 973 | info.state.lock(|s| { |
| 983 | poll_fn(|cx| { | 974 | let state = s.borrow(); |
| 984 | waker.register(cx.waker()); | 975 | match &state.rx_mode { |
| 985 | if info.regs.receive_frame_available() { | 976 | Self::NonBuffered(waker) => { |
| 986 | Poll::Ready(()) | 977 | waker.register(cx.waker()); |
| 987 | } else { | ||
| 988 | Poll::Pending | ||
| 989 | } | 978 | } |
| 990 | }) | 979 | _ => { |
| 991 | .await | 980 | panic!("Bad Mode") |
| 992 | } | 981 | } |
| 993 | _ => { | 982 | } |
| 994 | panic!("Bad Mode") | 983 | }); |
| 984 | if info.regs.receive_frame_available() { | ||
| 985 | Poll::Ready(()) | ||
| 986 | } else { | ||
| 987 | Poll::Pending | ||
| 995 | } | 988 | } |
| 996 | } | 989 | }) |
| 990 | .await | ||
| 997 | } | 991 | } |
| 998 | } | 992 | } |
| 999 | 993 | ||
| @@ -1008,21 +1002,25 @@ impl TxMode { | |||
| 1008 | tsr.tme(Mailbox::Mailbox0.index()) || tsr.tme(Mailbox::Mailbox1.index()) || tsr.tme(Mailbox::Mailbox2.index()) | 1002 | tsr.tme(Mailbox::Mailbox0.index()) || tsr.tme(Mailbox::Mailbox1.index()) || tsr.tme(Mailbox::Mailbox2.index()) |
| 1009 | } | 1003 | } |
| 1010 | pub fn on_interrupt<T: Instance>(&self) { | 1004 | pub fn on_interrupt<T: Instance>(&self) { |
| 1011 | match &T::state().tx_mode { | 1005 | T::info().state.lock(|state| { |
| 1012 | TxMode::NonBuffered(waker) => waker.wake(), | 1006 | let tx_mode = &state.borrow().tx_mode; |
| 1013 | TxMode::Buffered(buf) => { | 1007 | |
| 1014 | while self.buffer_free::<T>() { | 1008 | match tx_mode { |
| 1015 | match buf.tx_receiver.try_receive() { | 1009 | TxMode::NonBuffered(waker) => waker.wake(), |
| 1016 | Ok(frame) => { | 1010 | TxMode::Buffered(buf) => { |
| 1017 | _ = Registers(T::regs()).transmit(&frame); | 1011 | while self.buffer_free::<T>() { |
| 1018 | } | 1012 | match buf.tx_receiver.try_receive() { |
| 1019 | Err(_) => { | 1013 | Ok(frame) => { |
| 1020 | break; | 1014 | _ = Registers(T::regs()).transmit(&frame); |
| 1015 | } | ||
| 1016 | Err(_) => { | ||
| 1017 | break; | ||
| 1018 | } | ||
| 1021 | } | 1019 | } |
| 1022 | } | 1020 | } |
| 1023 | } | 1021 | } |
| 1024 | } | 1022 | } |
| 1025 | } | 1023 | }); |
| 1026 | } | 1024 | } |
| 1027 | 1025 | ||
| 1028 | fn register(&self, arg: &core::task::Waker) { | 1026 | fn register(&self, arg: &core::task::Waker) { |
| @@ -1057,14 +1055,15 @@ impl State { | |||
| 1057 | } | 1055 | } |
| 1058 | } | 1056 | } |
| 1059 | 1057 | ||
| 1058 | type SharedState = embassy_sync::blocking_mutex::Mutex<CriticalSectionRawMutex, core::cell::RefCell<State>>; | ||
| 1060 | pub(crate) struct Info { | 1059 | pub(crate) struct Info { |
| 1061 | regs: Registers, | 1060 | regs: Registers, |
| 1062 | tx_interrupt: crate::interrupt::Interrupt, | 1061 | tx_interrupt: crate::interrupt::Interrupt, |
| 1063 | rx0_interrupt: crate::interrupt::Interrupt, | 1062 | rx0_interrupt: crate::interrupt::Interrupt, |
| 1064 | rx1_interrupt: crate::interrupt::Interrupt, | 1063 | rx1_interrupt: crate::interrupt::Interrupt, |
| 1065 | sce_interrupt: crate::interrupt::Interrupt, | 1064 | sce_interrupt: crate::interrupt::Interrupt, |
| 1066 | tx_waker: fn(), | 1065 | pub(crate) tx_waker: fn(), |
| 1067 | internal_operation: fn(InternalOperation), | 1066 | state: SharedState, |
| 1068 | 1067 | ||
| 1069 | /// The total number of filter banks available to the instance. | 1068 | /// The total number of filter banks available to the instance. |
| 1070 | /// | 1069 | /// |
| @@ -1072,12 +1071,37 @@ pub(crate) struct Info { | |||
| 1072 | num_filter_banks: u8, | 1071 | num_filter_banks: u8, |
| 1073 | } | 1072 | } |
| 1074 | 1073 | ||
| 1074 | impl Info { | ||
| 1075 | pub(crate) fn adjust_reference_counter(&self, val: RefCountOp) { | ||
| 1076 | self.state.lock(|s| { | ||
| 1077 | let mut mut_state = s.borrow_mut(); | ||
| 1078 | match val { | ||
| 1079 | RefCountOp::NotifySenderCreated => { | ||
| 1080 | mut_state.sender_instance_count += 1; | ||
| 1081 | } | ||
| 1082 | RefCountOp::NotifySenderDestroyed => { | ||
| 1083 | mut_state.sender_instance_count -= 1; | ||
| 1084 | if 0 == mut_state.sender_instance_count { | ||
| 1085 | (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 1086 | } | ||
| 1087 | } | ||
| 1088 | RefCountOp::NotifyReceiverCreated => { | ||
| 1089 | mut_state.receiver_instance_count += 1; | ||
| 1090 | } | ||
| 1091 | RefCountOp::NotifyReceiverDestroyed => { | ||
| 1092 | mut_state.receiver_instance_count -= 1; | ||
| 1093 | if 0 == mut_state.receiver_instance_count { | ||
| 1094 | (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 1095 | } | ||
| 1096 | } | ||
| 1097 | } | ||
| 1098 | }); | ||
| 1099 | } | ||
| 1100 | } | ||
| 1101 | |||
| 1075 | trait SealedInstance { | 1102 | trait SealedInstance { |
| 1076 | fn info() -> &'static Info; | 1103 | fn info() -> &'static Info; |
| 1077 | fn regs() -> crate::pac::can::Can; | 1104 | fn regs() -> crate::pac::can::Can; |
| 1078 | fn state() -> &'static State; | ||
| 1079 | unsafe fn mut_state() -> &'static mut State; | ||
| 1080 | fn internal_operation(val: InternalOperation); | ||
| 1081 | } | 1105 | } |
| 1082 | 1106 | ||
| 1083 | /// CAN instance trait. | 1107 | /// CAN instance trait. |
| @@ -1135,53 +1159,14 @@ foreach_peripheral!( | |||
| 1135 | rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ, | 1159 | rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ, |
| 1136 | sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ, | 1160 | sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ, |
| 1137 | tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend, | 1161 | tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend, |
| 1138 | internal_operation: peripherals::$inst::internal_operation, | ||
| 1139 | num_filter_banks: peripherals::$inst::NUM_FILTER_BANKS, | 1162 | num_filter_banks: peripherals::$inst::NUM_FILTER_BANKS, |
| 1163 | state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(State::new())), | ||
| 1140 | }; | 1164 | }; |
| 1141 | &INFO | 1165 | &INFO |
| 1142 | } | 1166 | } |
| 1143 | fn regs() -> crate::pac::can::Can { | 1167 | fn regs() -> crate::pac::can::Can { |
| 1144 | crate::pac::$inst | 1168 | crate::pac::$inst |
| 1145 | } | 1169 | } |
| 1146 | |||
| 1147 | unsafe fn mut_state() -> & 'static mut State { | ||
| 1148 | static mut STATE: State = State::new(); | ||
| 1149 | &mut *core::ptr::addr_of_mut!(STATE) | ||
| 1150 | } | ||
| 1151 | fn state() -> &'static State { | ||
| 1152 | unsafe { peripherals::$inst::mut_state() } | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | |||
| 1156 | fn internal_operation(val: InternalOperation) { | ||
| 1157 | critical_section::with(|_| { | ||
| 1158 | //let state = self.state as *const State; | ||
| 1159 | unsafe { | ||
| 1160 | //let mut_state = state as *mut State; | ||
| 1161 | let mut_state = peripherals::$inst::mut_state(); | ||
| 1162 | match val { | ||
| 1163 | InternalOperation::NotifySenderCreated => { | ||
| 1164 | mut_state.sender_instance_count += 1; | ||
| 1165 | } | ||
| 1166 | InternalOperation::NotifySenderDestroyed => { | ||
| 1167 | mut_state.sender_instance_count -= 1; | ||
| 1168 | if ( 0 == mut_state.sender_instance_count) { | ||
| 1169 | (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 1170 | } | ||
| 1171 | } | ||
| 1172 | InternalOperation::NotifyReceiverCreated => { | ||
| 1173 | mut_state.receiver_instance_count += 1; | ||
| 1174 | } | ||
| 1175 | InternalOperation::NotifyReceiverDestroyed => { | ||
| 1176 | mut_state.receiver_instance_count -= 1; | ||
| 1177 | if ( 0 == mut_state.receiver_instance_count) { | ||
| 1178 | (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 1179 | } | ||
| 1180 | } | ||
| 1181 | } | ||
| 1182 | } | ||
| 1183 | }); | ||
| 1184 | } | ||
| 1185 | } | 1170 | } |
| 1186 | 1171 | ||
| 1187 | impl Instance for peripherals::$inst { | 1172 | impl Instance for peripherals::$inst { |
diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index 386d4467c..980f33a04 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs | |||
| @@ -24,22 +24,21 @@ pub(crate) struct FdBufferedTxInner { | |||
| 24 | /// Sender that can be used for sending CAN frames. | 24 | /// Sender that can be used for sending CAN frames. |
| 25 | pub struct BufferedSender<'ch, FRAME> { | 25 | pub struct BufferedSender<'ch, FRAME> { |
| 26 | pub(crate) tx_buf: embassy_sync::channel::SendDynamicSender<'ch, FRAME>, | 26 | pub(crate) tx_buf: embassy_sync::channel::SendDynamicSender<'ch, FRAME>, |
| 27 | pub(crate) waker: fn(), | 27 | pub(crate) info: TxInfoRef, |
| 28 | pub(crate) internal_operation: fn(InternalOperation), | ||
| 29 | } | 28 | } |
| 30 | 29 | ||
| 31 | impl<'ch, FRAME> BufferedSender<'ch, FRAME> { | 30 | impl<'ch, FRAME> BufferedSender<'ch, FRAME> { |
| 32 | /// Async write frame to TX buffer. | 31 | /// Async write frame to TX buffer. |
| 33 | pub fn try_write(&mut self, frame: FRAME) -> Result<(), embassy_sync::channel::TrySendError<FRAME>> { | 32 | pub fn try_write(&mut self, frame: FRAME) -> Result<(), embassy_sync::channel::TrySendError<FRAME>> { |
| 34 | self.tx_buf.try_send(frame)?; | 33 | self.tx_buf.try_send(frame)?; |
| 35 | (self.waker)(); | 34 | (self.info.tx_waker)(); |
| 36 | Ok(()) | 35 | Ok(()) |
| 37 | } | 36 | } |
| 38 | 37 | ||
| 39 | /// Async write frame to TX buffer. | 38 | /// Async write frame to TX buffer. |
| 40 | pub async fn write(&mut self, frame: FRAME) { | 39 | pub async fn write(&mut self, frame: FRAME) { |
| 41 | self.tx_buf.send(frame).await; | 40 | self.tx_buf.send(frame).await; |
| 42 | (self.waker)(); | 41 | (self.info.tx_waker)(); |
| 43 | } | 42 | } |
| 44 | 43 | ||
| 45 | /// Allows a poll_fn to poll until the channel is ready to write | 44 | /// Allows a poll_fn to poll until the channel is ready to write |
| @@ -50,28 +49,20 @@ impl<'ch, FRAME> BufferedSender<'ch, FRAME> { | |||
| 50 | 49 | ||
| 51 | impl<'ch, FRAME> Clone for BufferedSender<'ch, FRAME> { | 50 | impl<'ch, FRAME> Clone for BufferedSender<'ch, FRAME> { |
| 52 | fn clone(&self) -> Self { | 51 | fn clone(&self) -> Self { |
| 53 | (self.internal_operation)(InternalOperation::NotifySenderCreated); | ||
| 54 | Self { | 52 | Self { |
| 55 | tx_buf: self.tx_buf, | 53 | tx_buf: self.tx_buf, |
| 56 | waker: self.waker, | 54 | info: TxInfoRef::new(&self.info), |
| 57 | internal_operation: self.internal_operation, | ||
| 58 | } | 55 | } |
| 59 | } | 56 | } |
| 60 | } | 57 | } |
| 61 | 58 | ||
| 62 | impl<'ch, FRAME> Drop for BufferedSender<'ch, FRAME> { | ||
| 63 | fn drop(&mut self) { | ||
| 64 | (self.internal_operation)(InternalOperation::NotifySenderDestroyed); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Sender that can be used for sending Classic CAN frames. | 59 | /// Sender that can be used for sending Classic CAN frames. |
| 69 | pub type BufferedCanSender = BufferedSender<'static, Frame>; | 60 | pub type BufferedCanSender = BufferedSender<'static, Frame>; |
| 70 | 61 | ||
| 71 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | 62 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. |
| 72 | pub struct BufferedReceiver<'ch, ENVELOPE> { | 63 | pub struct BufferedReceiver<'ch, ENVELOPE> { |
| 73 | pub(crate) rx_buf: embassy_sync::channel::SendDynamicReceiver<'ch, Result<ENVELOPE, BusError>>, | 64 | pub(crate) rx_buf: embassy_sync::channel::SendDynamicReceiver<'ch, Result<ENVELOPE, BusError>>, |
| 74 | pub(crate) internal_operation: fn(InternalOperation), | 65 | pub(crate) info: RxInfoRef, |
| 75 | } | 66 | } |
| 76 | 67 | ||
| 77 | impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> { | 68 | impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> { |
| @@ -106,19 +97,99 @@ impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> { | |||
| 106 | 97 | ||
| 107 | impl<'ch, ENVELOPE> Clone for BufferedReceiver<'ch, ENVELOPE> { | 98 | impl<'ch, ENVELOPE> Clone for BufferedReceiver<'ch, ENVELOPE> { |
| 108 | fn clone(&self) -> Self { | 99 | fn clone(&self) -> Self { |
| 109 | (self.internal_operation)(InternalOperation::NotifyReceiverCreated); | ||
| 110 | Self { | 100 | Self { |
| 111 | rx_buf: self.rx_buf, | 101 | rx_buf: self.rx_buf, |
| 112 | internal_operation: self.internal_operation, | 102 | info: RxInfoRef::new(&self.info), |
| 113 | } | 103 | } |
| 114 | } | 104 | } |
| 115 | } | 105 | } |
| 116 | 106 | ||
| 117 | impl<'ch, ENVELOPE> Drop for BufferedReceiver<'ch, ENVELOPE> { | 107 | /// A BufferedCanReceiver for Classic CAN frames. |
| 108 | pub type BufferedCanReceiver = BufferedReceiver<'static, Envelope>; | ||
| 109 | |||
| 110 | /// Provides a reference to the driver internals and implements RAII for the internal reference | ||
| 111 | /// counting. Each type that can operate on the driver should contain either InfoRef | ||
| 112 | /// or the similar TxInfoRef or RxInfoRef. The new method and the Drop impl will automatically | ||
| 113 | /// call the reference counting function. Like this, the reference counting function does not | ||
| 114 | /// need to be called manually for each type. | ||
| 115 | pub(crate) struct InfoRef { | ||
| 116 | info: &'static super::Info, | ||
| 117 | } | ||
| 118 | impl InfoRef { | ||
| 119 | pub(crate) fn new(info: &'static super::Info) -> Self { | ||
| 120 | info.adjust_reference_counter(RefCountOp::NotifyReceiverCreated); | ||
| 121 | info.adjust_reference_counter(RefCountOp::NotifySenderCreated); | ||
| 122 | Self { info } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | impl Drop for InfoRef { | ||
| 118 | fn drop(&mut self) { | 127 | fn drop(&mut self) { |
| 119 | (self.internal_operation)(InternalOperation::NotifyReceiverDestroyed); | 128 | self.info.adjust_reference_counter(RefCountOp::NotifyReceiverDestroyed); |
| 129 | self.info.adjust_reference_counter(RefCountOp::NotifySenderDestroyed); | ||
| 120 | } | 130 | } |
| 121 | } | 131 | } |
| 122 | 132 | ||
| 123 | /// A BufferedCanReceiver for Classic CAN frames. | 133 | impl core::ops::Deref for InfoRef { |
| 124 | pub type BufferedCanReceiver = BufferedReceiver<'static, Envelope>; | 134 | type Target = &'static super::Info; |
| 135 | |||
| 136 | fn deref(&self) -> &Self::Target { | ||
| 137 | &self.info | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | /// Provides a reference to the driver internals and implements RAII for the internal reference | ||
| 142 | /// counting for Tx only types. | ||
| 143 | /// See InfoRef for further doc. | ||
| 144 | pub(crate) struct TxInfoRef { | ||
| 145 | info: &'static super::Info, | ||
| 146 | } | ||
| 147 | |||
| 148 | impl TxInfoRef { | ||
| 149 | pub(crate) fn new(info: &'static super::Info) -> Self { | ||
| 150 | info.adjust_reference_counter(RefCountOp::NotifySenderCreated); | ||
| 151 | Self { info } | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | impl Drop for TxInfoRef { | ||
| 156 | fn drop(&mut self) { | ||
| 157 | self.info.adjust_reference_counter(RefCountOp::NotifySenderDestroyed); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | impl core::ops::Deref for TxInfoRef { | ||
| 162 | type Target = &'static super::Info; | ||
| 163 | |||
| 164 | fn deref(&self) -> &Self::Target { | ||
| 165 | &self.info | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | /// Provides a reference to the driver internals and implements RAII for the internal reference | ||
| 170 | /// counting for Rx only types. | ||
| 171 | /// See InfoRef for further doc. | ||
| 172 | pub(crate) struct RxInfoRef { | ||
| 173 | info: &'static super::Info, | ||
| 174 | } | ||
| 175 | |||
| 176 | impl RxInfoRef { | ||
| 177 | pub(crate) fn new(info: &'static super::Info) -> Self { | ||
| 178 | info.adjust_reference_counter(RefCountOp::NotifyReceiverCreated); | ||
| 179 | Self { info } | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | impl Drop for RxInfoRef { | ||
| 184 | fn drop(&mut self) { | ||
| 185 | self.info.adjust_reference_counter(RefCountOp::NotifyReceiverDestroyed); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | impl core::ops::Deref for RxInfoRef { | ||
| 190 | type Target = &'static super::Info; | ||
| 191 | |||
| 192 | fn deref(&self) -> &Self::Target { | ||
| 193 | &self.info | ||
| 194 | } | ||
| 195 | } | ||
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 97cb47640..6d91020fc 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs | |||
| @@ -72,7 +72,7 @@ pub enum TryReadError { | |||
| 72 | /// Internal Operation | 72 | /// Internal Operation |
| 73 | #[derive(Debug)] | 73 | #[derive(Debug)] |
| 74 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 74 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 75 | pub enum InternalOperation { | 75 | pub enum RefCountOp { |
| 76 | /// Notify receiver created | 76 | /// Notify receiver created |
| 77 | NotifyReceiverCreated, | 77 | NotifyReceiverCreated, |
| 78 | /// Notify receiver destroyed | 78 | /// Notify receiver destroyed |
diff --git a/embassy-stm32/src/can/fd/message_ram/extended_filter.rs b/embassy-stm32/src/can/fd/message_ram/extended_filter.rs index 453e9056e..ac47901a8 100644 --- a/embassy-stm32/src/can/fd/message_ram/extended_filter.rs +++ b/embassy-stm32/src/can/fd/message_ram/extended_filter.rs | |||
| @@ -115,22 +115,22 @@ impl R { | |||
| 115 | impl W { | 115 | impl W { |
| 116 | #[doc = "Byte 0 - Bits 0:28 - EFID1"] | 116 | #[doc = "Byte 0 - Bits 0:28 - EFID1"] |
| 117 | #[inline(always)] | 117 | #[inline(always)] |
| 118 | pub fn efid1(&mut self) -> EFID1_W { | 118 | pub fn efid1(&mut self) -> EFID1_W<'_> { |
| 119 | EFID1_W { w: self } | 119 | EFID1_W { w: self } |
| 120 | } | 120 | } |
| 121 | #[doc = "Byte 0 - Bits 29:31 - EFEC"] | 121 | #[doc = "Byte 0 - Bits 29:31 - EFEC"] |
| 122 | #[inline(always)] | 122 | #[inline(always)] |
| 123 | pub fn efec(&mut self) -> EFEC_W { | 123 | pub fn efec(&mut self) -> EFEC_W<'_> { |
| 124 | EFEC_W { w: self } | 124 | EFEC_W { w: self } |
| 125 | } | 125 | } |
| 126 | #[doc = "Byte 1 - Bits 0:28 - EFID2"] | 126 | #[doc = "Byte 1 - Bits 0:28 - EFID2"] |
| 127 | #[inline(always)] | 127 | #[inline(always)] |
| 128 | pub fn efid2(&mut self) -> EFID2_W { | 128 | pub fn efid2(&mut self) -> EFID2_W<'_> { |
| 129 | EFID2_W { w: self } | 129 | EFID2_W { w: self } |
| 130 | } | 130 | } |
| 131 | #[doc = "Byte 1 - Bits 30:31 - EFT"] | 131 | #[doc = "Byte 1 - Bits 30:31 - EFT"] |
| 132 | #[inline(always)] | 132 | #[inline(always)] |
| 133 | pub fn eft(&mut self) -> EFT_W { | 133 | pub fn eft(&mut self) -> EFT_W<'_> { |
| 134 | EFT_W { w: self } | 134 | EFT_W { w: self } |
| 135 | } | 135 | } |
| 136 | } | 136 | } |
diff --git a/embassy-stm32/src/can/fd/message_ram/standard_filter.rs b/embassy-stm32/src/can/fd/message_ram/standard_filter.rs index 3a3bbcf12..f52646bfe 100644 --- a/embassy-stm32/src/can/fd/message_ram/standard_filter.rs +++ b/embassy-stm32/src/can/fd/message_ram/standard_filter.rs | |||
| @@ -115,22 +115,22 @@ impl R { | |||
| 115 | impl W { | 115 | impl W { |
| 116 | #[doc = "Bits 0:10 - SFID2"] | 116 | #[doc = "Bits 0:10 - SFID2"] |
| 117 | #[inline(always)] | 117 | #[inline(always)] |
| 118 | pub fn sfid2(&mut self) -> SFID2_W { | 118 | pub fn sfid2(&mut self) -> SFID2_W<'_> { |
| 119 | SFID2_W { w: self } | 119 | SFID2_W { w: self } |
| 120 | } | 120 | } |
| 121 | #[doc = "Bits 16:26 - SFID1"] | 121 | #[doc = "Bits 16:26 - SFID1"] |
| 122 | #[inline(always)] | 122 | #[inline(always)] |
| 123 | pub fn sfid1(&mut self) -> SFID1_W { | 123 | pub fn sfid1(&mut self) -> SFID1_W<'_> { |
| 124 | SFID1_W { w: self } | 124 | SFID1_W { w: self } |
| 125 | } | 125 | } |
| 126 | #[doc = "Bits 27:29 - SFEC"] | 126 | #[doc = "Bits 27:29 - SFEC"] |
| 127 | #[inline(always)] | 127 | #[inline(always)] |
| 128 | pub fn sfec(&mut self) -> SFEC_W { | 128 | pub fn sfec(&mut self) -> SFEC_W<'_> { |
| 129 | SFEC_W { w: self } | 129 | SFEC_W { w: self } |
| 130 | } | 130 | } |
| 131 | #[doc = "Bits 30:31 - SFT"] | 131 | #[doc = "Bits 30:31 - SFT"] |
| 132 | #[inline(always)] | 132 | #[inline(always)] |
| 133 | pub fn sft(&mut self) -> SFT_W { | 133 | pub fn sft(&mut self) -> SFT_W<'_> { |
| 134 | SFT_W { w: self } | 134 | SFT_W { w: self } |
| 135 | } | 135 | } |
| 136 | } | 136 | } |
diff --git a/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs b/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs index 455406a1c..6d65a86cb 100644 --- a/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs +++ b/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs | |||
| @@ -376,47 +376,47 @@ impl R { | |||
| 376 | impl W { | 376 | impl W { |
| 377 | #[doc = "Byte 0 - Bits 0:28 - ID"] | 377 | #[doc = "Byte 0 - Bits 0:28 - ID"] |
| 378 | #[inline(always)] | 378 | #[inline(always)] |
| 379 | pub fn id(&mut self) -> ID_W { | 379 | pub fn id(&mut self) -> ID_W<'_> { |
| 380 | ID_W { w: self } | 380 | ID_W { w: self } |
| 381 | } | 381 | } |
| 382 | #[doc = "Byte 0 - Bit 29 - RTR"] | 382 | #[doc = "Byte 0 - Bit 29 - RTR"] |
| 383 | #[inline(always)] | 383 | #[inline(always)] |
| 384 | pub fn rtr(&mut self) -> RTR_W { | 384 | pub fn rtr(&mut self) -> RTR_W<'_> { |
| 385 | RTR_W { w: self } | 385 | RTR_W { w: self } |
| 386 | } | 386 | } |
| 387 | #[doc = "Byte 0 - Bit 30 - XTD"] | 387 | #[doc = "Byte 0 - Bit 30 - XTD"] |
| 388 | #[inline(always)] | 388 | #[inline(always)] |
| 389 | pub fn xtd(&mut self) -> XTD_W { | 389 | pub fn xtd(&mut self) -> XTD_W<'_> { |
| 390 | XTD_W { w: self } | 390 | XTD_W { w: self } |
| 391 | } | 391 | } |
| 392 | #[doc = "Byte 0 - Bit 31 - ESI"] | 392 | #[doc = "Byte 0 - Bit 31 - ESI"] |
| 393 | #[inline(always)] | 393 | #[inline(always)] |
| 394 | pub fn esi(&mut self) -> ESI_W { | 394 | pub fn esi(&mut self) -> ESI_W<'_> { |
| 395 | ESI_W { w: self } | 395 | ESI_W { w: self } |
| 396 | } | 396 | } |
| 397 | #[doc = "Byte 1 - Bit 16:19 - DLC"] | 397 | #[doc = "Byte 1 - Bit 16:19 - DLC"] |
| 398 | #[inline(always)] | 398 | #[inline(always)] |
| 399 | pub fn dlc(&mut self) -> DLC_W { | 399 | pub fn dlc(&mut self) -> DLC_W<'_> { |
| 400 | DLC_W { w: self } | 400 | DLC_W { w: self } |
| 401 | } | 401 | } |
| 402 | #[doc = "Byte 1 - Bit 20 - BRS"] | 402 | #[doc = "Byte 1 - Bit 20 - BRS"] |
| 403 | #[inline(always)] | 403 | #[inline(always)] |
| 404 | pub fn brs(&mut self) -> BRS_W { | 404 | pub fn brs(&mut self) -> BRS_W<'_> { |
| 405 | BRS_W { w: self } | 405 | BRS_W { w: self } |
| 406 | } | 406 | } |
| 407 | #[doc = "Byte 1 - Bit 21 - FDF"] | 407 | #[doc = "Byte 1 - Bit 21 - FDF"] |
| 408 | #[inline(always)] | 408 | #[inline(always)] |
| 409 | pub fn fdf(&mut self) -> FDF_W { | 409 | pub fn fdf(&mut self) -> FDF_W<'_> { |
| 410 | FDF_W { w: self } | 410 | FDF_W { w: self } |
| 411 | } | 411 | } |
| 412 | #[doc = "Byte 1 - Bit 23 - EFC"] | 412 | #[doc = "Byte 1 - Bit 23 - EFC"] |
| 413 | #[inline(always)] | 413 | #[inline(always)] |
| 414 | pub fn efc(&mut self) -> EFC_W { | 414 | pub fn efc(&mut self) -> EFC_W<'_> { |
| 415 | EFC_W { w: self } | 415 | EFC_W { w: self } |
| 416 | } | 416 | } |
| 417 | #[doc = "Byte 1 - Bit 24:31 - MM"] | 417 | #[doc = "Byte 1 - Bit 24:31 - MM"] |
| 418 | #[inline(always)] | 418 | #[inline(always)] |
| 419 | pub fn mm(&mut self) -> MM_W { | 419 | pub fn mm(&mut self) -> MM_W<'_> { |
| 420 | MM_W { w: self } | 420 | MM_W { w: self } |
| 421 | } | 421 | } |
| 422 | #[doc = "Convenience function for setting the data length and frame format"] | 422 | #[doc = "Convenience function for setting the data length and frame format"] |
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 97d22315a..99e40ba62 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs | |||
| @@ -21,6 +21,7 @@ use self::fd::config::*; | |||
| 21 | use self::fd::filter::*; | 21 | use self::fd::filter::*; |
| 22 | pub use self::fd::{config, filter}; | 22 | pub use self::fd::{config, filter}; |
| 23 | pub use super::common::{BufferedCanReceiver, BufferedCanSender}; | 23 | pub use super::common::{BufferedCanReceiver, BufferedCanSender}; |
| 24 | use super::common::{InfoRef, RxInfoRef, TxInfoRef}; | ||
| 24 | use super::enums::*; | 25 | use super::enums::*; |
| 25 | use super::frame::*; | 26 | use super::frame::*; |
| 26 | use super::util; | 27 | use super::util; |
| @@ -167,10 +168,10 @@ fn calc_ns_per_timer_tick( | |||
| 167 | pub struct CanConfigurator<'d> { | 168 | pub struct CanConfigurator<'d> { |
| 168 | _phantom: PhantomData<&'d ()>, | 169 | _phantom: PhantomData<&'d ()>, |
| 169 | config: crate::can::fd::config::FdCanConfig, | 170 | config: crate::can::fd::config::FdCanConfig, |
| 170 | info: &'static Info, | ||
| 171 | /// Reference to internals. | 171 | /// Reference to internals. |
| 172 | properties: Properties, | 172 | properties: Properties, |
| 173 | periph_clock: crate::time::Hertz, | 173 | periph_clock: crate::time::Hertz, |
| 174 | info: InfoRef, | ||
| 174 | } | 175 | } |
| 175 | 176 | ||
| 176 | impl<'d> CanConfigurator<'d> { | 177 | impl<'d> CanConfigurator<'d> { |
| @@ -194,8 +195,6 @@ impl<'d> CanConfigurator<'d> { | |||
| 194 | s.borrow_mut().tx_pin_port = Some(tx.pin_port()); | 195 | s.borrow_mut().tx_pin_port = Some(tx.pin_port()); |
| 195 | s.borrow_mut().rx_pin_port = Some(rx.pin_port()); | 196 | s.borrow_mut().rx_pin_port = Some(rx.pin_port()); |
| 196 | }); | 197 | }); |
| 197 | (info.internal_operation)(InternalOperation::NotifySenderCreated); | ||
| 198 | (info.internal_operation)(InternalOperation::NotifyReceiverCreated); | ||
| 199 | 198 | ||
| 200 | let mut config = crate::can::fd::config::FdCanConfig::default(); | 199 | let mut config = crate::can::fd::config::FdCanConfig::default(); |
| 201 | config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); | 200 | config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); |
| @@ -211,9 +210,9 @@ impl<'d> CanConfigurator<'d> { | |||
| 211 | Self { | 210 | Self { |
| 212 | _phantom: PhantomData, | 211 | _phantom: PhantomData, |
| 213 | config, | 212 | config, |
| 214 | info, | ||
| 215 | properties: Properties::new(T::info()), | 213 | properties: Properties::new(T::info()), |
| 216 | periph_clock: T::frequency(), | 214 | periph_clock: T::frequency(), |
| 215 | info: InfoRef::new(info), | ||
| 217 | } | 216 | } |
| 218 | } | 217 | } |
| 219 | 218 | ||
| @@ -262,19 +261,17 @@ impl<'d> CanConfigurator<'d> { | |||
| 262 | 261 | ||
| 263 | /// Start in mode. | 262 | /// Start in mode. |
| 264 | pub fn start(self, mode: OperatingMode) -> Can<'d> { | 263 | pub fn start(self, mode: OperatingMode) -> Can<'d> { |
| 265 | let ns_per_timer_tick = calc_ns_per_timer_tick(self.info, self.periph_clock, self.config.frame_transmit); | 264 | let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit); |
| 266 | self.info.state.lock(|s| { | 265 | self.info.state.lock(|s| { |
| 267 | s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick; | 266 | s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick; |
| 268 | }); | 267 | }); |
| 269 | self.info.regs.into_mode(self.config, mode); | 268 | self.info.regs.into_mode(self.config, mode); |
| 270 | (self.info.internal_operation)(InternalOperation::NotifySenderCreated); | ||
| 271 | (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); | ||
| 272 | Can { | 269 | Can { |
| 273 | _phantom: PhantomData, | 270 | _phantom: PhantomData, |
| 274 | config: self.config, | 271 | config: self.config, |
| 275 | info: self.info, | ||
| 276 | _mode: mode, | 272 | _mode: mode, |
| 277 | properties: Properties::new(self.info), | 273 | properties: Properties::new(&self.info), |
| 274 | info: InfoRef::new(&self.info), | ||
| 278 | } | 275 | } |
| 279 | } | 276 | } |
| 280 | 277 | ||
| @@ -294,20 +291,13 @@ impl<'d> CanConfigurator<'d> { | |||
| 294 | } | 291 | } |
| 295 | } | 292 | } |
| 296 | 293 | ||
| 297 | impl<'d> Drop for CanConfigurator<'d> { | ||
| 298 | fn drop(&mut self) { | ||
| 299 | (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); | ||
| 300 | (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | /// FDCAN Instance | 294 | /// FDCAN Instance |
| 305 | pub struct Can<'d> { | 295 | pub struct Can<'d> { |
| 306 | _phantom: PhantomData<&'d ()>, | 296 | _phantom: PhantomData<&'d ()>, |
| 307 | config: crate::can::fd::config::FdCanConfig, | 297 | config: crate::can::fd::config::FdCanConfig, |
| 308 | info: &'static Info, | ||
| 309 | _mode: OperatingMode, | 298 | _mode: OperatingMode, |
| 310 | properties: Properties, | 299 | properties: Properties, |
| 300 | info: InfoRef, | ||
| 311 | } | 301 | } |
| 312 | 302 | ||
| 313 | impl<'d> Can<'d> { | 303 | impl<'d> Can<'d> { |
| @@ -341,12 +331,12 @@ impl<'d> Can<'d> { | |||
| 341 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 331 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 342 | /// transmitted, then tries again. | 332 | /// transmitted, then tries again. |
| 343 | pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { | 333 | pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { |
| 344 | TxMode::write(self.info, frame).await | 334 | TxMode::write(&self.info, frame).await |
| 345 | } | 335 | } |
| 346 | 336 | ||
| 347 | /// Returns the next received message frame | 337 | /// Returns the next received message frame |
| 348 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | 338 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 349 | RxMode::read_classic(self.info).await | 339 | RxMode::read_classic(&self.info).await |
| 350 | } | 340 | } |
| 351 | 341 | ||
| 352 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 342 | /// Queues the message to be sent but exerts backpressure. If a lower-priority |
| @@ -354,29 +344,27 @@ impl<'d> Can<'d> { | |||
| 354 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 344 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 355 | /// transmitted, then tries again. | 345 | /// transmitted, then tries again. |
| 356 | pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { | 346 | pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { |
| 357 | TxMode::write_fd(self.info, frame).await | 347 | TxMode::write_fd(&self.info, frame).await |
| 358 | } | 348 | } |
| 359 | 349 | ||
| 360 | /// Returns the next received message frame | 350 | /// Returns the next received message frame |
| 361 | pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> { | 351 | pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> { |
| 362 | RxMode::read_fd(self.info).await | 352 | RxMode::read_fd(&self.info).await |
| 363 | } | 353 | } |
| 364 | 354 | ||
| 365 | /// Split instance into separate portions: Tx(write), Rx(read), common properties | 355 | /// Split instance into separate portions: Tx(write), Rx(read), common properties |
| 366 | pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) { | 356 | pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) { |
| 367 | (self.info.internal_operation)(InternalOperation::NotifySenderCreated); | ||
| 368 | (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); | ||
| 369 | ( | 357 | ( |
| 370 | CanTx { | 358 | CanTx { |
| 371 | _phantom: PhantomData, | 359 | _phantom: PhantomData, |
| 372 | info: self.info, | ||
| 373 | config: self.config, | 360 | config: self.config, |
| 374 | _mode: self._mode, | 361 | _mode: self._mode, |
| 362 | info: TxInfoRef::new(&self.info), | ||
| 375 | }, | 363 | }, |
| 376 | CanRx { | 364 | CanRx { |
| 377 | _phantom: PhantomData, | 365 | _phantom: PhantomData, |
| 378 | info: self.info, | ||
| 379 | _mode: self._mode, | 366 | _mode: self._mode, |
| 367 | info: RxInfoRef::new(&self.info), | ||
| 380 | }, | 368 | }, |
| 381 | Properties { | 369 | Properties { |
| 382 | info: self.properties.info, | 370 | info: self.properties.info, |
| @@ -385,14 +373,12 @@ impl<'d> Can<'d> { | |||
| 385 | } | 373 | } |
| 386 | /// Join split rx and tx portions back together | 374 | /// Join split rx and tx portions back together |
| 387 | pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self { | 375 | pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self { |
| 388 | (tx.info.internal_operation)(InternalOperation::NotifySenderCreated); | ||
| 389 | (tx.info.internal_operation)(InternalOperation::NotifyReceiverCreated); | ||
| 390 | Can { | 376 | Can { |
| 391 | _phantom: PhantomData, | 377 | _phantom: PhantomData, |
| 392 | config: tx.config, | 378 | config: tx.config, |
| 393 | info: tx.info, | ||
| 394 | _mode: rx._mode, | 379 | _mode: rx._mode, |
| 395 | properties: Properties::new(tx.info), | 380 | properties: Properties::new(&tx.info), |
| 381 | info: InfoRef::new(&tx.info), | ||
| 396 | } | 382 | } |
| 397 | } | 383 | } |
| 398 | 384 | ||
| @@ -402,7 +388,7 @@ impl<'d> Can<'d> { | |||
| 402 | tx_buf: &'static mut TxBuf<TX_BUF_SIZE>, | 388 | tx_buf: &'static mut TxBuf<TX_BUF_SIZE>, |
| 403 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, | 389 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, |
| 404 | ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { | 390 | ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { |
| 405 | BufferedCan::new(self.info, self._mode, tx_buf, rxb) | 391 | BufferedCan::new(&self.info, self._mode, tx_buf, rxb) |
| 406 | } | 392 | } |
| 407 | 393 | ||
| 408 | /// Return a buffered instance of driver with CAN FD support. User must supply Buffers | 394 | /// Return a buffered instance of driver with CAN FD support. User must supply Buffers |
| @@ -411,14 +397,7 @@ impl<'d> Can<'d> { | |||
| 411 | tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>, | 397 | tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>, |
| 412 | rxb: &'static mut RxFdBuf<RX_BUF_SIZE>, | 398 | rxb: &'static mut RxFdBuf<RX_BUF_SIZE>, |
| 413 | ) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { | 399 | ) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { |
| 414 | BufferedCanFd::new(self.info, self._mode, tx_buf, rxb) | 400 | BufferedCanFd::new(&self.info, self._mode, tx_buf, rxb) |
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 418 | impl<'d> Drop for Can<'d> { | ||
| 419 | fn drop(&mut self) { | ||
| 420 | (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); | ||
| 421 | (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); | ||
| 422 | } | 401 | } |
| 423 | } | 402 | } |
| 424 | 403 | ||
| @@ -431,11 +410,11 @@ pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, | |||
| 431 | /// Buffered FDCAN Instance | 410 | /// Buffered FDCAN Instance |
| 432 | pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | 411 | pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { |
| 433 | _phantom: PhantomData<&'d ()>, | 412 | _phantom: PhantomData<&'d ()>, |
| 434 | info: &'static Info, | ||
| 435 | _mode: OperatingMode, | 413 | _mode: OperatingMode, |
| 436 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | 414 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, |
| 437 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | 415 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, |
| 438 | properties: Properties, | 416 | properties: Properties, |
| 417 | info: InfoRef, | ||
| 439 | } | 418 | } |
| 440 | 419 | ||
| 441 | impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { | 420 | impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { |
| @@ -445,15 +424,13 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, | |||
| 445 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | 424 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, |
| 446 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | 425 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, |
| 447 | ) -> Self { | 426 | ) -> Self { |
| 448 | (info.internal_operation)(InternalOperation::NotifySenderCreated); | ||
| 449 | (info.internal_operation)(InternalOperation::NotifyReceiverCreated); | ||
| 450 | BufferedCan { | 427 | BufferedCan { |
| 451 | _phantom: PhantomData, | 428 | _phantom: PhantomData, |
| 452 | info, | ||
| 453 | _mode, | 429 | _mode, |
| 454 | tx_buf, | 430 | tx_buf, |
| 455 | rx_buf, | 431 | rx_buf, |
| 456 | properties: Properties::new(info), | 432 | properties: Properties::new(info), |
| 433 | info: InfoRef::new(info), | ||
| 457 | } | 434 | } |
| 458 | .setup() | 435 | .setup() |
| 459 | } | 436 | } |
| @@ -492,31 +469,21 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, | |||
| 492 | 469 | ||
| 493 | /// Returns a sender that can be used for sending CAN frames. | 470 | /// Returns a sender that can be used for sending CAN frames. |
| 494 | pub fn writer(&self) -> BufferedCanSender { | 471 | pub fn writer(&self) -> BufferedCanSender { |
| 495 | (self.info.internal_operation)(InternalOperation::NotifySenderCreated); | ||
| 496 | BufferedCanSender { | 472 | BufferedCanSender { |
| 497 | tx_buf: self.tx_buf.sender().into(), | 473 | tx_buf: self.tx_buf.sender().into(), |
| 498 | waker: self.info.tx_waker, | 474 | info: TxInfoRef::new(&self.info), |
| 499 | internal_operation: self.info.internal_operation, | ||
| 500 | } | 475 | } |
| 501 | } | 476 | } |
| 502 | 477 | ||
| 503 | /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | 478 | /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. |
| 504 | pub fn reader(&self) -> BufferedCanReceiver { | 479 | pub fn reader(&self) -> BufferedCanReceiver { |
| 505 | (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); | ||
| 506 | BufferedCanReceiver { | 480 | BufferedCanReceiver { |
| 507 | rx_buf: self.rx_buf.receiver().into(), | 481 | rx_buf: self.rx_buf.receiver().into(), |
| 508 | internal_operation: self.info.internal_operation, | 482 | info: RxInfoRef::new(&self.info), |
| 509 | } | 483 | } |
| 510 | } | 484 | } |
| 511 | } | 485 | } |
| 512 | 486 | ||
| 513 | impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { | ||
| 514 | fn drop(&mut self) { | ||
| 515 | (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); | ||
| 516 | (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); | ||
| 517 | } | ||
| 518 | } | ||
| 519 | |||
| 520 | /// User supplied buffer for RX Buffering | 487 | /// User supplied buffer for RX Buffering |
| 521 | pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<FdEnvelope, BusError>, BUF_SIZE>; | 488 | pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<FdEnvelope, BusError>, BUF_SIZE>; |
| 522 | 489 | ||
| @@ -532,11 +499,11 @@ pub type BufferedFdCanReceiver = super::common::BufferedReceiver<'static, FdEnve | |||
| 532 | /// Buffered FDCAN Instance | 499 | /// Buffered FDCAN Instance |
| 533 | pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | 500 | pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { |
| 534 | _phantom: PhantomData<&'d ()>, | 501 | _phantom: PhantomData<&'d ()>, |
| 535 | info: &'static Info, | ||
| 536 | _mode: OperatingMode, | 502 | _mode: OperatingMode, |
| 537 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, | 503 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, |
| 538 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, | 504 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, |
| 539 | properties: Properties, | 505 | properties: Properties, |
| 506 | info: InfoRef, | ||
| 540 | } | 507 | } |
| 541 | 508 | ||
| 542 | impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { | 509 | impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { |
| @@ -546,15 +513,13 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' | |||
| 546 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, | 513 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, |
| 547 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, | 514 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, |
| 548 | ) -> Self { | 515 | ) -> Self { |
| 549 | (info.internal_operation)(InternalOperation::NotifySenderCreated); | ||
| 550 | (info.internal_operation)(InternalOperation::NotifyReceiverCreated); | ||
| 551 | BufferedCanFd { | 516 | BufferedCanFd { |
| 552 | _phantom: PhantomData, | 517 | _phantom: PhantomData, |
| 553 | info, | ||
| 554 | _mode, | 518 | _mode, |
| 555 | tx_buf, | 519 | tx_buf, |
| 556 | rx_buf, | 520 | rx_buf, |
| 557 | properties: Properties::new(info), | 521 | properties: Properties::new(info), |
| 522 | info: InfoRef::new(info), | ||
| 558 | } | 523 | } |
| 559 | .setup() | 524 | .setup() |
| 560 | } | 525 | } |
| @@ -593,36 +558,26 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' | |||
| 593 | 558 | ||
| 594 | /// Returns a sender that can be used for sending CAN frames. | 559 | /// Returns a sender that can be used for sending CAN frames. |
| 595 | pub fn writer(&self) -> BufferedFdCanSender { | 560 | pub fn writer(&self) -> BufferedFdCanSender { |
| 596 | (self.info.internal_operation)(InternalOperation::NotifySenderCreated); | ||
| 597 | BufferedFdCanSender { | 561 | BufferedFdCanSender { |
| 598 | tx_buf: self.tx_buf.sender().into(), | 562 | tx_buf: self.tx_buf.sender().into(), |
| 599 | waker: self.info.tx_waker, | 563 | info: TxInfoRef::new(&self.info), |
| 600 | internal_operation: self.info.internal_operation, | ||
| 601 | } | 564 | } |
| 602 | } | 565 | } |
| 603 | 566 | ||
| 604 | /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | 567 | /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. |
| 605 | pub fn reader(&self) -> BufferedFdCanReceiver { | 568 | pub fn reader(&self) -> BufferedFdCanReceiver { |
| 606 | (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); | ||
| 607 | BufferedFdCanReceiver { | 569 | BufferedFdCanReceiver { |
| 608 | rx_buf: self.rx_buf.receiver().into(), | 570 | rx_buf: self.rx_buf.receiver().into(), |
| 609 | internal_operation: self.info.internal_operation, | 571 | info: RxInfoRef::new(&self.info), |
| 610 | } | 572 | } |
| 611 | } | 573 | } |
| 612 | } | 574 | } |
| 613 | 575 | ||
| 614 | impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { | ||
| 615 | fn drop(&mut self) { | ||
| 616 | (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); | ||
| 617 | (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); | ||
| 618 | } | ||
| 619 | } | ||
| 620 | |||
| 621 | /// FDCAN Rx only Instance | 576 | /// FDCAN Rx only Instance |
| 622 | pub struct CanRx<'d> { | 577 | pub struct CanRx<'d> { |
| 623 | _phantom: PhantomData<&'d ()>, | 578 | _phantom: PhantomData<&'d ()>, |
| 624 | info: &'static Info, | ||
| 625 | _mode: OperatingMode, | 579 | _mode: OperatingMode, |
| 580 | info: RxInfoRef, | ||
| 626 | } | 581 | } |
| 627 | 582 | ||
| 628 | impl<'d> CanRx<'d> { | 583 | impl<'d> CanRx<'d> { |
| @@ -637,18 +592,12 @@ impl<'d> CanRx<'d> { | |||
| 637 | } | 592 | } |
| 638 | } | 593 | } |
| 639 | 594 | ||
| 640 | impl<'d> Drop for CanRx<'d> { | ||
| 641 | fn drop(&mut self) { | ||
| 642 | (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); | ||
| 643 | } | ||
| 644 | } | ||
| 645 | |||
| 646 | /// FDCAN Tx only Instance | 595 | /// FDCAN Tx only Instance |
| 647 | pub struct CanTx<'d> { | 596 | pub struct CanTx<'d> { |
| 648 | _phantom: PhantomData<&'d ()>, | 597 | _phantom: PhantomData<&'d ()>, |
| 649 | info: &'static Info, | ||
| 650 | config: crate::can::fd::config::FdCanConfig, | 598 | config: crate::can::fd::config::FdCanConfig, |
| 651 | _mode: OperatingMode, | 599 | _mode: OperatingMode, |
| 600 | info: TxInfoRef, | ||
| 652 | } | 601 | } |
| 653 | 602 | ||
| 654 | impl<'c, 'd> CanTx<'d> { | 603 | impl<'c, 'd> CanTx<'d> { |
| @@ -657,7 +606,7 @@ impl<'c, 'd> CanTx<'d> { | |||
| 657 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 606 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 658 | /// transmitted, then tries again. | 607 | /// transmitted, then tries again. |
| 659 | pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { | 608 | pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { |
| 660 | TxMode::write(self.info, frame).await | 609 | TxMode::write(&self.info, frame).await |
| 661 | } | 610 | } |
| 662 | 611 | ||
| 663 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 612 | /// Queues the message to be sent but exerts backpressure. If a lower-priority |
| @@ -665,13 +614,7 @@ impl<'c, 'd> CanTx<'d> { | |||
| 665 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 614 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 666 | /// transmitted, then tries again. | 615 | /// transmitted, then tries again. |
| 667 | pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { | 616 | pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { |
| 668 | TxMode::write_fd(self.info, frame).await | 617 | TxMode::write_fd(&self.info, frame).await |
| 669 | } | ||
| 670 | } | ||
| 671 | |||
| 672 | impl<'d> Drop for CanTx<'d> { | ||
| 673 | fn drop(&mut self) { | ||
| 674 | (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); | ||
| 675 | } | 618 | } |
| 676 | } | 619 | } |
| 677 | 620 | ||
| @@ -938,21 +881,56 @@ impl State { | |||
| 938 | } | 881 | } |
| 939 | 882 | ||
| 940 | type SharedState = embassy_sync::blocking_mutex::Mutex<CriticalSectionRawMutex, core::cell::RefCell<State>>; | 883 | type SharedState = embassy_sync::blocking_mutex::Mutex<CriticalSectionRawMutex, core::cell::RefCell<State>>; |
| 941 | struct Info { | 884 | pub(crate) struct Info { |
| 942 | regs: Registers, | 885 | regs: Registers, |
| 943 | interrupt0: crate::interrupt::Interrupt, | 886 | interrupt0: crate::interrupt::Interrupt, |
| 944 | _interrupt1: crate::interrupt::Interrupt, | 887 | _interrupt1: crate::interrupt::Interrupt, |
| 945 | tx_waker: fn(), | 888 | pub(crate) tx_waker: fn(), |
| 946 | internal_operation: fn(InternalOperation), | ||
| 947 | state: SharedState, | 889 | state: SharedState, |
| 948 | } | 890 | } |
| 949 | 891 | ||
| 892 | impl Info { | ||
| 893 | pub(crate) fn adjust_reference_counter(&self, val: RefCountOp) { | ||
| 894 | self.state.lock(|s| { | ||
| 895 | let mut mut_state = s.borrow_mut(); | ||
| 896 | match val { | ||
| 897 | RefCountOp::NotifySenderCreated => { | ||
| 898 | mut_state.sender_instance_count += 1; | ||
| 899 | } | ||
| 900 | RefCountOp::NotifySenderDestroyed => { | ||
| 901 | mut_state.sender_instance_count -= 1; | ||
| 902 | if 0 == mut_state.sender_instance_count { | ||
| 903 | (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 904 | } | ||
| 905 | } | ||
| 906 | RefCountOp::NotifyReceiverCreated => { | ||
| 907 | mut_state.receiver_instance_count += 1; | ||
| 908 | } | ||
| 909 | RefCountOp::NotifyReceiverDestroyed => { | ||
| 910 | mut_state.receiver_instance_count -= 1; | ||
| 911 | if 0 == mut_state.receiver_instance_count { | ||
| 912 | (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 913 | } | ||
| 914 | } | ||
| 915 | } | ||
| 916 | if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 { | ||
| 917 | unsafe { | ||
| 918 | let tx_pin = crate::gpio::AnyPin::steal(mut_state.tx_pin_port.unwrap()); | ||
| 919 | tx_pin.set_as_disconnected(); | ||
| 920 | let rx_pin = crate::gpio::AnyPin::steal(mut_state.rx_pin_port.unwrap()); | ||
| 921 | rx_pin.set_as_disconnected(); | ||
| 922 | self.interrupt0.disable(); | ||
| 923 | } | ||
| 924 | } | ||
| 925 | }); | ||
| 926 | } | ||
| 927 | } | ||
| 928 | |||
| 950 | trait SealedInstance { | 929 | trait SealedInstance { |
| 951 | const MSG_RAM_OFFSET: usize; | 930 | const MSG_RAM_OFFSET: usize; |
| 952 | 931 | ||
| 953 | fn info() -> &'static Info; | 932 | fn info() -> &'static Info; |
| 954 | fn registers() -> crate::can::fd::peripheral::Registers; | 933 | fn registers() -> crate::can::fd::peripheral::Registers; |
| 955 | fn internal_operation(val: InternalOperation); | ||
| 956 | } | 934 | } |
| 957 | 935 | ||
| 958 | /// Instance trait | 936 | /// Instance trait |
| @@ -974,41 +952,6 @@ macro_rules! impl_fdcan { | |||
| 974 | impl SealedInstance for peripherals::$inst { | 952 | impl SealedInstance for peripherals::$inst { |
| 975 | const MSG_RAM_OFFSET: usize = $msg_ram_offset; | 953 | const MSG_RAM_OFFSET: usize = $msg_ram_offset; |
| 976 | 954 | ||
| 977 | fn internal_operation(val: InternalOperation) { | ||
| 978 | peripherals::$inst::info().state.lock(|s| { | ||
| 979 | let mut mut_state = s.borrow_mut(); | ||
| 980 | match val { | ||
| 981 | InternalOperation::NotifySenderCreated => { | ||
| 982 | mut_state.sender_instance_count += 1; | ||
| 983 | } | ||
| 984 | InternalOperation::NotifySenderDestroyed => { | ||
| 985 | mut_state.sender_instance_count -= 1; | ||
| 986 | if ( 0 == mut_state.sender_instance_count) { | ||
| 987 | (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 988 | } | ||
| 989 | } | ||
| 990 | InternalOperation::NotifyReceiverCreated => { | ||
| 991 | mut_state.receiver_instance_count += 1; | ||
| 992 | } | ||
| 993 | InternalOperation::NotifyReceiverDestroyed => { | ||
| 994 | mut_state.receiver_instance_count -= 1; | ||
| 995 | if ( 0 == mut_state.receiver_instance_count) { | ||
| 996 | (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 997 | } | ||
| 998 | } | ||
| 999 | } | ||
| 1000 | if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 { | ||
| 1001 | unsafe { | ||
| 1002 | let tx_pin = crate::gpio::AnyPin::steal(mut_state.tx_pin_port.unwrap()); | ||
| 1003 | tx_pin.set_as_disconnected(); | ||
| 1004 | let rx_pin = crate::gpio::AnyPin::steal(mut_state.rx_pin_port.unwrap()); | ||
| 1005 | rx_pin.set_as_disconnected(); | ||
| 1006 | rcc::disable::<peripherals::$inst>(); | ||
| 1007 | } | ||
| 1008 | } | ||
| 1009 | }); | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | fn info() -> &'static Info { | 955 | fn info() -> &'static Info { |
| 1013 | 956 | ||
| 1014 | static INFO: Info = Info { | 957 | static INFO: Info = Info { |
| @@ -1016,7 +959,6 @@ macro_rules! impl_fdcan { | |||
| 1016 | interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ, | 959 | interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ, |
| 1017 | _interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ, | 960 | _interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ, |
| 1018 | tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend, | 961 | tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend, |
| 1019 | internal_operation: peripherals::$inst::internal_operation, | ||
| 1020 | state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(State::new())), | 962 | state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(State::new())), |
| 1021 | }; | 963 | }; |
| 1022 | &INFO | 964 | &INFO |
diff --git a/embassy-stm32/src/cordic/utils.rs b/embassy-stm32/src/cordic/utils.rs index 008f50270..9afa8ef53 100644 --- a/embassy-stm32/src/cordic/utils.rs +++ b/embassy-stm32/src/cordic/utils.rs | |||
| @@ -5,7 +5,7 @@ macro_rules! floating_fixed_convert { | |||
| 5 | ($f_to_q:ident, $q_to_f:ident, $unsigned_bin_typ:ty, $signed_bin_typ:ty, $float_ty:ty, $offset:literal, $min_positive:literal) => { | 5 | ($f_to_q:ident, $q_to_f:ident, $unsigned_bin_typ:ty, $signed_bin_typ:ty, $float_ty:ty, $offset:literal, $min_positive:literal) => { |
| 6 | /// convert float point to fixed point format | 6 | /// convert float point to fixed point format |
| 7 | pub fn $f_to_q(value: $float_ty) -> Result<$unsigned_bin_typ, NumberOutOfRange> { | 7 | pub fn $f_to_q(value: $float_ty) -> Result<$unsigned_bin_typ, NumberOutOfRange> { |
| 8 | const MIN_POSITIVE: $float_ty = unsafe { core::mem::transmute($min_positive) }; | 8 | const MIN_POSITIVE: $float_ty = <$float_ty>::from_bits($min_positive); |
| 9 | 9 | ||
| 10 | if value < -1.0 { | 10 | if value < -1.0 { |
| 11 | return Err(NumberOutOfRange::BelowLowerBound) | 11 | return Err(NumberOutOfRange::BelowLowerBound) |
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index fba3c0fd7..35d9f8cce 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] | 2 | #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] |
| 3 | use core::cmp::min; | 3 | use core::cmp::min; |
| 4 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 5 | use core::ptr; | ||
| 6 | 5 | ||
| 7 | use embassy_hal_internal::{Peri, PeripheralType}; | 6 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -1814,14 +1813,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> { | |||
| 1814 | assert_eq!(blocks.len() % block_size, 0); | 1813 | assert_eq!(blocks.len() % block_size, 0); |
| 1815 | // Configure DMA to transfer input to crypto core. | 1814 | // Configure DMA to transfer input to crypto core. |
| 1816 | let dst_ptr: *mut u32 = T::regs().din().as_ptr(); | 1815 | let dst_ptr: *mut u32 = T::regs().din().as_ptr(); |
| 1817 | let num_words = blocks.len() / 4; | ||
| 1818 | let src_ptr: *const [u8] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); | ||
| 1819 | let options = TransferOptions { | 1816 | let options = TransferOptions { |
| 1820 | #[cfg(not(gpdma))] | 1817 | #[cfg(not(gpdma))] |
| 1821 | priority: crate::dma::Priority::High, | 1818 | priority: crate::dma::Priority::High, |
| 1822 | ..Default::default() | 1819 | ..Default::default() |
| 1823 | }; | 1820 | }; |
| 1824 | let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr, options) }; | 1821 | let dma_transfer = unsafe { dma.write_raw(blocks, dst_ptr, options) }; |
| 1825 | T::regs().dmacr().modify(|w| w.set_dien(true)); | 1822 | T::regs().dmacr().modify(|w| w.set_dien(true)); |
| 1826 | // Wait for the transfer to complete. | 1823 | // Wait for the transfer to complete. |
| 1827 | dma_transfer.await; | 1824 | dma_transfer.await; |
| @@ -1836,14 +1833,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> { | |||
| 1836 | assert_eq!((blocks.len() * 4) % block_size, 0); | 1833 | assert_eq!((blocks.len() * 4) % block_size, 0); |
| 1837 | // Configure DMA to transfer input to crypto core. | 1834 | // Configure DMA to transfer input to crypto core. |
| 1838 | let dst_ptr: *mut u32 = T::regs().din().as_ptr(); | 1835 | let dst_ptr: *mut u32 = T::regs().din().as_ptr(); |
| 1839 | let num_words = blocks.len(); | ||
| 1840 | let src_ptr: *const [u32] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); | ||
| 1841 | let options = TransferOptions { | 1836 | let options = TransferOptions { |
| 1842 | #[cfg(not(gpdma))] | 1837 | #[cfg(not(gpdma))] |
| 1843 | priority: crate::dma::Priority::High, | 1838 | priority: crate::dma::Priority::High, |
| 1844 | ..Default::default() | 1839 | ..Default::default() |
| 1845 | }; | 1840 | }; |
| 1846 | let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr, options) }; | 1841 | let dma_transfer = unsafe { dma.write_raw(blocks, dst_ptr, options) }; |
| 1847 | T::regs().dmacr().modify(|w| w.set_dien(true)); | 1842 | T::regs().dmacr().modify(|w| w.set_dien(true)); |
| 1848 | // Wait for the transfer to complete. | 1843 | // Wait for the transfer to complete. |
| 1849 | dma_transfer.await; | 1844 | dma_transfer.await; |
| @@ -1857,14 +1852,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> { | |||
| 1857 | assert_eq!(blocks.len() % block_size, 0); | 1852 | assert_eq!(blocks.len() % block_size, 0); |
| 1858 | // Configure DMA to get output from crypto core. | 1853 | // Configure DMA to get output from crypto core. |
| 1859 | let src_ptr = T::regs().dout().as_ptr(); | 1854 | let src_ptr = T::regs().dout().as_ptr(); |
| 1860 | let num_words = blocks.len() / 4; | ||
| 1861 | let dst_ptr = ptr::slice_from_raw_parts_mut(blocks.as_mut_ptr().cast(), num_words); | ||
| 1862 | let options = TransferOptions { | 1855 | let options = TransferOptions { |
| 1863 | #[cfg(not(gpdma))] | 1856 | #[cfg(not(gpdma))] |
| 1864 | priority: crate::dma::Priority::VeryHigh, | 1857 | priority: crate::dma::Priority::VeryHigh, |
| 1865 | ..Default::default() | 1858 | ..Default::default() |
| 1866 | }; | 1859 | }; |
| 1867 | let dma_transfer = unsafe { dma.read_raw(src_ptr, dst_ptr, options) }; | 1860 | let dma_transfer = unsafe { dma.read_raw(src_ptr, blocks, options) }; |
| 1868 | T::regs().dmacr().modify(|w| w.set_doen(true)); | 1861 | T::regs().dmacr().modify(|w| w.set_doen(true)); |
| 1869 | // Wait for the transfer to complete. | 1862 | // Wait for the transfer to complete. |
| 1870 | dma_transfer.await; | 1863 | dma_transfer.await; |
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 30046849b..d8f1f96f2 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs | |||
| @@ -403,6 +403,46 @@ impl<'d, T: Instance> Dac<'d, T, Async> { | |||
| 403 | Mode::NormalExternalBuffered, | 403 | Mode::NormalExternalBuffered, |
| 404 | ) | 404 | ) |
| 405 | } | 405 | } |
| 406 | /// Create a new `Dac` instance with external output pins and unbuffered mode. | ||
| 407 | /// | ||
| 408 | /// This function consumes the underlying DAC peripheral and allows access to both channels. | ||
| 409 | /// The channels are configured for external output with the buffer disabled. | ||
| 410 | /// | ||
| 411 | /// The channels are enabled on creation and begin to drive their output pins. | ||
| 412 | /// Note that some methods, such as `set_trigger()` and `set_mode()`, will | ||
| 413 | /// disable the channel; you must re-enable them with `enable()`. | ||
| 414 | /// | ||
| 415 | /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` | ||
| 416 | /// method on the underlying channels. | ||
| 417 | /// | ||
| 418 | /// # Arguments | ||
| 419 | /// | ||
| 420 | /// * `peri` - The DAC peripheral instance. | ||
| 421 | /// * `dma_ch1` - The DMA channel for DAC channel 1. | ||
| 422 | /// * `dma_ch2` - The DMA channel for DAC channel 2. | ||
| 423 | /// * `pin_ch1` - The GPIO pin for DAC channel 1 output. | ||
| 424 | /// * `pin_ch2` - The GPIO pin for DAC channel 2 output. | ||
| 425 | /// | ||
| 426 | /// # Returns | ||
| 427 | /// | ||
| 428 | /// A new `Dac` instance in unbuffered mode. | ||
| 429 | pub fn new_unbuffered( | ||
| 430 | peri: Peri<'d, T>, | ||
| 431 | dma_ch1: Peri<'d, impl Dma<T, Ch1>>, | ||
| 432 | dma_ch2: Peri<'d, impl Dma<T, Ch2>>, | ||
| 433 | pin_ch1: Peri<'d, impl DacPin<T, Ch1> + crate::gpio::Pin>, | ||
| 434 | pin_ch2: Peri<'d, impl DacPin<T, Ch2> + crate::gpio::Pin>, | ||
| 435 | ) -> Self { | ||
| 436 | pin_ch1.set_as_analog(); | ||
| 437 | pin_ch2.set_as_analog(); | ||
| 438 | Self::new_inner( | ||
| 439 | peri, | ||
| 440 | new_dma!(dma_ch1), | ||
| 441 | new_dma!(dma_ch2), | ||
| 442 | #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] | ||
| 443 | Mode::NormalExternalUnbuffered, | ||
| 444 | ) | ||
| 445 | } | ||
| 406 | 446 | ||
| 407 | /// Create a new `Dac` instance where the external output pins are not used, | 447 | /// Create a new `Dac` instance where the external output pins are not used, |
| 408 | /// so the DAC can only be used to generate internal signals but the GPIO | 448 | /// so the DAC can only be used to generate internal signals but the GPIO |
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 7dbbe7b72..464823bfc 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs | |||
| @@ -341,9 +341,12 @@ impl AnyChannel { | |||
| 341 | mem_len: usize, | 341 | mem_len: usize, |
| 342 | incr_mem: bool, | 342 | incr_mem: bool, |
| 343 | mem_size: WordSize, | 343 | mem_size: WordSize, |
| 344 | peripheral_size: WordSize, | 344 | peri_size: WordSize, |
| 345 | options: TransferOptions, | 345 | options: TransferOptions, |
| 346 | ) { | 346 | ) { |
| 347 | // "Preceding reads and writes cannot be moved past subsequent writes." | ||
| 348 | fence(Ordering::SeqCst); | ||
| 349 | |||
| 347 | let info = self.info(); | 350 | let info = self.info(); |
| 348 | #[cfg(feature = "_dual-core")] | 351 | #[cfg(feature = "_dual-core")] |
| 349 | { | 352 | { |
| @@ -354,28 +357,48 @@ impl AnyChannel { | |||
| 354 | #[cfg(dmamux)] | 357 | #[cfg(dmamux)] |
| 355 | super::dmamux::configure_dmamux(&info.dmamux, _request); | 358 | super::dmamux::configure_dmamux(&info.dmamux, _request); |
| 356 | 359 | ||
| 357 | assert!(mem_len > 0 && mem_len <= 0xFFFF); | ||
| 358 | |||
| 359 | match self.info().dma { | 360 | match self.info().dma { |
| 360 | #[cfg(dma)] | 361 | #[cfg(dma)] |
| 361 | DmaInfo::Dma(r) => { | 362 | DmaInfo::Dma(r) => { |
| 362 | let state: &ChannelState = &STATE[self.id as usize]; | 363 | let state: &ChannelState = &STATE[self.id as usize]; |
| 363 | let ch = r.st(info.num); | 364 | let ch = r.st(info.num); |
| 364 | 365 | ||
| 365 | // "Preceding reads and writes cannot be moved past subsequent writes." | ||
| 366 | fence(Ordering::SeqCst); | ||
| 367 | |||
| 368 | state.complete_count.store(0, Ordering::Release); | 366 | state.complete_count.store(0, Ordering::Release); |
| 369 | self.clear_irqs(); | 367 | self.clear_irqs(); |
| 370 | 368 | ||
| 369 | // NDTR is the number of transfers in the *peripheral* word size. | ||
| 370 | // ex: if mem_size=1, peri_size=4 and ndtr=3 it'll do 12 mem transfers, 3 peri transfers. | ||
| 371 | let ndtr = match (mem_size, peri_size) { | ||
| 372 | (WordSize::FourBytes, WordSize::OneByte) => mem_len * 4, | ||
| 373 | (WordSize::FourBytes, WordSize::TwoBytes) | (WordSize::TwoBytes, WordSize::OneByte) => mem_len * 2, | ||
| 374 | (WordSize::FourBytes, WordSize::FourBytes) | ||
| 375 | | (WordSize::TwoBytes, WordSize::TwoBytes) | ||
| 376 | | (WordSize::OneByte, WordSize::OneByte) => mem_len, | ||
| 377 | (WordSize::TwoBytes, WordSize::FourBytes) | (WordSize::OneByte, WordSize::TwoBytes) => { | ||
| 378 | assert!(mem_len % 2 == 0); | ||
| 379 | mem_len / 2 | ||
| 380 | } | ||
| 381 | (WordSize::OneByte, WordSize::FourBytes) => { | ||
| 382 | assert!(mem_len % 4 == 0); | ||
| 383 | mem_len / 4 | ||
| 384 | } | ||
| 385 | }; | ||
| 386 | |||
| 387 | assert!(ndtr > 0 && ndtr <= 0xFFFF); | ||
| 388 | |||
| 371 | ch.par().write_value(peri_addr as u32); | 389 | ch.par().write_value(peri_addr as u32); |
| 372 | ch.m0ar().write_value(mem_addr as u32); | 390 | ch.m0ar().write_value(mem_addr as u32); |
| 373 | ch.ndtr().write_value(pac::dma::regs::Ndtr(mem_len as _)); | 391 | ch.ndtr().write_value(pac::dma::regs::Ndtr(ndtr as _)); |
| 374 | ch.fcr().write(|w| { | 392 | ch.fcr().write(|w| { |
| 375 | if let Some(fth) = options.fifo_threshold { | 393 | if let Some(fth) = options.fifo_threshold { |
| 376 | // FIFO mode | 394 | // FIFO mode |
| 377 | w.set_dmdis(pac::dma::vals::Dmdis::DISABLED); | 395 | w.set_dmdis(pac::dma::vals::Dmdis::DISABLED); |
| 378 | w.set_fth(fth.into()); | 396 | w.set_fth(fth.into()); |
| 397 | } else if mem_size != peri_size { | ||
| 398 | // force FIFO mode if msize != psize | ||
| 399 | // packing/unpacking doesn't work in direct mode. | ||
| 400 | w.set_dmdis(pac::dma::vals::Dmdis::DISABLED); | ||
| 401 | w.set_fth(FifoThreshold::Half.into()); | ||
| 379 | } else { | 402 | } else { |
| 380 | // Direct mode | 403 | // Direct mode |
| 381 | w.set_dmdis(pac::dma::vals::Dmdis::ENABLED); | 404 | w.set_dmdis(pac::dma::vals::Dmdis::ENABLED); |
| @@ -384,7 +407,7 @@ impl AnyChannel { | |||
| 384 | ch.cr().write(|w| { | 407 | ch.cr().write(|w| { |
| 385 | w.set_dir(dir.into()); | 408 | w.set_dir(dir.into()); |
| 386 | w.set_msize(mem_size.into()); | 409 | w.set_msize(mem_size.into()); |
| 387 | w.set_psize(peripheral_size.into()); | 410 | w.set_psize(peri_size.into()); |
| 388 | w.set_pl(options.priority.into()); | 411 | w.set_pl(options.priority.into()); |
| 389 | w.set_minc(incr_mem); | 412 | w.set_minc(incr_mem); |
| 390 | w.set_pinc(false); | 413 | w.set_pinc(false); |
| @@ -404,6 +427,8 @@ impl AnyChannel { | |||
| 404 | } | 427 | } |
| 405 | #[cfg(bdma)] | 428 | #[cfg(bdma)] |
| 406 | DmaInfo::Bdma(r) => { | 429 | DmaInfo::Bdma(r) => { |
| 430 | assert!(mem_len > 0 && mem_len <= 0xFFFF); | ||
| 431 | |||
| 407 | #[cfg(bdma_v2)] | 432 | #[cfg(bdma_v2)] |
| 408 | critical_section::with(|_| r.cselr().modify(|w| w.set_cs(info.num, _request))); | 433 | critical_section::with(|_| r.cselr().modify(|w| w.set_cs(info.num, _request))); |
| 409 | 434 | ||
| @@ -417,7 +442,7 @@ impl AnyChannel { | |||
| 417 | ch.mar().write_value(mem_addr as u32); | 442 | ch.mar().write_value(mem_addr as u32); |
| 418 | ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); | 443 | ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); |
| 419 | ch.cr().write(|w| { | 444 | ch.cr().write(|w| { |
| 420 | w.set_psize(peripheral_size.into()); | 445 | w.set_psize(peri_size.into()); |
| 421 | w.set_msize(mem_size.into()); | 446 | w.set_msize(mem_size.into()); |
| 422 | w.set_minc(incr_mem); | 447 | w.set_minc(incr_mem); |
| 423 | w.set_dir(dir.into()); | 448 | w.set_dir(dir.into()); |
| @@ -587,11 +612,11 @@ impl<'a> Transfer<'a> { | |||
| 587 | } | 612 | } |
| 588 | 613 | ||
| 589 | /// Create a new read DMA transfer (peripheral to memory), using raw pointers. | 614 | /// Create a new read DMA transfer (peripheral to memory), using raw pointers. |
| 590 | pub unsafe fn new_read_raw<W: Word>( | 615 | pub unsafe fn new_read_raw<MW: Word, PW: Word>( |
| 591 | channel: Peri<'a, impl Channel>, | 616 | channel: Peri<'a, impl Channel>, |
| 592 | request: Request, | 617 | request: Request, |
| 593 | peri_addr: *mut W, | 618 | peri_addr: *mut PW, |
| 594 | buf: *mut [W], | 619 | buf: *mut [MW], |
| 595 | options: TransferOptions, | 620 | options: TransferOptions, |
| 596 | ) -> Self { | 621 | ) -> Self { |
| 597 | Self::new_inner( | 622 | Self::new_inner( |
| @@ -599,11 +624,11 @@ impl<'a> Transfer<'a> { | |||
| 599 | request, | 624 | request, |
| 600 | Dir::PeripheralToMemory, | 625 | Dir::PeripheralToMemory, |
| 601 | peri_addr as *const u32, | 626 | peri_addr as *const u32, |
| 602 | buf as *mut W as *mut u32, | 627 | buf as *mut MW as *mut u32, |
| 603 | buf.len(), | 628 | buf.len(), |
| 604 | true, | 629 | true, |
| 605 | W::size(), | 630 | MW::size(), |
| 606 | W::size(), | 631 | PW::size(), |
| 607 | options, | 632 | options, |
| 608 | ) | 633 | ) |
| 609 | } | 634 | } |
| @@ -672,22 +697,14 @@ impl<'a> Transfer<'a> { | |||
| 672 | mem_addr: *mut u32, | 697 | mem_addr: *mut u32, |
| 673 | mem_len: usize, | 698 | mem_len: usize, |
| 674 | incr_mem: bool, | 699 | incr_mem: bool, |
| 675 | data_size: WordSize, | 700 | mem_size: WordSize, |
| 676 | peripheral_size: WordSize, | 701 | peri_size: WordSize, |
| 677 | options: TransferOptions, | 702 | options: TransferOptions, |
| 678 | ) -> Self { | 703 | ) -> Self { |
| 679 | assert!(mem_len > 0 && mem_len <= 0xFFFF); | 704 | assert!(mem_len > 0 && mem_len <= 0xFFFF); |
| 680 | 705 | ||
| 681 | channel.configure( | 706 | channel.configure( |
| 682 | _request, | 707 | _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options, |
| 683 | dir, | ||
| 684 | peri_addr, | ||
| 685 | mem_addr, | ||
| 686 | mem_len, | ||
| 687 | incr_mem, | ||
| 688 | data_size, | ||
| 689 | peripheral_size, | ||
| 690 | options, | ||
| 691 | ); | 708 | ); |
| 692 | channel.start(); | 709 | channel.start(); |
| 693 | Self { channel } | 710 | Self { channel } |
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index ade70fb55..151e4ab9f 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs | |||
| @@ -125,11 +125,11 @@ impl<'a> Transfer<'a> { | |||
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | /// Create a new read DMA transfer (peripheral to memory), using raw pointers. | 127 | /// Create a new read DMA transfer (peripheral to memory), using raw pointers. |
| 128 | pub unsafe fn new_read_raw<W: Word>( | 128 | pub unsafe fn new_read_raw<MW: Word, PW: Word>( |
| 129 | channel: Peri<'a, impl Channel>, | 129 | channel: Peri<'a, impl Channel>, |
| 130 | request: Request, | 130 | request: Request, |
| 131 | peri_addr: *mut W, | 131 | peri_addr: *mut PW, |
| 132 | buf: *mut [W], | 132 | buf: *mut [MW], |
| 133 | options: TransferOptions, | 133 | options: TransferOptions, |
| 134 | ) -> Self { | 134 | ) -> Self { |
| 135 | Self::new_inner( | 135 | Self::new_inner( |
| @@ -137,11 +137,11 @@ impl<'a> Transfer<'a> { | |||
| 137 | request, | 137 | request, |
| 138 | Dir::PeripheralToMemory, | 138 | Dir::PeripheralToMemory, |
| 139 | peri_addr as *const u32, | 139 | peri_addr as *const u32, |
| 140 | buf as *mut W as *mut u32, | 140 | buf as *mut MW as *mut u32, |
| 141 | buf.len(), | 141 | buf.len(), |
| 142 | true, | 142 | true, |
| 143 | W::size(), | 143 | PW::size(), |
| 144 | W::size(), | 144 | MW::size(), |
| 145 | options, | 145 | options, |
| 146 | ) | 146 | ) |
| 147 | } | 147 | } |
diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs index 8bf89e2fe..3245887c1 100644 --- a/embassy-stm32/src/dma/util.rs +++ b/embassy-stm32/src/dma/util.rs | |||
| @@ -20,10 +20,10 @@ impl<'d> ChannelAndRequest<'d> { | |||
| 20 | Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options) | 20 | Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options) |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | pub unsafe fn read_raw<'a, W: Word>( | 23 | pub unsafe fn read_raw<'a, MW: Word, PW: Word>( |
| 24 | &'a mut self, | 24 | &'a mut self, |
| 25 | peri_addr: *mut W, | 25 | peri_addr: *mut PW, |
| 26 | buf: *mut [W], | 26 | buf: *mut [MW], |
| 27 | options: TransferOptions, | 27 | options: TransferOptions, |
| 28 | ) -> Transfer<'a> { | 28 | ) -> Transfer<'a> { |
| 29 | Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options) | 29 | Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options) |
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 01e321bce..b9746231f 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs | |||
| @@ -122,7 +122,10 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 122 | 122 | ||
| 123 | // Select RMII (Reduced Media Independent Interface) | 123 | // Select RMII (Reduced Media Independent Interface) |
| 124 | // Must be done prior to enabling peripheral clock | 124 | // Must be done prior to enabling peripheral clock |
| 125 | AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true)); | 125 | AFIO.mapr().modify(|w| { |
| 126 | w.set_mii_rmii_sel(true); | ||
| 127 | w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP); | ||
| 128 | }); | ||
| 126 | 129 | ||
| 127 | RCC.ahbenr().modify(|w| { | 130 | RCC.ahbenr().modify(|w| { |
| 128 | w.set_ethen(true); | 131 | w.set_ethen(true); |
| @@ -316,7 +319,10 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 316 | 319 | ||
| 317 | // Select MII (Media Independent Interface) | 320 | // Select MII (Media Independent Interface) |
| 318 | // Must be done prior to enabling peripheral clock | 321 | // Must be done prior to enabling peripheral clock |
| 319 | AFIO.mapr().modify(|w| w.set_mii_rmii_sel(false)); | 322 | AFIO.mapr().modify(|w| { |
| 323 | w.set_mii_rmii_sel(false); | ||
| 324 | w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP); | ||
| 325 | }); | ||
| 320 | 326 | ||
| 321 | RCC.ahbenr().modify(|w| { | 327 | RCC.ahbenr().modify(|w| { |
| 322 | w.set_ethen(true); | 328 | w.set_ethen(true); |
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs index 131caa195..6c3d4b422 100644 --- a/embassy-stm32/src/flash/u5.rs +++ b/embassy-stm32/src/flash/u5.rs | |||
| @@ -30,19 +30,19 @@ pub(crate) unsafe fn enable_blocking_write() { | |||
| 30 | 30 | ||
| 31 | #[cfg(feature = "trustzone-secure")] | 31 | #[cfg(feature = "trustzone-secure")] |
| 32 | pac::FLASH.seccr().write(|w| { | 32 | pac::FLASH.seccr().write(|w| { |
| 33 | w.set_pg(pac::flash::vals::SeccrPg::B_0X1); | 33 | w.set_pg(true); |
| 34 | }); | 34 | }); |
| 35 | #[cfg(not(feature = "trustzone-secure"))] | 35 | #[cfg(not(feature = "trustzone-secure"))] |
| 36 | pac::FLASH.nscr().write(|w| { | 36 | pac::FLASH.nscr().write(|w| { |
| 37 | w.set_pg(pac::flash::vals::NscrPg::B_0X1); | 37 | w.set_pg(true); |
| 38 | }); | 38 | }); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | pub(crate) unsafe fn disable_blocking_write() { | 41 | pub(crate) unsafe fn disable_blocking_write() { |
| 42 | #[cfg(feature = "trustzone-secure")] | 42 | #[cfg(feature = "trustzone-secure")] |
| 43 | pac::FLASH.seccr().write(|w| w.set_pg(pac::flash::vals::SeccrPg::B_0X0)); | 43 | pac::FLASH.seccr().write(|w| w.set_pg(false)); |
| 44 | #[cfg(not(feature = "trustzone-secure"))] | 44 | #[cfg(not(feature = "trustzone-secure"))] |
| 45 | pac::FLASH.nscr().write(|w| w.set_pg(pac::flash::vals::NscrPg::B_0X0)); | 45 | pac::FLASH.nscr().write(|w| w.set_pg(false)); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | 48 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { |
| @@ -65,19 +65,19 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 65 | w.set_pnb(sector.index_in_bank); | 65 | w.set_pnb(sector.index_in_bank); |
| 66 | // TODO: add check for bank swap | 66 | // TODO: add check for bank swap |
| 67 | w.set_bker(match sector.bank { | 67 | w.set_bker(match sector.bank { |
| 68 | FlashBank::Bank1 => pac::flash::vals::SeccrBker::B_0X0, | 68 | FlashBank::Bank1 => false, |
| 69 | FlashBank::Bank2 => pac::flash::vals::SeccrBker::B_0X1, | 69 | FlashBank::Bank2 => true, |
| 70 | _ => unreachable!(), | 70 | _ => unreachable!(), |
| 71 | }); | 71 | }); |
| 72 | }); | 72 | }); |
| 73 | #[cfg(not(feature = "trustzone-secure"))] | 73 | #[cfg(not(feature = "trustzone-secure"))] |
| 74 | pac::FLASH.nscr().modify(|w| { | 74 | pac::FLASH.nscr().modify(|w| { |
| 75 | w.set_per(pac::flash::vals::NscrPer::B_0X1); | 75 | w.set_per(true); |
| 76 | w.set_pnb(sector.index_in_bank); | 76 | w.set_pnb(sector.index_in_bank); |
| 77 | // TODO: add check for bank swap | 77 | // TODO: add check for bank swap |
| 78 | w.set_bker(match sector.bank { | 78 | w.set_bker(match sector.bank { |
| 79 | FlashBank::Bank1 => pac::flash::vals::NscrBker::B_0X0, | 79 | FlashBank::Bank1 => false, |
| 80 | FlashBank::Bank2 => pac::flash::vals::NscrBker::B_0X1, | 80 | FlashBank::Bank2 => true, |
| 81 | _ => unreachable!(), | 81 | _ => unreachable!(), |
| 82 | }); | 82 | }); |
| 83 | }); | 83 | }); |
| @@ -93,13 +93,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 93 | 93 | ||
| 94 | let ret: Result<(), Error> = blocking_wait_ready(); | 94 | let ret: Result<(), Error> = blocking_wait_ready(); |
| 95 | #[cfg(feature = "trustzone-secure")] | 95 | #[cfg(feature = "trustzone-secure")] |
| 96 | pac::FLASH | 96 | pac::FLASH.seccr().modify(|w| w.set_per(false)); |
| 97 | .seccr() | ||
| 98 | .modify(|w| w.set_per(pac::flash::vals::SeccrPer::B_0X0)); | ||
| 99 | #[cfg(not(feature = "trustzone-secure"))] | 97 | #[cfg(not(feature = "trustzone-secure"))] |
| 100 | pac::FLASH | 98 | pac::FLASH.nscr().modify(|w| w.set_per(false)); |
| 101 | .nscr() | ||
| 102 | .modify(|w| w.set_per(pac::flash::vals::NscrPer::B_0X0)); | ||
| 103 | clear_all_err(); | 99 | clear_all_err(); |
| 104 | ret | 100 | ret |
| 105 | } | 101 | } |
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs index 31527bcdb..573a1851d 100644 --- a/embassy-stm32/src/hsem/mod.rs +++ b/embassy-stm32/src/hsem/mod.rs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | use embassy_hal_internal::PeripheralType; | 3 | use embassy_hal_internal::PeripheralType; |
| 4 | 4 | ||
| 5 | use crate::pac; | 5 | use crate::pac; |
| 6 | use crate::rcc::RccPeripheral; | 6 | use crate::rcc::{self, RccPeripheral}; |
| 7 | // TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. | 7 | // TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. |
| 8 | // Those MCUs have a different HSEM implementation (Secure semaphore lock support, | 8 | // Those MCUs have a different HSEM implementation (Secure semaphore lock support, |
| 9 | // Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), | 9 | // Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), |
| @@ -46,7 +46,7 @@ pub enum CoreId { | |||
| 46 | #[inline(always)] | 46 | #[inline(always)] |
| 47 | pub fn get_current_coreid() -> CoreId { | 47 | pub fn get_current_coreid() -> CoreId { |
| 48 | let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() }; | 48 | let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() }; |
| 49 | match cpuid & 0x000000F0 { | 49 | match (cpuid & 0x000000F0) >> 4 { |
| 50 | #[cfg(any(stm32wb, stm32wl))] | 50 | #[cfg(any(stm32wb, stm32wl))] |
| 51 | 0x0 => CoreId::Core1, | 51 | 0x0 => CoreId::Core1, |
| 52 | 52 | ||
| @@ -80,6 +80,8 @@ pub struct HardwareSemaphore<'d, T: Instance> { | |||
| 80 | impl<'d, T: Instance> HardwareSemaphore<'d, T> { | 80 | impl<'d, T: Instance> HardwareSemaphore<'d, T> { |
| 81 | /// Creates a new HardwareSemaphore instance. | 81 | /// Creates a new HardwareSemaphore instance. |
| 82 | pub fn new(peripheral: Peri<'d, T>) -> Self { | 82 | pub fn new(peripheral: Peri<'d, T>) -> Self { |
| 83 | rcc::enable_and_reset::<T>(); | ||
| 84 | |||
| 83 | HardwareSemaphore { _peri: peripheral } | 85 | HardwareSemaphore { _peri: peripheral } |
| 84 | } | 86 | } |
| 85 | 87 | ||
diff --git a/embassy-stm32/src/i2c/config.rs b/embassy-stm32/src/i2c/config.rs new file mode 100644 index 000000000..daae43bcd --- /dev/null +++ b/embassy-stm32/src/i2c/config.rs | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | #[cfg(gpio_v2)] | ||
| 2 | use crate::gpio::Pull; | ||
| 3 | use crate::gpio::{AfType, OutputType, Speed}; | ||
| 4 | |||
| 5 | #[repr(u8)] | ||
| 6 | #[derive(Copy, Clone)] | ||
| 7 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 8 | /// Bits of the I2C OA2 register to mask out. | ||
| 9 | pub enum AddrMask { | ||
| 10 | /// No mask | ||
| 11 | NOMASK, | ||
| 12 | /// OA2\[1\] is masked and don’t care. Only OA2\[7:2\] are compared. | ||
| 13 | MASK1, | ||
| 14 | /// OA2\[2:1\] are masked and don’t care. Only OA2\[7:3\] are compared. | ||
| 15 | MASK2, | ||
| 16 | /// OA2\[3:1\] are masked and don’t care. Only OA2\[7:4\] are compared. | ||
| 17 | MASK3, | ||
| 18 | /// OA2\[4:1\] are masked and don’t care. Only OA2\[7:5\] are compared. | ||
| 19 | MASK4, | ||
| 20 | /// OA2\[5:1\] are masked and don’t care. Only OA2\[7:6\] are compared. | ||
| 21 | MASK5, | ||
| 22 | /// OA2\[6:1\] are masked and don’t care. Only OA2\[7:6\] are compared. | ||
| 23 | MASK6, | ||
| 24 | /// OA2\[7:1\] are masked and don’t care. No comparison is done, and all (except reserved) 7-bit received addresses are acknowledged | ||
| 25 | MASK7, | ||
| 26 | } | ||
| 27 | |||
| 28 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 29 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 30 | /// An I2C address. Either 7 or 10 bit. | ||
| 31 | pub enum Address { | ||
| 32 | /// A 7 bit address | ||
| 33 | SevenBit(u8), | ||
| 34 | /// A 10 bit address. | ||
| 35 | /// | ||
| 36 | /// When using an address to configure the Own Address, only the OA1 register can be set to a 10-bit address. | ||
| 37 | TenBit(u16), | ||
| 38 | } | ||
| 39 | impl From<u8> for Address { | ||
| 40 | fn from(value: u8) -> Self { | ||
| 41 | Address::SevenBit(value) | ||
| 42 | } | ||
| 43 | } | ||
| 44 | impl From<u16> for Address { | ||
| 45 | fn from(value: u16) -> Self { | ||
| 46 | assert!(value < 0x400, "Ten bit address must be less than 0x400"); | ||
| 47 | Address::TenBit(value) | ||
| 48 | } | ||
| 49 | } | ||
| 50 | impl Address { | ||
| 51 | /// Get the inner address as a u16. | ||
| 52 | /// | ||
| 53 | /// For 7 bit addresses, the u8 that was used to store the address is returned as a u16. | ||
| 54 | pub fn addr(&self) -> u16 { | ||
| 55 | match self { | ||
| 56 | Address::SevenBit(addr) => *addr as u16, | ||
| 57 | Address::TenBit(addr) => *addr, | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | #[derive(Copy, Clone)] | ||
| 63 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 64 | /// The second Own Address register. | ||
| 65 | pub struct OA2 { | ||
| 66 | /// The address. | ||
| 67 | pub addr: u8, | ||
| 68 | /// The bit mask that will affect how the own address 2 register is compared. | ||
| 69 | pub mask: AddrMask, | ||
| 70 | } | ||
| 71 | |||
| 72 | #[derive(Copy, Clone)] | ||
| 73 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 74 | /// The Own Address(es) of the I2C peripheral. | ||
| 75 | pub enum OwnAddresses { | ||
| 76 | /// Configuration for only the OA1 register. | ||
| 77 | OA1(Address), | ||
| 78 | /// Configuration for only the OA2 register. | ||
| 79 | OA2(OA2), | ||
| 80 | /// Configuration for both the OA1 and OA2 registers. | ||
| 81 | Both { | ||
| 82 | /// The [Address] for the OA1 register. | ||
| 83 | oa1: Address, | ||
| 84 | /// The [OA2] configuration. | ||
| 85 | oa2: OA2, | ||
| 86 | }, | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Slave Configuration | ||
| 90 | #[derive(Copy, Clone)] | ||
| 91 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 92 | pub struct SlaveAddrConfig { | ||
| 93 | /// Target Address(es) | ||
| 94 | pub addr: OwnAddresses, | ||
| 95 | /// Control if the peripheral should respond to the general call address | ||
| 96 | pub general_call: bool, | ||
| 97 | } | ||
| 98 | impl SlaveAddrConfig { | ||
| 99 | /// Create a new slave address configuration with only the OA1 register set in 7 bit mode and the general call disabled. | ||
| 100 | pub fn basic(addr: u8) -> Self { | ||
| 101 | Self { | ||
| 102 | addr: OwnAddresses::OA1(Address::SevenBit(addr)), | ||
| 103 | general_call: false, | ||
| 104 | } | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | /// I2C config | ||
| 109 | #[non_exhaustive] | ||
| 110 | #[derive(Copy, Clone)] | ||
| 111 | pub struct Config { | ||
| 112 | /// Enable internal pullup on SDA. | ||
| 113 | /// | ||
| 114 | /// Using external pullup resistors is recommended for I2C. If you do | ||
| 115 | /// have external pullups you should not enable this. | ||
| 116 | #[cfg(gpio_v2)] | ||
| 117 | pub sda_pullup: bool, | ||
| 118 | /// Enable internal pullup on SCL. | ||
| 119 | /// | ||
| 120 | /// Using external pullup resistors is recommended for I2C. If you do | ||
| 121 | /// have external pullups you should not enable this. | ||
| 122 | #[cfg(gpio_v2)] | ||
| 123 | pub scl_pullup: bool, | ||
| 124 | /// Timeout. | ||
| 125 | #[cfg(feature = "time")] | ||
| 126 | pub timeout: embassy_time::Duration, | ||
| 127 | } | ||
| 128 | |||
| 129 | impl Default for Config { | ||
| 130 | fn default() -> Self { | ||
| 131 | Self { | ||
| 132 | #[cfg(gpio_v2)] | ||
| 133 | sda_pullup: false, | ||
| 134 | #[cfg(gpio_v2)] | ||
| 135 | scl_pullup: false, | ||
| 136 | #[cfg(feature = "time")] | ||
| 137 | timeout: embassy_time::Duration::from_millis(1000), | ||
| 138 | } | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | impl Config { | ||
| 143 | pub(super) fn scl_af(&self) -> AfType { | ||
| 144 | #[cfg(gpio_v1)] | ||
| 145 | return AfType::output(OutputType::OpenDrain, Speed::Medium); | ||
| 146 | #[cfg(gpio_v2)] | ||
| 147 | return AfType::output_pull( | ||
| 148 | OutputType::OpenDrain, | ||
| 149 | Speed::Medium, | ||
| 150 | match self.scl_pullup { | ||
| 151 | true => Pull::Up, | ||
| 152 | false => Pull::Down, | ||
| 153 | }, | ||
| 154 | ); | ||
| 155 | } | ||
| 156 | |||
| 157 | pub(super) fn sda_af(&self) -> AfType { | ||
| 158 | #[cfg(gpio_v1)] | ||
| 159 | return AfType::output(OutputType::OpenDrain, Speed::Medium); | ||
| 160 | #[cfg(gpio_v2)] | ||
| 161 | return AfType::output_pull( | ||
| 162 | OutputType::OpenDrain, | ||
| 163 | Speed::Medium, | ||
| 164 | match self.sda_pullup { | ||
| 165 | true => Pull::Up, | ||
| 166 | false => Pull::Down, | ||
| 167 | }, | ||
| 168 | ); | ||
| 169 | } | ||
| 170 | } | ||
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 1689fdb84..825dd240c 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -5,19 +5,22 @@ | |||
| 5 | #[cfg_attr(any(i2c_v2, i2c_v3), path = "v2.rs")] | 5 | #[cfg_attr(any(i2c_v2, i2c_v3), path = "v2.rs")] |
| 6 | mod _version; | 6 | mod _version; |
| 7 | 7 | ||
| 8 | mod config; | ||
| 9 | |||
| 8 | use core::future::Future; | 10 | use core::future::Future; |
| 9 | use core::iter; | 11 | use core::iter; |
| 10 | use core::marker::PhantomData; | 12 | use core::marker::PhantomData; |
| 11 | 13 | ||
| 14 | pub use config::*; | ||
| 12 | use embassy_hal_internal::Peri; | 15 | use embassy_hal_internal::Peri; |
| 13 | use embassy_sync::waitqueue::AtomicWaker; | 16 | use embassy_sync::waitqueue::AtomicWaker; |
| 14 | #[cfg(feature = "time")] | 17 | #[cfg(feature = "time")] |
| 15 | use embassy_time::{Duration, Instant}; | 18 | use embassy_time::{Duration, Instant}; |
| 19 | use mode::MasterMode; | ||
| 20 | pub use mode::{Master, MultiMaster}; | ||
| 16 | 21 | ||
| 17 | use crate::dma::ChannelAndRequest; | 22 | use crate::dma::ChannelAndRequest; |
| 18 | #[cfg(gpio_v2)] | 23 | use crate::gpio::{AnyPin, SealedPin as _}; |
| 19 | use crate::gpio::Pull; | ||
| 20 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed}; | ||
| 21 | use crate::interrupt::typelevel::Interrupt; | 24 | use crate::interrupt::typelevel::Interrupt; |
| 22 | use crate::mode::{Async, Blocking, Mode}; | 25 | use crate::mode::{Async, Blocking, Mode}; |
| 23 | use crate::rcc::{RccInfo, SealedRccPeripheral}; | 26 | use crate::rcc::{RccInfo, SealedRccPeripheral}; |
| @@ -62,85 +65,89 @@ impl core::fmt::Display for Error { | |||
| 62 | 65 | ||
| 63 | impl core::error::Error for Error {} | 66 | impl core::error::Error for Error {} |
| 64 | 67 | ||
| 65 | /// I2C config | 68 | /// I2C modes |
| 66 | #[non_exhaustive] | 69 | pub mod mode { |
| 67 | #[derive(Copy, Clone)] | 70 | trait SealedMode {} |
| 68 | pub struct Config { | 71 | |
| 69 | /// Enable internal pullup on SDA. | 72 | /// Trait for I2C master operations. |
| 70 | /// | 73 | #[allow(private_bounds)] |
| 71 | /// Using external pullup resistors is recommended for I2C. If you do | 74 | pub trait MasterMode: SealedMode {} |
| 72 | /// have external pullups you should not enable this. | 75 | |
| 73 | #[cfg(gpio_v2)] | 76 | /// Mode allowing for I2C master operations. |
| 74 | pub sda_pullup: bool, | 77 | pub struct Master; |
| 75 | /// Enable internal pullup on SCL. | 78 | /// Mode allowing for I2C master and slave operations. |
| 76 | /// | 79 | pub struct MultiMaster; |
| 77 | /// Using external pullup resistors is recommended for I2C. If you do | 80 | |
| 78 | /// have external pullups you should not enable this. | 81 | impl SealedMode for Master {} |
| 79 | #[cfg(gpio_v2)] | 82 | impl MasterMode for Master {} |
| 80 | pub scl_pullup: bool, | 83 | |
| 81 | /// Timeout. | 84 | impl SealedMode for MultiMaster {} |
| 82 | #[cfg(feature = "time")] | 85 | impl MasterMode for MultiMaster {} |
| 83 | pub timeout: embassy_time::Duration, | ||
| 84 | } | 86 | } |
| 85 | 87 | ||
| 86 | impl Default for Config { | 88 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 87 | fn default() -> Self { | 89 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 88 | Self { | 90 | /// The command kind to the slave from the master |
| 89 | #[cfg(gpio_v2)] | 91 | pub enum SlaveCommandKind { |
| 90 | sda_pullup: false, | 92 | /// Write to the slave |
| 91 | #[cfg(gpio_v2)] | 93 | Write, |
| 92 | scl_pullup: false, | 94 | /// Read from the slave |
| 93 | #[cfg(feature = "time")] | 95 | Read, |
| 94 | timeout: embassy_time::Duration::from_millis(1000), | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | 96 | } |
| 98 | 97 | ||
| 99 | impl Config { | 98 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 100 | fn scl_af(&self) -> AfType { | 99 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 101 | #[cfg(gpio_v1)] | 100 | /// The command kind to the slave from the master and the address that the slave matched |
| 102 | return AfType::output(OutputType::OpenDrain, Speed::Medium); | 101 | pub struct SlaveCommand { |
| 103 | #[cfg(gpio_v2)] | 102 | /// The kind of command |
| 104 | return AfType::output_pull( | 103 | pub kind: SlaveCommandKind, |
| 105 | OutputType::OpenDrain, | 104 | /// The address that the slave matched |
| 106 | Speed::Medium, | 105 | pub address: Address, |
| 107 | match self.scl_pullup { | 106 | } |
| 108 | true => Pull::Up, | ||
| 109 | false => Pull::None, | ||
| 110 | }, | ||
| 111 | ); | ||
| 112 | } | ||
| 113 | 107 | ||
| 114 | fn sda_af(&self) -> AfType { | 108 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 115 | #[cfg(gpio_v1)] | 109 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 116 | return AfType::output(OutputType::OpenDrain, Speed::Medium); | 110 | /// The status of the slave send operation |
| 117 | #[cfg(gpio_v2)] | 111 | pub enum SendStatus { |
| 118 | return AfType::output_pull( | 112 | /// The slave send operation is done, all bytes have been sent and the master is not requesting more |
| 119 | OutputType::OpenDrain, | 113 | Done, |
| 120 | Speed::Medium, | 114 | /// The slave send operation is done, but there are leftover bytes that the master did not read |
| 121 | match self.sda_pullup { | 115 | LeftoverBytes(usize), |
| 122 | true => Pull::Up, | 116 | } |
| 123 | false => Pull::None, | 117 | |
| 124 | }, | 118 | struct I2CDropGuard<'d> { |
| 125 | ); | 119 | info: &'static Info, |
| 120 | scl: Option<Peri<'d, AnyPin>>, | ||
| 121 | sda: Option<Peri<'d, AnyPin>>, | ||
| 122 | } | ||
| 123 | impl<'d> Drop for I2CDropGuard<'d> { | ||
| 124 | fn drop(&mut self) { | ||
| 125 | if let Some(x) = self.scl.as_ref() { | ||
| 126 | x.set_as_disconnected() | ||
| 127 | } | ||
| 128 | if let Some(x) = self.sda.as_ref() { | ||
| 129 | x.set_as_disconnected() | ||
| 130 | } | ||
| 131 | |||
| 132 | self.info.rcc.disable(); | ||
| 126 | } | 133 | } |
| 127 | } | 134 | } |
| 128 | 135 | ||
| 129 | /// I2C driver. | 136 | /// I2C driver. |
| 130 | pub struct I2c<'d, M: Mode> { | 137 | pub struct I2c<'d, M: Mode, IM: MasterMode> { |
| 131 | info: &'static Info, | 138 | info: &'static Info, |
| 132 | state: &'static State, | 139 | state: &'static State, |
| 133 | kernel_clock: Hertz, | 140 | kernel_clock: Hertz, |
| 134 | scl: Option<Peri<'d, AnyPin>>, | ||
| 135 | sda: Option<Peri<'d, AnyPin>>, | ||
| 136 | tx_dma: Option<ChannelAndRequest<'d>>, | 141 | tx_dma: Option<ChannelAndRequest<'d>>, |
| 137 | rx_dma: Option<ChannelAndRequest<'d>>, | 142 | rx_dma: Option<ChannelAndRequest<'d>>, |
| 138 | #[cfg(feature = "time")] | 143 | #[cfg(feature = "time")] |
| 139 | timeout: Duration, | 144 | timeout: Duration, |
| 140 | _phantom: PhantomData<M>, | 145 | _phantom: PhantomData<M>, |
| 146 | _phantom2: PhantomData<IM>, | ||
| 147 | _drop_guard: I2CDropGuard<'d>, | ||
| 141 | } | 148 | } |
| 142 | 149 | ||
| 143 | impl<'d> I2c<'d, Async> { | 150 | impl<'d> I2c<'d, Async, Master> { |
| 144 | /// Create a new I2C driver. | 151 | /// Create a new I2C driver. |
| 145 | pub fn new<T: Instance>( | 152 | pub fn new<T: Instance>( |
| 146 | peri: Peri<'d, T>, | 153 | peri: Peri<'d, T>, |
| @@ -166,7 +173,7 @@ impl<'d> I2c<'d, Async> { | |||
| 166 | } | 173 | } |
| 167 | } | 174 | } |
| 168 | 175 | ||
| 169 | impl<'d> I2c<'d, Blocking> { | 176 | impl<'d> I2c<'d, Blocking, Master> { |
| 170 | /// Create a new blocking I2C driver. | 177 | /// Create a new blocking I2C driver. |
| 171 | pub fn new_blocking<T: Instance>( | 178 | pub fn new_blocking<T: Instance>( |
| 172 | peri: Peri<'d, T>, | 179 | peri: Peri<'d, T>, |
| @@ -187,7 +194,7 @@ impl<'d> I2c<'d, Blocking> { | |||
| 187 | } | 194 | } |
| 188 | } | 195 | } |
| 189 | 196 | ||
| 190 | impl<'d, M: Mode> I2c<'d, M> { | 197 | impl<'d, M: Mode> I2c<'d, M, Master> { |
| 191 | /// Create a new I2C driver. | 198 | /// Create a new I2C driver. |
| 192 | fn new_inner<T: Instance>( | 199 | fn new_inner<T: Instance>( |
| 193 | _peri: Peri<'d, T>, | 200 | _peri: Peri<'d, T>, |
| @@ -205,15 +212,20 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 205 | info: T::info(), | 212 | info: T::info(), |
| 206 | state: T::state(), | 213 | state: T::state(), |
| 207 | kernel_clock: T::frequency(), | 214 | kernel_clock: T::frequency(), |
| 208 | scl, | ||
| 209 | sda, | ||
| 210 | tx_dma, | 215 | tx_dma, |
| 211 | rx_dma, | 216 | rx_dma, |
| 212 | #[cfg(feature = "time")] | 217 | #[cfg(feature = "time")] |
| 213 | timeout: config.timeout, | 218 | timeout: config.timeout, |
| 214 | _phantom: PhantomData, | 219 | _phantom: PhantomData, |
| 220 | _phantom2: PhantomData, | ||
| 221 | _drop_guard: I2CDropGuard { | ||
| 222 | info: T::info(), | ||
| 223 | scl, | ||
| 224 | sda, | ||
| 225 | }, | ||
| 215 | }; | 226 | }; |
| 216 | this.enable_and_init(freq, config); | 227 | this.enable_and_init(freq, config); |
| 228 | |||
| 217 | this | 229 | this |
| 218 | } | 230 | } |
| 219 | 231 | ||
| @@ -221,7 +233,9 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 221 | self.info.rcc.enable_and_reset(); | 233 | self.info.rcc.enable_and_reset(); |
| 222 | self.init(freq, config); | 234 | self.init(freq, config); |
| 223 | } | 235 | } |
| 236 | } | ||
| 224 | 237 | ||
| 238 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | ||
| 225 | fn timeout(&self) -> Timeout { | 239 | fn timeout(&self) -> Timeout { |
| 226 | Timeout { | 240 | Timeout { |
| 227 | #[cfg(feature = "time")] | 241 | #[cfg(feature = "time")] |
| @@ -230,15 +244,6 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 230 | } | 244 | } |
| 231 | } | 245 | } |
| 232 | 246 | ||
| 233 | impl<'d, M: Mode> Drop for I2c<'d, M> { | ||
| 234 | fn drop(&mut self) { | ||
| 235 | self.scl.as_ref().map(|x| x.set_as_disconnected()); | ||
| 236 | self.sda.as_ref().map(|x| x.set_as_disconnected()); | ||
| 237 | |||
| 238 | self.info.rcc.disable() | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | #[derive(Copy, Clone)] | 247 | #[derive(Copy, Clone)] |
| 243 | struct Timeout { | 248 | struct Timeout { |
| 244 | #[cfg(feature = "time")] | 249 | #[cfg(feature = "time")] |
| @@ -347,7 +352,7 @@ foreach_peripheral!( | |||
| 347 | }; | 352 | }; |
| 348 | ); | 353 | ); |
| 349 | 354 | ||
| 350 | impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, M> { | 355 | impl<'d, M: Mode, IM: MasterMode> embedded_hal_02::blocking::i2c::Read for I2c<'d, M, IM> { |
| 351 | type Error = Error; | 356 | type Error = Error; |
| 352 | 357 | ||
| 353 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | 358 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { |
| @@ -355,7 +360,7 @@ impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, M> { | |||
| 355 | } | 360 | } |
| 356 | } | 361 | } |
| 357 | 362 | ||
| 358 | impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, M> { | 363 | impl<'d, M: Mode, IM: MasterMode> embedded_hal_02::blocking::i2c::Write for I2c<'d, M, IM> { |
| 359 | type Error = Error; | 364 | type Error = Error; |
| 360 | 365 | ||
| 361 | fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { | 366 | fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { |
| @@ -363,7 +368,7 @@ impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, M> { | |||
| 363 | } | 368 | } |
| 364 | } | 369 | } |
| 365 | 370 | ||
| 366 | impl<'d, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, M> { | 371 | impl<'d, M: Mode, IM: MasterMode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, M, IM> { |
| 367 | type Error = Error; | 372 | type Error = Error; |
| 368 | 373 | ||
| 369 | fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { | 374 | fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { |
| @@ -387,11 +392,11 @@ impl embedded_hal_1::i2c::Error for Error { | |||
| 387 | } | 392 | } |
| 388 | } | 393 | } |
| 389 | 394 | ||
| 390 | impl<'d, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, M> { | 395 | impl<'d, M: Mode, IM: MasterMode> embedded_hal_1::i2c::ErrorType for I2c<'d, M, IM> { |
| 391 | type Error = Error; | 396 | type Error = Error; |
| 392 | } | 397 | } |
| 393 | 398 | ||
| 394 | impl<'d, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, M> { | 399 | impl<'d, M: Mode, IM: MasterMode> embedded_hal_1::i2c::I2c for I2c<'d, M, IM> { |
| 395 | fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { | 400 | fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { |
| 396 | self.blocking_read(address, read) | 401 | self.blocking_read(address, read) |
| 397 | } | 402 | } |
| @@ -413,7 +418,7 @@ impl<'d, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, M> { | |||
| 413 | } | 418 | } |
| 414 | } | 419 | } |
| 415 | 420 | ||
| 416 | impl<'d> embedded_hal_async::i2c::I2c for I2c<'d, Async> { | 421 | impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> { |
| 417 | async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { | 422 | async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { |
| 418 | self.read(address, read).await | 423 | self.read(address, read).await |
| 419 | } | 424 | } |
| @@ -529,9 +534,7 @@ fn operation_frames<'a, 'b: 'a>( | |||
| 529 | let mut next_first_frame = true; | 534 | let mut next_first_frame = true; |
| 530 | 535 | ||
| 531 | Ok(iter::from_fn(move || { | 536 | Ok(iter::from_fn(move || { |
| 532 | let Some(op) = operations.next() else { | 537 | let op = operations.next()?; |
| 533 | return None; | ||
| 534 | }; | ||
| 535 | 538 | ||
| 536 | // Is `op` first frame of its type? | 539 | // Is `op` first frame of its type? |
| 537 | let first_frame = next_first_frame; | 540 | let first_frame = next_first_frame; |
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 28026f83c..35f13ab46 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -11,6 +11,7 @@ use embassy_embedded_hal::SetConfig; | |||
| 11 | use embassy_futures::select::{select, Either}; | 11 | use embassy_futures::select::{select, Either}; |
| 12 | use embassy_hal_internal::drop::OnDrop; | 12 | use embassy_hal_internal::drop::OnDrop; |
| 13 | use embedded_hal_1::i2c::Operation; | 13 | use embedded_hal_1::i2c::Operation; |
| 14 | use mode::Master; | ||
| 14 | 15 | ||
| 15 | use super::*; | 16 | use super::*; |
| 16 | use crate::mode::Mode as PeriMode; | 17 | use crate::mode::Mode as PeriMode; |
| @@ -41,7 +42,7 @@ pub unsafe fn on_interrupt<T: Instance>() { | |||
| 41 | }); | 42 | }); |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | impl<'d, M: PeriMode> I2c<'d, M> { | 45 | impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { |
| 45 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { | 46 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { |
| 46 | self.info.regs.cr1().modify(|reg| { | 47 | self.info.regs.cr1().modify(|reg| { |
| 47 | reg.set_pe(false); | 48 | reg.set_pe(false); |
| @@ -354,7 +355,7 @@ impl<'d, M: PeriMode> I2c<'d, M> { | |||
| 354 | } | 355 | } |
| 355 | } | 356 | } |
| 356 | 357 | ||
| 357 | impl<'d> I2c<'d, Async> { | 358 | impl<'d, IM: MasterMode> I2c<'d, Async, IM> { |
| 358 | async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { | 359 | async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { |
| 359 | self.info.regs.cr2().modify(|w| { | 360 | self.info.regs.cr2().modify(|w| { |
| 360 | // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for | 361 | // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for |
| @@ -800,7 +801,7 @@ impl Timings { | |||
| 800 | } | 801 | } |
| 801 | } | 802 | } |
| 802 | 803 | ||
| 803 | impl<'d, M: PeriMode> SetConfig for I2c<'d, M> { | 804 | impl<'d, M: PeriMode> SetConfig for I2c<'d, M, Master> { |
| 804 | type Config = Hertz; | 805 | type Config = Hertz; |
| 805 | type ConfigError = (); | 806 | type ConfigError = (); |
| 806 | fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { | 807 | fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 50a25754e..e24cce5c6 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -2,22 +2,87 @@ use core::cmp; | |||
| 2 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use config::{Address, OwnAddresses, OA2}; | ||
| 5 | use embassy_embedded_hal::SetConfig; | 6 | use embassy_embedded_hal::SetConfig; |
| 6 | use embassy_hal_internal::drop::OnDrop; | 7 | use embassy_hal_internal::drop::OnDrop; |
| 7 | use embedded_hal_1::i2c::Operation; | 8 | use embedded_hal_1::i2c::Operation; |
| 9 | use mode::{Master, MultiMaster}; | ||
| 10 | use stm32_metapac::i2c::vals::{Addmode, Oamsk}; | ||
| 8 | 11 | ||
| 9 | use super::*; | 12 | use super::*; |
| 10 | use crate::pac::i2c; | 13 | use crate::pac::i2c; |
| 11 | 14 | ||
| 15 | impl From<AddrMask> for Oamsk { | ||
| 16 | fn from(value: AddrMask) -> Self { | ||
| 17 | match value { | ||
| 18 | AddrMask::NOMASK => Oamsk::NO_MASK, | ||
| 19 | AddrMask::MASK1 => Oamsk::MASK1, | ||
| 20 | AddrMask::MASK2 => Oamsk::MASK2, | ||
| 21 | AddrMask::MASK3 => Oamsk::MASK3, | ||
| 22 | AddrMask::MASK4 => Oamsk::MASK4, | ||
| 23 | AddrMask::MASK5 => Oamsk::MASK5, | ||
| 24 | AddrMask::MASK6 => Oamsk::MASK6, | ||
| 25 | AddrMask::MASK7 => Oamsk::MASK7, | ||
| 26 | } | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | impl Address { | ||
| 31 | pub(super) fn add_mode(&self) -> stm32_metapac::i2c::vals::Addmode { | ||
| 32 | match self { | ||
| 33 | Address::SevenBit(_) => stm32_metapac::i2c::vals::Addmode::BIT7, | ||
| 34 | Address::TenBit(_) => stm32_metapac::i2c::vals::Addmode::BIT10, | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | enum ReceiveResult { | ||
| 40 | DataAvailable, | ||
| 41 | StopReceived, | ||
| 42 | NewStart, | ||
| 43 | } | ||
| 44 | |||
| 45 | fn debug_print_interrupts(isr: stm32_metapac::i2c::regs::Isr) { | ||
| 46 | if isr.tcr() { | ||
| 47 | trace!("interrupt: tcr"); | ||
| 48 | } | ||
| 49 | if isr.tc() { | ||
| 50 | trace!("interrupt: tc"); | ||
| 51 | } | ||
| 52 | if isr.addr() { | ||
| 53 | trace!("interrupt: addr"); | ||
| 54 | } | ||
| 55 | if isr.stopf() { | ||
| 56 | trace!("interrupt: stopf"); | ||
| 57 | } | ||
| 58 | if isr.nackf() { | ||
| 59 | trace!("interrupt: nackf"); | ||
| 60 | } | ||
| 61 | if isr.berr() { | ||
| 62 | trace!("interrupt: berr"); | ||
| 63 | } | ||
| 64 | if isr.arlo() { | ||
| 65 | trace!("interrupt: arlo"); | ||
| 66 | } | ||
| 67 | if isr.ovr() { | ||
| 68 | trace!("interrupt: ovr"); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 12 | pub(crate) unsafe fn on_interrupt<T: Instance>() { | 72 | pub(crate) unsafe fn on_interrupt<T: Instance>() { |
| 13 | let regs = T::info().regs; | 73 | let regs = T::info().regs; |
| 14 | let isr = regs.isr().read(); | 74 | let isr = regs.isr().read(); |
| 15 | 75 | ||
| 16 | if isr.tcr() || isr.tc() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() { | 76 | if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() { |
| 77 | debug_print_interrupts(isr); | ||
| 78 | |||
| 17 | T::state().waker.wake(); | 79 | T::state().waker.wake(); |
| 18 | } | 80 | } |
| 81 | |||
| 19 | critical_section::with(|_| { | 82 | critical_section::with(|_| { |
| 20 | regs.cr1().modify(|w| { | 83 | regs.cr1().modify(|w| { |
| 84 | w.set_addrie(false); | ||
| 85 | w.set_stopie(false); | ||
| 21 | // The flag can only be cleared by writting to nbytes, we won't do that here | 86 | // The flag can only be cleared by writting to nbytes, we won't do that here |
| 22 | w.set_tcie(false); | 87 | w.set_tcie(false); |
| 23 | // Error flags are to be read in the routines, so we also don't clear them here | 88 | // Error flags are to be read in the routines, so we also don't clear them here |
| @@ -27,7 +92,7 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() { | |||
| 27 | }); | 92 | }); |
| 28 | } | 93 | } |
| 29 | 94 | ||
| 30 | impl<'d, M: Mode> I2c<'d, M> { | 95 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { |
| 31 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { | 96 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { |
| 32 | self.info.regs.cr1().modify(|reg| { | 97 | self.info.regs.cr1().modify(|reg| { |
| 33 | reg.set_pe(false); | 98 | reg.set_pe(false); |
| @@ -55,7 +120,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 55 | 120 | ||
| 56 | fn master_read( | 121 | fn master_read( |
| 57 | info: &'static Info, | 122 | info: &'static Info, |
| 58 | address: u8, | 123 | address: Address, |
| 59 | length: usize, | 124 | length: usize, |
| 60 | stop: Stop, | 125 | stop: Stop, |
| 61 | reload: bool, | 126 | reload: bool, |
| @@ -84,8 +149,8 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 84 | }; | 149 | }; |
| 85 | 150 | ||
| 86 | info.regs.cr2().modify(|w| { | 151 | info.regs.cr2().modify(|w| { |
| 87 | w.set_sadd((address << 1 | 0) as u16); | 152 | w.set_sadd(address.addr() << 1); |
| 88 | w.set_add10(i2c::vals::Addmode::BIT7); | 153 | w.set_add10(address.add_mode()); |
| 89 | w.set_dir(i2c::vals::Dir::READ); | 154 | w.set_dir(i2c::vals::Dir::READ); |
| 90 | w.set_nbytes(length as u8); | 155 | w.set_nbytes(length as u8); |
| 91 | w.set_start(true); | 156 | w.set_start(true); |
| @@ -98,7 +163,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 98 | 163 | ||
| 99 | fn master_write( | 164 | fn master_write( |
| 100 | info: &'static Info, | 165 | info: &'static Info, |
| 101 | address: u8, | 166 | address: Address, |
| 102 | length: usize, | 167 | length: usize, |
| 103 | stop: Stop, | 168 | stop: Stop, |
| 104 | reload: bool, | 169 | reload: bool, |
| @@ -128,8 +193,8 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 128 | // START bit can be set even if the bus is BUSY or | 193 | // START bit can be set even if the bus is BUSY or |
| 129 | // I2C is in slave mode. | 194 | // I2C is in slave mode. |
| 130 | info.regs.cr2().modify(|w| { | 195 | info.regs.cr2().modify(|w| { |
| 131 | w.set_sadd((address << 1 | 0) as u16); | 196 | w.set_sadd(address.addr() << 1); |
| 132 | w.set_add10(i2c::vals::Addmode::BIT7); | 197 | w.set_add10(address.add_mode()); |
| 133 | w.set_dir(i2c::vals::Dir::WRITE); | 198 | w.set_dir(i2c::vals::Dir::WRITE); |
| 134 | w.set_nbytes(length as u8); | 199 | w.set_nbytes(length as u8); |
| 135 | w.set_start(true); | 200 | w.set_start(true); |
| @@ -140,14 +205,14 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 140 | Ok(()) | 205 | Ok(()) |
| 141 | } | 206 | } |
| 142 | 207 | ||
| 143 | fn master_continue(info: &'static Info, length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> { | 208 | fn reload(info: &'static Info, length: usize, will_reload: bool, timeout: Timeout) -> Result<(), Error> { |
| 144 | assert!(length < 256 && length > 0); | 209 | assert!(length < 256 && length > 0); |
| 145 | 210 | ||
| 146 | while !info.regs.isr().read().tcr() { | 211 | while !info.regs.isr().read().tcr() { |
| 147 | timeout.check()?; | 212 | timeout.check()?; |
| 148 | } | 213 | } |
| 149 | 214 | ||
| 150 | let reload = if reload { | 215 | let will_reload = if will_reload { |
| 151 | i2c::vals::Reload::NOT_COMPLETED | 216 | i2c::vals::Reload::NOT_COMPLETED |
| 152 | } else { | 217 | } else { |
| 153 | i2c::vals::Reload::COMPLETED | 218 | i2c::vals::Reload::COMPLETED |
| @@ -155,7 +220,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 155 | 220 | ||
| 156 | info.regs.cr2().modify(|w| { | 221 | info.regs.cr2().modify(|w| { |
| 157 | w.set_nbytes(length as u8); | 222 | w.set_nbytes(length as u8); |
| 158 | w.set_reload(reload); | 223 | w.set_reload(will_reload); |
| 159 | }); | 224 | }); |
| 160 | 225 | ||
| 161 | Ok(()) | 226 | Ok(()) |
| @@ -163,49 +228,132 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 163 | 228 | ||
| 164 | fn flush_txdr(&self) { | 229 | fn flush_txdr(&self) { |
| 165 | if self.info.regs.isr().read().txis() { | 230 | if self.info.regs.isr().read().txis() { |
| 166 | self.info.regs.txdr().write(|w| w.set_txdata(0)); | 231 | trace!("Flush TXDATA with zeroes"); |
| 232 | self.info.regs.txdr().modify(|w| w.set_txdata(0)); | ||
| 167 | } | 233 | } |
| 168 | if !self.info.regs.isr().read().txe() { | 234 | if !self.info.regs.isr().read().txe() { |
| 235 | trace!("Flush TXDR"); | ||
| 169 | self.info.regs.isr().modify(|w| w.set_txe(true)) | 236 | self.info.regs.isr().modify(|w| w.set_txe(true)) |
| 170 | } | 237 | } |
| 171 | } | 238 | } |
| 172 | 239 | ||
| 173 | fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> { | 240 | fn error_occurred(&self, isr: &i2c::regs::Isr, timeout: Timeout) -> Result<(), Error> { |
| 241 | if isr.nackf() { | ||
| 242 | trace!("NACK triggered."); | ||
| 243 | self.info.regs.icr().modify(|reg| reg.set_nackcf(true)); | ||
| 244 | // NACK should be followed by STOP | ||
| 245 | if let Ok(()) = self.wait_stop(timeout) { | ||
| 246 | trace!("Got STOP after NACK, clearing flag."); | ||
| 247 | self.info.regs.icr().modify(|reg| reg.set_stopcf(true)); | ||
| 248 | } | ||
| 249 | self.flush_txdr(); | ||
| 250 | return Err(Error::Nack); | ||
| 251 | } else if isr.berr() { | ||
| 252 | trace!("BERR triggered."); | ||
| 253 | self.info.regs.icr().modify(|reg| reg.set_berrcf(true)); | ||
| 254 | self.flush_txdr(); | ||
| 255 | return Err(Error::Bus); | ||
| 256 | } else if isr.arlo() { | ||
| 257 | trace!("ARLO triggered."); | ||
| 258 | self.info.regs.icr().modify(|reg| reg.set_arlocf(true)); | ||
| 259 | self.flush_txdr(); | ||
| 260 | return Err(Error::Arbitration); | ||
| 261 | } else if isr.ovr() { | ||
| 262 | trace!("OVR triggered."); | ||
| 263 | self.info.regs.icr().modify(|reg| reg.set_ovrcf(true)); | ||
| 264 | return Err(Error::Overrun); | ||
| 265 | } | ||
| 266 | return Ok(()); | ||
| 267 | } | ||
| 268 | |||
| 269 | fn wait_txis(&self, timeout: Timeout) -> Result<(), Error> { | ||
| 270 | let mut first_loop = true; | ||
| 271 | |||
| 174 | loop { | 272 | loop { |
| 175 | let isr = self.info.regs.isr().read(); | 273 | let isr = self.info.regs.isr().read(); |
| 176 | if isr.txe() { | 274 | self.error_occurred(&isr, timeout)?; |
| 275 | if isr.txis() { | ||
| 276 | trace!("TXIS"); | ||
| 177 | return Ok(()); | 277 | return Ok(()); |
| 178 | } else if isr.berr() { | ||
| 179 | self.info.regs.icr().write(|reg| reg.set_berrcf(true)); | ||
| 180 | return Err(Error::Bus); | ||
| 181 | } else if isr.arlo() { | ||
| 182 | self.info.regs.icr().write(|reg| reg.set_arlocf(true)); | ||
| 183 | return Err(Error::Arbitration); | ||
| 184 | } else if isr.nackf() { | ||
| 185 | self.info.regs.icr().write(|reg| reg.set_nackcf(true)); | ||
| 186 | self.flush_txdr(); | ||
| 187 | return Err(Error::Nack); | ||
| 188 | } | 278 | } |
| 189 | 279 | ||
| 280 | { | ||
| 281 | if first_loop { | ||
| 282 | trace!("Waiting for TXIS..."); | ||
| 283 | first_loop = false; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | timeout.check()?; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | fn wait_stop_or_err(&self, timeout: Timeout) -> Result<(), Error> { | ||
| 291 | loop { | ||
| 292 | let isr = self.info.regs.isr().read(); | ||
| 293 | self.error_occurred(&isr, timeout)?; | ||
| 294 | if isr.stopf() { | ||
| 295 | trace!("STOP triggered."); | ||
| 296 | self.info.regs.icr().modify(|reg| reg.set_stopcf(true)); | ||
| 297 | return Ok(()); | ||
| 298 | } | ||
| 299 | timeout.check()?; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | fn wait_stop(&self, timeout: Timeout) -> Result<(), Error> { | ||
| 303 | loop { | ||
| 304 | let isr = self.info.regs.isr().read(); | ||
| 305 | if isr.stopf() { | ||
| 306 | trace!("STOP triggered."); | ||
| 307 | self.info.regs.icr().modify(|reg| reg.set_stopcf(true)); | ||
| 308 | return Ok(()); | ||
| 309 | } | ||
| 190 | timeout.check()?; | 310 | timeout.check()?; |
| 191 | } | 311 | } |
| 192 | } | 312 | } |
| 193 | 313 | ||
| 194 | fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> { | 314 | fn wait_af(&self, timeout: Timeout) -> Result<(), Error> { |
| 195 | loop { | 315 | loop { |
| 196 | let isr = self.info.regs.isr().read(); | 316 | let isr = self.info.regs.isr().read(); |
| 197 | if isr.rxne() { | 317 | if isr.nackf() { |
| 318 | trace!("AF triggered."); | ||
| 319 | self.info.regs.icr().modify(|reg| reg.set_nackcf(true)); | ||
| 198 | return Ok(()); | 320 | return Ok(()); |
| 199 | } else if isr.berr() { | 321 | } |
| 200 | self.info.regs.icr().write(|reg| reg.set_berrcf(true)); | 322 | timeout.check()?; |
| 201 | return Err(Error::Bus); | 323 | } |
| 202 | } else if isr.arlo() { | 324 | } |
| 203 | self.info.regs.icr().write(|reg| reg.set_arlocf(true)); | 325 | |
| 204 | return Err(Error::Arbitration); | 326 | fn wait_rxne(&self, timeout: Timeout) -> Result<ReceiveResult, Error> { |
| 205 | } else if isr.nackf() { | 327 | let mut first_loop = true; |
| 206 | self.info.regs.icr().write(|reg| reg.set_nackcf(true)); | 328 | |
| 207 | self.flush_txdr(); | 329 | loop { |
| 208 | return Err(Error::Nack); | 330 | let isr = self.info.regs.isr().read(); |
| 331 | self.error_occurred(&isr, timeout)?; | ||
| 332 | if isr.stopf() { | ||
| 333 | trace!("STOP when waiting for RXNE."); | ||
| 334 | if self.info.regs.isr().read().rxne() { | ||
| 335 | trace!("Data received with STOP."); | ||
| 336 | return Ok(ReceiveResult::DataAvailable); | ||
| 337 | } | ||
| 338 | trace!("STOP triggered without data."); | ||
| 339 | return Ok(ReceiveResult::StopReceived); | ||
| 340 | } else if isr.rxne() { | ||
| 341 | trace!("RXNE."); | ||
| 342 | return Ok(ReceiveResult::DataAvailable); | ||
| 343 | } else if isr.addr() { | ||
| 344 | // Another addr event received, which means START was sent again | ||
| 345 | // which happens when accessing memory registers (common i2c interface design) | ||
| 346 | // e.g. master sends: START, write 1 byte (register index), START, read N bytes (until NACK) | ||
| 347 | // Possible to receive this flag at the same time as rxne, so check rxne first | ||
| 348 | trace!("START when waiting for RXNE. Ending receive loop."); | ||
| 349 | // Return without clearing ADDR so `listen` can catch it | ||
| 350 | return Ok(ReceiveResult::NewStart); | ||
| 351 | } | ||
| 352 | { | ||
| 353 | if first_loop { | ||
| 354 | trace!("Waiting for RXNE..."); | ||
| 355 | first_loop = false; | ||
| 356 | } | ||
| 209 | } | 357 | } |
| 210 | 358 | ||
| 211 | timeout.check()?; | 359 | timeout.check()?; |
| @@ -215,25 +363,21 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 215 | fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> { | 363 | fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> { |
| 216 | loop { | 364 | loop { |
| 217 | let isr = self.info.regs.isr().read(); | 365 | let isr = self.info.regs.isr().read(); |
| 366 | self.error_occurred(&isr, timeout)?; | ||
| 218 | if isr.tc() { | 367 | if isr.tc() { |
| 219 | return Ok(()); | 368 | return Ok(()); |
| 220 | } else if isr.berr() { | ||
| 221 | self.info.regs.icr().write(|reg| reg.set_berrcf(true)); | ||
| 222 | return Err(Error::Bus); | ||
| 223 | } else if isr.arlo() { | ||
| 224 | self.info.regs.icr().write(|reg| reg.set_arlocf(true)); | ||
| 225 | return Err(Error::Arbitration); | ||
| 226 | } else if isr.nackf() { | ||
| 227 | self.info.regs.icr().write(|reg| reg.set_nackcf(true)); | ||
| 228 | self.flush_txdr(); | ||
| 229 | return Err(Error::Nack); | ||
| 230 | } | 369 | } |
| 231 | |||
| 232 | timeout.check()?; | 370 | timeout.check()?; |
| 233 | } | 371 | } |
| 234 | } | 372 | } |
| 235 | 373 | ||
| 236 | fn read_internal(&mut self, address: u8, read: &mut [u8], restart: bool, timeout: Timeout) -> Result<(), Error> { | 374 | fn read_internal( |
| 375 | &mut self, | ||
| 376 | address: Address, | ||
| 377 | read: &mut [u8], | ||
| 378 | restart: bool, | ||
| 379 | timeout: Timeout, | ||
| 380 | ) -> Result<(), Error> { | ||
| 237 | let completed_chunks = read.len() / 255; | 381 | let completed_chunks = read.len() / 255; |
| 238 | let total_chunks = if completed_chunks * 255 == read.len() { | 382 | let total_chunks = if completed_chunks * 255 == read.len() { |
| 239 | completed_chunks | 383 | completed_chunks |
| @@ -254,7 +398,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 254 | 398 | ||
| 255 | for (number, chunk) in read.chunks_mut(255).enumerate() { | 399 | for (number, chunk) in read.chunks_mut(255).enumerate() { |
| 256 | if number != 0 { | 400 | if number != 0 { |
| 257 | Self::master_continue(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | 401 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; |
| 258 | } | 402 | } |
| 259 | 403 | ||
| 260 | for byte in chunk { | 404 | for byte in chunk { |
| @@ -267,7 +411,13 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 267 | Ok(()) | 411 | Ok(()) |
| 268 | } | 412 | } |
| 269 | 413 | ||
| 270 | fn write_internal(&mut self, address: u8, write: &[u8], send_stop: bool, timeout: Timeout) -> Result<(), Error> { | 414 | fn write_internal( |
| 415 | &mut self, | ||
| 416 | address: Address, | ||
| 417 | write: &[u8], | ||
| 418 | send_stop: bool, | ||
| 419 | timeout: Timeout, | ||
| 420 | ) -> Result<(), Error> { | ||
| 271 | let completed_chunks = write.len() / 255; | 421 | let completed_chunks = write.len() / 255; |
| 272 | let total_chunks = if completed_chunks * 255 == write.len() { | 422 | let total_chunks = if completed_chunks * 255 == write.len() { |
| 273 | completed_chunks | 423 | completed_chunks |
| @@ -295,14 +445,14 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 295 | 445 | ||
| 296 | for (number, chunk) in write.chunks(255).enumerate() { | 446 | for (number, chunk) in write.chunks(255).enumerate() { |
| 297 | if number != 0 { | 447 | if number != 0 { |
| 298 | Self::master_continue(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | 448 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; |
| 299 | } | 449 | } |
| 300 | 450 | ||
| 301 | for byte in chunk { | 451 | for byte in chunk { |
| 302 | // Wait until we are allowed to send data | 452 | // Wait until we are allowed to send data |
| 303 | // (START has been ACKed or last byte when | 453 | // (START has been ACKed or last byte when |
| 304 | // through) | 454 | // through) |
| 305 | if let Err(err) = self.wait_txe(timeout) { | 455 | if let Err(err) = self.wait_txis(timeout) { |
| 306 | if send_stop { | 456 | if send_stop { |
| 307 | self.master_stop(); | 457 | self.master_stop(); |
| 308 | } | 458 | } |
| @@ -325,20 +475,20 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 325 | 475 | ||
| 326 | /// Blocking read. | 476 | /// Blocking read. |
| 327 | pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { | 477 | pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { |
| 328 | self.read_internal(address, read, false, self.timeout()) | 478 | self.read_internal(address.into(), read, false, self.timeout()) |
| 329 | // Automatic Stop | 479 | // Automatic Stop |
| 330 | } | 480 | } |
| 331 | 481 | ||
| 332 | /// Blocking write. | 482 | /// Blocking write. |
| 333 | pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { | 483 | pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |
| 334 | self.write_internal(address, write, true, self.timeout()) | 484 | self.write_internal(address.into(), write, true, self.timeout()) |
| 335 | } | 485 | } |
| 336 | 486 | ||
| 337 | /// Blocking write, restart, read. | 487 | /// Blocking write, restart, read. |
| 338 | pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | 488 | pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
| 339 | let timeout = self.timeout(); | 489 | let timeout = self.timeout(); |
| 340 | self.write_internal(address, write, false, timeout)?; | 490 | self.write_internal(address.into(), write, false, timeout)?; |
| 341 | self.read_internal(address, read, true, timeout) | 491 | self.read_internal(address.into(), read, true, timeout) |
| 342 | // Automatic Stop | 492 | // Automatic Stop |
| 343 | } | 493 | } |
| 344 | 494 | ||
| @@ -368,7 +518,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 368 | 518 | ||
| 369 | if let Err(err) = Self::master_write( | 519 | if let Err(err) = Self::master_write( |
| 370 | self.info, | 520 | self.info, |
| 371 | address, | 521 | address.into(), |
| 372 | first_length.min(255), | 522 | first_length.min(255), |
| 373 | Stop::Software, | 523 | Stop::Software, |
| 374 | (first_length > 255) || (last_slice_index != 0), | 524 | (first_length > 255) || (last_slice_index != 0), |
| @@ -389,7 +539,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 389 | let last_chunk_idx = total_chunks.saturating_sub(1); | 539 | let last_chunk_idx = total_chunks.saturating_sub(1); |
| 390 | 540 | ||
| 391 | if idx != 0 { | 541 | if idx != 0 { |
| 392 | if let Err(err) = Self::master_continue( | 542 | if let Err(err) = Self::reload( |
| 393 | self.info, | 543 | self.info, |
| 394 | slice_len.min(255), | 544 | slice_len.min(255), |
| 395 | (idx != last_slice_index) || (slice_len > 255), | 545 | (idx != last_slice_index) || (slice_len > 255), |
| @@ -402,7 +552,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 402 | 552 | ||
| 403 | for (number, chunk) in slice.chunks(255).enumerate() { | 553 | for (number, chunk) in slice.chunks(255).enumerate() { |
| 404 | if number != 0 { | 554 | if number != 0 { |
| 405 | if let Err(err) = Self::master_continue( | 555 | if let Err(err) = Self::reload( |
| 406 | self.info, | 556 | self.info, |
| 407 | chunk.len(), | 557 | chunk.len(), |
| 408 | (number != last_chunk_idx) || (idx != last_slice_index), | 558 | (number != last_chunk_idx) || (idx != last_slice_index), |
| @@ -417,7 +567,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 417 | // Wait until we are allowed to send data | 567 | // Wait until we are allowed to send data |
| 418 | // (START has been ACKed or last byte when | 568 | // (START has been ACKed or last byte when |
| 419 | // through) | 569 | // through) |
| 420 | if let Err(err) = self.wait_txe(timeout) { | 570 | if let Err(err) = self.wait_txis(timeout) { |
| 421 | self.master_stop(); | 571 | self.master_stop(); |
| 422 | return Err(err); | 572 | return Err(err); |
| 423 | } | 573 | } |
| @@ -435,10 +585,10 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 435 | } | 585 | } |
| 436 | } | 586 | } |
| 437 | 587 | ||
| 438 | impl<'d> I2c<'d, Async> { | 588 | impl<'d, IM: MasterMode> I2c<'d, Async, IM> { |
| 439 | async fn write_dma_internal( | 589 | async fn write_dma_internal( |
| 440 | &mut self, | 590 | &mut self, |
| 441 | address: u8, | 591 | address: Address, |
| 442 | write: &[u8], | 592 | write: &[u8], |
| 443 | first_slice: bool, | 593 | first_slice: bool, |
| 444 | last_slice: bool, | 594 | last_slice: bool, |
| @@ -512,7 +662,7 @@ impl<'d> I2c<'d, Async> { | |||
| 512 | timeout, | 662 | timeout, |
| 513 | )?; | 663 | )?; |
| 514 | } else { | 664 | } else { |
| 515 | Self::master_continue(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; | 665 | Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; |
| 516 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); | 666 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); |
| 517 | } | 667 | } |
| 518 | } else if !(isr.tcr() || isr.tc()) { | 668 | } else if !(isr.tcr() || isr.tc()) { |
| @@ -523,7 +673,7 @@ impl<'d> I2c<'d, Async> { | |||
| 523 | } else { | 673 | } else { |
| 524 | let last_piece = (remaining_len <= 255) && last_slice; | 674 | let last_piece = (remaining_len <= 255) && last_slice; |
| 525 | 675 | ||
| 526 | if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) { | 676 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { |
| 527 | return Poll::Ready(Err(e)); | 677 | return Poll::Ready(Err(e)); |
| 528 | } | 678 | } |
| 529 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); | 679 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); |
| @@ -551,7 +701,7 @@ impl<'d> I2c<'d, Async> { | |||
| 551 | 701 | ||
| 552 | async fn read_dma_internal( | 702 | async fn read_dma_internal( |
| 553 | &mut self, | 703 | &mut self, |
| 554 | address: u8, | 704 | address: Address, |
| 555 | buffer: &mut [u8], | 705 | buffer: &mut [u8], |
| 556 | restart: bool, | 706 | restart: bool, |
| 557 | timeout: Timeout, | 707 | timeout: Timeout, |
| @@ -626,7 +776,7 @@ impl<'d> I2c<'d, Async> { | |||
| 626 | } else { | 776 | } else { |
| 627 | let last_piece = remaining_len <= 255; | 777 | let last_piece = remaining_len <= 255; |
| 628 | 778 | ||
| 629 | if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) { | 779 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { |
| 630 | return Poll::Ready(Err(e)); | 780 | return Poll::Ready(Err(e)); |
| 631 | } | 781 | } |
| 632 | // Return here if we are on last chunk, | 782 | // Return here if we are on last chunk, |
| @@ -647,7 +797,6 @@ impl<'d> I2c<'d, Async> { | |||
| 647 | 797 | ||
| 648 | Ok(()) | 798 | Ok(()) |
| 649 | } | 799 | } |
| 650 | |||
| 651 | // ========================= | 800 | // ========================= |
| 652 | // Async public API | 801 | // Async public API |
| 653 | 802 | ||
| @@ -655,10 +804,10 @@ impl<'d> I2c<'d, Async> { | |||
| 655 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { | 804 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |
| 656 | let timeout = self.timeout(); | 805 | let timeout = self.timeout(); |
| 657 | if write.is_empty() { | 806 | if write.is_empty() { |
| 658 | self.write_internal(address, write, true, timeout) | 807 | self.write_internal(address.into(), write, true, timeout) |
| 659 | } else { | 808 | } else { |
| 660 | timeout | 809 | timeout |
| 661 | .with(self.write_dma_internal(address, write, true, true, true, timeout)) | 810 | .with(self.write_dma_internal(address.into(), write, true, true, true, timeout)) |
| 662 | .await | 811 | .await |
| 663 | } | 812 | } |
| 664 | } | 813 | } |
| @@ -666,7 +815,7 @@ impl<'d> I2c<'d, Async> { | |||
| 666 | /// Write multiple buffers. | 815 | /// Write multiple buffers. |
| 667 | /// | 816 | /// |
| 668 | /// The buffers are concatenated in a single write transaction. | 817 | /// The buffers are concatenated in a single write transaction. |
| 669 | pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { | 818 | pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { |
| 670 | let timeout = self.timeout(); | 819 | let timeout = self.timeout(); |
| 671 | 820 | ||
| 672 | if write.is_empty() { | 821 | if write.is_empty() { |
| @@ -693,9 +842,9 @@ impl<'d> I2c<'d, Async> { | |||
| 693 | let timeout = self.timeout(); | 842 | let timeout = self.timeout(); |
| 694 | 843 | ||
| 695 | if buffer.is_empty() { | 844 | if buffer.is_empty() { |
| 696 | self.read_internal(address, buffer, false, timeout) | 845 | self.read_internal(address.into(), buffer, false, timeout) |
| 697 | } else { | 846 | } else { |
| 698 | let fut = self.read_dma_internal(address, buffer, false, timeout); | 847 | let fut = self.read_dma_internal(address.into(), buffer, false, timeout); |
| 699 | timeout.with(fut).await | 848 | timeout.with(fut).await |
| 700 | } | 849 | } |
| 701 | } | 850 | } |
| @@ -705,16 +854,16 @@ impl<'d> I2c<'d, Async> { | |||
| 705 | let timeout = self.timeout(); | 854 | let timeout = self.timeout(); |
| 706 | 855 | ||
| 707 | if write.is_empty() { | 856 | if write.is_empty() { |
| 708 | self.write_internal(address, write, false, timeout)?; | 857 | self.write_internal(address.into(), write, false, timeout)?; |
| 709 | } else { | 858 | } else { |
| 710 | let fut = self.write_dma_internal(address, write, true, true, false, timeout); | 859 | let fut = self.write_dma_internal(address.into(), write, true, true, false, timeout); |
| 711 | timeout.with(fut).await?; | 860 | timeout.with(fut).await?; |
| 712 | } | 861 | } |
| 713 | 862 | ||
| 714 | if read.is_empty() { | 863 | if read.is_empty() { |
| 715 | self.read_internal(address, read, true, timeout)?; | 864 | self.read_internal(address.into(), read, true, timeout)?; |
| 716 | } else { | 865 | } else { |
| 717 | let fut = self.read_dma_internal(address, read, true, timeout); | 866 | let fut = self.read_dma_internal(address.into(), read, true, timeout); |
| 718 | timeout.with(fut).await?; | 867 | timeout.with(fut).await?; |
| 719 | } | 868 | } |
| 720 | 869 | ||
| @@ -733,6 +882,414 @@ impl<'d> I2c<'d, Async> { | |||
| 733 | } | 882 | } |
| 734 | } | 883 | } |
| 735 | 884 | ||
| 885 | impl<'d, M: Mode> I2c<'d, M, Master> { | ||
| 886 | /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster) | ||
| 887 | pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> { | ||
| 888 | let mut slave = I2c { | ||
| 889 | info: self.info, | ||
| 890 | state: self.state, | ||
| 891 | kernel_clock: self.kernel_clock, | ||
| 892 | tx_dma: self.tx_dma.take(), | ||
| 893 | rx_dma: self.rx_dma.take(), | ||
| 894 | #[cfg(feature = "time")] | ||
| 895 | timeout: self.timeout, | ||
| 896 | _phantom: PhantomData, | ||
| 897 | _phantom2: PhantomData, | ||
| 898 | _drop_guard: self._drop_guard, | ||
| 899 | }; | ||
| 900 | slave.init_slave(slave_addr_config); | ||
| 901 | slave | ||
| 902 | } | ||
| 903 | } | ||
| 904 | |||
| 905 | impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | ||
| 906 | pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { | ||
| 907 | self.info.regs.cr1().modify(|reg| { | ||
| 908 | reg.set_pe(false); | ||
| 909 | }); | ||
| 910 | |||
| 911 | self.info.regs.cr1().modify(|reg| { | ||
| 912 | reg.set_nostretch(false); | ||
| 913 | reg.set_gcen(config.general_call); | ||
| 914 | reg.set_sbc(true); | ||
| 915 | reg.set_pe(true); | ||
| 916 | }); | ||
| 917 | |||
| 918 | self.reconfigure_addresses(config.addr); | ||
| 919 | } | ||
| 920 | |||
| 921 | /// Configure the slave address. | ||
| 922 | pub fn reconfigure_addresses(&mut self, addresses: OwnAddresses) { | ||
| 923 | match addresses { | ||
| 924 | OwnAddresses::OA1(oa1) => self.configure_oa1(oa1), | ||
| 925 | OwnAddresses::OA2(oa2) => self.configure_oa2(oa2), | ||
| 926 | OwnAddresses::Both { oa1, oa2 } => { | ||
| 927 | self.configure_oa1(oa1); | ||
| 928 | self.configure_oa2(oa2); | ||
| 929 | } | ||
| 930 | } | ||
| 931 | } | ||
| 932 | |||
| 933 | fn configure_oa1(&mut self, oa1: Address) { | ||
| 934 | match oa1 { | ||
| 935 | Address::SevenBit(addr) => self.info.regs.oar1().write(|reg| { | ||
| 936 | reg.set_oa1en(false); | ||
| 937 | reg.set_oa1((addr << 1) as u16); | ||
| 938 | reg.set_oa1mode(Addmode::BIT7); | ||
| 939 | reg.set_oa1en(true); | ||
| 940 | }), | ||
| 941 | Address::TenBit(addr) => self.info.regs.oar1().write(|reg| { | ||
| 942 | reg.set_oa1en(false); | ||
| 943 | reg.set_oa1(addr); | ||
| 944 | reg.set_oa1mode(Addmode::BIT10); | ||
| 945 | reg.set_oa1en(true); | ||
| 946 | }), | ||
| 947 | } | ||
| 948 | } | ||
| 949 | |||
| 950 | fn configure_oa2(&mut self, oa2: OA2) { | ||
| 951 | self.info.regs.oar2().write(|reg| { | ||
| 952 | reg.set_oa2en(false); | ||
| 953 | reg.set_oa2msk(oa2.mask.into()); | ||
| 954 | reg.set_oa2(oa2.addr << 1); | ||
| 955 | reg.set_oa2en(true); | ||
| 956 | }); | ||
| 957 | } | ||
| 958 | |||
| 959 | fn determine_matched_address(&self) -> Result<Address, Error> { | ||
| 960 | let matched = self.info.regs.isr().read().addcode(); | ||
| 961 | |||
| 962 | if matched >> 3 == 0b11110 { | ||
| 963 | // is 10-bit address and we need to get the other 8 bits from the rxdr | ||
| 964 | // we do this by doing a blocking read of 1 byte | ||
| 965 | let mut buffer = [0]; | ||
| 966 | self.slave_read_internal(&mut buffer, self.timeout())?; | ||
| 967 | Ok(Address::TenBit((matched as u16) << 6 | buffer[0] as u16)) | ||
| 968 | } else { | ||
| 969 | Ok(Address::SevenBit(matched)) | ||
| 970 | } | ||
| 971 | } | ||
| 972 | } | ||
| 973 | |||
| 974 | impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | ||
| 975 | /// # Safety | ||
| 976 | /// This function will clear the address flag which will stop the clock stretching. | ||
| 977 | /// This should only be done after the dma transfer has been set up. | ||
| 978 | fn slave_start(info: &'static Info, length: usize, reload: bool) { | ||
| 979 | assert!(length < 256); | ||
| 980 | |||
| 981 | let reload = if reload { | ||
| 982 | i2c::vals::Reload::NOT_COMPLETED | ||
| 983 | } else { | ||
| 984 | i2c::vals::Reload::COMPLETED | ||
| 985 | }; | ||
| 986 | |||
| 987 | info.regs.cr2().modify(|w| { | ||
| 988 | w.set_nbytes(length as u8); | ||
| 989 | w.set_reload(reload); | ||
| 990 | }); | ||
| 991 | |||
| 992 | // clear the address flag, will stop the clock stretching. | ||
| 993 | // this should only be done after the dma transfer has been set up. | ||
| 994 | info.regs.icr().modify(|reg| reg.set_addrcf(true)); | ||
| 995 | trace!("ADDRCF cleared (ADDR interrupt enabled, clock stretching ended)"); | ||
| 996 | } | ||
| 997 | |||
| 998 | // A blocking read operation | ||
| 999 | fn slave_read_internal(&self, read: &mut [u8], timeout: Timeout) -> Result<usize, Error> { | ||
| 1000 | let completed_chunks = read.len() / 255; | ||
| 1001 | let total_chunks = if completed_chunks * 255 == read.len() { | ||
| 1002 | completed_chunks | ||
| 1003 | } else { | ||
| 1004 | completed_chunks + 1 | ||
| 1005 | }; | ||
| 1006 | let last_chunk_idx = total_chunks.saturating_sub(1); | ||
| 1007 | let total_len = read.len(); | ||
| 1008 | let mut remaining_len = total_len; | ||
| 1009 | |||
| 1010 | for (number, chunk) in read.chunks_mut(255).enumerate() { | ||
| 1011 | trace!( | ||
| 1012 | "--- Slave RX transmission start - chunk: {}, expected (max) size: {}", | ||
| 1013 | number, | ||
| 1014 | chunk.len() | ||
| 1015 | ); | ||
| 1016 | if number == 0 { | ||
| 1017 | Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); | ||
| 1018 | } else { | ||
| 1019 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | let mut index = 0; | ||
| 1023 | |||
| 1024 | for byte in chunk { | ||
| 1025 | // Wait until we have received something | ||
| 1026 | match self.wait_rxne(timeout) { | ||
| 1027 | Ok(ReceiveResult::StopReceived) | Ok(ReceiveResult::NewStart) => { | ||
| 1028 | trace!("--- Slave RX transmission end (early)"); | ||
| 1029 | return Ok(total_len - remaining_len); // Return N bytes read | ||
| 1030 | } | ||
| 1031 | Ok(ReceiveResult::DataAvailable) => { | ||
| 1032 | *byte = self.info.regs.rxdr().read().rxdata(); | ||
| 1033 | remaining_len = remaining_len.saturating_sub(1); | ||
| 1034 | { | ||
| 1035 | trace!("Slave RX data {}: {:#04x}", index, byte); | ||
| 1036 | index = index + 1; | ||
| 1037 | } | ||
| 1038 | } | ||
| 1039 | Err(e) => return Err(e), | ||
| 1040 | }; | ||
| 1041 | } | ||
| 1042 | } | ||
| 1043 | self.wait_stop_or_err(timeout)?; | ||
| 1044 | |||
| 1045 | trace!("--- Slave RX transmission end"); | ||
| 1046 | Ok(total_len - remaining_len) // Return N bytes read | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | // A blocking write operation | ||
| 1050 | fn slave_write_internal(&mut self, write: &[u8], timeout: Timeout) -> Result<(), Error> { | ||
| 1051 | let completed_chunks = write.len() / 255; | ||
| 1052 | let total_chunks = if completed_chunks * 255 == write.len() { | ||
| 1053 | completed_chunks | ||
| 1054 | } else { | ||
| 1055 | completed_chunks + 1 | ||
| 1056 | }; | ||
| 1057 | let last_chunk_idx = total_chunks.saturating_sub(1); | ||
| 1058 | |||
| 1059 | for (number, chunk) in write.chunks(255).enumerate() { | ||
| 1060 | trace!( | ||
| 1061 | "--- Slave TX transmission start - chunk: {}, size: {}", | ||
| 1062 | number, | ||
| 1063 | chunk.len() | ||
| 1064 | ); | ||
| 1065 | if number == 0 { | ||
| 1066 | Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); | ||
| 1067 | } else { | ||
| 1068 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | let mut index = 0; | ||
| 1072 | |||
| 1073 | for byte in chunk { | ||
| 1074 | // Wait until we are allowed to send data | ||
| 1075 | // (START has been ACKed or last byte when through) | ||
| 1076 | self.wait_txis(timeout)?; | ||
| 1077 | |||
| 1078 | { | ||
| 1079 | trace!("Slave TX data {}: {:#04x}", index, byte); | ||
| 1080 | index = index + 1; | ||
| 1081 | } | ||
| 1082 | self.info.regs.txdr().write(|w| w.set_txdata(*byte)); | ||
| 1083 | } | ||
| 1084 | } | ||
| 1085 | self.wait_af(timeout)?; | ||
| 1086 | self.flush_txdr(); | ||
| 1087 | self.wait_stop_or_err(timeout)?; | ||
| 1088 | |||
| 1089 | trace!("--- Slave TX transmission end"); | ||
| 1090 | Ok(()) | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | /// Listen for incoming I2C messages. | ||
| 1094 | /// | ||
| 1095 | /// The listen method is an asynchronous method but it does not require DMA to be asynchronous. | ||
| 1096 | pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { | ||
| 1097 | let state = self.state; | ||
| 1098 | self.info.regs.cr1().modify(|reg| { | ||
| 1099 | reg.set_addrie(true); | ||
| 1100 | trace!("Enable ADDRIE"); | ||
| 1101 | }); | ||
| 1102 | |||
| 1103 | poll_fn(|cx| { | ||
| 1104 | state.waker.register(cx.waker()); | ||
| 1105 | let isr = self.info.regs.isr().read(); | ||
| 1106 | if !isr.addr() { | ||
| 1107 | Poll::Pending | ||
| 1108 | } else { | ||
| 1109 | trace!("ADDR triggered (address match)"); | ||
| 1110 | // we do not clear the address flag here as it will be cleared by the dma read/write | ||
| 1111 | // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it | ||
| 1112 | match isr.dir() { | ||
| 1113 | i2c::vals::Dir::WRITE => { | ||
| 1114 | trace!("DIR: write"); | ||
| 1115 | Poll::Ready(Ok(SlaveCommand { | ||
| 1116 | kind: SlaveCommandKind::Write, | ||
| 1117 | address: self.determine_matched_address()?, | ||
| 1118 | })) | ||
| 1119 | } | ||
| 1120 | i2c::vals::Dir::READ => { | ||
| 1121 | trace!("DIR: read"); | ||
| 1122 | Poll::Ready(Ok(SlaveCommand { | ||
| 1123 | kind: SlaveCommandKind::Read, | ||
| 1124 | address: self.determine_matched_address()?, | ||
| 1125 | })) | ||
| 1126 | } | ||
| 1127 | } | ||
| 1128 | } | ||
| 1129 | }) | ||
| 1130 | .await | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | /// Respond to a write command. | ||
| 1134 | /// | ||
| 1135 | /// Returns total number of bytes received. | ||
| 1136 | pub fn blocking_respond_to_write(&self, read: &mut [u8]) -> Result<usize, Error> { | ||
| 1137 | let timeout = self.timeout(); | ||
| 1138 | self.slave_read_internal(read, timeout) | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | /// Respond to a read command. | ||
| 1142 | pub fn blocking_respond_to_read(&mut self, write: &[u8]) -> Result<(), Error> { | ||
| 1143 | let timeout = self.timeout(); | ||
| 1144 | self.slave_write_internal(write, timeout) | ||
| 1145 | } | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | impl<'d> I2c<'d, Async, MultiMaster> { | ||
| 1149 | /// Respond to a write command. | ||
| 1150 | /// | ||
| 1151 | /// Returns the total number of bytes received. | ||
| 1152 | pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | ||
| 1153 | let timeout = self.timeout(); | ||
| 1154 | timeout.with(self.read_dma_internal_slave(buffer, timeout)).await | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | /// Respond to a read request from an I2C master. | ||
| 1158 | pub async fn respond_to_read(&mut self, write: &[u8]) -> Result<SendStatus, Error> { | ||
| 1159 | let timeout = self.timeout(); | ||
| 1160 | timeout.with(self.write_dma_internal_slave(write, timeout)).await | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | // for data reception in slave mode | ||
| 1164 | // | ||
| 1165 | // returns the total number of bytes received | ||
| 1166 | async fn read_dma_internal_slave(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> { | ||
| 1167 | let total_len = buffer.len(); | ||
| 1168 | let mut remaining_len = total_len; | ||
| 1169 | |||
| 1170 | let regs = self.info.regs; | ||
| 1171 | |||
| 1172 | let dma_transfer = unsafe { | ||
| 1173 | regs.cr1().modify(|w| { | ||
| 1174 | w.set_rxdmaen(true); | ||
| 1175 | w.set_stopie(true); | ||
| 1176 | w.set_tcie(true); | ||
| 1177 | }); | ||
| 1178 | let src = regs.rxdr().as_ptr() as *mut u8; | ||
| 1179 | |||
| 1180 | self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) | ||
| 1181 | }; | ||
| 1182 | |||
| 1183 | let state = self.state; | ||
| 1184 | |||
| 1185 | let on_drop = OnDrop::new(|| { | ||
| 1186 | regs.cr1().modify(|w| { | ||
| 1187 | w.set_rxdmaen(false); | ||
| 1188 | w.set_stopie(false); | ||
| 1189 | w.set_tcie(false); | ||
| 1190 | }); | ||
| 1191 | }); | ||
| 1192 | |||
| 1193 | let total_received = poll_fn(|cx| { | ||
| 1194 | state.waker.register(cx.waker()); | ||
| 1195 | |||
| 1196 | let isr = regs.isr().read(); | ||
| 1197 | |||
| 1198 | if remaining_len == total_len { | ||
| 1199 | Self::slave_start(self.info, total_len.min(255), total_len > 255); | ||
| 1200 | remaining_len = remaining_len.saturating_sub(255); | ||
| 1201 | Poll::Pending | ||
| 1202 | } else if isr.tcr() { | ||
| 1203 | let is_last_slice = remaining_len <= 255; | ||
| 1204 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { | ||
| 1205 | return Poll::Ready(Err(e)); | ||
| 1206 | } | ||
| 1207 | remaining_len = remaining_len.saturating_sub(255); | ||
| 1208 | regs.cr1().modify(|w| w.set_tcie(true)); | ||
| 1209 | Poll::Pending | ||
| 1210 | } else if isr.stopf() { | ||
| 1211 | regs.icr().write(|reg| reg.set_stopcf(true)); | ||
| 1212 | let poll = Poll::Ready(Ok(total_len - remaining_len)); | ||
| 1213 | poll | ||
| 1214 | } else { | ||
| 1215 | Poll::Pending | ||
| 1216 | } | ||
| 1217 | }) | ||
| 1218 | .await?; | ||
| 1219 | |||
| 1220 | dma_transfer.await; | ||
| 1221 | |||
| 1222 | drop(on_drop); | ||
| 1223 | |||
| 1224 | Ok(total_received) | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | async fn write_dma_internal_slave(&mut self, buffer: &[u8], timeout: Timeout) -> Result<SendStatus, Error> { | ||
| 1228 | let total_len = buffer.len(); | ||
| 1229 | let mut remaining_len = total_len; | ||
| 1230 | |||
| 1231 | let mut dma_transfer = unsafe { | ||
| 1232 | let regs = self.info.regs; | ||
| 1233 | regs.cr1().modify(|w| { | ||
| 1234 | w.set_txdmaen(true); | ||
| 1235 | w.set_stopie(true); | ||
| 1236 | w.set_tcie(true); | ||
| 1237 | }); | ||
| 1238 | let dst = regs.txdr().as_ptr() as *mut u8; | ||
| 1239 | |||
| 1240 | self.tx_dma.as_mut().unwrap().write(buffer, dst, Default::default()) | ||
| 1241 | }; | ||
| 1242 | |||
| 1243 | let on_drop = OnDrop::new(|| { | ||
| 1244 | let regs = self.info.regs; | ||
| 1245 | regs.cr1().modify(|w| { | ||
| 1246 | w.set_txdmaen(false); | ||
| 1247 | w.set_stopie(false); | ||
| 1248 | w.set_tcie(false); | ||
| 1249 | }) | ||
| 1250 | }); | ||
| 1251 | |||
| 1252 | let state = self.state; | ||
| 1253 | |||
| 1254 | let size = poll_fn(|cx| { | ||
| 1255 | state.waker.register(cx.waker()); | ||
| 1256 | |||
| 1257 | let isr = self.info.regs.isr().read(); | ||
| 1258 | |||
| 1259 | if remaining_len == total_len { | ||
| 1260 | Self::slave_start(self.info, total_len.min(255), total_len > 255); | ||
| 1261 | remaining_len = remaining_len.saturating_sub(255); | ||
| 1262 | Poll::Pending | ||
| 1263 | } else if isr.tcr() { | ||
| 1264 | let is_last_slice = remaining_len <= 255; | ||
| 1265 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { | ||
| 1266 | return Poll::Ready(Err(e)); | ||
| 1267 | } | ||
| 1268 | remaining_len = remaining_len.saturating_sub(255); | ||
| 1269 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); | ||
| 1270 | Poll::Pending | ||
| 1271 | } else if isr.stopf() { | ||
| 1272 | self.info.regs.icr().write(|reg| reg.set_stopcf(true)); | ||
| 1273 | if remaining_len > 0 { | ||
| 1274 | dma_transfer.request_stop(); | ||
| 1275 | Poll::Ready(Ok(SendStatus::LeftoverBytes(remaining_len as usize))) | ||
| 1276 | } else { | ||
| 1277 | Poll::Ready(Ok(SendStatus::Done)) | ||
| 1278 | } | ||
| 1279 | } else { | ||
| 1280 | Poll::Pending | ||
| 1281 | } | ||
| 1282 | }) | ||
| 1283 | .await?; | ||
| 1284 | |||
| 1285 | dma_transfer.await; | ||
| 1286 | |||
| 1287 | drop(on_drop); | ||
| 1288 | |||
| 1289 | Ok(size) | ||
| 1290 | } | ||
| 1291 | } | ||
| 1292 | |||
| 736 | /// I2C Stop Configuration | 1293 | /// I2C Stop Configuration |
| 737 | /// | 1294 | /// |
| 738 | /// Peripheral options for generating the STOP condition | 1295 | /// Peripheral options for generating the STOP condition |
| @@ -857,7 +1414,7 @@ impl Timings { | |||
| 857 | } | 1414 | } |
| 858 | } | 1415 | } |
| 859 | 1416 | ||
| 860 | impl<'d, M: Mode> SetConfig for I2c<'d, M> { | 1417 | impl<'d, M: Mode> SetConfig for I2c<'d, M, Master> { |
| 861 | type Config = Hertz; | 1418 | type Config = Hertz; |
| 862 | type ConfigError = (); | 1419 | type ConfigError = (); |
| 863 | fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { | 1420 | fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { |
| @@ -882,3 +1439,21 @@ impl<'d, M: Mode> SetConfig for I2c<'d, M> { | |||
| 882 | Ok(()) | 1439 | Ok(()) |
| 883 | } | 1440 | } |
| 884 | } | 1441 | } |
| 1442 | |||
| 1443 | impl<'d, M: Mode> SetConfig for I2c<'d, M, MultiMaster> { | ||
| 1444 | type Config = (Hertz, SlaveAddrConfig); | ||
| 1445 | type ConfigError = (); | ||
| 1446 | fn set_config(&mut self, (config, addr_config): &Self::Config) -> Result<(), ()> { | ||
| 1447 | let timings = Timings::new(self.kernel_clock, *config); | ||
| 1448 | self.info.regs.timingr().write(|reg| { | ||
| 1449 | reg.set_presc(timings.prescale); | ||
| 1450 | reg.set_scll(timings.scll); | ||
| 1451 | reg.set_sclh(timings.sclh); | ||
| 1452 | reg.set_sdadel(timings.sdadel); | ||
| 1453 | reg.set_scldel(timings.scldel); | ||
| 1454 | }); | ||
| 1455 | self.init_slave(*addr_config); | ||
| 1456 | |||
| 1457 | Ok(()) | ||
| 1458 | } | ||
| 1459 | } | ||
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 20cd20dca..670d8332c 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs | |||
| @@ -104,9 +104,6 @@ impl Ipcc { | |||
| 104 | rcc::enable_and_reset::<IPCC>(); | 104 | rcc::enable_and_reset::<IPCC>(); |
| 105 | IPCC::set_cpu2(true); | 105 | IPCC::set_cpu2(true); |
| 106 | 106 | ||
| 107 | // set RF wake-up clock = LSE | ||
| 108 | crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01)); | ||
| 109 | |||
| 110 | let regs = IPCC::regs(); | 107 | let regs = IPCC::regs(); |
| 111 | 108 | ||
| 112 | regs.cpu(0).cr().modify(|w| { | 109 | regs.cpu(0).cr().modify(|w| { |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 973acc9bb..c7a33ed72 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -178,7 +178,7 @@ pub use crate::_generated::interrupt; | |||
| 178 | macro_rules! bind_interrupts { | 178 | macro_rules! bind_interrupts { |
| 179 | ($(#[$outer:meta])* $vis:vis struct $name:ident { | 179 | ($(#[$outer:meta])* $vis:vis struct $name:ident { |
| 180 | $( | 180 | $( |
| 181 | $(#[$inner:meta])* | 181 | $(#[doc = $doc:literal])* |
| 182 | $(#[cfg($cond_irq:meta)])? | 182 | $(#[cfg($cond_irq:meta)])? |
| 183 | $irq:ident => $( | 183 | $irq:ident => $( |
| 184 | $(#[cfg($cond_handler:meta)])? | 184 | $(#[cfg($cond_handler:meta)])? |
| @@ -194,13 +194,15 @@ macro_rules! bind_interrupts { | |||
| 194 | #[allow(non_snake_case)] | 194 | #[allow(non_snake_case)] |
| 195 | #[no_mangle] | 195 | #[no_mangle] |
| 196 | $(#[cfg($cond_irq)])? | 196 | $(#[cfg($cond_irq)])? |
| 197 | $(#[$inner])* | 197 | $(#[doc = $doc])* |
| 198 | unsafe extern "C" fn $irq() { | 198 | unsafe extern "C" fn $irq() { |
| 199 | $( | 199 | unsafe { |
| 200 | $(#[cfg($cond_handler)])? | 200 | $( |
| 201 | <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); | 201 | $(#[cfg($cond_handler)])? |
| 202 | <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); | ||
| 202 | 203 | ||
| 203 | )* | 204 | )* |
| 205 | } | ||
| 204 | } | 206 | } |
| 205 | 207 | ||
| 206 | $(#[cfg($cond_irq)])? | 208 | $(#[cfg($cond_irq)])? |
| @@ -242,12 +244,12 @@ pub struct Config { | |||
| 242 | #[cfg(dbgmcu)] | 244 | #[cfg(dbgmcu)] |
| 243 | pub enable_debug_during_sleep: bool, | 245 | pub enable_debug_during_sleep: bool, |
| 244 | 246 | ||
| 245 | /// On low-power boards (eg. `stm32l4`, `stm32l5` and `stm32u5`), | 247 | /// On low-power boards (eg. `stm32l4`, `stm32l5`, `stm32wba` and `stm32u5`), |
| 246 | /// some GPIO pins are powered by an auxiliary, independent power supply (`VDDIO2`), | 248 | /// some GPIO pins are powered by an auxiliary, independent power supply (`VDDIO2`), |
| 247 | /// which needs to be enabled before these pins can be used. | 249 | /// which needs to be enabled before these pins can be used. |
| 248 | /// | 250 | /// |
| 249 | /// May increase power consumption. Defaults to true. | 251 | /// May increase power consumption. Defaults to true. |
| 250 | #[cfg(any(stm32l4, stm32l5, stm32u5))] | 252 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))] |
| 251 | pub enable_independent_io_supply: bool, | 253 | pub enable_independent_io_supply: bool, |
| 252 | 254 | ||
| 253 | /// On the U5 series all analog peripherals are powered by a separate supply. | 255 | /// On the U5 series all analog peripherals are powered by a separate supply. |
| @@ -291,7 +293,7 @@ impl Default for Config { | |||
| 291 | rcc: Default::default(), | 293 | rcc: Default::default(), |
| 292 | #[cfg(dbgmcu)] | 294 | #[cfg(dbgmcu)] |
| 293 | enable_debug_during_sleep: true, | 295 | enable_debug_during_sleep: true, |
| 294 | #[cfg(any(stm32l4, stm32l5, stm32u5))] | 296 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))] |
| 295 | enable_independent_io_supply: true, | 297 | enable_independent_io_supply: true, |
| 296 | #[cfg(stm32u5)] | 298 | #[cfg(stm32u5)] |
| 297 | enable_independent_analog_supply: true, | 299 | enable_independent_analog_supply: true, |
| @@ -540,6 +542,13 @@ fn init_hw(config: Config) -> Peripherals { | |||
| 540 | w.set_iosv(config.enable_independent_io_supply); | 542 | w.set_iosv(config.enable_independent_io_supply); |
| 541 | }); | 543 | }); |
| 542 | } | 544 | } |
| 545 | #[cfg(stm32wba)] | ||
| 546 | { | ||
| 547 | use crate::pac::pwr::vals; | ||
| 548 | crate::pac::PWR.svmcr().modify(|w| { | ||
| 549 | w.set_io2sv(vals::Io2sv::B_0X1); | ||
| 550 | }); | ||
| 551 | } | ||
| 543 | #[cfg(stm32u5)] | 552 | #[cfg(stm32u5)] |
| 544 | { | 553 | { |
| 545 | crate::pac::PWR.svmcr().modify(|w| { | 554 | crate::pac::PWR.svmcr().modify(|w| { |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 7734365f1..d13df5a6b 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -124,15 +124,18 @@ pub enum StopMode { | |||
| 124 | Stop2, | 124 | Stop2, |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0))] | 127 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32u0))] |
| 128 | use stm32_metapac::pwr::vals::Lpms; | 128 | use stm32_metapac::pwr::vals::Lpms; |
| 129 | 129 | ||
| 130 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0))] | 130 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32u0))] |
| 131 | impl Into<Lpms> for StopMode { | 131 | impl Into<Lpms> for StopMode { |
| 132 | fn into(self) -> Lpms { | 132 | fn into(self) -> Lpms { |
| 133 | match self { | 133 | match self { |
| 134 | StopMode::Stop1 => Lpms::STOP1, | 134 | StopMode::Stop1 => Lpms::STOP1, |
| 135 | #[cfg(not(stm32wba))] | ||
| 135 | StopMode::Stop2 => Lpms::STOP2, | 136 | StopMode::Stop2 => Lpms::STOP2, |
| 137 | #[cfg(stm32wba)] | ||
| 138 | StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2? | ||
| 136 | } | 139 | } |
| 137 | } | 140 | } |
| 138 | } | 141 | } |
| @@ -198,7 +201,7 @@ impl Executor { | |||
| 198 | 201 | ||
| 199 | #[allow(unused_variables)] | 202 | #[allow(unused_variables)] |
| 200 | fn configure_stop(&mut self, stop_mode: StopMode) { | 203 | fn configure_stop(&mut self, stop_mode: StopMode) { |
| 201 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0))] | 204 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba))] |
| 202 | crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); | 205 | crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); |
| 203 | #[cfg(stm32h5)] | 206 | #[cfg(stm32h5)] |
| 204 | crate::pac::PWR.pmcr().modify(|v| { | 207 | crate::pac::PWR.pmcr().modify(|v| { |
diff --git a/embassy-stm32/src/lptim/timer/mod.rs b/embassy-stm32/src/lptim/timer/mod.rs index a629be62b..648da5940 100644 --- a/embassy-stm32/src/lptim/timer/mod.rs +++ b/embassy-stm32/src/lptim/timer/mod.rs | |||
| @@ -115,6 +115,31 @@ impl<'d, T: Instance> Timer<'d, T> { | |||
| 115 | .ccmr(0) | 115 | .ccmr(0) |
| 116 | .modify(|w| w.set_ccsel(channel.index(), direction.into())); | 116 | .modify(|w| w.set_ccsel(channel.index(), direction.into())); |
| 117 | } | 117 | } |
| 118 | |||
| 119 | /// Enable the timer interrupt. | ||
| 120 | pub fn enable_interrupt(&self) { | ||
| 121 | T::regs().dier().modify(|w| w.set_arrmie(true)); | ||
| 122 | } | ||
| 123 | |||
| 124 | /// Disable the timer interrupt. | ||
| 125 | pub fn disable_interrupt(&self) { | ||
| 126 | T::regs().dier().modify(|w| w.set_arrmie(false)); | ||
| 127 | } | ||
| 128 | |||
| 129 | /// Check if the timer interrupt is enabled. | ||
| 130 | pub fn is_interrupt_enabled(&self) -> bool { | ||
| 131 | T::regs().dier().read().arrmie() | ||
| 132 | } | ||
| 133 | |||
| 134 | /// Check if the timer interrupt is pending. | ||
| 135 | pub fn is_interrupt_pending(&self) -> bool { | ||
| 136 | T::regs().isr().read().arrm() | ||
| 137 | } | ||
| 138 | |||
| 139 | /// Clear the timer interrupt. | ||
| 140 | pub fn clear_interrupt(&self) { | ||
| 141 | T::regs().icr().write(|w| w.set_arrmcf(true)); | ||
| 142 | } | ||
| 118 | } | 143 | } |
| 119 | 144 | ||
| 120 | #[cfg(not(any(lptim_v2a, lptim_v2b)))] | 145 | #[cfg(not(any(lptim_v2a, lptim_v2b)))] |
| @@ -128,4 +153,29 @@ impl<'d, T: Instance> Timer<'d, T> { | |||
| 128 | pub fn get_compare_value(&self) -> u16 { | 153 | pub fn get_compare_value(&self) -> u16 { |
| 129 | T::regs().cmp().read().cmp() | 154 | T::regs().cmp().read().cmp() |
| 130 | } | 155 | } |
| 156 | |||
| 157 | /// Enable the timer interrupt. | ||
| 158 | pub fn enable_interrupt(&self) { | ||
| 159 | T::regs().ier().modify(|w| w.set_arrmie(true)); | ||
| 160 | } | ||
| 161 | |||
| 162 | /// Disable the timer interrupt. | ||
| 163 | pub fn disable_interrupt(&self) { | ||
| 164 | T::regs().ier().modify(|w| w.set_arrmie(false)); | ||
| 165 | } | ||
| 166 | |||
| 167 | /// Check if the timer interrupt is enabled. | ||
| 168 | pub fn is_interrupt_enabled(&self) -> bool { | ||
| 169 | T::regs().ier().read().arrmie() | ||
| 170 | } | ||
| 171 | |||
| 172 | /// Check if the timer interrupt is pending. | ||
| 173 | pub fn is_interrupt_pending(&self) -> bool { | ||
| 174 | T::regs().isr().read().arrm() | ||
| 175 | } | ||
| 176 | |||
| 177 | /// Clear the timer interrupt. | ||
| 178 | pub fn clear_interrupt(&self) { | ||
| 179 | T::regs().icr().write(|w| w.set_arrmcf(true)); | ||
| 180 | } | ||
| 131 | } | 181 | } |
diff --git a/embassy-stm32/src/macros.rs b/embassy-stm32/src/macros.rs index 7526bb180..3a0b490ba 100644 --- a/embassy-stm32/src/macros.rs +++ b/embassy-stm32/src/macros.rs | |||
| @@ -81,17 +81,28 @@ macro_rules! dma_trait { | |||
| 81 | /// Note: in some chips, ST calls this the "channel", and calls channels "streams". | 81 | /// Note: in some chips, ST calls this the "channel", and calls channels "streams". |
| 82 | /// `embassy-stm32` always uses the "channel" and "request number" names. | 82 | /// `embassy-stm32` always uses the "channel" and "request number" names. |
| 83 | fn request(&self) -> crate::dma::Request; | 83 | fn request(&self) -> crate::dma::Request; |
| 84 | #[doc = "Remap the DMA channel"] | ||
| 85 | fn remap(&self); | ||
| 84 | } | 86 | } |
| 85 | }; | 87 | }; |
| 86 | } | 88 | } |
| 87 | 89 | ||
| 88 | #[allow(unused)] | 90 | #[allow(unused)] |
| 89 | macro_rules! dma_trait_impl { | 91 | macro_rules! dma_trait_impl { |
| 90 | (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $channel:ident, $request:expr) => { | 92 | (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $channel:ident, $request:expr, $remap:expr) => { |
| 91 | impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$channel { | 93 | impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$channel { |
| 92 | fn request(&self) -> crate::dma::Request { | 94 | fn request(&self) -> crate::dma::Request { |
| 93 | $request | 95 | $request |
| 94 | } | 96 | } |
| 97 | |||
| 98 | fn remap(&self) { | ||
| 99 | critical_section::with(|_| { | ||
| 100 | #[allow(unused_unsafe)] | ||
| 101 | unsafe { | ||
| 102 | $remap; | ||
| 103 | } | ||
| 104 | }); | ||
| 105 | } | ||
| 95 | } | 106 | } |
| 96 | }; | 107 | }; |
| 97 | } | 108 | } |
| @@ -111,6 +122,7 @@ macro_rules! new_dma_nonopt { | |||
| 111 | macro_rules! new_dma { | 122 | macro_rules! new_dma { |
| 112 | ($name:ident) => {{ | 123 | ($name:ident) => {{ |
| 113 | let dma = $name; | 124 | let dma = $name; |
| 125 | dma.remap(); | ||
| 114 | let request = dma.request(); | 126 | let request = dma.request(); |
| 115 | Some(crate::dma::ChannelAndRequest { | 127 | Some(crate::dma::ChannelAndRequest { |
| 116 | channel: dma.into(), | 128 | channel: dma.into(), |
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index 2eb2e61c1..e36719ef3 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs | |||
| @@ -4,10 +4,12 @@ | |||
| 4 | use embassy_hal_internal::PeripheralType; | 4 | use embassy_hal_internal::PeripheralType; |
| 5 | 5 | ||
| 6 | use crate::pac::opamp::vals::*; | 6 | use crate::pac::opamp::vals::*; |
| 7 | #[cfg(not(any(stm32g4, stm32f3)))] | ||
| 8 | use crate::rcc::RccInfo; | ||
| 7 | use crate::Peri; | 9 | use crate::Peri; |
| 8 | 10 | ||
| 9 | /// Performs a busy-wait delay for a specified number of microseconds. | 11 | /// Performs a busy-wait delay for a specified number of microseconds. |
| 10 | #[cfg(opamp_g4)] | 12 | #[cfg(opamp_v5)] |
| 11 | fn blocking_delay_ms(ms: u32) { | 13 | fn blocking_delay_ms(ms: u32) { |
| 12 | #[cfg(feature = "time")] | 14 | #[cfg(feature = "time")] |
| 13 | embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64)); | 15 | embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64)); |
| @@ -23,13 +25,13 @@ pub enum OpAmpGain { | |||
| 23 | Mul4, | 25 | Mul4, |
| 24 | Mul8, | 26 | Mul8, |
| 25 | Mul16, | 27 | Mul16, |
| 26 | #[cfg(opamp_g4)] | 28 | #[cfg(opamp_v5)] |
| 27 | Mul32, | 29 | Mul32, |
| 28 | #[cfg(opamp_g4)] | 30 | #[cfg(opamp_v5)] |
| 29 | Mul64, | 31 | Mul64, |
| 30 | } | 32 | } |
| 31 | 33 | ||
| 32 | #[cfg(opamp_g4)] | 34 | #[cfg(opamp_v5)] |
| 33 | enum OpAmpDifferentialPair { | 35 | enum OpAmpDifferentialPair { |
| 34 | P, | 36 | P, |
| 35 | N, | 37 | N, |
| @@ -53,7 +55,7 @@ pub struct OpAmpOutput<'d, T: Instance> { | |||
| 53 | /// OpAmp internal outputs, wired directly to ADC inputs. | 55 | /// OpAmp internal outputs, wired directly to ADC inputs. |
| 54 | /// | 56 | /// |
| 55 | /// This struct can be used as an ADC input. | 57 | /// This struct can be used as an ADC input. |
| 56 | #[cfg(opamp_g4)] | 58 | #[cfg(opamp_v5)] |
| 57 | pub struct OpAmpInternalOutput<'d, T: Instance> { | 59 | pub struct OpAmpInternalOutput<'d, T: Instance> { |
| 58 | _inner: &'d OpAmp<'d, T>, | 60 | _inner: &'d OpAmp<'d, T>, |
| 59 | } | 61 | } |
| @@ -67,8 +69,10 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 67 | /// Create a new driver instance. | 69 | /// Create a new driver instance. |
| 68 | /// | 70 | /// |
| 69 | /// Does not enable the opamp, but does set the speed mode on some families. | 71 | /// Does not enable the opamp, but does set the speed mode on some families. |
| 70 | pub fn new(opamp: Peri<'d, T>, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self { | 72 | pub fn new(opamp: Peri<'d, T>, #[cfg(opamp_v5)] speed: OpAmpSpeed) -> Self { |
| 71 | #[cfg(opamp_g4)] | 73 | #[cfg(not(any(stm32g4, stm32f3)))] |
| 74 | T::info().rcc.enable_and_reset(); | ||
| 75 | #[cfg(opamp_v5)] | ||
| 72 | T::regs().csr().modify(|w| { | 76 | T::regs().csr().modify(|w| { |
| 73 | w.set_opahsm(speed == OpAmpSpeed::HighSpeed); | 77 | w.set_opahsm(speed == OpAmpSpeed::HighSpeed); |
| 74 | }); | 78 | }); |
| @@ -94,15 +98,15 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 94 | in_pin.set_as_analog(); | 98 | in_pin.set_as_analog(); |
| 95 | out_pin.set_as_analog(); | 99 | out_pin.set_as_analog(); |
| 96 | 100 | ||
| 97 | #[cfg(opamp_g4)] | 101 | #[cfg(opamp_v5)] |
| 98 | let vm_sel = VmSel::OUTPUT; | 102 | let vm_sel = VmSel::OUTPUT; |
| 99 | #[cfg(not(opamp_g4))] | 103 | #[cfg(not(opamp_v5))] |
| 100 | let vm_sel = VmSel::from_bits(0b11); | 104 | let vm_sel = VmSel::from_bits(0b11); |
| 101 | 105 | ||
| 102 | T::regs().csr().modify(|w| { | 106 | T::regs().csr().modify(|w| { |
| 103 | w.set_vp_sel(VpSel::from_bits(in_pin.channel())); | 107 | w.set_vp_sel(VpSel::from_bits(in_pin.channel())); |
| 104 | w.set_vm_sel(vm_sel); | 108 | w.set_vm_sel(vm_sel); |
| 105 | #[cfg(opamp_g4)] | 109 | #[cfg(opamp_v5)] |
| 106 | w.set_opaintoen(false); | 110 | w.set_opaintoen(false); |
| 107 | w.set_opampen(true); | 111 | w.set_opampen(true); |
| 108 | }); | 112 | }); |
| @@ -129,12 +133,12 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 129 | in_pin.set_as_analog(); | 133 | in_pin.set_as_analog(); |
| 130 | out_pin.set_as_analog(); | 134 | out_pin.set_as_analog(); |
| 131 | 135 | ||
| 132 | #[cfg(opamp_g4)] | 136 | #[cfg(opamp_v5)] |
| 133 | let vm_sel = VmSel::PGA; | 137 | let vm_sel = VmSel::PGA; |
| 134 | #[cfg(not(opamp_g4))] | 138 | #[cfg(not(opamp_v5))] |
| 135 | let vm_sel = VmSel::from_bits(0b10); | 139 | let vm_sel = VmSel::from_bits(0b10); |
| 136 | 140 | ||
| 137 | #[cfg(opamp_g4)] | 141 | #[cfg(opamp_v5)] |
| 138 | let pga_gain = match gain { | 142 | let pga_gain = match gain { |
| 139 | OpAmpGain::Mul2 => PgaGain::GAIN2, | 143 | OpAmpGain::Mul2 => PgaGain::GAIN2, |
| 140 | OpAmpGain::Mul4 => PgaGain::GAIN4, | 144 | OpAmpGain::Mul4 => PgaGain::GAIN4, |
| @@ -143,7 +147,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 143 | OpAmpGain::Mul32 => PgaGain::GAIN32, | 147 | OpAmpGain::Mul32 => PgaGain::GAIN32, |
| 144 | OpAmpGain::Mul64 => PgaGain::GAIN64, | 148 | OpAmpGain::Mul64 => PgaGain::GAIN64, |
| 145 | }; | 149 | }; |
| 146 | #[cfg(not(opamp_g4))] | 150 | #[cfg(not(opamp_v5))] |
| 147 | let pga_gain = PgaGain::from_bits(match gain { | 151 | let pga_gain = PgaGain::from_bits(match gain { |
| 148 | OpAmpGain::Mul2 => 0b00, | 152 | OpAmpGain::Mul2 => 0b00, |
| 149 | OpAmpGain::Mul4 => 0b01, | 153 | OpAmpGain::Mul4 => 0b01, |
| @@ -155,7 +159,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 155 | w.set_vp_sel(VpSel::from_bits(in_pin.channel())); | 159 | w.set_vp_sel(VpSel::from_bits(in_pin.channel())); |
| 156 | w.set_vm_sel(vm_sel); | 160 | w.set_vm_sel(vm_sel); |
| 157 | w.set_pga_gain(pga_gain); | 161 | w.set_pga_gain(pga_gain); |
| 158 | #[cfg(opamp_g4)] | 162 | #[cfg(opamp_v5)] |
| 159 | w.set_opaintoen(false); | 163 | w.set_opaintoen(false); |
| 160 | w.set_opampen(true); | 164 | w.set_opampen(true); |
| 161 | }); | 165 | }); |
| @@ -170,7 +174,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 170 | /// preventing it being used elsewhere. The `OpAmpOutput` can then be | 174 | /// preventing it being used elsewhere. The `OpAmpOutput` can then be |
| 171 | /// directly used as an ADC input. The opamp will be disabled when the | 175 | /// directly used as an ADC input. The opamp will be disabled when the |
| 172 | /// [`OpAmpOutput`] is dropped. | 176 | /// [`OpAmpOutput`] is dropped. |
| 173 | #[cfg(opamp_g4)] | 177 | #[cfg(opamp_v5)] |
| 174 | pub fn buffer_dac(&mut self, out_pin: Peri<'_, impl OutputPin<T> + crate::gpio::Pin>) -> OpAmpOutput<'_, T> { | 178 | pub fn buffer_dac(&mut self, out_pin: Peri<'_, impl OutputPin<T> + crate::gpio::Pin>) -> OpAmpOutput<'_, T> { |
| 175 | out_pin.set_as_analog(); | 179 | out_pin.set_as_analog(); |
| 176 | 180 | ||
| @@ -194,7 +198,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 194 | /// | 198 | /// |
| 195 | /// The returned `OpAmpInternalOutput` struct may be used as an ADC input. | 199 | /// The returned `OpAmpInternalOutput` struct may be used as an ADC input. |
| 196 | /// The opamp output will be disabled when it is dropped. | 200 | /// The opamp output will be disabled when it is dropped. |
| 197 | #[cfg(opamp_g4)] | 201 | #[cfg(opamp_v5)] |
| 198 | pub fn buffer_int( | 202 | pub fn buffer_int( |
| 199 | &mut self, | 203 | &mut self, |
| 200 | pin: Peri<'_, impl NonInvertingPin<T> + crate::gpio::Pin>, | 204 | pin: Peri<'_, impl NonInvertingPin<T> + crate::gpio::Pin>, |
| @@ -204,7 +208,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 204 | T::regs().csr().modify(|w| { | 208 | T::regs().csr().modify(|w| { |
| 205 | w.set_vp_sel(VpSel::from_bits(pin.channel())); | 209 | w.set_vp_sel(VpSel::from_bits(pin.channel())); |
| 206 | w.set_vm_sel(VmSel::OUTPUT); | 210 | w.set_vm_sel(VmSel::OUTPUT); |
| 207 | #[cfg(opamp_g4)] | 211 | #[cfg(opamp_v5)] |
| 208 | w.set_opaintoen(true); | 212 | w.set_opaintoen(true); |
| 209 | w.set_opampen(true); | 213 | w.set_opampen(true); |
| 210 | }); | 214 | }); |
| @@ -220,7 +224,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 220 | /// | 224 | /// |
| 221 | /// The returned `OpAmpInternalOutput` struct may be used as an ADC input. | 225 | /// The returned `OpAmpInternalOutput` struct may be used as an ADC input. |
| 222 | /// The opamp output will be disabled when it is dropped. | 226 | /// The opamp output will be disabled when it is dropped. |
| 223 | #[cfg(opamp_g4)] | 227 | #[cfg(opamp_v5)] |
| 224 | pub fn pga_int( | 228 | pub fn pga_int( |
| 225 | &mut self, | 229 | &mut self, |
| 226 | pin: Peri<'_, impl NonInvertingPin<T> + crate::gpio::Pin>, | 230 | pin: Peri<'_, impl NonInvertingPin<T> + crate::gpio::Pin>, |
| @@ -257,7 +261,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 257 | /// | 261 | /// |
| 258 | /// The returned `OpAmpInternalOutput` struct may be used as an ADC | 262 | /// The returned `OpAmpInternalOutput` struct may be used as an ADC |
| 259 | /// input. The opamp output will be disabled when it is dropped. | 263 | /// input. The opamp output will be disabled when it is dropped. |
| 260 | #[cfg(opamp_g4)] | 264 | #[cfg(opamp_v5)] |
| 261 | pub fn standalone_dac_int( | 265 | pub fn standalone_dac_int( |
| 262 | &mut self, | 266 | &mut self, |
| 263 | m_pin: Peri<'_, impl InvertingPin<T> + crate::gpio::Pin>, | 267 | m_pin: Peri<'_, impl InvertingPin<T> + crate::gpio::Pin>, |
| @@ -285,7 +289,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 285 | /// The output pin is held within the returned [`OpAmpOutput`] struct, | 289 | /// The output pin is held within the returned [`OpAmpOutput`] struct, |
| 286 | /// preventing it being used elsewhere. The opamp will be disabled when | 290 | /// preventing it being used elsewhere. The opamp will be disabled when |
| 287 | /// the [`OpAmpOutput`] is dropped. | 291 | /// the [`OpAmpOutput`] is dropped. |
| 288 | #[cfg(opamp_g4)] | 292 | #[cfg(opamp_v5)] |
| 289 | pub fn standalone_dac_ext( | 293 | pub fn standalone_dac_ext( |
| 290 | &mut self, | 294 | &mut self, |
| 291 | m_pin: Peri<'_, impl InvertingPin<T> + crate::gpio::Pin>, | 295 | m_pin: Peri<'_, impl InvertingPin<T> + crate::gpio::Pin>, |
| @@ -315,7 +319,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 315 | /// The output pin is held within the returned [`OpAmpOutput`] struct, | 319 | /// The output pin is held within the returned [`OpAmpOutput`] struct, |
| 316 | /// preventing it being used elsewhere. The opamp will be disabled when | 320 | /// preventing it being used elsewhere. The opamp will be disabled when |
| 317 | /// the [`OpAmpOutput`] is dropped. | 321 | /// the [`OpAmpOutput`] is dropped. |
| 318 | #[cfg(opamp_g4)] | 322 | #[cfg(opamp_v5)] |
| 319 | pub fn standalone_ext( | 323 | pub fn standalone_ext( |
| 320 | &mut self, | 324 | &mut self, |
| 321 | p_pin: Peri<'d, impl NonInvertingPin<T> + crate::gpio::Pin>, | 325 | p_pin: Peri<'d, impl NonInvertingPin<T> + crate::gpio::Pin>, |
| @@ -346,7 +350,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 346 | /// | 350 | /// |
| 347 | /// The returned `OpAmpOutput` struct may be used as an ADC | 351 | /// The returned `OpAmpOutput` struct may be used as an ADC |
| 348 | /// input. The opamp output will be disabled when it is dropped. | 352 | /// input. The opamp output will be disabled when it is dropped. |
| 349 | #[cfg(opamp_g4)] | 353 | #[cfg(opamp_v5)] |
| 350 | pub fn standalone_int( | 354 | pub fn standalone_int( |
| 351 | &mut self, | 355 | &mut self, |
| 352 | p_pin: Peri<'d, impl NonInvertingPin<T> + crate::gpio::Pin>, | 356 | p_pin: Peri<'d, impl NonInvertingPin<T> + crate::gpio::Pin>, |
| @@ -374,7 +378,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 374 | /// while for high-speed mode, only the P differential pair is calibrated. | 378 | /// while for high-speed mode, only the P differential pair is calibrated. |
| 375 | /// | 379 | /// |
| 376 | /// Calibrating a differential pair requires waiting 12ms in the worst case (binary method). | 380 | /// Calibrating a differential pair requires waiting 12ms in the worst case (binary method). |
| 377 | #[cfg(opamp_g4)] | 381 | #[cfg(opamp_v5)] |
| 378 | pub fn calibrate(&mut self) { | 382 | pub fn calibrate(&mut self) { |
| 379 | T::regs().csr().modify(|w| { | 383 | T::regs().csr().modify(|w| { |
| 380 | w.set_opampen(true); | 384 | w.set_opampen(true); |
| @@ -403,7 +407,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 403 | /// The calibration range is from 0 to 31. | 407 | /// The calibration range is from 0 to 31. |
| 404 | /// | 408 | /// |
| 405 | /// The result is stored in the OPAMP_CSR register. | 409 | /// The result is stored in the OPAMP_CSR register. |
| 406 | #[cfg(opamp_g4)] | 410 | #[cfg(opamp_v5)] |
| 407 | fn calibrate_differential_pair(&mut self, pair: OpAmpDifferentialPair) { | 411 | fn calibrate_differential_pair(&mut self, pair: OpAmpDifferentialPair) { |
| 408 | let mut low = 0; | 412 | let mut low = 0; |
| 409 | let mut high = 31; | 413 | let mut high = 31; |
| @@ -452,6 +456,13 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 452 | } | 456 | } |
| 453 | } | 457 | } |
| 454 | 458 | ||
| 459 | #[cfg(not(any(stm32g4, stm32f3)))] | ||
| 460 | impl<'d, T: Instance> Drop for OpAmp<'d, T> { | ||
| 461 | fn drop(&mut self) { | ||
| 462 | T::info().rcc.disable(); | ||
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 455 | impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { | 466 | impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { |
| 456 | fn drop(&mut self) { | 467 | fn drop(&mut self) { |
| 457 | T::regs().csr().modify(|w| { | 468 | T::regs().csr().modify(|w| { |
| @@ -460,7 +471,7 @@ impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { | |||
| 460 | } | 471 | } |
| 461 | } | 472 | } |
| 462 | 473 | ||
| 463 | #[cfg(opamp_g4)] | 474 | #[cfg(opamp_v5)] |
| 464 | impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { | 475 | impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { |
| 465 | fn drop(&mut self) { | 476 | fn drop(&mut self) { |
| 466 | T::regs().csr().modify(|w| { | 477 | T::regs().csr().modify(|w| { |
| @@ -469,7 +480,14 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { | |||
| 469 | } | 480 | } |
| 470 | } | 481 | } |
| 471 | 482 | ||
| 483 | #[cfg(not(any(stm32g4, stm32f3)))] | ||
| 484 | pub(crate) struct Info { | ||
| 485 | rcc: RccInfo, | ||
| 486 | } | ||
| 487 | |||
| 472 | pub(crate) trait SealedInstance { | 488 | pub(crate) trait SealedInstance { |
| 489 | #[cfg(not(any(stm32g4, stm32f3)))] | ||
| 490 | fn info() -> &'static Info; | ||
| 473 | fn regs() -> crate::pac::opamp::Opamp; | 491 | fn regs() -> crate::pac::opamp::Opamp; |
| 474 | } | 492 | } |
| 475 | 493 | ||
| @@ -545,7 +563,7 @@ foreach_peripheral!( | |||
| 545 | }; | 563 | }; |
| 546 | ); | 564 | ); |
| 547 | 565 | ||
| 548 | #[cfg(opamp_g4)] | 566 | #[cfg(opamp_v5)] |
| 549 | macro_rules! impl_opamp_internal_output { | 567 | macro_rules! impl_opamp_internal_output { |
| 550 | ($inst:ident, $adc:ident, $ch:expr) => { | 568 | ($inst:ident, $adc:ident, $ch:expr) => { |
| 551 | foreach_adc!( | 569 | foreach_adc!( |
| @@ -567,7 +585,7 @@ macro_rules! impl_opamp_internal_output { | |||
| 567 | }; | 585 | }; |
| 568 | } | 586 | } |
| 569 | 587 | ||
| 570 | #[cfg(opamp_g4)] | 588 | #[cfg(opamp_v5)] |
| 571 | foreach_peripheral!( | 589 | foreach_peripheral!( |
| 572 | (opamp, OPAMP1) => { | 590 | (opamp, OPAMP1) => { |
| 573 | impl_opamp_internal_output!(OPAMP1, ADC1, 13); | 591 | impl_opamp_internal_output!(OPAMP1, ADC1, 13); |
| @@ -600,6 +618,15 @@ foreach_peripheral!( | |||
| 600 | foreach_peripheral! { | 618 | foreach_peripheral! { |
| 601 | (opamp, $inst:ident) => { | 619 | (opamp, $inst:ident) => { |
| 602 | impl SealedInstance for crate::peripherals::$inst { | 620 | impl SealedInstance for crate::peripherals::$inst { |
| 621 | // G4 and F3 use SYSCFGEN, which is always enabled | ||
| 622 | #[cfg(not(any(stm32g4, stm32f3)))] | ||
| 623 | fn info() -> &'static Info { | ||
| 624 | use crate::rcc::SealedRccPeripheral; | ||
| 625 | static INFO: Info = Info { | ||
| 626 | rcc: crate::peripherals::$inst::RCC_INFO, | ||
| 627 | }; | ||
| 628 | &INFO | ||
| 629 | } | ||
| 603 | fn regs() -> crate::pac::opamp::Opamp { | 630 | fn regs() -> crate::pac::opamp::Opamp { |
| 604 | crate::pac::$inst | 631 | crate::pac::$inst |
| 605 | } | 632 | } |
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs index 9ec4c1b43..fa5e36d06 100644 --- a/embassy-stm32/src/qspi/enums.rs +++ b/embassy-stm32/src/qspi/enums.rs | |||
| @@ -331,3 +331,19 @@ impl From<DummyCycles> for u8 { | |||
| 331 | } | 331 | } |
| 332 | } | 332 | } |
| 333 | } | 333 | } |
| 334 | |||
| 335 | #[allow(missing_docs)] | ||
| 336 | #[derive(Copy, Clone)] | ||
| 337 | pub enum SampleShifting { | ||
| 338 | None, | ||
| 339 | HalfCycle, | ||
| 340 | } | ||
| 341 | |||
| 342 | impl From<SampleShifting> for bool { | ||
| 343 | fn from(value: SampleShifting) -> Self { | ||
| 344 | match value { | ||
| 345 | SampleShifting::None => false, | ||
| 346 | SampleShifting::HalfCycle => true, | ||
| 347 | } | ||
| 348 | } | ||
| 349 | } | ||
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 0df057c53..1e20d7cd3 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs | |||
| @@ -58,6 +58,8 @@ pub struct Config { | |||
| 58 | pub fifo_threshold: FIFOThresholdLevel, | 58 | pub fifo_threshold: FIFOThresholdLevel, |
| 59 | /// Minimum number of cycles that chip select must be high between issued commands | 59 | /// Minimum number of cycles that chip select must be high between issued commands |
| 60 | pub cs_high_time: ChipSelectHighTime, | 60 | pub cs_high_time: ChipSelectHighTime, |
| 61 | /// Shift sampling point of input data (none, or half-cycle) | ||
| 62 | pub sample_shifting: SampleShifting, | ||
| 61 | } | 63 | } |
| 62 | 64 | ||
| 63 | impl Default for Config { | 65 | impl Default for Config { |
| @@ -68,6 +70,7 @@ impl Default for Config { | |||
| 68 | prescaler: 128, | 70 | prescaler: 128, |
| 69 | fifo_threshold: FIFOThresholdLevel::_17Bytes, | 71 | fifo_threshold: FIFOThresholdLevel::_17Bytes, |
| 70 | cs_high_time: ChipSelectHighTime::_5Cycle, | 72 | cs_high_time: ChipSelectHighTime::_5Cycle, |
| 73 | sample_shifting: SampleShifting::None, | ||
| 71 | } | 74 | } |
| 72 | } | 75 | } |
| 73 | } | 76 | } |
| @@ -120,7 +123,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { | |||
| 120 | T::REGS.cr().modify(|w| { | 123 | T::REGS.cr().modify(|w| { |
| 121 | w.set_en(true); | 124 | w.set_en(true); |
| 122 | //w.set_tcen(false); | 125 | //w.set_tcen(false); |
| 123 | w.set_sshift(false); | 126 | w.set_sshift(config.sample_shifting.into()); |
| 124 | w.set_fthres(config.fifo_threshold.into()); | 127 | w.set_fthres(config.fifo_threshold.into()); |
| 125 | w.set_prescaler(config.prescaler); | 128 | w.set_prescaler(config.prescaler); |
| 126 | w.set_fsel(fsel.into()); | 129 | w.set_fsel(fsel.into()); |
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index cac2a9149..c2295bab6 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs | |||
| @@ -190,6 +190,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 190 | // TODO | 190 | // TODO |
| 191 | lsi: None, | 191 | lsi: None, |
| 192 | lse: None, | 192 | lse: None, |
| 193 | #[cfg(crs)] | ||
| 194 | hsi48: None, | ||
| 193 | ); | 195 | ); |
| 194 | 196 | ||
| 195 | RCC.ccipr() | 197 | RCC.ccipr() |
diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs index 3ea5c96c9..49be4af5e 100644 --- a/embassy-stm32/src/rcc/hsi48.rs +++ b/embassy-stm32/src/rcc/hsi48.rs | |||
| @@ -39,9 +39,9 @@ pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz { | |||
| 39 | }); | 39 | }); |
| 40 | 40 | ||
| 41 | // Enable HSI48 | 41 | // Enable HSI48 |
| 42 | #[cfg(not(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba, stm32f0)))] | 42 | #[cfg(not(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba, stm32f0, stm32c071)))] |
| 43 | let r = RCC.crrcr(); | 43 | let r = RCC.crrcr(); |
| 44 | #[cfg(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba))] | 44 | #[cfg(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba, stm32c071))] |
| 45 | let r = RCC.cr(); | 45 | let r = RCC.cr(); |
| 46 | #[cfg(any(stm32f0))] | 46 | #[cfg(any(stm32f0))] |
| 47 | let r = RCC.cr2(); | 47 | let r = RCC.cr2(); |
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index c50e071fb..96e628b1a 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs | |||
| @@ -74,7 +74,7 @@ macro_rules! impl_peri { | |||
| 74 | }; | 74 | }; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | #[cfg(any(rcc_c0, rcc_g0, rcc_u0))] | 77 | #[cfg(any(rcc_c0, rcc_c0v2, rcc_g0x0, rcc_g0x1, rcc_u0))] |
| 78 | #[allow(unused_imports)] | 78 | #[allow(unused_imports)] |
| 79 | use self::{McoSource as Mco1Source, McoSource as Mco2Source}; | 79 | use self::{McoSource as Mco1Source, McoSource as Mco2Source}; |
| 80 | 80 | ||
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 3733fed56..c41f81816 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -95,6 +95,15 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks { | |||
| 95 | unwrap!(CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).as_ref()).assume_init_ref() | 95 | unwrap!(CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).as_ref()).assume_init_ref() |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | /// Get the current clock configuration of the chip. | ||
| 99 | pub fn clocks<'a>(_rcc: &'a crate::Peri<'a, crate::peripherals::RCC>) -> &'a Clocks { | ||
| 100 | // Safety: the existence of a `Peri<RCC>` means that `rcc::init()` | ||
| 101 | // has already been called, so `CLOCK_FREQS` must be initialized. | ||
| 102 | // The clocks could be modified again by `reinit()`, but reinit | ||
| 103 | // (for this reason) requires an exclusive reference to `Peri<RCC>`. | ||
| 104 | unsafe { get_freqs() } | ||
| 105 | } | ||
| 106 | |||
| 98 | pub(crate) trait SealedRccPeripheral { | 107 | pub(crate) trait SealedRccPeripheral { |
| 99 | fn frequency() -> Hertz; | 108 | fn frequency() -> Hertz; |
| 100 | #[allow(dead_code)] | 109 | #[allow(dead_code)] |
| @@ -381,7 +390,7 @@ pub fn disable<T: RccPeripheral>() { | |||
| 381 | /// | 390 | /// |
| 382 | /// This should only be called after `init`. | 391 | /// This should only be called after `init`. |
| 383 | #[cfg(not(feature = "_dual-core"))] | 392 | #[cfg(not(feature = "_dual-core"))] |
| 384 | pub fn reinit(config: Config) { | 393 | pub fn reinit<'a>(config: Config, _rcc: &'a mut crate::Peri<'a, crate::peripherals::RCC>) { |
| 385 | critical_section::with(|cs| init_rcc(cs, config)) | 394 | critical_section::with(|cs| init_rcc(cs, config)) |
| 386 | } | 395 | } |
| 387 | 396 | ||
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 97eb2eb6d..06895a99a 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs | |||
| @@ -5,7 +5,7 @@ pub use crate::pac::rcc::vals::{ | |||
| 5 | Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, | 5 | Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, |
| 6 | Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, | 6 | Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, |
| 7 | }; | 7 | }; |
| 8 | use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge}; | 8 | use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge}; |
| 9 | #[cfg(all(peri_usb_otg_hs))] | 9 | #[cfg(all(peri_usb_otg_hs))] |
| 10 | pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; | 10 | pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; |
| 11 | use crate::pac::{FLASH, PWR, RCC}; | 11 | use crate::pac::{FLASH, PWR, RCC}; |
| @@ -64,6 +64,46 @@ pub struct Pll { | |||
| 64 | pub divr: Option<PllDiv>, | 64 | pub divr: Option<PllDiv>, |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | #[derive(Clone, Copy, PartialEq)] | ||
| 68 | pub enum MsiAutoCalibration { | ||
| 69 | /// MSI auto-calibration is disabled | ||
| 70 | Disabled, | ||
| 71 | /// MSIS is given priority for auto-calibration | ||
| 72 | MSIS, | ||
| 73 | /// MSIK is given priority for auto-calibration | ||
| 74 | MSIK, | ||
| 75 | /// MSIS with fast mode (always on) | ||
| 76 | MsisFast, | ||
| 77 | /// MSIK with fast mode (always on) | ||
| 78 | MsikFast, | ||
| 79 | } | ||
| 80 | |||
| 81 | impl MsiAutoCalibration { | ||
| 82 | const fn default() -> Self { | ||
| 83 | MsiAutoCalibration::Disabled | ||
| 84 | } | ||
| 85 | |||
| 86 | fn base_mode(&self) -> Self { | ||
| 87 | match self { | ||
| 88 | MsiAutoCalibration::Disabled => MsiAutoCalibration::Disabled, | ||
| 89 | MsiAutoCalibration::MSIS => MsiAutoCalibration::MSIS, | ||
| 90 | MsiAutoCalibration::MSIK => MsiAutoCalibration::MSIK, | ||
| 91 | MsiAutoCalibration::MsisFast => MsiAutoCalibration::MSIS, | ||
| 92 | MsiAutoCalibration::MsikFast => MsiAutoCalibration::MSIK, | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | fn is_fast(&self) -> bool { | ||
| 97 | matches!(self, MsiAutoCalibration::MsisFast | MsiAutoCalibration::MsikFast) | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | impl Default for MsiAutoCalibration { | ||
| 102 | fn default() -> Self { | ||
| 103 | Self::default() | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 67 | #[derive(Clone, Copy)] | 107 | #[derive(Clone, Copy)] |
| 68 | pub struct Config { | 108 | pub struct Config { |
| 69 | // base clock sources | 109 | // base clock sources |
| @@ -95,6 +135,7 @@ pub struct Config { | |||
| 95 | 135 | ||
| 96 | /// Per-peripheral kernel clock selection muxes | 136 | /// Per-peripheral kernel clock selection muxes |
| 97 | pub mux: super::mux::ClockMux, | 137 | pub mux: super::mux::ClockMux, |
| 138 | pub auto_calibration: MsiAutoCalibration, | ||
| 98 | } | 139 | } |
| 99 | 140 | ||
| 100 | impl Config { | 141 | impl Config { |
| @@ -116,6 +157,7 @@ impl Config { | |||
| 116 | voltage_range: VoltageScale::RANGE1, | 157 | voltage_range: VoltageScale::RANGE1, |
| 117 | ls: crate::rcc::LsConfig::new(), | 158 | ls: crate::rcc::LsConfig::new(), |
| 118 | mux: super::mux::ClockMux::default(), | 159 | mux: super::mux::ClockMux::default(), |
| 160 | auto_calibration: MsiAutoCalibration::default(), | ||
| 119 | } | 161 | } |
| 120 | } | 162 | } |
| 121 | } | 163 | } |
| @@ -131,7 +173,42 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 131 | PWR.vosr().modify(|w| w.set_vos(config.voltage_range)); | 173 | PWR.vosr().modify(|w| w.set_vos(config.voltage_range)); |
| 132 | while !PWR.vosr().read().vosrdy() {} | 174 | while !PWR.vosr().read().vosrdy() {} |
| 133 | 175 | ||
| 134 | let msis = config.msis.map(|range| { | 176 | let lse_calibration_freq = if config.auto_calibration != MsiAutoCalibration::Disabled { |
| 177 | // LSE must be configured and peripherals clocked for MSI auto-calibration | ||
| 178 | let lse_config = config | ||
| 179 | .ls | ||
| 180 | .lse | ||
| 181 | .clone() | ||
| 182 | .expect("LSE must be configured for MSI auto-calibration"); | ||
| 183 | assert!(lse_config.peripherals_clocked); | ||
| 184 | |||
| 185 | // Expect less than +/- 5% deviation for LSE frequency | ||
| 186 | if (31_100..=34_400).contains(&lse_config.frequency.0) { | ||
| 187 | // Check that the calibration is applied to an active clock | ||
| 188 | match ( | ||
| 189 | config.auto_calibration.base_mode(), | ||
| 190 | config.msis.is_some(), | ||
| 191 | config.msik.is_some(), | ||
| 192 | ) { | ||
| 193 | (MsiAutoCalibration::MSIS, true, _) => { | ||
| 194 | // MSIS is active and using LSE for auto-calibration | ||
| 195 | Some(lse_config.frequency) | ||
| 196 | } | ||
| 197 | (MsiAutoCalibration::MSIK, _, true) => { | ||
| 198 | // MSIK is active and using LSE for auto-calibration | ||
| 199 | Some(lse_config.frequency) | ||
| 200 | } | ||
| 201 | // improper configuration | ||
| 202 | _ => panic!("MSIx auto-calibration is enabled for a source that has not been configured."), | ||
| 203 | } | ||
| 204 | } else { | ||
| 205 | panic!("LSE frequency more than 5% off from 32.768 kHz, cannot use for MSI auto-calibration"); | ||
| 206 | } | ||
| 207 | } else { | ||
| 208 | None | ||
| 209 | }; | ||
| 210 | |||
| 211 | let mut msis = config.msis.map(|range| { | ||
| 135 | // Check MSI output per RM0456 § 11.4.10 | 212 | // Check MSI output per RM0456 § 11.4.10 |
| 136 | match config.voltage_range { | 213 | match config.voltage_range { |
| 137 | VoltageScale::RANGE4 => { | 214 | VoltageScale::RANGE4 => { |
| @@ -156,11 +233,21 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 156 | w.set_msipllen(false); | 233 | w.set_msipllen(false); |
| 157 | w.set_msison(true); | 234 | w.set_msison(true); |
| 158 | }); | 235 | }); |
| 236 | let msis = if let (Some(freq), MsiAutoCalibration::MSIS) = | ||
| 237 | (lse_calibration_freq, config.auto_calibration.base_mode()) | ||
| 238 | { | ||
| 239 | // Enable the MSIS auto-calibration feature | ||
| 240 | RCC.cr().modify(|w| w.set_msipllsel(Msipllsel::MSIS)); | ||
| 241 | RCC.cr().modify(|w| w.set_msipllen(true)); | ||
| 242 | calculate_calibrated_msi_frequency(range, freq) | ||
| 243 | } else { | ||
| 244 | msirange_to_hertz(range) | ||
| 245 | }; | ||
| 159 | while !RCC.cr().read().msisrdy() {} | 246 | while !RCC.cr().read().msisrdy() {} |
| 160 | msirange_to_hertz(range) | 247 | msis |
| 161 | }); | 248 | }); |
| 162 | 249 | ||
| 163 | let msik = config.msik.map(|range| { | 250 | let mut msik = config.msik.map(|range| { |
| 164 | // Check MSI output per RM0456 § 11.4.10 | 251 | // Check MSI output per RM0456 § 11.4.10 |
| 165 | match config.voltage_range { | 252 | match config.voltage_range { |
| 166 | VoltageScale::RANGE4 => { | 253 | VoltageScale::RANGE4 => { |
| @@ -184,10 +271,44 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 184 | RCC.cr().modify(|w| { | 271 | RCC.cr().modify(|w| { |
| 185 | w.set_msikon(true); | 272 | w.set_msikon(true); |
| 186 | }); | 273 | }); |
| 274 | let msik = if let (Some(freq), MsiAutoCalibration::MSIK) = | ||
| 275 | (lse_calibration_freq, config.auto_calibration.base_mode()) | ||
| 276 | { | ||
| 277 | // Enable the MSIK auto-calibration feature | ||
| 278 | RCC.cr().modify(|w| w.set_msipllsel(Msipllsel::MSIK)); | ||
| 279 | RCC.cr().modify(|w| w.set_msipllen(true)); | ||
| 280 | calculate_calibrated_msi_frequency(range, freq) | ||
| 281 | } else { | ||
| 282 | msirange_to_hertz(range) | ||
| 283 | }; | ||
| 187 | while !RCC.cr().read().msikrdy() {} | 284 | while !RCC.cr().read().msikrdy() {} |
| 188 | msirange_to_hertz(range) | 285 | msik |
| 189 | }); | 286 | }); |
| 190 | 287 | ||
| 288 | if let Some(lse_freq) = lse_calibration_freq { | ||
| 289 | // If both MSIS and MSIK are enabled, we need to check if they are using the same internal source. | ||
| 290 | if let (Some(msis_range), Some(msik_range)) = (config.msis, config.msik) { | ||
| 291 | if (msis_range as u8 >> 2) == (msik_range as u8 >> 2) { | ||
| 292 | // Clock source is shared, both will be auto calibrated, recalculate other frequency | ||
| 293 | match config.auto_calibration.base_mode() { | ||
| 294 | MsiAutoCalibration::MSIS => { | ||
| 295 | msik = Some(calculate_calibrated_msi_frequency(msik_range, lse_freq)); | ||
| 296 | } | ||
| 297 | MsiAutoCalibration::MSIK => { | ||
| 298 | msis = Some(calculate_calibrated_msi_frequency(msis_range, lse_freq)); | ||
| 299 | } | ||
| 300 | _ => {} | ||
| 301 | } | ||
| 302 | } | ||
| 303 | } | ||
| 304 | // Check if Fast mode should be used | ||
| 305 | if config.auto_calibration.is_fast() { | ||
| 306 | RCC.cr().modify(|w| { | ||
| 307 | w.set_msipllfast(Msipllfast::FAST); | ||
| 308 | }); | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 191 | let hsi = config.hsi.then(|| { | 312 | let hsi = config.hsi.then(|| { |
| 192 | RCC.cr().modify(|w| w.set_hsion(true)); | 313 | RCC.cr().modify(|w| w.set_hsion(true)); |
| 193 | while !RCC.cr().read().hsirdy() {} | 314 | while !RCC.cr().read().hsirdy() {} |
| @@ -514,3 +635,37 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput, voltag | |||
| 514 | 635 | ||
| 515 | PllOutput { p, q, r } | 636 | PllOutput { p, q, r } |
| 516 | } | 637 | } |
| 638 | |||
| 639 | /// Fraction structure for MSI auto-calibration | ||
| 640 | /// Represents the multiplier as numerator/denominator that LSE frequency is multiplied by | ||
| 641 | #[derive(Debug, Clone, Copy)] | ||
| 642 | struct MsiFraction { | ||
| 643 | numerator: u32, | ||
| 644 | denominator: u32, | ||
| 645 | } | ||
| 646 | |||
| 647 | impl MsiFraction { | ||
| 648 | const fn new(numerator: u32, denominator: u32) -> Self { | ||
| 649 | Self { numerator, denominator } | ||
| 650 | } | ||
| 651 | |||
| 652 | /// Calculate the calibrated frequency given an LSE frequency | ||
| 653 | fn calculate_frequency(&self, lse_freq: Hertz) -> Hertz { | ||
| 654 | Hertz(lse_freq.0 * self.numerator / self.denominator) | ||
| 655 | } | ||
| 656 | } | ||
| 657 | |||
| 658 | fn get_msi_calibration_fraction(range: Msirange) -> MsiFraction { | ||
| 659 | // Exploiting the MSIx internals to make calculations compact | ||
| 660 | let denominator = (range as u32 & 0x03) + 1; | ||
| 661 | // Base multipliers are deduced from Table 82: MSI oscillator characteristics in data sheet | ||
| 662 | let numerator = [1465, 122, 94, 12][range as usize >> 2]; | ||
| 663 | |||
| 664 | MsiFraction::new(numerator, denominator) | ||
| 665 | } | ||
| 666 | |||
| 667 | /// Calculate the calibrated MSI frequency for a given range and LSE frequency | ||
| 668 | fn calculate_calibrated_msi_frequency(range: Msirange, lse_freq: Hertz) -> Hertz { | ||
| 669 | let fraction = get_msi_calibration_fraction(range); | ||
| 670 | fraction.calculate_frequency(lse_freq) | ||
| 671 | } | ||
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index b9fc4e423..b494997b3 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs | |||
| @@ -176,6 +176,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 176 | // TODO | 176 | // TODO |
| 177 | lse: None, | 177 | lse: None, |
| 178 | lsi: None, | 178 | lsi: None, |
| 179 | pll1_p: None, | ||
| 179 | pll1_q: None, | 180 | pll1_q: None, |
| 180 | ); | 181 | ); |
| 181 | } | 182 | } |
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index cd075f3de..78ccd3e6c 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs | |||
| @@ -66,7 +66,7 @@ pub(crate) enum WakeupPrescaler { | |||
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | #[cfg(any( | 68 | #[cfg(any( |
| 69 | stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0 | 69 | stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba |
| 70 | ))] | 70 | ))] |
| 71 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | 71 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { |
| 72 | fn from(val: WakeupPrescaler) -> Self { | 72 | fn from(val: WakeupPrescaler) -> Self { |
| @@ -82,7 +82,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | |||
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | #[cfg(any( | 84 | #[cfg(any( |
| 85 | stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0 | 85 | stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba |
| 86 | ))] | 86 | ))] |
| 87 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { | 87 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { |
| 88 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { | 88 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { |
| @@ -227,7 +227,7 @@ impl Rtc { | |||
| 227 | <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); | 227 | <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); |
| 228 | unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; | 228 | unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; |
| 229 | 229 | ||
| 230 | #[cfg(not(any(stm32u5, stm32u0)))] | 230 | #[cfg(not(any(stm32u5, stm32u0, stm32wba)))] |
| 231 | { | 231 | { |
| 232 | use crate::pac::EXTI; | 232 | use crate::pac::EXTI; |
| 233 | EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | 233 | EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); |
| @@ -247,5 +247,11 @@ impl Rtc { | |||
| 247 | RCC.srdamr().modify(|w| w.set_rtcapbamen(true)); | 247 | RCC.srdamr().modify(|w| w.set_rtcapbamen(true)); |
| 248 | RCC.apb3smenr().modify(|w| w.set_rtcapbsmen(true)); | 248 | RCC.apb3smenr().modify(|w| w.set_rtcapbsmen(true)); |
| 249 | } | 249 | } |
| 250 | #[cfg(stm32wba)] | ||
| 251 | { | ||
| 252 | use crate::pac::RCC; | ||
| 253 | // RCC.srdamr().modify(|w| w.set_rtcapbamen(true)); | ||
| 254 | RCC.apb7smenr().modify(|w| w.set_rtcapbsmen(true)); | ||
| 255 | } | ||
| 250 | } | 256 | } |
| 251 | } | 257 | } |
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 49f423f37..449f3008a 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -25,7 +25,7 @@ use crate::time::Hertz; | |||
| 25 | ), | 25 | ), |
| 26 | path = "v2.rs" | 26 | path = "v2.rs" |
| 27 | )] | 27 | )] |
| 28 | #[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5, rtc_v3h7rs), path = "v3.rs")] | 28 | #[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5, rtc_v3h7rs, rtc_v3c0), path = "v3.rs")] |
| 29 | mod _version; | 29 | mod _version; |
| 30 | #[allow(unused_imports)] | 30 | #[allow(unused_imports)] |
| 31 | pub use _version::*; | 31 | pub use _version::*; |
| @@ -296,7 +296,7 @@ trait SealedInstance { | |||
| 296 | const BACKUP_REGISTER_COUNT: usize; | 296 | const BACKUP_REGISTER_COUNT: usize; |
| 297 | 297 | ||
| 298 | #[cfg(feature = "low-power")] | 298 | #[cfg(feature = "low-power")] |
| 299 | #[cfg(not(any(stm32u5, stm32u0)))] | 299 | #[cfg(not(any(stm32wba, stm32u5, stm32u0)))] |
| 300 | const EXTI_WAKEUP_LINE: usize; | 300 | const EXTI_WAKEUP_LINE: usize; |
| 301 | 301 | ||
| 302 | #[cfg(feature = "low-power")] | 302 | #[cfg(feature = "low-power")] |
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 39aa6c5cb..d0b52049e 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs | |||
| @@ -146,7 +146,7 @@ impl SealedInstance for crate::peripherals::RTC { | |||
| 146 | type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; | 146 | type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; |
| 147 | } else if #[cfg(any(stm32g0, stm32u0))] { | 147 | } else if #[cfg(any(stm32g0, stm32u0))] { |
| 148 | type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; | 148 | type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; |
| 149 | } else if #[cfg(any(stm32l5, stm32h5, stm32u5))] { | 149 | } else if #[cfg(any(stm32l5, stm32h5, stm32u5, stm32wba))] { |
| 150 | type WakeupInterrupt = crate::interrupt::typelevel::RTC; | 150 | type WakeupInterrupt = crate::interrupt::typelevel::RTC; |
| 151 | } | 151 | } |
| 152 | ); | 152 | ); |
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 6a02aae70..6e5d735d7 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -32,25 +32,48 @@ pub struct InterruptHandler<T: Instance> { | |||
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | impl<T: Instance> InterruptHandler<T> { | 34 | impl<T: Instance> InterruptHandler<T> { |
| 35 | fn data_interrupts(enable: bool) { | 35 | fn enable_interrupts() { |
| 36 | let regs = T::regs(); | 36 | let regs = T::regs(); |
| 37 | regs.maskr().write(|w| { | 37 | regs.maskr().write(|w| { |
| 38 | w.set_dcrcfailie(enable); | 38 | w.set_dcrcfailie(true); |
| 39 | w.set_dtimeoutie(enable); | 39 | w.set_dtimeoutie(true); |
| 40 | w.set_dataendie(enable); | 40 | w.set_dataendie(true); |
| 41 | w.set_dbckendie(true); | ||
| 41 | 42 | ||
| 42 | #[cfg(sdmmc_v1)] | 43 | #[cfg(sdmmc_v1)] |
| 43 | w.set_stbiterre(enable); | 44 | w.set_stbiterre(true); |
| 44 | #[cfg(sdmmc_v2)] | 45 | #[cfg(sdmmc_v2)] |
| 45 | w.set_dabortie(enable); | 46 | w.set_dabortie(true); |
| 46 | }); | 47 | }); |
| 47 | } | 48 | } |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | 51 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 51 | unsafe fn on_interrupt() { | 52 | unsafe fn on_interrupt() { |
| 52 | Self::data_interrupts(false); | ||
| 53 | T::state().wake(); | 53 | T::state().wake(); |
| 54 | let status = T::regs().star().read(); | ||
| 55 | T::regs().maskr().modify(|w| { | ||
| 56 | if status.dcrcfail() { | ||
| 57 | w.set_dcrcfailie(false) | ||
| 58 | } | ||
| 59 | if status.dtimeout() { | ||
| 60 | w.set_dtimeoutie(false) | ||
| 61 | } | ||
| 62 | if status.dataend() { | ||
| 63 | w.set_dataendie(false) | ||
| 64 | } | ||
| 65 | if status.dbckend() { | ||
| 66 | w.set_dbckendie(false) | ||
| 67 | } | ||
| 68 | #[cfg(sdmmc_v1)] | ||
| 69 | if status.stbiterr() { | ||
| 70 | w.set_stbiterre(false) | ||
| 71 | } | ||
| 72 | #[cfg(sdmmc_v2)] | ||
| 73 | if status.dabort() { | ||
| 74 | w.set_dabortie(false) | ||
| 75 | } | ||
| 76 | }); | ||
| 54 | } | 77 | } |
| 55 | } | 78 | } |
| 56 | 79 | ||
| @@ -225,8 +248,7 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u8, Hertz), Error> { | |||
| 225 | return Ok((true, 0, ker_ck)); | 248 | return Ok((true, 0, ker_ck)); |
| 226 | } | 249 | } |
| 227 | 250 | ||
| 228 | // `ker_ck / sdmmc_ck` rounded up | 251 | let clk_div = match ker_ck.0.div_ceil(sdmmc_ck) { |
| 229 | let clk_div = match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck { | ||
| 230 | 0 | 1 => Ok(0), | 252 | 0 | 1 => Ok(0), |
| 231 | x @ 2..=258 => Ok((x - 2) as u8), | 253 | x @ 2..=258 => Ok((x - 2) as u8), |
| 232 | _ => Err(Error::BadClock), | 254 | _ => Err(Error::BadClock), |
| @@ -244,12 +266,11 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u8, Hertz), Error> { | |||
| 244 | /// `clk_div` is the divisor register value and `clk_f` is the resulting new clock frequency. | 266 | /// `clk_div` is the divisor register value and `clk_f` is the resulting new clock frequency. |
| 245 | #[cfg(sdmmc_v2)] | 267 | #[cfg(sdmmc_v2)] |
| 246 | fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u16, Hertz), Error> { | 268 | fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u16, Hertz), Error> { |
| 247 | // `ker_ck / sdmmc_ck` rounded up | 269 | match ker_ck.0.div_ceil(sdmmc_ck) { |
| 248 | match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck { | ||
| 249 | 0 | 1 => Ok((false, 0, ker_ck)), | 270 | 0 | 1 => Ok((false, 0, ker_ck)), |
| 250 | x @ 2..=2046 => { | 271 | x @ 2..=2046 => { |
| 251 | // SDMMC_CK frequency = SDMMCCLK / [CLKDIV * 2] | 272 | // SDMMC_CK frequency = SDMMCCLK / [CLKDIV * 2] |
| 252 | let clk_div = ((x + 1) / 2) as u16; | 273 | let clk_div = x.div_ceil(2) as u16; |
| 253 | let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2)); | 274 | let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2)); |
| 254 | 275 | ||
| 255 | Ok((false, clk_div, clk)) | 276 | Ok((false, clk_div, clk)) |
| @@ -751,7 +772,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 751 | Self::wait_idle(); | 772 | Self::wait_idle(); |
| 752 | Self::clear_interrupt_flags(); | 773 | Self::clear_interrupt_flags(); |
| 753 | 774 | ||
| 754 | regs.dtimer().write(|w| w.set_datatime(config.data_transfer_timeout)); | ||
| 755 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | 775 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); |
| 756 | 776 | ||
| 757 | #[cfg(sdmmc_v1)] | 777 | #[cfg(sdmmc_v1)] |
| @@ -789,8 +809,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 789 | Self::wait_idle(); | 809 | Self::wait_idle(); |
| 790 | Self::clear_interrupt_flags(); | 810 | Self::clear_interrupt_flags(); |
| 791 | 811 | ||
| 792 | regs.dtimer() | ||
| 793 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 794 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | 812 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); |
| 795 | 813 | ||
| 796 | #[cfg(sdmmc_v1)] | 814 | #[cfg(sdmmc_v1)] |
| @@ -1007,14 +1025,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1007 | // Wait for the abort | 1025 | // Wait for the abort |
| 1008 | while Self::data_active() {} | 1026 | while Self::data_active() {} |
| 1009 | } | 1027 | } |
| 1010 | InterruptHandler::<T>::data_interrupts(false); | 1028 | regs.maskr().write(|_| ()); // disable irqs |
| 1011 | Self::clear_interrupt_flags(); | 1029 | Self::clear_interrupt_flags(); |
| 1012 | Self::stop_datapath(); | 1030 | Self::stop_datapath(); |
| 1013 | } | 1031 | } |
| 1014 | 1032 | ||
| 1015 | /// Wait for a previously started datapath transfer to complete from an interrupt. | 1033 | /// Wait for a previously started datapath transfer to complete from an interrupt. |
| 1016 | #[inline] | 1034 | #[inline] |
| 1017 | async fn complete_datapath_transfer() -> Result<(), Error> { | 1035 | async fn complete_datapath_transfer(block: bool) -> Result<(), Error> { |
| 1018 | let regs = T::regs(); | 1036 | let regs = T::regs(); |
| 1019 | 1037 | ||
| 1020 | let res = poll_fn(|cx| { | 1038 | let res = poll_fn(|cx| { |
| @@ -1034,7 +1052,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1034 | if status.stbiterr() { | 1052 | if status.stbiterr() { |
| 1035 | return Poll::Ready(Err(Error::StBitErr)); | 1053 | return Poll::Ready(Err(Error::StBitErr)); |
| 1036 | } | 1054 | } |
| 1037 | if status.dataend() { | 1055 | let done = match block { |
| 1056 | true => status.dbckend(), | ||
| 1057 | false => status.dataend(), | ||
| 1058 | }; | ||
| 1059 | if done { | ||
| 1038 | return Poll::Ready(Ok(())); | 1060 | return Poll::Ready(Ok(())); |
| 1039 | } | 1061 | } |
| 1040 | Poll::Pending | 1062 | Poll::Pending |
| @@ -1072,10 +1094,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1072 | 512, | 1094 | 512, |
| 1073 | 9, | 1095 | 9, |
| 1074 | ); | 1096 | ); |
| 1075 | InterruptHandler::<T>::data_interrupts(true); | 1097 | InterruptHandler::<T>::enable_interrupts(); |
| 1076 | Self::cmd(common_cmd::read_single_block(address), true)?; | 1098 | Self::cmd(common_cmd::read_single_block(address), true)?; |
| 1077 | 1099 | ||
| 1078 | let res = Self::complete_datapath_transfer().await; | 1100 | let res = Self::complete_datapath_transfer(true).await; |
| 1079 | 1101 | ||
| 1080 | if res.is_ok() { | 1102 | if res.is_ok() { |
| 1081 | on_drop.defuse(); | 1103 | on_drop.defuse(); |
| @@ -1105,7 +1127,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1105 | }; | 1127 | }; |
| 1106 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | 1128 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 |
| 1107 | 1129 | ||
| 1108 | let regs = T::regs(); | ||
| 1109 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1130 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 1110 | 1131 | ||
| 1111 | let transfer = Self::prepare_datapath_read( | 1132 | let transfer = Self::prepare_datapath_read( |
| @@ -1116,30 +1137,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1116 | 512 * blocks.len() as u32, | 1137 | 512 * blocks.len() as u32, |
| 1117 | 9, | 1138 | 9, |
| 1118 | ); | 1139 | ); |
| 1119 | InterruptHandler::<T>::data_interrupts(true); | 1140 | InterruptHandler::<T>::enable_interrupts(); |
| 1120 | 1141 | ||
| 1121 | Self::cmd(common_cmd::read_multiple_blocks(address), true)?; | 1142 | Self::cmd(common_cmd::read_multiple_blocks(address), true)?; |
| 1122 | 1143 | ||
| 1123 | let res = poll_fn(|cx| { | 1144 | let res = Self::complete_datapath_transfer(false).await; |
| 1124 | T::state().register(cx.waker()); | ||
| 1125 | let status = regs.star().read(); | ||
| 1126 | |||
| 1127 | if status.dcrcfail() { | ||
| 1128 | return Poll::Ready(Err(Error::Crc)); | ||
| 1129 | } | ||
| 1130 | if status.dtimeout() { | ||
| 1131 | return Poll::Ready(Err(Error::Timeout)); | ||
| 1132 | } | ||
| 1133 | #[cfg(sdmmc_v1)] | ||
| 1134 | if status.stbiterr() { | ||
| 1135 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 1136 | } | ||
| 1137 | if status.dataend() { | ||
| 1138 | return Poll::Ready(Ok(())); | ||
| 1139 | } | ||
| 1140 | Poll::Pending | ||
| 1141 | }) | ||
| 1142 | .await; | ||
| 1143 | 1145 | ||
| 1144 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 | 1146 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 |
| 1145 | Self::clear_interrupt_flags(); | 1147 | Self::clear_interrupt_flags(); |
| @@ -1174,12 +1176,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1174 | Self::cmd(common_cmd::write_single_block(address), true)?; | 1176 | Self::cmd(common_cmd::write_single_block(address), true)?; |
| 1175 | 1177 | ||
| 1176 | let transfer = self.prepare_datapath_write(buffer, 512, 9); | 1178 | let transfer = self.prepare_datapath_write(buffer, 512, 9); |
| 1177 | InterruptHandler::<T>::data_interrupts(true); | 1179 | InterruptHandler::<T>::enable_interrupts(); |
| 1178 | 1180 | ||
| 1179 | #[cfg(sdmmc_v2)] | 1181 | #[cfg(sdmmc_v2)] |
| 1180 | Self::cmd(common_cmd::write_single_block(address), true)?; | 1182 | Self::cmd(common_cmd::write_single_block(address), true)?; |
| 1181 | 1183 | ||
| 1182 | let res = Self::complete_datapath_transfer().await; | 1184 | let res = Self::complete_datapath_transfer(true).await; |
| 1183 | 1185 | ||
| 1184 | match res { | 1186 | match res { |
| 1185 | Ok(_) => { | 1187 | Ok(_) => { |
| @@ -1230,7 +1232,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1230 | 1232 | ||
| 1231 | let block_count = blocks.len(); | 1233 | let block_count = blocks.len(); |
| 1232 | 1234 | ||
| 1233 | let regs = T::regs(); | ||
| 1234 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1235 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 1235 | 1236 | ||
| 1236 | #[cfg(sdmmc_v1)] | 1237 | #[cfg(sdmmc_v1)] |
| @@ -1238,36 +1239,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1238 | 1239 | ||
| 1239 | // Setup write command | 1240 | // Setup write command |
| 1240 | let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); | 1241 | let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); |
| 1241 | InterruptHandler::<T>::data_interrupts(true); | 1242 | InterruptHandler::<T>::enable_interrupts(); |
| 1242 | 1243 | ||
| 1243 | #[cfg(sdmmc_v2)] | 1244 | #[cfg(sdmmc_v2)] |
| 1244 | Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | 1245 | Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 |
| 1245 | 1246 | ||
| 1246 | let res = poll_fn(|cx| { | 1247 | let res = Self::complete_datapath_transfer(false).await; |
| 1247 | T::state().register(cx.waker()); | ||
| 1248 | |||
| 1249 | let status = regs.star().read(); | ||
| 1250 | |||
| 1251 | if status.dcrcfail() { | ||
| 1252 | return Poll::Ready(Err(Error::Crc)); | ||
| 1253 | } | ||
| 1254 | if status.dtimeout() { | ||
| 1255 | return Poll::Ready(Err(Error::Timeout)); | ||
| 1256 | } | ||
| 1257 | if status.txunderr() { | ||
| 1258 | return Poll::Ready(Err(Error::Underrun)); | ||
| 1259 | } | ||
| 1260 | #[cfg(sdmmc_v1)] | ||
| 1261 | if status.stbiterr() { | ||
| 1262 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 1263 | } | ||
| 1264 | if status.dataend() { | ||
| 1265 | return Poll::Ready(Ok(())); | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | Poll::Pending | ||
| 1269 | }) | ||
| 1270 | .await; | ||
| 1271 | 1248 | ||
| 1272 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 | 1249 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 |
| 1273 | Self::clear_interrupt_flags(); | 1250 | Self::clear_interrupt_flags(); |
| @@ -1349,6 +1326,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1349 | #[cfg(sdmmc_v1)] | 1326 | #[cfg(sdmmc_v1)] |
| 1350 | w.set_bypass(_bypass); | 1327 | w.set_bypass(_bypass); |
| 1351 | }); | 1328 | }); |
| 1329 | regs.dtimer() | ||
| 1330 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 1352 | 1331 | ||
| 1353 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | 1332 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); |
| 1354 | Self::cmd(common_cmd::idle(), false)?; | 1333 | Self::cmd(common_cmd::idle(), false)?; |
| @@ -1600,10 +1579,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1600 | 64, | 1579 | 64, |
| 1601 | 6, | 1580 | 6, |
| 1602 | ); | 1581 | ); |
| 1603 | InterruptHandler::<T>::data_interrupts(true); | 1582 | InterruptHandler::<T>::enable_interrupts(); |
| 1604 | Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 | 1583 | Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 |
| 1605 | 1584 | ||
| 1606 | let res = Self::complete_datapath_transfer().await; | 1585 | let res = Self::complete_datapath_transfer(true).await; |
| 1607 | 1586 | ||
| 1608 | // Host is allowed to use the new functions at least 8 | 1587 | // Host is allowed to use the new functions at least 8 |
| 1609 | // clocks after the end of the switch command | 1588 | // clocks after the end of the switch command |
| @@ -1660,10 +1639,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1660 | 8, | 1639 | 8, |
| 1661 | 3, | 1640 | 3, |
| 1662 | ); | 1641 | ); |
| 1663 | InterruptHandler::<T>::data_interrupts(true); | 1642 | InterruptHandler::<T>::enable_interrupts(); |
| 1664 | Self::cmd(sd_cmd::send_scr(), true)?; | 1643 | Self::cmd(sd_cmd::send_scr(), true)?; |
| 1665 | 1644 | ||
| 1666 | let res = Self::complete_datapath_transfer().await; | 1645 | let res = Self::complete_datapath_transfer(true).await; |
| 1667 | 1646 | ||
| 1668 | if res.is_ok() { | 1647 | if res.is_ok() { |
| 1669 | on_drop.defuse(); | 1648 | on_drop.defuse(); |
| @@ -1706,10 +1685,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1706 | 64, | 1685 | 64, |
| 1707 | 6, | 1686 | 6, |
| 1708 | ); | 1687 | ); |
| 1709 | InterruptHandler::<T>::data_interrupts(true); | 1688 | InterruptHandler::<T>::enable_interrupts(); |
| 1710 | Self::cmd(sd_cmd::sd_status(), true)?; | 1689 | Self::cmd(sd_cmd::sd_status(), true)?; |
| 1711 | 1690 | ||
| 1712 | let res = Self::complete_datapath_transfer().await; | 1691 | let res = Self::complete_datapath_transfer(true).await; |
| 1713 | 1692 | ||
| 1714 | if res.is_ok() { | 1693 | if res.is_ok() { |
| 1715 | on_drop.defuse(); | 1694 | on_drop.defuse(); |
| @@ -1756,10 +1735,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1756 | 512, | 1735 | 512, |
| 1757 | 9, | 1736 | 9, |
| 1758 | ); | 1737 | ); |
| 1759 | InterruptHandler::<T>::data_interrupts(true); | 1738 | InterruptHandler::<T>::enable_interrupts(); |
| 1760 | Self::cmd(emmc_cmd::send_ext_csd(), true)?; | 1739 | Self::cmd(emmc_cmd::send_ext_csd(), true)?; |
| 1761 | 1740 | ||
| 1762 | let res = Self::complete_datapath_transfer().await; | 1741 | let res = Self::complete_datapath_transfer(true).await; |
| 1763 | 1742 | ||
| 1764 | if res.is_ok() { | 1743 | if res.is_ok() { |
| 1765 | on_drop.defuse(); | 1744 | on_drop.defuse(); |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 9e2ba093a..c8d83f07e 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -843,7 +843,7 @@ impl<'d> Spi<'d, Async> { | |||
| 843 | 843 | ||
| 844 | set_rxdmaen(self.info.regs, true); | 844 | set_rxdmaen(self.info.regs, true); |
| 845 | 845 | ||
| 846 | let rx_src = self.info.regs.rx_ptr(); | 846 | let rx_src = self.info.regs.rx_ptr::<W>(); |
| 847 | let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) }; | 847 | let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) }; |
| 848 | 848 | ||
| 849 | let tx_dst: *mut W = self.info.regs.tx_ptr(); | 849 | let tx_dst: *mut W = self.info.regs.tx_ptr(); |
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 8eec6c0c7..b00cc18ad 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -5,14 +5,12 @@ use core::marker::PhantomData; | |||
| 5 | use stm32_metapac::timer::vals::Ckd; | 5 | use stm32_metapac::timer::vals::Ckd; |
| 6 | 6 | ||
| 7 | use super::low_level::{CountingMode, OutputPolarity, Timer}; | 7 | use super::low_level::{CountingMode, OutputPolarity, Timer}; |
| 8 | use super::simple_pwm::{Ch1, Ch2, Ch3, Ch4, PwmPin}; | 8 | use super::simple_pwm::PwmPin; |
| 9 | use super::{ | 9 | use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; |
| 10 | AdvancedInstance4Channel, Channel, Channel1ComplementaryPin, Channel2ComplementaryPin, Channel3ComplementaryPin, | ||
| 11 | Channel4ComplementaryPin, | ||
| 12 | }; | ||
| 13 | use crate::gpio::{AnyPin, OutputType}; | 10 | use crate::gpio::{AnyPin, OutputType}; |
| 14 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 15 | use crate::timer::low_level::OutputCompareMode; | 12 | use crate::timer::low_level::OutputCompareMode; |
| 13 | use crate::timer::TimerChannel; | ||
| 16 | use crate::Peri; | 14 | use crate::Peri; |
| 17 | 15 | ||
| 18 | /// Complementary PWM pin wrapper. | 16 | /// Complementary PWM pin wrapper. |
| @@ -23,32 +21,23 @@ pub struct ComplementaryPwmPin<'d, T, C> { | |||
| 23 | phantom: PhantomData<(T, C)>, | 21 | phantom: PhantomData<(T, C)>, |
| 24 | } | 22 | } |
| 25 | 23 | ||
| 26 | macro_rules! complementary_channel_impl { | 24 | impl<'d, T: AdvancedInstance4Channel, C: TimerChannel> ComplementaryPwmPin<'d, T, C> { |
| 27 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 25 | /// Create a new complementary PWM pin instance. |
| 28 | impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> { | 26 | pub fn new(pin: Peri<'d, impl TimerComplementaryPin<T, C>>, output_type: OutputType) -> Self { |
| 29 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] | 27 | critical_section::with(|_| { |
| 30 | pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, output_type: OutputType) -> Self { | 28 | pin.set_low(); |
| 31 | critical_section::with(|_| { | 29 | pin.set_as_af( |
| 32 | pin.set_low(); | 30 | pin.af_num(), |
| 33 | pin.set_as_af( | 31 | crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh), |
| 34 | pin.af_num(), | 32 | ); |
| 35 | crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh), | 33 | }); |
| 36 | ); | 34 | ComplementaryPwmPin { |
| 37 | }); | 35 | _pin: pin.into(), |
| 38 | ComplementaryPwmPin { | 36 | phantom: PhantomData, |
| 39 | _pin: pin.into(), | ||
| 40 | phantom: PhantomData, | ||
| 41 | } | ||
| 42 | } | ||
| 43 | } | 37 | } |
| 44 | }; | 38 | } |
| 45 | } | 39 | } |
| 46 | 40 | ||
| 47 | complementary_channel_impl!(new_ch1, Ch1, Channel1ComplementaryPin); | ||
| 48 | complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin); | ||
| 49 | complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); | ||
| 50 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); | ||
| 51 | |||
| 52 | /// PWM driver with support for standard and complementary outputs. | 41 | /// PWM driver with support for standard and complementary outputs. |
| 53 | pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> { | 42 | pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> { |
| 54 | inner: Timer<'d, T>, | 43 | inner: Timer<'d, T>, |
| @@ -88,6 +77,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 88 | this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); | 77 | this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); |
| 89 | this.inner.set_output_compare_preload(channel, true); | 78 | this.inner.set_output_compare_preload(channel, true); |
| 90 | }); | 79 | }); |
| 80 | this.inner.set_autoreload_preload(true); | ||
| 91 | 81 | ||
| 92 | this | 82 | this |
| 93 | } | 83 | } |
| @@ -121,7 +111,11 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 121 | /// | 111 | /// |
| 122 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 112 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 123 | pub fn get_max_duty(&self) -> u16 { | 113 | pub fn get_max_duty(&self) -> u16 { |
| 124 | self.inner.get_max_compare_value() as u16 + 1 | 114 | if self.inner.get_counting_mode().is_center_aligned() { |
| 115 | self.inner.get_max_compare_value() as u16 | ||
| 116 | } else { | ||
| 117 | self.inner.get_max_compare_value() as u16 + 1 | ||
| 118 | } | ||
| 125 | } | 119 | } |
| 126 | 120 | ||
| 127 | /// Set the duty for a given channel. | 121 | /// Set the duty for a given channel. |
| @@ -171,7 +165,11 @@ impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm< | |||
| 171 | } | 165 | } |
| 172 | 166 | ||
| 173 | fn get_max_duty(&self) -> Self::Duty { | 167 | fn get_max_duty(&self) -> Self::Duty { |
| 174 | self.inner.get_max_compare_value() as u16 + 1 | 168 | if self.inner.get_counting_mode().is_center_aligned() { |
| 169 | self.inner.get_max_compare_value() as u16 | ||
| 170 | } else { | ||
| 171 | self.inner.get_max_compare_value() as u16 + 1 | ||
| 172 | } | ||
| 175 | } | 173 | } |
| 176 | 174 | ||
| 177 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { | 175 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { |
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index ec8b1ddf1..dda33e7f1 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs | |||
| @@ -6,14 +6,12 @@ use core::pin::Pin; | |||
| 6 | use core::task::{Context, Poll}; | 6 | use core::task::{Context, Poll}; |
| 7 | 7 | ||
| 8 | use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; | 8 | use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; |
| 9 | use super::{ | 9 | use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin}; |
| 10 | CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, | ||
| 11 | GeneralInstance4Channel, | ||
| 12 | }; | ||
| 13 | pub use super::{Ch1, Ch2, Ch3, Ch4}; | 10 | pub use super::{Ch1, Ch2, Ch3, Ch4}; |
| 14 | use crate::gpio::{AfType, AnyPin, Pull}; | 11 | use crate::gpio::{AfType, AnyPin, Pull}; |
| 15 | use crate::interrupt::typelevel::{Binding, Interrupt}; | 12 | use crate::interrupt::typelevel::{Binding, Interrupt}; |
| 16 | use crate::time::Hertz; | 13 | use crate::time::Hertz; |
| 14 | use crate::timer::TimerChannel; | ||
| 17 | use crate::Peri; | 15 | use crate::Peri; |
| 18 | 16 | ||
| 19 | /// Capture pin wrapper. | 17 | /// Capture pin wrapper. |
| @@ -23,27 +21,17 @@ pub struct CapturePin<'d, T, C> { | |||
| 23 | _pin: Peri<'d, AnyPin>, | 21 | _pin: Peri<'d, AnyPin>, |
| 24 | phantom: PhantomData<(T, C)>, | 22 | phantom: PhantomData<(T, C)>, |
| 25 | } | 23 | } |
| 26 | 24 | impl<'d, T: GeneralInstance4Channel, C: TimerChannel> CapturePin<'d, T, C> { | |
| 27 | macro_rules! channel_impl { | 25 | /// Create a new capture pin instance. |
| 28 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 26 | pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, pull: Pull) -> Self { |
| 29 | impl<'d, T: GeneralInstance4Channel> CapturePin<'d, T, $channel> { | 27 | pin.set_as_af(pin.af_num(), AfType::input(pull)); |
| 30 | #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")] | 28 | CapturePin { |
| 31 | pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, pull: Pull) -> Self { | 29 | _pin: pin.into(), |
| 32 | pin.set_as_af(pin.af_num(), AfType::input(pull)); | 30 | phantom: PhantomData, |
| 33 | CapturePin { | ||
| 34 | _pin: pin.into(), | ||
| 35 | phantom: PhantomData, | ||
| 36 | } | ||
| 37 | } | ||
| 38 | } | 31 | } |
| 39 | }; | 32 | } |
| 40 | } | 33 | } |
| 41 | 34 | ||
| 42 | channel_impl!(new_ch1, Ch1, Channel1Pin); | ||
| 43 | channel_impl!(new_ch2, Ch2, Channel2Pin); | ||
| 44 | channel_impl!(new_ch3, Ch3, Channel3Pin); | ||
| 45 | channel_impl!(new_ch4, Ch4, Channel4Pin); | ||
| 46 | |||
| 47 | /// Input capture driver. | 35 | /// Input capture driver. |
| 48 | pub struct InputCapture<'d, T: GeneralInstance4Channel> { | 36 | pub struct InputCapture<'d, T: GeneralInstance4Channel> { |
| 49 | inner: Timer<'d, T>, | 37 | inner: Timer<'d, T>, |
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index b29382fc8..7062f5f4c 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -51,6 +51,80 @@ pub enum Ch3 {} | |||
| 51 | /// Channel 4 marker type. | 51 | /// Channel 4 marker type. |
| 52 | pub enum Ch4 {} | 52 | pub enum Ch4 {} |
| 53 | 53 | ||
| 54 | /// Timer channel trait. | ||
| 55 | #[allow(private_bounds)] | ||
| 56 | pub trait TimerChannel: SealedTimerChannel { | ||
| 57 | /// The runtime channel. | ||
| 58 | const CHANNEL: Channel; | ||
| 59 | } | ||
| 60 | |||
| 61 | trait SealedTimerChannel {} | ||
| 62 | |||
| 63 | impl TimerChannel for Ch1 { | ||
| 64 | const CHANNEL: Channel = Channel::Ch1; | ||
| 65 | } | ||
| 66 | |||
| 67 | impl TimerChannel for Ch2 { | ||
| 68 | const CHANNEL: Channel = Channel::Ch2; | ||
| 69 | } | ||
| 70 | |||
| 71 | impl TimerChannel for Ch3 { | ||
| 72 | const CHANNEL: Channel = Channel::Ch3; | ||
| 73 | } | ||
| 74 | |||
| 75 | impl TimerChannel for Ch4 { | ||
| 76 | const CHANNEL: Channel = Channel::Ch4; | ||
| 77 | } | ||
| 78 | |||
| 79 | impl SealedTimerChannel for Ch1 {} | ||
| 80 | impl SealedTimerChannel for Ch2 {} | ||
| 81 | impl SealedTimerChannel for Ch3 {} | ||
| 82 | impl SealedTimerChannel for Ch4 {} | ||
| 83 | |||
| 84 | /// Timer break input. | ||
| 85 | #[derive(Clone, Copy)] | ||
| 86 | pub enum BkIn { | ||
| 87 | /// Break input 1. | ||
| 88 | BkIn1, | ||
| 89 | /// Break input 2. | ||
| 90 | BkIn2, | ||
| 91 | } | ||
| 92 | |||
| 93 | impl BkIn { | ||
| 94 | /// Get the channel index (0..3) | ||
| 95 | pub fn index(&self) -> usize { | ||
| 96 | match self { | ||
| 97 | BkIn::BkIn1 => 0, | ||
| 98 | BkIn::BkIn2 => 1, | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | /// Break input 1 marker type. | ||
| 104 | pub enum BkIn1 {} | ||
| 105 | /// Break input 2 marker type. | ||
| 106 | pub enum BkIn2 {} | ||
| 107 | |||
| 108 | /// Timer channel trait. | ||
| 109 | #[allow(private_bounds)] | ||
| 110 | pub trait BreakInput: SealedBreakInput { | ||
| 111 | /// The runtim timer channel. | ||
| 112 | const INPUT: BkIn; | ||
| 113 | } | ||
| 114 | |||
| 115 | trait SealedBreakInput {} | ||
| 116 | |||
| 117 | impl BreakInput for BkIn1 { | ||
| 118 | const INPUT: BkIn = BkIn::BkIn1; | ||
| 119 | } | ||
| 120 | |||
| 121 | impl BreakInput for BkIn2 { | ||
| 122 | const INPUT: BkIn = BkIn::BkIn2; | ||
| 123 | } | ||
| 124 | |||
| 125 | impl SealedBreakInput for BkIn1 {} | ||
| 126 | impl SealedBreakInput for BkIn2 {} | ||
| 127 | |||
| 54 | /// Amount of bits of a timer. | 128 | /// Amount of bits of a timer. |
| 55 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 129 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 56 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 130 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| @@ -149,33 +223,20 @@ pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + Ad | |||
| 149 | /// Advanced 16-bit timer with 4 channels instance. | 223 | /// Advanced 16-bit timer with 4 channels instance. |
| 150 | pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} | 224 | pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} |
| 151 | 225 | ||
| 152 | pin_trait!(Channel1Pin, GeneralInstance4Channel); | 226 | pin_trait!(TimerPin, GeneralInstance4Channel, TimerChannel); |
| 153 | pin_trait!(Channel2Pin, GeneralInstance4Channel); | ||
| 154 | pin_trait!(Channel3Pin, GeneralInstance4Channel); | ||
| 155 | pin_trait!(Channel4Pin, GeneralInstance4Channel); | ||
| 156 | pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); | 227 | pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); |
| 157 | 228 | ||
| 158 | pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel); | 229 | pin_trait!(TimerComplementaryPin, AdvancedInstance4Channel, TimerChannel); |
| 159 | pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel); | ||
| 160 | pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel); | ||
| 161 | pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel); | ||
| 162 | |||
| 163 | pin_trait!(BreakInputPin, AdvancedInstance4Channel); | ||
| 164 | pin_trait!(BreakInput2Pin, AdvancedInstance4Channel); | ||
| 165 | 230 | ||
| 166 | pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel); | 231 | pin_trait!(BreakInputPin, AdvancedInstance4Channel, BreakInput); |
| 167 | pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel); | ||
| 168 | 232 | ||
| 169 | pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel); | 233 | pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel, BreakInput); |
| 170 | pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel); | 234 | pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel, BreakInput); |
| 171 | 235 | ||
| 172 | // Update Event trigger DMA for every timer | 236 | // Update Event trigger DMA for every timer |
| 173 | dma_trait!(UpDma, BasicInstance); | 237 | dma_trait!(UpDma, BasicInstance); |
| 174 | 238 | ||
| 175 | dma_trait!(Ch1Dma, GeneralInstance4Channel); | 239 | dma_trait!(Dma, GeneralInstance4Channel, TimerChannel); |
| 176 | dma_trait!(Ch2Dma, GeneralInstance4Channel); | ||
| 177 | dma_trait!(Ch3Dma, GeneralInstance4Channel); | ||
| 178 | dma_trait!(Ch4Dma, GeneralInstance4Channel); | ||
| 179 | 240 | ||
| 180 | #[allow(unused)] | 241 | #[allow(unused)] |
| 181 | macro_rules! impl_core_timer { | 242 | macro_rules! impl_core_timer { |
diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs index 933165ef9..498d9c082 100644 --- a/embassy-stm32/src/timer/one_pulse.rs +++ b/embassy-stm32/src/timer/one_pulse.rs | |||
| @@ -7,11 +7,9 @@ use core::pin::Pin; | |||
| 7 | use core::task::{Context, Poll}; | 7 | use core::task::{Context, Poll}; |
| 8 | 8 | ||
| 9 | use super::low_level::{ | 9 | use super::low_level::{ |
| 10 | CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource, | 10 | CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource as Ts, |
| 11 | }; | ||
| 12 | use super::{ | ||
| 13 | CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, ExternalTriggerPin, GeneralInstance4Channel, | ||
| 14 | }; | 11 | }; |
| 12 | use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin}; | ||
| 15 | pub use super::{Ch1, Ch2}; | 13 | pub use super::{Ch1, Ch2}; |
| 16 | use crate::gpio::{AfType, AnyPin, Pull}; | 14 | use crate::gpio::{AfType, AnyPin, Pull}; |
| 17 | use crate::interrupt::typelevel::{Binding, Interrupt}; | 15 | use crate::interrupt::typelevel::{Binding, Interrupt}; |
| @@ -48,24 +46,78 @@ pub struct TriggerPin<'d, T, C> { | |||
| 48 | phantom: PhantomData<(T, C)>, | 46 | phantom: PhantomData<(T, C)>, |
| 49 | } | 47 | } |
| 50 | 48 | ||
| 51 | macro_rules! channel_impl { | 49 | trait SealedTriggerSource {} |
| 52 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 50 | |
| 53 | impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, $channel> { | 51 | /// Marker trait for a trigger source. |
| 54 | #[doc = concat!("Create a new ", stringify!($channel), " trigger pin instance.")] | 52 | #[expect(private_bounds)] |
| 55 | pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, pull: Pull) -> Self { | 53 | pub trait TriggerSource: SealedTriggerSource {} |
| 56 | pin.set_as_af(pin.af_num(), AfType::input(pull)); | 54 | |
| 57 | TriggerPin { | 55 | impl TriggerSource for Ch1 {} |
| 58 | _pin: pin.into(), | 56 | impl TriggerSource for Ch2 {} |
| 59 | phantom: PhantomData, | 57 | impl TriggerSource for Ext {} |
| 60 | } | 58 | |
| 61 | } | 59 | impl SealedTriggerSource for Ch1 {} |
| 62 | } | 60 | impl SealedTriggerSource for Ch2 {} |
| 63 | }; | 61 | impl SealedTriggerSource for Ext {} |
| 62 | |||
| 63 | trait SealedTimerTriggerPin<T, S>: crate::gpio::Pin {} | ||
| 64 | |||
| 65 | /// Marker trait for a trigger pin. | ||
| 66 | #[expect(private_bounds)] | ||
| 67 | // TODO: find better naming scheme than prefixing all pin traits with "Timer". | ||
| 68 | // The trait name cannot conflict with the corresponding type's name. | ||
| 69 | // Applies to other timer submodules as well. | ||
| 70 | pub trait TimerTriggerPin<T, S>: SealedTimerTriggerPin<T, S> { | ||
| 71 | /// Get the AF number needed to use this pin as a trigger source. | ||
| 72 | fn af_num(&self) -> u8; | ||
| 73 | } | ||
| 74 | |||
| 75 | impl<T, P, C> TimerTriggerPin<T, C> for P | ||
| 76 | where | ||
| 77 | T: GeneralInstance4Channel, | ||
| 78 | P: TimerPin<T, C>, | ||
| 79 | C: super::TimerChannel + TriggerSource, | ||
| 80 | { | ||
| 81 | fn af_num(&self) -> u8 { | ||
| 82 | TimerPin::af_num(self) | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | impl<T, P> TimerTriggerPin<T, Ext> for P | ||
| 87 | where | ||
| 88 | T: GeneralInstance4Channel, | ||
| 89 | P: ExternalTriggerPin<T>, | ||
| 90 | { | ||
| 91 | fn af_num(&self) -> u8 { | ||
| 92 | ExternalTriggerPin::af_num(self) | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | impl<T, P, C> SealedTimerTriggerPin<T, C> for P | ||
| 97 | where | ||
| 98 | T: GeneralInstance4Channel, | ||
| 99 | P: TimerPin<T, C>, | ||
| 100 | C: super::TimerChannel + TriggerSource, | ||
| 101 | { | ||
| 64 | } | 102 | } |
| 65 | 103 | ||
| 66 | channel_impl!(new_ch1, Ch1, Channel1Pin); | 104 | impl<T, P> SealedTimerTriggerPin<T, Ext> for P |
| 67 | channel_impl!(new_ch2, Ch2, Channel2Pin); | 105 | where |
| 68 | channel_impl!(new_ext, Ext, ExternalTriggerPin); | 106 | T: GeneralInstance4Channel, |
| 107 | P: ExternalTriggerPin<T>, | ||
| 108 | { | ||
| 109 | } | ||
| 110 | |||
| 111 | impl<'d, T: GeneralInstance4Channel, C: TriggerSource> TriggerPin<'d, T, C> { | ||
| 112 | /// "Create a new Ch1 trigger pin instance. | ||
| 113 | pub fn new(pin: Peri<'d, impl TimerTriggerPin<T, C>>, pull: Pull) -> Self { | ||
| 114 | pin.set_as_af(pin.af_num(), AfType::input(pull)); | ||
| 115 | TriggerPin { | ||
| 116 | _pin: pin.into(), | ||
| 117 | phantom: PhantomData, | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 69 | 121 | ||
| 70 | /// One pulse driver. | 122 | /// One pulse driver. |
| 71 | /// | 123 | /// |
| @@ -89,7 +141,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { | |||
| 89 | ) -> Self { | 141 | ) -> Self { |
| 90 | let mut this = Self { inner: Timer::new(tim) }; | 142 | let mut this = Self { inner: Timer::new(tim) }; |
| 91 | 143 | ||
| 92 | this.inner.set_trigger_source(TriggerSource::TI1F_ED); | 144 | this.inner.set_trigger_source(Ts::TI1F_ED); |
| 93 | this.inner | 145 | this.inner |
| 94 | .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal); | 146 | .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal); |
| 95 | this.inner | 147 | this.inner |
| @@ -114,7 +166,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { | |||
| 114 | ) -> Self { | 166 | ) -> Self { |
| 115 | let mut this = Self { inner: Timer::new(tim) }; | 167 | let mut this = Self { inner: Timer::new(tim) }; |
| 116 | 168 | ||
| 117 | this.inner.set_trigger_source(TriggerSource::TI1FP1); | 169 | this.inner.set_trigger_source(Ts::TI1FP1); |
| 118 | this.inner | 170 | this.inner |
| 119 | .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal); | 171 | .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal); |
| 120 | this.inner | 172 | this.inner |
| @@ -131,7 +183,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { | |||
| 131 | /// as an output. | 183 | /// as an output. |
| 132 | pub fn new_ch2( | 184 | pub fn new_ch2( |
| 133 | tim: Peri<'d, T>, | 185 | tim: Peri<'d, T>, |
| 134 | _pin: TriggerPin<'d, T, Ch1>, | 186 | _pin: TriggerPin<'d, T, Ch2>, |
| 135 | _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd, | 187 | _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd, |
| 136 | freq: Hertz, | 188 | freq: Hertz, |
| 137 | pulse_end: u32, | 189 | pulse_end: u32, |
| @@ -140,7 +192,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { | |||
| 140 | ) -> Self { | 192 | ) -> Self { |
| 141 | let mut this = Self { inner: Timer::new(tim) }; | 193 | let mut this = Self { inner: Timer::new(tim) }; |
| 142 | 194 | ||
| 143 | this.inner.set_trigger_source(TriggerSource::TI2FP2); | 195 | this.inner.set_trigger_source(Ts::TI2FP2); |
| 144 | this.inner | 196 | this.inner |
| 145 | .set_input_ti_selection(Channel::Ch2, InputTISelection::Normal); | 197 | .set_input_ti_selection(Channel::Ch2, InputTISelection::Normal); |
| 146 | this.inner | 198 | this.inner |
| @@ -172,7 +224,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { | |||
| 172 | // No filtering | 224 | // No filtering |
| 173 | r.set_etf(FilterValue::NO_FILTER); | 225 | r.set_etf(FilterValue::NO_FILTER); |
| 174 | }); | 226 | }); |
| 175 | this.inner.set_trigger_source(TriggerSource::ETRF); | 227 | this.inner.set_trigger_source(Ts::ETRF); |
| 176 | this.new_inner(freq, pulse_end, counting_mode); | 228 | this.new_inner(freq, pulse_end, counting_mode); |
| 177 | 229 | ||
| 178 | this | 230 | this |
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs index 98b798634..1e55f2919 100644 --- a/embassy-stm32/src/timer/pwm_input.rs +++ b/embassy-stm32/src/timer/pwm_input.rs | |||
| @@ -1,12 +1,16 @@ | |||
| 1 | //! PWM Input driver. | 1 | //! PWM Input driver. |
| 2 | 2 | ||
| 3 | use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; | 3 | use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; |
| 4 | use super::{Channel, Channel1Pin, Channel2Pin, GeneralInstance4Channel}; | 4 | use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin}; |
| 5 | use crate::gpio::{AfType, Pull}; | 5 | use crate::gpio::{AfType, Pull}; |
| 6 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| 7 | use crate::Peri; | 7 | use crate::Peri; |
| 8 | 8 | ||
| 9 | /// PWM Input driver. | 9 | /// PWM Input driver. |
| 10 | /// | ||
| 11 | /// Only works with CH1 or CH2 | ||
| 12 | /// Note: Not all timer peripherals are supported | ||
| 13 | /// Double check your chips reference manual | ||
| 10 | pub struct PwmInput<'d, T: GeneralInstance4Channel> { | 14 | pub struct PwmInput<'d, T: GeneralInstance4Channel> { |
| 11 | channel: Channel, | 15 | channel: Channel, |
| 12 | inner: Timer<'d, T>, | 16 | inner: Timer<'d, T>, |
| @@ -14,14 +18,14 @@ pub struct PwmInput<'d, T: GeneralInstance4Channel> { | |||
| 14 | 18 | ||
| 15 | impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { | 19 | impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { |
| 16 | /// Create a new PWM input driver. | 20 | /// Create a new PWM input driver. |
| 17 | pub fn new(tim: Peri<'d, T>, pin: Peri<'d, impl Channel1Pin<T>>, pull: Pull, freq: Hertz) -> Self { | 21 | pub fn new_ch1(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch1>>, pull: Pull, freq: Hertz) -> Self { |
| 18 | pin.set_as_af(pin.af_num(), AfType::input(pull)); | 22 | pin.set_as_af(pin.af_num(), AfType::input(pull)); |
| 19 | 23 | ||
| 20 | Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2) | 24 | Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2) |
| 21 | } | 25 | } |
| 22 | 26 | ||
| 23 | /// Create a new PWM input driver. | 27 | /// Create a new PWM input driver. |
| 24 | pub fn new_alt(tim: Peri<'d, T>, pin: Peri<'d, impl Channel2Pin<T>>, pull: Pull, freq: Hertz) -> Self { | 28 | pub fn new_ch2(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch2>>, pull: Pull, freq: Hertz) -> Self { |
| 25 | pin.set_as_af(pin.af_num(), AfType::input(pull)); | 29 | pin.set_as_af(pin.af_num(), AfType::input(pull)); |
| 26 | 30 | ||
| 27 | Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1) | 31 | Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1) |
| @@ -37,6 +41,7 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { | |||
| 37 | 41 | ||
| 38 | // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6 | 42 | // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6 |
| 39 | // or ST RM0008 (STM32F103) chapter 15.3.6 Input capture mode | 43 | // or ST RM0008 (STM32F103) chapter 15.3.6 Input capture mode |
| 44 | // or ST RM0440 (STM32G4) chapter 30.4.8 PWM input mode | ||
| 40 | inner.set_input_ti_selection(ch1, InputTISelection::Normal); | 45 | inner.set_input_ti_selection(ch1, InputTISelection::Normal); |
| 41 | inner.set_input_capture_mode(ch1, InputCaptureMode::Rising); | 46 | inner.set_input_capture_mode(ch1, InputCaptureMode::Rising); |
| 42 | 47 | ||
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index f3c81667c..eabe1b22a 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs | |||
| @@ -6,8 +6,9 @@ use stm32_metapac::timer::vals; | |||
| 6 | 6 | ||
| 7 | use super::low_level::Timer; | 7 | use super::low_level::Timer; |
| 8 | pub use super::{Ch1, Ch2}; | 8 | pub use super::{Ch1, Ch2}; |
| 9 | use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel}; | 9 | use super::{GeneralInstance4Channel, TimerPin}; |
| 10 | use crate::gpio::{AfType, AnyPin, Pull}; | 10 | use crate::gpio::{AfType, AnyPin, Pull}; |
| 11 | use crate::timer::TimerChannel; | ||
| 11 | use crate::Peri; | 12 | use crate::Peri; |
| 12 | 13 | ||
| 13 | /// Counting direction | 14 | /// Counting direction |
| @@ -24,26 +25,31 @@ pub struct QeiPin<'d, T, Channel> { | |||
| 24 | phantom: PhantomData<(T, Channel)>, | 25 | phantom: PhantomData<(T, Channel)>, |
| 25 | } | 26 | } |
| 26 | 27 | ||
| 27 | macro_rules! channel_impl { | 28 | impl<'d, T: GeneralInstance4Channel, C: QeiChannel> QeiPin<'d, T, C> { |
| 28 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 29 | /// Create a new QEI pin instance. |
| 29 | impl<'d, T: GeneralInstance4Channel> QeiPin<'d, T, $channel> { | 30 | pub fn new(pin: Peri<'d, impl TimerPin<T, C>>) -> Self { |
| 30 | #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] | 31 | critical_section::with(|_| { |
| 31 | pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self { | 32 | pin.set_low(); |
| 32 | critical_section::with(|_| { | 33 | pin.set_as_af(pin.af_num(), AfType::input(Pull::None)); |
| 33 | pin.set_low(); | 34 | }); |
| 34 | pin.set_as_af(pin.af_num(), AfType::input(Pull::None)); | 35 | QeiPin { |
| 35 | }); | 36 | _pin: pin.into(), |
| 36 | QeiPin { | 37 | phantom: PhantomData, |
| 37 | _pin: pin.into(), | ||
| 38 | phantom: PhantomData, | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | 38 | } |
| 42 | }; | 39 | } |
| 43 | } | 40 | } |
| 44 | 41 | ||
| 45 | channel_impl!(new_ch1, Ch1, Channel1Pin); | 42 | trait SealedQeiChannel: TimerChannel {} |
| 46 | channel_impl!(new_ch2, Ch2, Channel2Pin); | 43 | |
| 44 | /// Marker trait for a timer channel eligible for use with QEI. | ||
| 45 | #[expect(private_bounds)] | ||
| 46 | pub trait QeiChannel: SealedQeiChannel {} | ||
| 47 | |||
| 48 | impl QeiChannel for Ch1 {} | ||
| 49 | impl QeiChannel for Ch2 {} | ||
| 50 | |||
| 51 | impl SealedQeiChannel for Ch1 {} | ||
| 52 | impl SealedQeiChannel for Ch2 {} | ||
| 47 | 53 | ||
| 48 | /// Quadrature decoder driver. | 54 | /// Quadrature decoder driver. |
| 49 | pub struct Qei<'d, T: GeneralInstance4Channel> { | 55 | pub struct Qei<'d, T: GeneralInstance4Channel> { |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index f7f433154..c04b1ab97 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -4,22 +4,13 @@ use core::marker::PhantomData; | |||
| 4 | use core::mem::ManuallyDrop; | 4 | use core::mem::ManuallyDrop; |
| 5 | 5 | ||
| 6 | use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; | 6 | use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; |
| 7 | use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel, TimerBits}; | 7 | use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin}; |
| 8 | #[cfg(gpio_v2)] | 8 | #[cfg(gpio_v2)] |
| 9 | use crate::gpio::Pull; | 9 | use crate::gpio::Pull; |
| 10 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; | 10 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; |
| 11 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 12 | use crate::Peri; | 12 | use crate::Peri; |
| 13 | 13 | ||
| 14 | /// Channel 1 marker type. | ||
| 15 | pub enum Ch1 {} | ||
| 16 | /// Channel 2 marker type. | ||
| 17 | pub enum Ch2 {} | ||
| 18 | /// Channel 3 marker type. | ||
| 19 | pub enum Ch3 {} | ||
| 20 | /// Channel 4 marker type. | ||
| 21 | pub enum Ch4 {} | ||
| 22 | |||
| 23 | /// PWM pin wrapper. | 14 | /// PWM pin wrapper. |
| 24 | /// | 15 | /// |
| 25 | /// This wraps a pin to make it usable with PWM. | 16 | /// This wraps a pin to make it usable with PWM. |
| @@ -43,46 +34,37 @@ pub struct PwmPinConfig { | |||
| 43 | pub pull: Pull, | 34 | pub pull: Pull, |
| 44 | } | 35 | } |
| 45 | 36 | ||
| 46 | macro_rules! channel_impl { | 37 | impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> { |
| 47 | ($new_chx:ident, $new_chx_with_config:ident, $channel:ident, $pin_trait:ident) => { | 38 | /// Create a new PWM pin instance. |
| 48 | impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> { | 39 | pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, output_type: OutputType) -> Self { |
| 49 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] | 40 | critical_section::with(|_| { |
| 50 | pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, output_type: OutputType) -> Self { | 41 | pin.set_low(); |
| 51 | critical_section::with(|_| { | 42 | pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh)); |
| 52 | pin.set_low(); | 43 | }); |
| 53 | pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh)); | 44 | PwmPin { |
| 54 | }); | 45 | _pin: pin.into(), |
| 55 | PwmPin { | 46 | phantom: PhantomData, |
| 56 | _pin: pin.into(), | ||
| 57 | phantom: PhantomData, | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with config.")] | ||
| 62 | pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait<T>>, pin_config: PwmPinConfig) -> Self { | ||
| 63 | critical_section::with(|_| { | ||
| 64 | pin.set_low(); | ||
| 65 | pin.set_as_af( | ||
| 66 | pin.af_num(), | ||
| 67 | #[cfg(gpio_v1)] | ||
| 68 | AfType::output(pin_config.output_type, pin_config.speed), | ||
| 69 | #[cfg(gpio_v2)] | ||
| 70 | AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), | ||
| 71 | ); | ||
| 72 | }); | ||
| 73 | PwmPin { | ||
| 74 | _pin: pin.into(), | ||
| 75 | phantom: PhantomData, | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | 47 | } |
| 79 | }; | 48 | } |
| 80 | } | ||
| 81 | 49 | ||
| 82 | channel_impl!(new_ch1, new_ch1_with_config, Ch1, Channel1Pin); | 50 | /// Create a new PWM pin instance with config. |
| 83 | channel_impl!(new_ch2, new_ch2_with_config, Ch2, Channel2Pin); | 51 | pub fn new_with_config(pin: Peri<'d, impl TimerPin<T, C>>, pin_config: PwmPinConfig) -> Self { |
| 84 | channel_impl!(new_ch3, new_ch3_with_config, Ch3, Channel3Pin); | 52 | critical_section::with(|_| { |
| 85 | channel_impl!(new_ch4, new_ch4_with_config, Ch4, Channel4Pin); | 53 | pin.set_low(); |
| 54 | pin.set_as_af( | ||
| 55 | pin.af_num(), | ||
| 56 | #[cfg(gpio_v1)] | ||
| 57 | AfType::output(pin_config.output_type, pin_config.speed), | ||
| 58 | #[cfg(gpio_v2)] | ||
| 59 | AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), | ||
| 60 | ); | ||
| 61 | }); | ||
| 62 | PwmPin { | ||
| 63 | _pin: pin.into(), | ||
| 64 | phantom: PhantomData, | ||
| 65 | } | ||
| 66 | } | ||
| 67 | } | ||
| 86 | 68 | ||
| 87 | /// A single channel of a pwm, obtained from [`SimplePwm::split`], | 69 | /// A single channel of a pwm, obtained from [`SimplePwm::split`], |
| 88 | /// [`SimplePwm::channel`], [`SimplePwm::ch1`], etc. | 70 | /// [`SimplePwm::channel`], [`SimplePwm::ch1`], etc. |
| @@ -466,107 +448,98 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 466 | } | 448 | } |
| 467 | } | 449 | } |
| 468 | 450 | ||
| 469 | macro_rules! impl_waveform_chx { | 451 | impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { |
| 470 | ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { | 452 | /// Generate a sequence of PWM waveform |
| 471 | impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | 453 | pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { |
| 472 | /// Generate a sequence of PWM waveform | 454 | use crate::pac::timer::vals::Ccds; |
| 473 | pub async fn $fn_name(&mut self, dma: Peri<'_, impl super::$dma_ch<T>>, duty: &[u16]) { | 455 | |
| 474 | use crate::pac::timer::vals::Ccds; | 456 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| 457 | let req = dma.request(); | ||
| 475 | 458 | ||
| 476 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 459 | let cc_channel = C::CHANNEL; |
| 477 | let req = dma.request(); | ||
| 478 | 460 | ||
| 479 | let cc_channel = Channel::$cc_ch; | 461 | let original_duty_state = self.channel(cc_channel).current_duty_cycle(); |
| 462 | let original_enable_state = self.channel(cc_channel).is_enabled(); | ||
| 463 | let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE; | ||
| 464 | let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); | ||
| 480 | 465 | ||
| 481 | let original_duty_state = self.channel(cc_channel).current_duty_cycle(); | 466 | // redirect CC DMA request onto Update Event |
| 482 | let original_enable_state = self.channel(cc_channel).is_enabled(); | 467 | if !original_cc_dma_on_update { |
| 483 | let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE; | 468 | self.inner.set_cc_dma_selection(Ccds::ON_UPDATE) |
| 484 | let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); | 469 | } |
| 485 | 470 | ||
| 486 | // redirect CC DMA request onto Update Event | 471 | if !original_cc_dma_enabled { |
| 487 | if !original_cc_dma_on_update { | 472 | self.inner.set_cc_dma_enable_state(cc_channel, true); |
| 488 | self.inner.set_cc_dma_selection(Ccds::ON_UPDATE) | 473 | } |
| 489 | } | ||
| 490 | 474 | ||
| 491 | if !original_cc_dma_enabled { | 475 | if !original_enable_state { |
| 492 | self.inner.set_cc_dma_enable_state(cc_channel, true); | 476 | self.channel(cc_channel).enable(); |
| 493 | } | 477 | } |
| 494 | 478 | ||
| 495 | if !original_enable_state { | 479 | unsafe { |
| 496 | self.channel(cc_channel).enable(); | 480 | #[cfg(not(any(bdma, gpdma)))] |
| 497 | } | 481 | use crate::dma::{Burst, FifoThreshold}; |
| 482 | use crate::dma::{Transfer, TransferOptions}; | ||
| 498 | 483 | ||
| 499 | unsafe { | 484 | let dma_transfer_option = TransferOptions { |
| 485 | #[cfg(not(any(bdma, gpdma)))] | ||
| 486 | fifo_threshold: Some(FifoThreshold::Full), | ||
| 487 | #[cfg(not(any(bdma, gpdma)))] | ||
| 488 | mburst: Burst::Incr8, | ||
| 489 | ..Default::default() | ||
| 490 | }; | ||
| 491 | |||
| 492 | match self.inner.bits() { | ||
| 493 | TimerBits::Bits16 => { | ||
| 494 | Transfer::new_write( | ||
| 495 | dma, | ||
| 496 | req, | ||
| 497 | duty, | ||
| 498 | self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, | ||
| 499 | dma_transfer_option, | ||
| 500 | ) | ||
| 501 | .await | ||
| 502 | } | ||
| 503 | #[cfg(not(any(stm32l0)))] | ||
| 504 | TimerBits::Bits32 => { | ||
| 500 | #[cfg(not(any(bdma, gpdma)))] | 505 | #[cfg(not(any(bdma, gpdma)))] |
| 501 | use crate::dma::{Burst, FifoThreshold}; | 506 | panic!("unsupported timer bits"); |
| 502 | use crate::dma::{Transfer, TransferOptions}; | 507 | |
| 503 | 508 | #[cfg(any(bdma, gpdma))] | |
| 504 | let dma_transfer_option = TransferOptions { | 509 | Transfer::new_write( |
| 505 | #[cfg(not(any(bdma, gpdma)))] | 510 | dma, |
| 506 | fifo_threshold: Some(FifoThreshold::Full), | 511 | req, |
| 507 | #[cfg(not(any(bdma, gpdma)))] | 512 | duty, |
| 508 | mburst: Burst::Incr8, | 513 | self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, |
| 509 | ..Default::default() | 514 | dma_transfer_option, |
| 510 | }; | 515 | ) |
| 511 | 516 | .await | |
| 512 | match self.inner.bits() { | ||
| 513 | TimerBits::Bits16 => { | ||
| 514 | Transfer::new_write( | ||
| 515 | dma, | ||
| 516 | req, | ||
| 517 | duty, | ||
| 518 | self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, | ||
| 519 | dma_transfer_option, | ||
| 520 | ) | ||
| 521 | .await | ||
| 522 | } | ||
| 523 | #[cfg(not(any(stm32l0)))] | ||
| 524 | TimerBits::Bits32 => { | ||
| 525 | #[cfg(not(any(bdma, gpdma)))] | ||
| 526 | panic!("unsupported timer bits"); | ||
| 527 | |||
| 528 | #[cfg(any(bdma, gpdma))] | ||
| 529 | Transfer::new_write( | ||
| 530 | dma, | ||
| 531 | req, | ||
| 532 | duty, | ||
| 533 | self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, | ||
| 534 | dma_transfer_option, | ||
| 535 | ) | ||
| 536 | .await | ||
| 537 | } | ||
| 538 | }; | ||
| 539 | }; | ||
| 540 | |||
| 541 | // restore output compare state | ||
| 542 | if !original_enable_state { | ||
| 543 | self.channel(cc_channel).disable(); | ||
| 544 | } | 517 | } |
| 518 | }; | ||
| 519 | }; | ||
| 520 | |||
| 521 | // restore output compare state | ||
| 522 | if !original_enable_state { | ||
| 523 | self.channel(cc_channel).disable(); | ||
| 524 | } | ||
| 545 | 525 | ||
| 546 | self.channel(cc_channel).set_duty_cycle(original_duty_state); | 526 | self.channel(cc_channel).set_duty_cycle(original_duty_state); |
| 547 | 527 | ||
| 548 | // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, | 528 | // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, |
| 549 | // this can almost always trigger a DMA FIFO error. | 529 | // this can almost always trigger a DMA FIFO error. |
| 550 | // | 530 | // |
| 551 | // optional TODO: | 531 | // optional TODO: |
| 552 | // clean FEIF after disable UDE | 532 | // clean FEIF after disable UDE |
| 553 | if !original_cc_dma_enabled { | 533 | if !original_cc_dma_enabled { |
| 554 | self.inner.set_cc_dma_enable_state(cc_channel, false); | 534 | self.inner.set_cc_dma_enable_state(cc_channel, false); |
| 555 | } | 535 | } |
| 556 | 536 | ||
| 557 | if !original_cc_dma_on_update { | 537 | if !original_cc_dma_on_update { |
| 558 | self.inner.set_cc_dma_selection(Ccds::ON_COMPARE) | 538 | self.inner.set_cc_dma_selection(Ccds::ON_COMPARE) |
| 559 | } | ||
| 560 | } | ||
| 561 | } | 539 | } |
| 562 | }; | 540 | } |
| 563 | } | 541 | } |
| 564 | 542 | ||
| 565 | impl_waveform_chx!(waveform_ch1, Ch1Dma, Ch1); | ||
| 566 | impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); | ||
| 567 | impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); | ||
| 568 | impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); | ||
| 569 | |||
| 570 | impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { | 543 | impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { |
| 571 | type Error = core::convert::Infallible; | 544 | type Error = core::convert::Infallible; |
| 572 | } | 545 | } |
diff --git a/embassy-stm32/src/tsc/acquisition_banks.rs b/embassy-stm32/src/tsc/acquisition_banks.rs index 6791ef6c1..7d6442b48 100644 --- a/embassy-stm32/src/tsc/acquisition_banks.rs +++ b/embassy-stm32/src/tsc/acquisition_banks.rs | |||
| @@ -32,7 +32,7 @@ impl AcquisitionBankPins { | |||
| 32 | /// Returns an iterator over the pins in this acquisition bank. | 32 | /// Returns an iterator over the pins in this acquisition bank. |
| 33 | /// | 33 | /// |
| 34 | /// This method allows for easy traversal of all configured pins in the bank. | 34 | /// This method allows for easy traversal of all configured pins in the bank. |
| 35 | pub fn iter(&self) -> AcquisitionBankPinsIterator { | 35 | pub fn iter(&self) -> AcquisitionBankPinsIterator<'_> { |
| 36 | AcquisitionBankPinsIterator(AcquisitionBankIterator::new(self)) | 36 | AcquisitionBankPinsIterator(AcquisitionBankIterator::new(self)) |
| 37 | } | 37 | } |
| 38 | } | 38 | } |
| @@ -90,7 +90,7 @@ impl<'a> Iterator for AcquisitionBankPinsIterator<'a> { | |||
| 90 | 90 | ||
| 91 | impl AcquisitionBankPins { | 91 | impl AcquisitionBankPins { |
| 92 | /// Returns an iterator over the available pins in the bank | 92 | /// Returns an iterator over the available pins in the bank |
| 93 | pub fn pins_iterator(&self) -> AcquisitionBankPinsIterator { | 93 | pub fn pins_iterator(&self) -> AcquisitionBankPinsIterator<'_> { |
| 94 | AcquisitionBankPinsIterator(AcquisitionBankIterator::new(self)) | 94 | AcquisitionBankPinsIterator(AcquisitionBankIterator::new(self)) |
| 95 | } | 95 | } |
| 96 | } | 96 | } |
| @@ -107,7 +107,7 @@ pub struct AcquisitionBank { | |||
| 107 | 107 | ||
| 108 | impl AcquisitionBank { | 108 | impl AcquisitionBank { |
| 109 | /// Returns an iterator over the available pins in the bank. | 109 | /// Returns an iterator over the available pins in the bank. |
| 110 | pub fn pins_iterator(&self) -> AcquisitionBankPinsIterator { | 110 | pub fn pins_iterator(&self) -> AcquisitionBankPinsIterator<'_> { |
| 111 | self.pins.pins_iterator() | 111 | self.pins.pins_iterator() |
| 112 | } | 112 | } |
| 113 | 113 | ||
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 73ab46404..729440c46 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -87,6 +87,8 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) { | |||
| 87 | 87 | ||
| 88 | r.cr1().modify(|w| { | 88 | r.cr1().modify(|w| { |
| 89 | w.set_tcie(false); | 89 | w.set_tcie(false); |
| 90 | // Reenable receiver for half-duplex if it was disabled | ||
| 91 | w.set_re(true); | ||
| 90 | }); | 92 | }); |
| 91 | 93 | ||
| 92 | state.tx_done.store(true, Ordering::Release); | 94 | state.tx_done.store(true, Ordering::Release); |
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index b3f8bc00c..5bece6d66 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -550,6 +550,20 @@ impl<'d, M: Mode> UartTx<'d, M> { | |||
| 550 | reconfigure(self.info, self.kernel_clock, config) | 550 | reconfigure(self.info, self.kernel_clock, config) |
| 551 | } | 551 | } |
| 552 | 552 | ||
| 553 | /// Write a single u8 if there is tx empty, otherwise return WouldBlock | ||
| 554 | pub(crate) fn nb_write(&mut self, byte: u8) -> Result<(), nb::Error<Error>> { | ||
| 555 | let r = self.info.regs; | ||
| 556 | let sr = sr(r).read(); | ||
| 557 | if sr.txe() { | ||
| 558 | unsafe { | ||
| 559 | tdr(r).write_volatile(byte); | ||
| 560 | } | ||
| 561 | Ok(()) | ||
| 562 | } else { | ||
| 563 | Err(nb::Error::WouldBlock) | ||
| 564 | } | ||
| 565 | } | ||
| 566 | |||
| 553 | /// Perform a blocking UART write | 567 | /// Perform a blocking UART write |
| 554 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 568 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 555 | let r = self.info.regs; | 569 | let r = self.info.regs; |
| @@ -637,7 +651,7 @@ pub fn send_break(regs: &Regs) { | |||
| 637 | /// In case of readback, keep Receiver enabled | 651 | /// In case of readback, keep Receiver enabled |
| 638 | fn half_duplex_set_rx_tx_before_write(r: &Regs, enable_readback: bool) { | 652 | fn half_duplex_set_rx_tx_before_write(r: &Regs, enable_readback: bool) { |
| 639 | let mut cr1 = r.cr1().read(); | 653 | let mut cr1 = r.cr1().read(); |
| 640 | if r.cr3().read().hdsel() && !cr1.te() { | 654 | if r.cr3().read().hdsel() { |
| 641 | cr1.set_te(true); | 655 | cr1.set_te(true); |
| 642 | cr1.set_re(enable_readback); | 656 | cr1.set_re(enable_readback); |
| 643 | r.cr1().write_value(cr1); | 657 | r.cr1().write_value(cr1); |
| @@ -1864,7 +1878,7 @@ impl<'d, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, M> { | |||
| 1864 | 1878 | ||
| 1865 | impl<'d, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, M> { | 1879 | impl<'d, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, M> { |
| 1866 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | 1880 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { |
| 1867 | self.blocking_write(&[char]).map_err(nb::Error::Other) | 1881 | self.nb_write(char) |
| 1868 | } | 1882 | } |
| 1869 | 1883 | ||
| 1870 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | 1884 | fn flush(&mut self) -> nb::Result<(), Self::Error> { |
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index ae5963420..692897b59 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs | |||
| @@ -15,7 +15,7 @@ fn common_init<T: Instance>() { | |||
| 15 | let freq = T::frequency(); | 15 | let freq = T::frequency(); |
| 16 | 16 | ||
| 17 | // On the H7RS, the USBPHYC embeds a PLL accepting one of the input frequencies listed below and providing 48MHz to OTG_FS and 60MHz to OTG_HS internally | 17 | // On the H7RS, the USBPHYC embeds a PLL accepting one of the input frequencies listed below and providing 48MHz to OTG_FS and 60MHz to OTG_HS internally |
| 18 | #[cfg(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs)))] | 18 | #[cfg(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs), all(stm32wba, peri_usb_otg_hs)))] |
| 19 | if ![16_000_000, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&freq.0) { | 19 | if ![16_000_000, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&freq.0) { |
| 20 | panic!( | 20 | panic!( |
| 21 | "USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but is {} Hz. Please double-check your RCC settings.", | 21 | "USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but is {} Hz. Please double-check your RCC settings.", |
| @@ -25,7 +25,7 @@ fn common_init<T: Instance>() { | |||
| 25 | // Check frequency is within the 0.25% tolerance allowed by the spec. | 25 | // Check frequency is within the 0.25% tolerance allowed by the spec. |
| 26 | // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user | 26 | // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user |
| 27 | // has tight clock restrictions due to something else (like audio). | 27 | // has tight clock restrictions due to something else (like audio). |
| 28 | #[cfg(not(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs))))] | 28 | #[cfg(not(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs), all(stm32wba, peri_usb_otg_hs))))] |
| 29 | if freq.0.abs_diff(48_000_000) > 120_000 { | 29 | if freq.0.abs_diff(48_000_000) > 120_000 { |
| 30 | panic!( | 30 | panic!( |
| 31 | "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.", | 31 | "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.", |
| @@ -102,6 +102,30 @@ fn common_init<T: Instance>() { | |||
| 102 | } | 102 | } |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | #[cfg(stm32wba)] | ||
| 106 | { | ||
| 107 | // Enable USB power | ||
| 108 | critical_section::with(|_| { | ||
| 109 | crate::pac::PWR.svmcr().modify(|w| { | ||
| 110 | w.set_usv(crate::pac::pwr::vals::Usv::B_0X1); | ||
| 111 | // w.set_uvmen(true); | ||
| 112 | }) | ||
| 113 | }); | ||
| 114 | |||
| 115 | // Wait for USB power to stabilize | ||
| 116 | while !crate::pac::PWR.vosr().read().vdd11usbrdy() {} | ||
| 117 | |||
| 118 | // Now set up transceiver power if it's a OTG-HS | ||
| 119 | #[cfg(peri_usb_otg_hs)] | ||
| 120 | { | ||
| 121 | crate::pac::PWR.vosr().modify(|w| { | ||
| 122 | w.set_usbpwren(true); | ||
| 123 | w.set_usbboosten(true); | ||
| 124 | }); | ||
| 125 | while !crate::pac::PWR.vosr().read().usbboostrdy() {} | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 105 | T::Interrupt::unpend(); | 129 | T::Interrupt::unpend(); |
| 106 | unsafe { T::Interrupt::enable() }; | 130 | unsafe { T::Interrupt::enable() }; |
| 107 | 131 | ||
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 590d1a427..b074cfa1b 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs | |||
| @@ -105,7 +105,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 105 | config: Config, | 105 | config: Config, |
| 106 | ) -> Self { | 106 | ) -> Self { |
| 107 | // For STM32U5 High speed pins need to be left in analog mode | 107 | // For STM32U5 High speed pins need to be left in analog mode |
| 108 | #[cfg(not(all(stm32u5, peri_usb_otg_hs)))] | 108 | #[cfg(not(any(all(stm32u5, peri_usb_otg_hs), all(stm32wba, peri_usb_otg_hs))))] |
| 109 | { | 109 | { |
| 110 | _dp.set_as_af(_dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); | 110 | _dp.set_as_af(_dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); |
| 111 | _dm.set_as_af(_dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); | 111 | _dm.set_as_af(_dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); |
| @@ -231,19 +231,23 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { | |||
| 231 | fn alloc_endpoint_in( | 231 | fn alloc_endpoint_in( |
| 232 | &mut self, | 232 | &mut self, |
| 233 | ep_type: EndpointType, | 233 | ep_type: EndpointType, |
| 234 | ep_addr: Option<EndpointAddress>, | ||
| 234 | max_packet_size: u16, | 235 | max_packet_size: u16, |
| 235 | interval_ms: u8, | 236 | interval_ms: u8, |
| 236 | ) -> Result<Self::EndpointIn, EndpointAllocError> { | 237 | ) -> Result<Self::EndpointIn, EndpointAllocError> { |
| 237 | self.inner.alloc_endpoint_in(ep_type, max_packet_size, interval_ms) | 238 | self.inner |
| 239 | .alloc_endpoint_in(ep_type, ep_addr, max_packet_size, interval_ms) | ||
| 238 | } | 240 | } |
| 239 | 241 | ||
| 240 | fn alloc_endpoint_out( | 242 | fn alloc_endpoint_out( |
| 241 | &mut self, | 243 | &mut self, |
| 242 | ep_type: EndpointType, | 244 | ep_type: EndpointType, |
| 245 | ep_addr: Option<EndpointAddress>, | ||
| 243 | max_packet_size: u16, | 246 | max_packet_size: u16, |
| 244 | interval_ms: u8, | 247 | interval_ms: u8, |
| 245 | ) -> Result<Self::EndpointOut, EndpointAllocError> { | 248 | ) -> Result<Self::EndpointOut, EndpointAllocError> { |
| 246 | self.inner.alloc_endpoint_out(ep_type, max_packet_size, interval_ms) | 249 | self.inner |
| 250 | .alloc_endpoint_out(ep_type, ep_addr, max_packet_size, interval_ms) | ||
| 247 | } | 251 | } |
| 248 | 252 | ||
| 249 | fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { | 253 | fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { |
| @@ -323,6 +327,20 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 323 | }); | 327 | }); |
| 324 | } | 328 | } |
| 325 | 329 | ||
| 330 | #[cfg(all(stm32wba, peri_usb_otg_hs))] | ||
| 331 | { | ||
| 332 | crate::pac::SYSCFG.otghsphycr().modify(|w| { | ||
| 333 | w.set_en(true); | ||
| 334 | }); | ||
| 335 | |||
| 336 | critical_section::with(|_| { | ||
| 337 | crate::pac::RCC.ahb2enr().modify(|w| { | ||
| 338 | w.set_usb_otg_hsen(true); | ||
| 339 | w.set_otghsphyen(true); | ||
| 340 | }); | ||
| 341 | }); | ||
| 342 | } | ||
| 343 | |||
| 326 | let r = T::regs(); | 344 | let r = T::regs(); |
| 327 | let core_id = r.cid().read().0; | 345 | let core_id = r.cid().read().0; |
| 328 | trace!("Core id {:08x}", core_id); | 346 | trace!("Core id {:08x}", core_id); |
| @@ -464,6 +482,7 @@ foreach_interrupt!( | |||
| 464 | stm32f7, | 482 | stm32f7, |
| 465 | stm32l4, | 483 | stm32l4, |
| 466 | stm32u5, | 484 | stm32u5, |
| 485 | stm32wba, | ||
| 467 | ))] { | 486 | ))] { |
| 468 | const FIFO_DEPTH_WORDS: u16 = 320; | 487 | const FIFO_DEPTH_WORDS: u16 = 320; |
| 469 | const ENDPOINT_COUNT: usize = 6; | 488 | const ENDPOINT_COUNT: usize = 6; |
| @@ -473,7 +492,7 @@ foreach_interrupt!( | |||
| 473 | } else if #[cfg(any(stm32h7, stm32h7rs))] { | 492 | } else if #[cfg(any(stm32h7, stm32h7rs))] { |
| 474 | const FIFO_DEPTH_WORDS: u16 = 1024; | 493 | const FIFO_DEPTH_WORDS: u16 = 1024; |
| 475 | const ENDPOINT_COUNT: usize = 9; | 494 | const ENDPOINT_COUNT: usize = 9; |
| 476 | } else if #[cfg(stm32u5)] { | 495 | } else if #[cfg(any(stm32wba, stm32u5))] { |
| 477 | const FIFO_DEPTH_WORDS: u16 = 320; | 496 | const FIFO_DEPTH_WORDS: u16 = 320; |
| 478 | const ENDPOINT_COUNT: usize = 6; | 497 | const ENDPOINT_COUNT: usize = 6; |
| 479 | } else { | 498 | } else { |
| @@ -523,7 +542,7 @@ foreach_interrupt!( | |||
| 523 | ))] { | 542 | ))] { |
| 524 | const FIFO_DEPTH_WORDS: u16 = 1024; | 543 | const FIFO_DEPTH_WORDS: u16 = 1024; |
| 525 | const ENDPOINT_COUNT: usize = 9; | 544 | const ENDPOINT_COUNT: usize = 9; |
| 526 | } else if #[cfg(stm32u5)] { | 545 | } else if #[cfg(any(stm32u5, stm32wba))] { |
| 527 | const FIFO_DEPTH_WORDS: u16 = 1024; | 546 | const FIFO_DEPTH_WORDS: u16 = 1024; |
| 528 | const ENDPOINT_COUNT: usize = 9; | 547 | const ENDPOINT_COUNT: usize = 9; |
| 529 | } else { | 548 | } else { |
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 3e8e74a1f..92c1601cc 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -359,9 +359,38 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 359 | addr | 359 | addr |
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | fn is_endpoint_available<D: Dir>(&self, index: usize, ep_type: EndpointType) -> bool { | ||
| 363 | if index == 0 && ep_type != EndpointType::Control { | ||
| 364 | return false; // EP0 is reserved for control | ||
| 365 | } | ||
| 366 | |||
| 367 | let ep = match self.alloc.get(index) { | ||
| 368 | Some(ep) => ep, | ||
| 369 | None => return false, | ||
| 370 | }; | ||
| 371 | |||
| 372 | let used = ep.used_out || ep.used_in; | ||
| 373 | |||
| 374 | if used && ep.ep_type == EndpointType::Isochronous { | ||
| 375 | // Isochronous endpoints are always double-buffered. | ||
| 376 | // Their corresponding endpoint/channel registers are forced to be unidirectional. | ||
| 377 | // Do not reuse this index. | ||
| 378 | // FIXME: Bulk endpoints can be double buffered, but are not in the current implementation. | ||
| 379 | return false; | ||
| 380 | } | ||
| 381 | |||
| 382 | let used_dir = match D::dir() { | ||
| 383 | Direction::Out => ep.used_out, | ||
| 384 | Direction::In => ep.used_in, | ||
| 385 | }; | ||
| 386 | |||
| 387 | !used || (ep.ep_type == ep_type && !used_dir) | ||
| 388 | } | ||
| 389 | |||
| 362 | fn alloc_endpoint<D: Dir>( | 390 | fn alloc_endpoint<D: Dir>( |
| 363 | &mut self, | 391 | &mut self, |
| 364 | ep_type: EndpointType, | 392 | ep_type: EndpointType, |
| 393 | ep_addr: Option<EndpointAddress>, | ||
| 365 | max_packet_size: u16, | 394 | max_packet_size: u16, |
| 366 | interval_ms: u8, | 395 | interval_ms: u8, |
| 367 | ) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> { | 396 | ) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> { |
| @@ -373,28 +402,17 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 373 | D::dir() | 402 | D::dir() |
| 374 | ); | 403 | ); |
| 375 | 404 | ||
| 376 | let index = self.alloc.iter_mut().enumerate().find(|(i, ep)| { | 405 | let index = if let Some(addr) = ep_addr { |
| 377 | if *i == 0 && ep_type != EndpointType::Control { | 406 | // Use the specified endpoint address |
| 378 | return false; // reserved for control pipe | 407 | self.is_endpoint_available::<D>(addr.index(), ep_type) |
| 379 | } | 408 | .then_some(addr.index()) |
| 380 | let used = ep.used_out || ep.used_in; | 409 | } else { |
| 381 | if used && (ep.ep_type == EndpointType::Isochronous) { | 410 | // Find any available endpoint |
| 382 | // Isochronous endpoints are always double-buffered. | 411 | (0..self.alloc.len()).find(|&i| self.is_endpoint_available::<D>(i, ep_type)) |
| 383 | // Their corresponding endpoint/channel registers are forced to be unidirectional. | 412 | }; |
| 384 | // Do not reuse this index. | ||
| 385 | // FIXME: Bulk endpoints can be double buffered, but are not in the current implementation. | ||
| 386 | return false; | ||
| 387 | } | ||
| 388 | |||
| 389 | let used_dir = match D::dir() { | ||
| 390 | Direction::Out => ep.used_out, | ||
| 391 | Direction::In => ep.used_in, | ||
| 392 | }; | ||
| 393 | !used || (ep.ep_type == ep_type && !used_dir) | ||
| 394 | }); | ||
| 395 | 413 | ||
| 396 | let (index, ep) = match index { | 414 | let (index, ep) = match index { |
| 397 | Some(x) => x, | 415 | Some(i) => (i, &mut self.alloc[i]), |
| 398 | None => return Err(EndpointAllocError), | 416 | None => return Err(EndpointAllocError), |
| 399 | }; | 417 | }; |
| 400 | 418 | ||
| @@ -479,27 +497,29 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 479 | fn alloc_endpoint_in( | 497 | fn alloc_endpoint_in( |
| 480 | &mut self, | 498 | &mut self, |
| 481 | ep_type: EndpointType, | 499 | ep_type: EndpointType, |
| 500 | ep_addr: Option<EndpointAddress>, | ||
| 482 | max_packet_size: u16, | 501 | max_packet_size: u16, |
| 483 | interval_ms: u8, | 502 | interval_ms: u8, |
| 484 | ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { | 503 | ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { |
| 485 | self.alloc_endpoint(ep_type, max_packet_size, interval_ms) | 504 | self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms) |
| 486 | } | 505 | } |
| 487 | 506 | ||
| 488 | fn alloc_endpoint_out( | 507 | fn alloc_endpoint_out( |
| 489 | &mut self, | 508 | &mut self, |
| 490 | ep_type: EndpointType, | 509 | ep_type: EndpointType, |
| 510 | ep_addr: Option<EndpointAddress>, | ||
| 491 | max_packet_size: u16, | 511 | max_packet_size: u16, |
| 492 | interval_ms: u8, | 512 | interval_ms: u8, |
| 493 | ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { | 513 | ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { |
| 494 | self.alloc_endpoint(ep_type, max_packet_size, interval_ms) | 514 | self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms) |
| 495 | } | 515 | } |
| 496 | 516 | ||
| 497 | fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { | 517 | fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { |
| 498 | let ep_out = self | 518 | let ep_out = self |
| 499 | .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) | 519 | .alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0) |
| 500 | .unwrap(); | 520 | .unwrap(); |
| 501 | let ep_in = self | 521 | let ep_in = self |
| 502 | .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) | 522 | .alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0) |
| 503 | .unwrap(); | 523 | .unwrap(); |
| 504 | assert_eq!(ep_out.info.addr.index(), 0); | 524 | assert_eq!(ep_out.info.addr.index(), 0); |
| 505 | assert_eq!(ep_in.info.addr.index(), 0); | 525 | assert_eq!(ep_in.info.addr.index(), 0); |
