diff options
Diffstat (limited to 'embassy-stm32')
41 files changed, 2296 insertions, 1762 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 6c36bc108..38f22b1c3 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 7 | 7 | ||
| 8 | ## Unreleased - ReleaseDate | 8 | ## Unreleased - ReleaseDate |
| 9 | 9 | ||
| 10 | - fix: stm32: GPDMA driver reset ignored during channel configuration | ||
| 11 | - fix: stm32: SPI driver SSOE and SSM manegment, add `nss_output_disable` to SPI Config | ||
| 12 | - change: stm32: use typelevel timer type to allow dma for 32 bit timers | ||
| 10 | - fix: fix incorrect handling of split interrupts in timer driver | 13 | - fix: fix incorrect handling of split interrupts in timer driver |
| 11 | - feat: allow granular stop for regular usart | 14 | - feat: allow granular stop for regular usart |
| 12 | - feat: Add continuous waveform method to SimplePWM | 15 | - feat: Add continuous waveform method to SimplePWM |
| @@ -85,8 +88,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 85 | - fix: build script ensures EXTI2_TSC is listed as the IRQ of EXTI2 even if the PAC doesn't | 88 | - fix: build script ensures EXTI2_TSC is listed as the IRQ of EXTI2 even if the PAC doesn't |
| 86 | - feat: stm32/lcd: added implementation | 89 | - feat: stm32/lcd: added implementation |
| 87 | - change: add error messages to can timing calculations ([#4961](https://github.com/embassy-rs/embassy/pull/4961)) | 90 | - change: add error messages to can timing calculations ([#4961](https://github.com/embassy-rs/embassy/pull/4961)) |
| 91 | - feat: stm32/spi bidirectional mode | ||
| 88 | - fix: stm32/i2c v2: add stop flag on stop received | 92 | - fix: stm32/i2c v2: add stop flag on stop received |
| 89 | - stm32: Add blocking_listen for blocking I2C driver | 93 | - stm32: Add blocking_listen for blocking I2C driver |
| 94 | - fix: stm32l47*/stm32l48* adc analog pin setup | ||
| 95 | - fix: keep stm32/sai: make NODIV independent of MCKDIV | ||
| 90 | 96 | ||
| 91 | ## 0.4.0 - 2025-08-26 | 97 | ## 0.4.0 - 2025-08-26 |
| 92 | 98 | ||
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index e10409112..7989fc5d7 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -200,11 +200,11 @@ aligned = "0.4.1" | |||
| 200 | heapless = "0.9.1" | 200 | heapless = "0.9.1" |
| 201 | 201 | ||
| 202 | #stm32-metapac = { version = "18" } | 202 | #stm32-metapac = { version = "18" } |
| 203 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f61ed017ef12ec84ff04c49e3147694bda3b29cb" } | 203 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-497fb3042b49b765d8974aac87b8ab4fa3566d74" } |
| 204 | 204 | ||
| 205 | [build-dependencies] | 205 | [build-dependencies] |
| 206 | #stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} | 206 | #stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} |
| 207 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f61ed017ef12ec84ff04c49e3147694bda3b29cb", default-features = false, features = ["metadata"] } | 207 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-497fb3042b49b765d8974aac87b8ab4fa3566d74", default-features = false, features = ["metadata"] } |
| 208 | 208 | ||
| 209 | proc-macro2 = "1.0.36" | 209 | proc-macro2 = "1.0.36" |
| 210 | quote = "1.0.15" | 210 | quote = "1.0.15" |
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 453513309..43509873f 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs | |||
| @@ -5,7 +5,7 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR | |||
| 5 | use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; | 5 | use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; |
| 6 | 6 | ||
| 7 | use super::blocking_delay_us; | 7 | use super::blocking_delay_us; |
| 8 | use crate::adc::ConversionMode; | 8 | use crate::adc::{AdcRegs, ConversionMode, Instance}; |
| 9 | #[cfg(stm32u5)] | 9 | #[cfg(stm32u5)] |
| 10 | pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; | 10 | pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; |
| 11 | #[cfg(stm32wba)] | 11 | #[cfg(stm32wba)] |
| @@ -90,135 +90,112 @@ fn from_ker_ck(frequency: Hertz) -> Presc { | |||
| 90 | } | 90 | } |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | pub trait SealedInstance { | 93 | impl AdcRegs for crate::pac::adc::Adc4 { |
| 94 | #[allow(unused)] | 94 | fn data(&self) -> *mut u16 { |
| 95 | fn regs() -> crate::pac::adc::Adc4; | 95 | crate::pac::adc::Adc4::dr(*self).as_ptr() as *mut u16 |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { | 98 | fn enable(&self) { |
| 99 | type Interrupt: crate::interrupt::typelevel::Interrupt; | 99 | if !self.cr().read().aden() || !self.isr().read().adrdy() { |
| 100 | } | 100 | self.isr().write(|w| w.set_adrdy(true)); |
| 101 | self.cr().modify(|w| w.set_aden(true)); | ||
| 102 | while !self.isr().read().adrdy() {} | ||
| 103 | } | ||
| 104 | } | ||
| 101 | 105 | ||
| 102 | foreach_adc!( | 106 | fn start(&self) { |
| 103 | (ADC4, $common_inst:ident, $clock:ident) => { | 107 | // Start conversion |
| 104 | use crate::peripherals::ADC4; | 108 | self.cr().modify(|reg| { |
| 109 | reg.set_adstart(true); | ||
| 110 | }); | ||
| 111 | } | ||
| 105 | 112 | ||
| 106 | impl super::BasicAnyInstance for ADC4 { | 113 | fn stop(&self) { |
| 107 | type SampleTime = SampleTime; | 114 | let cr = self.cr().read(); |
| 115 | if cr.adstart() { | ||
| 116 | self.cr().modify(|w| w.set_adstp(true)); | ||
| 117 | while self.cr().read().adstart() {} | ||
| 108 | } | 118 | } |
| 109 | 119 | ||
| 110 | impl super::SealedAnyInstance for ADC4 { | 120 | if cr.aden() || cr.adstart() { |
| 111 | fn dr() -> *mut u16 { | 121 | self.cr().modify(|w| w.set_addis(true)); |
| 112 | ADC4::regs().dr().as_ptr() as *mut u16 | 122 | while self.cr().read().aden() {} |
| 113 | } | 123 | } |
| 114 | 124 | ||
| 115 | fn enable() { | 125 | // Reset configuration. |
| 116 | if !ADC4::regs().cr().read().aden() || !ADC4::regs().isr().read().adrdy() { | 126 | self.cfgr1().modify(|reg| { |
| 117 | ADC4::regs().isr().write(|w| w.set_adrdy(true)); | 127 | reg.set_dmaen(false); |
| 118 | ADC4::regs().cr().modify(|w| w.set_aden(true)); | 128 | }); |
| 119 | while !ADC4::regs().isr().read().adrdy() {} | 129 | } |
| 120 | } | ||
| 121 | } | ||
| 122 | 130 | ||
| 123 | fn start() { | 131 | fn configure_dma(&self, conversion_mode: ConversionMode) { |
| 124 | // Start conversion | 132 | match conversion_mode { |
| 125 | ADC4::regs().cr().modify(|reg| { | 133 | ConversionMode::Singular => { |
| 126 | reg.set_adstart(true); | 134 | self.isr().modify(|reg| { |
| 135 | reg.set_ovr(true); | ||
| 136 | reg.set_eos(true); | ||
| 137 | reg.set_eoc(true); | ||
| 127 | }); | 138 | }); |
| 128 | } | ||
| 129 | 139 | ||
| 130 | fn stop() { | 140 | self.cfgr1().modify(|reg| { |
| 131 | let cr = ADC4::regs().cr().read(); | 141 | reg.set_dmaen(true); |
| 132 | if cr.adstart() { | 142 | reg.set_dmacfg(Dmacfg::ONE_SHOT); |
| 133 | ADC4::regs().cr().modify(|w| w.set_adstp(true)); | 143 | #[cfg(stm32u5)] |
| 134 | while ADC4::regs().cr().read().adstart() {} | 144 | reg.set_chselrmod(false); |
| 135 | } | 145 | #[cfg(stm32wba)] |
| 136 | 146 | reg.set_chselrmod(Chselrmod::ENABLE_INPUT) | |
| 137 | if cr.aden() || cr.adstart() { | ||
| 138 | ADC4::regs().cr().modify(|w| w.set_addis(true)); | ||
| 139 | while ADC4::regs().cr().read().aden() {} | ||
| 140 | } | ||
| 141 | |||
| 142 | // Reset configuration. | ||
| 143 | ADC4::regs().cfgr1().modify(|reg| { | ||
| 144 | reg.set_dmaen(false); | ||
| 145 | }); | 147 | }); |
| 146 | } | 148 | } |
| 149 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 150 | _ => unreachable!(), | ||
| 151 | } | ||
| 152 | } | ||
| 147 | 153 | ||
| 148 | fn configure_dma(conversion_mode: ConversionMode) { | 154 | fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 149 | match conversion_mode { | 155 | let mut prev_channel: i16 = -1; |
| 150 | ConversionMode::Singular => { | 156 | #[cfg(stm32wba)] |
| 151 | ADC4::regs().isr().modify(|reg| { | 157 | self.chselr().write_value(Chselr(0_u32)); |
| 152 | reg.set_ovr(true); | 158 | #[cfg(stm32u5)] |
| 153 | reg.set_eos(true); | 159 | self.chselrmod0().write_value(Chselr(0_u32)); |
| 154 | reg.set_eoc(true); | 160 | for (_i, ((channel, _), sample_time)) in sequence.enumerate() { |
| 155 | }); | 161 | self.smpr().modify(|w| { |
| 156 | 162 | w.set_smp(_i, sample_time); | |
| 157 | ADC4::regs().cfgr1().modify(|reg| { | 163 | }); |
| 158 | reg.set_dmaen(true); | 164 | |
| 159 | reg.set_dmacfg(Dmacfg::ONE_SHOT); | 165 | let channel_num = channel; |
| 160 | #[cfg(stm32u5)] | 166 | if channel_num as i16 <= prev_channel { |
| 161 | reg.set_chselrmod(false); | 167 | return; |
| 162 | #[cfg(stm32wba)] | 168 | }; |
| 163 | reg.set_chselrmod(Chselrmod::ENABLE_INPUT) | 169 | prev_channel = channel_num as i16; |
| 164 | }); | ||
| 165 | } | ||
| 166 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 167 | _ => unreachable!(), | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | ||
| 172 | let mut prev_channel: i16 = -1; | ||
| 173 | #[cfg(stm32wba)] | ||
| 174 | ADC4::regs().chselr().write_value(Chselr(0_u32)); | ||
| 175 | #[cfg(stm32u5)] | ||
| 176 | ADC4::regs().chselrmod0().write_value(Chselr(0_u32)); | ||
| 177 | for (_i, ((channel, _), sample_time)) in sequence.enumerate() { | ||
| 178 | ADC4::regs().smpr().modify(|w| { | ||
| 179 | w.set_smp(_i, sample_time); | ||
| 180 | }); | ||
| 181 | |||
| 182 | let channel_num = channel; | ||
| 183 | if channel_num as i16 <= prev_channel { | ||
| 184 | return; | ||
| 185 | }; | ||
| 186 | prev_channel = channel_num as i16; | ||
| 187 | |||
| 188 | #[cfg(stm32wba)] | ||
| 189 | ADC4::regs().chselr().modify(|w| { | ||
| 190 | w.set_chsel0(channel as usize, true); | ||
| 191 | }); | ||
| 192 | #[cfg(stm32u5)] | ||
| 193 | ADC4::regs().chselrmod0().modify(|w| { | ||
| 194 | w.set_chsel(channel as usize, true); | ||
| 195 | }); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | 170 | ||
| 199 | fn convert() -> u16 { | 171 | #[cfg(stm32wba)] |
| 200 | // Reset interrupts | 172 | self.chselr().modify(|w| { |
| 201 | ADC4::regs().isr().modify(|reg| { | 173 | w.set_chsel0(channel as usize, true); |
| 202 | reg.set_eos(true); | 174 | }); |
| 203 | reg.set_eoc(true); | 175 | #[cfg(stm32u5)] |
| 204 | }); | 176 | self.chselrmod0().modify(|w| { |
| 177 | w.set_chsel(channel as usize, true); | ||
| 178 | }); | ||
| 179 | } | ||
| 180 | } | ||
| 205 | 181 | ||
| 206 | // Start conversion | 182 | fn convert(&self) { |
| 207 | ADC4::regs().cr().modify(|reg| { | 183 | // Reset interrupts |
| 208 | reg.set_adstart(true); | 184 | self.isr().modify(|reg| { |
| 209 | }); | 185 | reg.set_eos(true); |
| 186 | reg.set_eoc(true); | ||
| 187 | }); | ||
| 210 | 188 | ||
| 211 | while !ADC4::regs().isr().read().eos() { | 189 | // Start conversion |
| 212 | // spin | 190 | self.cr().modify(|reg| { |
| 213 | } | 191 | reg.set_adstart(true); |
| 192 | }); | ||
| 214 | 193 | ||
| 215 | ADC4::regs().dr().read().0 as u16 | 194 | while !self.isr().read().eos() { |
| 216 | } | 195 | // spin |
| 217 | } | 196 | } |
| 218 | 197 | } | |
| 219 | impl super::AnyInstance for ADC4 {} | 198 | } |
| 220 | }; | ||
| 221 | ); | ||
| 222 | 199 | ||
| 223 | pub struct Adc4<'d, T: Instance> { | 200 | pub struct Adc4<'d, T: Instance> { |
| 224 | #[allow(unused)] | 201 | #[allow(unused)] |
| @@ -231,7 +208,7 @@ pub enum Adc4Error { | |||
| 231 | DMAError, | 208 | DMAError, |
| 232 | } | 209 | } |
| 233 | 210 | ||
| 234 | impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> { | 211 | impl<'d, T: Instance<Regs = crate::pac::adc::Adc4>> super::Adc<'d, T> { |
| 235 | /// Create a new ADC driver. | 212 | /// Create a new ADC driver. |
| 236 | pub fn new_adc4(adc: Peri<'d, T>) -> Self { | 213 | pub fn new_adc4(adc: Peri<'d, T>) -> Self { |
| 237 | rcc::enable_and_reset::<T>(); | 214 | rcc::enable_and_reset::<T>(); |
| @@ -267,7 +244,7 @@ impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> { | |||
| 267 | 244 | ||
| 268 | blocking_delay_us(1); | 245 | blocking_delay_us(1); |
| 269 | 246 | ||
| 270 | T::enable(); | 247 | T::regs().enable(); |
| 271 | 248 | ||
| 272 | // single conversion mode, software trigger | 249 | // single conversion mode, software trigger |
| 273 | T::regs().cfgr1().modify(|w| { | 250 | T::regs().cfgr1().modify(|w| { |
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index 3e109e429..2f0f326af 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs | |||
| @@ -4,7 +4,7 @@ use pac::adccommon::vals::Presc; | |||
| 4 | use stm32_metapac::adc::vals::{SampleTime, Scandir}; | 4 | use stm32_metapac::adc::vals::{SampleTime, Scandir}; |
| 5 | 5 | ||
| 6 | use super::{Adc, Instance, Resolution, blocking_delay_us}; | 6 | use super::{Adc, Instance, Resolution, blocking_delay_us}; |
| 7 | use crate::adc::{AnyInstance, ConversionMode}; | 7 | use crate::adc::{AdcRegs, ConversionMode}; |
| 8 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| 9 | use crate::{Peri, pac, rcc}; | 9 | use crate::{Peri, pac, rcc}; |
| 10 | 10 | ||
| @@ -43,52 +43,52 @@ fn from_ker_ck(frequency: Hertz) -> Presc { | |||
| 43 | } | 43 | } |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | impl<T: Instance> super::SealedAnyInstance for T { | 46 | impl AdcRegs for crate::pac::adc::Adc { |
| 47 | fn dr() -> *mut u16 { | 47 | fn data(&self) -> *mut u16 { |
| 48 | T::regs().dr().as_ptr() as *mut u16 | 48 | crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | fn enable() { | 51 | fn enable(&self) { |
| 52 | T::regs().isr().modify(|w| w.set_adrdy(true)); | 52 | self.isr().modify(|w| w.set_adrdy(true)); |
| 53 | T::regs().cr().modify(|w| w.set_aden(true)); | 53 | self.cr().modify(|w| w.set_aden(true)); |
| 54 | // ADRDY is "ADC ready". Wait until it will be True. | 54 | // ADRDY is "ADC ready". Wait until it will be True. |
| 55 | while !T::regs().isr().read().adrdy() {} | 55 | while !self.isr().read().adrdy() {} |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | fn start() { | 58 | fn start(&self) { |
| 59 | // Start conversion | 59 | // Start conversion |
| 60 | T::regs().cr().modify(|reg| { | 60 | self.cr().modify(|reg| { |
| 61 | reg.set_adstart(true); | 61 | reg.set_adstart(true); |
| 62 | }); | 62 | }); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | fn stop() { | 65 | fn stop(&self) { |
| 66 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | 66 | if self.cr().read().adstart() && !self.cr().read().addis() { |
| 67 | T::regs().cr().modify(|reg| { | 67 | self.cr().modify(|reg| { |
| 68 | reg.set_adstp(Adstp::STOP); | 68 | reg.set_adstp(Adstp::STOP); |
| 69 | }); | 69 | }); |
| 70 | while T::regs().cr().read().adstart() {} | 70 | while self.cr().read().adstart() {} |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | // Reset configuration. | 73 | // Reset configuration. |
| 74 | T::regs().cfgr1().modify(|reg| { | 74 | self.cfgr1().modify(|reg| { |
| 75 | reg.set_cont(false); | 75 | reg.set_cont(false); |
| 76 | reg.set_dmacfg(Dmacfg::from_bits(0)); | 76 | reg.set_dmacfg(Dmacfg::from_bits(0)); |
| 77 | reg.set_dmaen(false); | 77 | reg.set_dmaen(false); |
| 78 | }); | 78 | }); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | fn configure_dma(conversion_mode: super::ConversionMode) { | 81 | fn configure_dma(&self, conversion_mode: super::ConversionMode) { |
| 82 | match conversion_mode { | 82 | match conversion_mode { |
| 83 | ConversionMode::Singular => { | 83 | ConversionMode::Singular => { |
| 84 | // Enable overrun control, so no new DMA requests will be generated until | 84 | // Enable overrun control, so no new DMA requests will be generated until |
| 85 | // previous DR values is read. | 85 | // previous DR values is read. |
| 86 | T::regs().isr().modify(|reg| { | 86 | self.isr().modify(|reg| { |
| 87 | reg.set_ovr(true); | 87 | reg.set_ovr(true); |
| 88 | }); | 88 | }); |
| 89 | 89 | ||
| 90 | // Set continuous mode with oneshot dma. | 90 | // Set continuous mode with oneshot dma. |
| 91 | T::regs().cfgr1().modify(|reg| { | 91 | self.cfgr1().modify(|reg| { |
| 92 | reg.set_discen(false); | 92 | reg.set_discen(false); |
| 93 | reg.set_cont(true); | 93 | reg.set_cont(true); |
| 94 | reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT); | 94 | reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT); |
| @@ -99,7 +99,7 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 99 | } | 99 | } |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>) { | 102 | fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>) { |
| 103 | let mut needs_hw = sequence.len() == 1 || sequence.len() > CHSELR_SQ_SIZE; | 103 | let mut needs_hw = sequence.len() == 1 || sequence.len() > CHSELR_SQ_SIZE; |
| 104 | let mut is_ordered_up = true; | 104 | let mut is_ordered_up = true; |
| 105 | let mut is_ordered_down = true; | 105 | let mut is_ordered_down = true; |
| @@ -109,7 +109,7 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 109 | let mut last_channel: u8 = 0; | 109 | let mut last_channel: u8 = 0; |
| 110 | let mut sample_time: Self::SampleTime = SampleTime::CYCLES2_5; | 110 | let mut sample_time: Self::SampleTime = SampleTime::CYCLES2_5; |
| 111 | 111 | ||
| 112 | T::regs().chselr_sq().write(|w| { | 112 | self.chselr_sq().write(|w| { |
| 113 | for (i, ((channel, _), _sample_time)) in sequence.enumerate() { | 113 | for (i, ((channel, _), _sample_time)) in sequence.enumerate() { |
| 114 | assert!( | 114 | assert!( |
| 115 | sample_time == _sample_time || i == 0, | 115 | sample_time == _sample_time || i == 0, |
| @@ -146,42 +146,40 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 146 | ); | 146 | ); |
| 147 | 147 | ||
| 148 | // Set required channels for multi-convert. | 148 | // Set required channels for multi-convert. |
| 149 | unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } | 149 | unsafe { (self.chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | T::regs().smpr().modify(|w| { | 152 | self.smpr().modify(|w| { |
| 153 | w.smpsel(0); | 153 | w.smpsel(0); |
| 154 | w.set_smp1(sample_time); | 154 | w.set_smp1(sample_time); |
| 155 | }); | 155 | }); |
| 156 | 156 | ||
| 157 | T::regs().cfgr1().modify(|reg| { | 157 | self.cfgr1().modify(|reg| { |
| 158 | reg.set_chselrmod(!needs_hw); | 158 | reg.set_chselrmod(!needs_hw); |
| 159 | reg.set_align(Align::RIGHT); | 159 | reg.set_align(Align::RIGHT); |
| 160 | reg.set_scandir(if is_ordered_up { Scandir::UP } else { Scandir::BACK }); | 160 | reg.set_scandir(if is_ordered_up { Scandir::UP } else { Scandir::BACK }); |
| 161 | }); | 161 | }); |
| 162 | 162 | ||
| 163 | // Trigger and wait for the channel selection procedure to complete. | 163 | // Trigger and wait for the channel selection procedure to complete. |
| 164 | T::regs().isr().modify(|w| w.set_ccrdy(false)); | 164 | self.isr().modify(|w| w.set_ccrdy(false)); |
| 165 | while !T::regs().isr().read().ccrdy() {} | 165 | while !self.isr().read().ccrdy() {} |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | fn convert() -> u16 { | 168 | fn convert(&self) { |
| 169 | // Set single conversion mode. | 169 | // Set single conversion mode. |
| 170 | T::regs().cfgr1().modify(|w| w.set_cont(false)); | 170 | self.cfgr1().modify(|w| w.set_cont(false)); |
| 171 | 171 | ||
| 172 | // Start conversion | 172 | // Start conversion |
| 173 | T::regs().cr().modify(|reg| { | 173 | self.cr().modify(|reg| { |
| 174 | reg.set_adstart(true); | 174 | reg.set_adstart(true); |
| 175 | }); | 175 | }); |
| 176 | 176 | ||
| 177 | // Waiting for End Of Conversion (EOC). | 177 | // Waiting for End Of Conversion (EOC). |
| 178 | while !T::regs().isr().read().eoc() {} | 178 | while !self.isr().read().eoc() {} |
| 179 | |||
| 180 | T::regs().dr().read().data() as u16 | ||
| 181 | } | 179 | } |
| 182 | } | 180 | } |
| 183 | 181 | ||
| 184 | impl<'d, T: AnyInstance> Adc<'d, T> { | 182 | impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> { |
| 185 | /// Create a new ADC driver. | 183 | /// Create a new ADC driver. |
| 186 | pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { | 184 | pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { |
| 187 | rcc::enable_and_reset::<T>(); | 185 | rcc::enable_and_reset::<T>(); |
| @@ -225,7 +223,7 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 225 | 223 | ||
| 226 | T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); | 224 | T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); |
| 227 | 225 | ||
| 228 | T::enable(); | 226 | T::regs().enable(); |
| 229 | 227 | ||
| 230 | // single conversion mode, software trigger | 228 | // single conversion mode, software trigger |
| 231 | T::regs().cfgr1().modify(|w| { | 229 | T::regs().cfgr1().modify(|w| { |
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 1767a3bb3..e93ed945f 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs | |||
| @@ -12,7 +12,8 @@ use super::{ | |||
| 12 | Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, | 12 | Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, |
| 13 | blocking_delay_us, | 13 | blocking_delay_us, |
| 14 | }; | 14 | }; |
| 15 | use crate::adc::{AnyInstance, SealedAdcChannel}; | 15 | use crate::adc::{AdcRegs, BasicAdcRegs, SealedAdcChannel}; |
| 16 | use crate::pac::adc::regs::{Smpr, Smpr2, Sqr1, Sqr2, Sqr3, Sqr4}; | ||
| 16 | use crate::time::Hertz; | 17 | use crate::time::Hertz; |
| 17 | use crate::{Peri, pac, rcc}; | 18 | use crate::{Peri, pac, rcc}; |
| 18 | 19 | ||
| @@ -68,79 +69,77 @@ pub struct ConversionTrigger { | |||
| 68 | pub edge: Exten, | 69 | pub edge: Exten, |
| 69 | } | 70 | } |
| 70 | 71 | ||
| 71 | impl<T: Instance> super::SealedAnyInstance for T { | 72 | impl super::AdcRegs for crate::pac::adc::Adc { |
| 72 | fn dr() -> *mut u16 { | 73 | fn data(&self) -> *mut u16 { |
| 73 | T::regs().dr().as_ptr() as *mut u16 | 74 | crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 |
| 74 | } | 75 | } |
| 75 | 76 | ||
| 76 | fn enable() { | 77 | fn enable(&self) { |
| 77 | // Make sure bits are off | 78 | // Make sure bits are off |
| 78 | while T::regs().cr().read().addis() { | 79 | while self.cr().read().addis() { |
| 79 | // spin | 80 | // spin |
| 80 | } | 81 | } |
| 81 | 82 | ||
| 82 | if !T::regs().cr().read().aden() { | 83 | if !self.cr().read().aden() { |
| 83 | // Enable ADC | 84 | // Enable ADC |
| 84 | T::regs().isr().modify(|reg| { | 85 | self.isr().modify(|reg| { |
| 85 | reg.set_adrdy(true); | 86 | reg.set_adrdy(true); |
| 86 | }); | 87 | }); |
| 87 | T::regs().cr().modify(|reg| { | 88 | self.cr().modify(|reg| { |
| 88 | reg.set_aden(true); | 89 | reg.set_aden(true); |
| 89 | }); | 90 | }); |
| 90 | 91 | ||
| 91 | while !T::regs().isr().read().adrdy() { | 92 | while !self.isr().read().adrdy() { |
| 92 | // spin | 93 | // spin |
| 93 | } | 94 | } |
| 94 | } | 95 | } |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | fn start() { | 98 | fn start(&self) { |
| 98 | T::regs().cr().modify(|reg| { | 99 | self.cr().modify(|reg| { |
| 99 | reg.set_adstart(true); | 100 | reg.set_adstart(true); |
| 100 | }); | 101 | }); |
| 101 | } | 102 | } |
| 102 | 103 | ||
| 103 | fn stop() { | 104 | fn stop(&self) { |
| 104 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | 105 | if self.cr().read().adstart() && !self.cr().read().addis() { |
| 105 | T::regs().cr().modify(|reg| { | 106 | self.cr().modify(|reg| { |
| 106 | reg.set_adstp(Adstp::STOP); | 107 | reg.set_adstp(Adstp::STOP); |
| 107 | }); | 108 | }); |
| 108 | // The software must poll ADSTART until the bit is reset before assuming the | 109 | // The software must poll ADSTART until the bit is reset before assuming the |
| 109 | // ADC is completely stopped | 110 | // ADC is completely stopped |
| 110 | while T::regs().cr().read().adstart() {} | 111 | while self.cr().read().adstart() {} |
| 111 | } | 112 | } |
| 112 | 113 | ||
| 113 | // Disable dma control and continuous conversion, if enabled | 114 | // Disable dma control and continuous conversion, if enabled |
| 114 | T::regs().cfgr().modify(|reg| { | 115 | self.cfgr().modify(|reg| { |
| 115 | reg.set_cont(false); | 116 | reg.set_cont(false); |
| 116 | reg.set_dmaen(Dmaen::DISABLE); | 117 | reg.set_dmaen(Dmaen::DISABLE); |
| 117 | }); | 118 | }); |
| 118 | } | 119 | } |
| 119 | 120 | ||
| 120 | fn convert() -> u16 { | 121 | fn convert(&self) { |
| 121 | T::regs().isr().modify(|reg| { | 122 | self.isr().modify(|reg| { |
| 122 | reg.set_eos(true); | 123 | reg.set_eos(true); |
| 123 | reg.set_eoc(true); | 124 | reg.set_eoc(true); |
| 124 | }); | 125 | }); |
| 125 | 126 | ||
| 126 | // Start conversion | 127 | // Start conversion |
| 127 | T::regs().cr().modify(|reg| { | 128 | self.cr().modify(|reg| { |
| 128 | reg.set_adstart(true); | 129 | reg.set_adstart(true); |
| 129 | }); | 130 | }); |
| 130 | 131 | ||
| 131 | while !T::regs().isr().read().eos() { | 132 | while !self.isr().read().eos() { |
| 132 | // spin | 133 | // spin |
| 133 | } | 134 | } |
| 134 | |||
| 135 | T::regs().dr().read().0 as u16 | ||
| 136 | } | 135 | } |
| 137 | 136 | ||
| 138 | fn configure_dma(conversion_mode: ConversionMode) { | 137 | fn configure_dma(&self, conversion_mode: ConversionMode) { |
| 139 | T::regs().isr().modify(|reg| { | 138 | self.isr().modify(|reg| { |
| 140 | reg.set_ovr(true); | 139 | reg.set_ovr(true); |
| 141 | }); | 140 | }); |
| 142 | 141 | ||
| 143 | T::regs().cfgr().modify(|reg| { | 142 | self.cfgr().modify(|reg| { |
| 144 | reg.set_discen(false); // Convert all channels for each trigger | 143 | reg.set_discen(false); // Convert all channels for each trigger |
| 145 | reg.set_dmacfg(match conversion_mode { | 144 | reg.set_dmacfg(match conversion_mode { |
| 146 | ConversionMode::Singular => Dmacfg::ONE_SHOT, | 145 | ConversionMode::Singular => Dmacfg::ONE_SHOT, |
| @@ -152,43 +151,41 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 152 | if let ConversionMode::Repeated(mode) = conversion_mode { | 151 | if let ConversionMode::Repeated(mode) = conversion_mode { |
| 153 | match mode { | 152 | match mode { |
| 154 | RegularConversionMode::Continuous => { | 153 | RegularConversionMode::Continuous => { |
| 155 | T::regs().cfgr().modify(|reg| { | 154 | self.cfgr().modify(|reg| { |
| 156 | reg.set_cont(true); | 155 | reg.set_cont(true); |
| 157 | }); | 156 | }); |
| 158 | } | 157 | } |
| 159 | RegularConversionMode::Triggered(trigger) => { | 158 | RegularConversionMode::Triggered(trigger) => { |
| 160 | T::regs().cfgr().modify(|r| { | 159 | self.cfgr().modify(|r| { |
| 161 | r.set_cont(false); // New trigger is neede for each sample to be read | 160 | r.set_cont(false); // New trigger is neede for each sample to be read |
| 162 | }); | 161 | }); |
| 163 | 162 | ||
| 164 | T::regs().cfgr().modify(|r| { | 163 | self.cfgr().modify(|r| { |
| 165 | r.set_extsel(trigger.channel); | 164 | r.set_extsel(trigger.channel); |
| 166 | r.set_exten(trigger.edge); | 165 | r.set_exten(trigger.edge); |
| 167 | }); | 166 | }); |
| 168 | 167 | ||
| 169 | // Regular conversions uses DMA so no need to generate interrupt | 168 | // Regular conversions uses DMA so no need to generate interrupt |
| 170 | T::regs().ier().modify(|r| r.set_eosie(false)); | 169 | self.ier().modify(|r| r.set_eosie(false)); |
| 171 | } | 170 | } |
| 172 | } | 171 | } |
| 173 | } | 172 | } |
| 174 | } | 173 | } |
| 175 | 174 | ||
| 176 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | 175 | fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 177 | T::regs().cr().modify(|w| w.set_aden(false)); | 176 | self.cr().modify(|w| w.set_aden(false)); |
| 178 | |||
| 179 | // Set sequence length | ||
| 180 | T::regs().sqr1().modify(|w| { | ||
| 181 | w.set_l(sequence.len() as u8 - 1); | ||
| 182 | }); | ||
| 183 | 177 | ||
| 184 | #[cfg(stm32g4)] | 178 | #[cfg(stm32g4)] |
| 185 | let mut difsel = DifselReg::default(); | 179 | let mut difsel = DifselReg::default(); |
| 186 | let mut smpr = T::regs().smpr().read(); | 180 | let mut smpr = Smpr::default(); |
| 187 | let mut smpr2 = T::regs().smpr2().read(); | 181 | let mut smpr2 = Smpr2::default(); |
| 188 | let mut sqr1 = T::regs().sqr1().read(); | 182 | let mut sqr1 = Sqr1::default(); |
| 189 | let mut sqr2 = T::regs().sqr2().read(); | 183 | let mut sqr2 = Sqr2::default(); |
| 190 | let mut sqr3 = T::regs().sqr3().read(); | 184 | let mut sqr3 = Sqr3::default(); |
| 191 | let mut sqr4 = T::regs().sqr4().read(); | 185 | let mut sqr4 = Sqr4::default(); |
| 186 | |||
| 187 | // Set sequence length | ||
| 188 | sqr1.set_l(sequence.len() as u8 - 1); | ||
| 192 | 189 | ||
| 193 | // Configure channels and ranks | 190 | // Configure channels and ranks |
| 194 | for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() { | 191 | for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() { |
| @@ -230,18 +227,18 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 230 | } | 227 | } |
| 231 | } | 228 | } |
| 232 | 229 | ||
| 233 | T::regs().smpr().write_value(smpr); | 230 | self.smpr().write_value(smpr); |
| 234 | T::regs().smpr2().write_value(smpr2); | 231 | self.smpr2().write_value(smpr2); |
| 235 | T::regs().sqr1().write_value(sqr1); | 232 | self.sqr1().write_value(sqr1); |
| 236 | T::regs().sqr2().write_value(sqr2); | 233 | self.sqr2().write_value(sqr2); |
| 237 | T::regs().sqr3().write_value(sqr3); | 234 | self.sqr3().write_value(sqr3); |
| 238 | T::regs().sqr4().write_value(sqr4); | 235 | self.sqr4().write_value(sqr4); |
| 239 | #[cfg(stm32g4)] | 236 | #[cfg(stm32g4)] |
| 240 | T::regs().difsel().write_value(difsel); | 237 | self.difsel().write_value(difsel); |
| 241 | } | 238 | } |
| 242 | } | 239 | } |
| 243 | 240 | ||
| 244 | impl<'d, T: Instance + AnyInstance> Adc<'d, T> { | 241 | impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> { |
| 245 | /// Create a new ADC driver. | 242 | /// Create a new ADC driver. |
| 246 | pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { | 243 | pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { |
| 247 | rcc::enable_and_reset::<T>(); | 244 | rcc::enable_and_reset::<T>(); |
| @@ -293,7 +290,7 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { | |||
| 293 | 290 | ||
| 294 | blocking_delay_us(20); | 291 | blocking_delay_us(20); |
| 295 | 292 | ||
| 296 | T::enable(); | 293 | T::regs().enable(); |
| 297 | 294 | ||
| 298 | // single conversion mode, software trigger | 295 | // single conversion mode, software trigger |
| 299 | T::regs().cfgr().modify(|w| { | 296 | T::regs().cfgr().modify(|w| { |
| @@ -409,10 +406,10 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { | |||
| 409 | /// `InjectedAdc<T, N>` to enforce bounds at compile time. | 406 | /// `InjectedAdc<T, N>` to enforce bounds at compile time. |
| 410 | pub fn setup_injected_conversions<'a, const N: usize>( | 407 | pub fn setup_injected_conversions<'a, const N: usize>( |
| 411 | self, | 408 | self, |
| 412 | sequence: [(AnyAdcChannel<T>, SampleTime); N], | 409 | sequence: [(AnyAdcChannel<'a, T>, SampleTime); N], |
| 413 | trigger: ConversionTrigger, | 410 | trigger: ConversionTrigger, |
| 414 | interrupt: bool, | 411 | interrupt: bool, |
| 415 | ) -> InjectedAdc<T, N> { | 412 | ) -> InjectedAdc<'a, T, N> { |
| 416 | assert!(N != 0, "Read sequence cannot be empty"); | 413 | assert!(N != 0, "Read sequence cannot be empty"); |
| 417 | assert!( | 414 | assert!( |
| 418 | N <= NR_INJECTED_RANKS, | 415 | N <= NR_INJECTED_RANKS, |
| @@ -420,12 +417,12 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { | |||
| 420 | NR_INJECTED_RANKS | 417 | NR_INJECTED_RANKS |
| 421 | ); | 418 | ); |
| 422 | 419 | ||
| 423 | T::enable(); | 420 | T::regs().enable(); |
| 424 | 421 | ||
| 425 | T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); | 422 | T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); |
| 426 | 423 | ||
| 427 | for (n, (channel, sample_time)) in sequence.into_iter().enumerate() { | 424 | for (n, (channel, sample_time)) in sequence.iter().enumerate() { |
| 428 | let sample_time = sample_time.into(); | 425 | let sample_time = sample_time.clone().into(); |
| 429 | if channel.channel() <= 9 { | 426 | if channel.channel() <= 9 { |
| 430 | T::regs() | 427 | T::regs() |
| 431 | .smpr() | 428 | .smpr() |
| @@ -487,16 +484,16 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { | |||
| 487 | /// This function is `unsafe` because it clones the ADC peripheral handle unchecked. Both the | 484 | /// This function is `unsafe` because it clones the ADC peripheral handle unchecked. Both the |
| 488 | /// `RingBufferedAdc` and `InjectedAdc` take ownership of the handle and drop it independently. | 485 | /// `RingBufferedAdc` and `InjectedAdc` take ownership of the handle and drop it independently. |
| 489 | /// Ensure no other code concurrently accesses the same ADC instance in a conflicting way. | 486 | /// Ensure no other code concurrently accesses the same ADC instance in a conflicting way. |
| 490 | pub fn into_ring_buffered_and_injected<'a, const N: usize>( | 487 | pub fn into_ring_buffered_and_injected<'a, 'b, const N: usize>( |
| 491 | self, | 488 | self, |
| 492 | dma: Peri<'a, impl RxDma<T>>, | 489 | dma: Peri<'a, impl RxDma<T>>, |
| 493 | dma_buf: &'a mut [u16], | 490 | dma_buf: &'a mut [u16], |
| 494 | regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, T::SampleTime)>, | 491 | regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<'b, T>, <T::Regs as BasicAdcRegs>::SampleTime)>, |
| 495 | regular_conversion_mode: RegularConversionMode, | 492 | regular_conversion_mode: RegularConversionMode, |
| 496 | injected_sequence: [(AnyAdcChannel<T>, SampleTime); N], | 493 | injected_sequence: [(AnyAdcChannel<'b, T>, SampleTime); N], |
| 497 | injected_trigger: ConversionTrigger, | 494 | injected_trigger: ConversionTrigger, |
| 498 | injected_interrupt: bool, | 495 | injected_interrupt: bool, |
| 499 | ) -> (super::RingBufferedAdc<'a, T>, InjectedAdc<T, N>) { | 496 | ) -> (super::RingBufferedAdc<'a, T>, InjectedAdc<'b, T, N>) { |
| 500 | unsafe { | 497 | unsafe { |
| 501 | ( | 498 | ( |
| 502 | Self { | 499 | Self { |
| @@ -531,7 +528,7 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { | |||
| 531 | } | 528 | } |
| 532 | } | 529 | } |
| 533 | 530 | ||
| 534 | impl<T: Instance, const N: usize> InjectedAdc<T, N> { | 531 | impl<'a, T: Instance<Regs = crate::pac::adc::Adc>, const N: usize> InjectedAdc<'a, T, N> { |
| 535 | /// Read sampled data from all injected ADC injected ranks | 532 | /// Read sampled data from all injected ADC injected ranks |
| 536 | /// Clear the JEOS flag to allow a new injected sequence | 533 | /// Clear the JEOS flag to allow a new injected sequence |
| 537 | pub(super) fn read_injected_data() -> [u16; N] { | 534 | pub(super) fn read_injected_data() -> [u16; N] { |
diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs index ccaa5d1b2..029722b84 100644 --- a/embassy-stm32/src/adc/injected.rs +++ b/embassy-stm32/src/adc/injected.rs | |||
| @@ -4,19 +4,19 @@ use core::sync::atomic::{Ordering, compiler_fence}; | |||
| 4 | #[allow(unused_imports)] | 4 | #[allow(unused_imports)] |
| 5 | use embassy_hal_internal::Peri; | 5 | use embassy_hal_internal::Peri; |
| 6 | 6 | ||
| 7 | use super::{AnyAdcChannel, SampleTime}; | 7 | use super::{AdcRegs, AnyAdcChannel, SampleTime}; |
| 8 | use crate::adc::Adc; | ||
| 8 | #[allow(unused_imports)] | 9 | #[allow(unused_imports)] |
| 9 | use crate::adc::Instance; | 10 | use crate::adc::Instance; |
| 10 | use crate::adc::{Adc, AnyInstance}; | ||
| 11 | 11 | ||
| 12 | /// Injected ADC sequence with owned channels. | 12 | /// Injected ADC sequence with owned channels. |
| 13 | pub struct InjectedAdc<T: Instance, const N: usize> { | 13 | pub struct InjectedAdc<'a, T: Instance<Regs = crate::pac::adc::Adc>, const N: usize> { |
| 14 | _channels: [(AnyAdcChannel<T>, SampleTime); N], | 14 | _channels: [(AnyAdcChannel<'a, T>, SampleTime); N], |
| 15 | _phantom: PhantomData<T>, | 15 | _phantom: PhantomData<T>, |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | impl<T: Instance, const N: usize> InjectedAdc<T, N> { | 18 | impl<'a, T: Instance<Regs = crate::pac::adc::Adc>, const N: usize> InjectedAdc<'a, T, N> { |
| 19 | pub(crate) fn new(channels: [(AnyAdcChannel<T>, SampleTime); N]) -> Self { | 19 | pub(crate) fn new(channels: [(AnyAdcChannel<'a, T>, SampleTime); N]) -> Self { |
| 20 | Self { | 20 | Self { |
| 21 | _channels: channels, | 21 | _channels: channels, |
| 22 | _phantom: PhantomData, | 22 | _phantom: PhantomData, |
| @@ -36,9 +36,9 @@ impl<T: Instance, const N: usize> InjectedAdc<T, N> { | |||
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | impl<T: Instance + AnyInstance, const N: usize> Drop for InjectedAdc<T, N> { | 39 | impl<'a, T: Instance<Regs = crate::pac::adc::Adc>, const N: usize> Drop for InjectedAdc<'a, T, N> { |
| 40 | fn drop(&mut self) { | 40 | fn drop(&mut self) { |
| 41 | T::stop(); | 41 | T::regs().stop(); |
| 42 | compiler_fence(Ordering::SeqCst); | 42 | compiler_fence(Ordering::SeqCst); |
| 43 | } | 43 | } |
| 44 | } | 44 | } |
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 6d53d9b91..a6af1175a 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -25,12 +25,18 @@ use core::marker::PhantomData; | |||
| 25 | #[allow(unused)] | 25 | #[allow(unused)] |
| 26 | #[cfg(not(any(adc_f3v3, adc_wba)))] | 26 | #[cfg(not(any(adc_f3v3, adc_wba)))] |
| 27 | pub use _version::*; | 27 | pub use _version::*; |
| 28 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; | 28 | #[allow(unused)] |
| 29 | use embassy_hal_internal::PeripheralType; | ||
| 29 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] | 30 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] |
| 30 | use embassy_sync::waitqueue::AtomicWaker; | 31 | use embassy_sync::waitqueue::AtomicWaker; |
| 31 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | 32 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] |
| 32 | pub use ringbuffered::RingBufferedAdc; | 33 | pub use ringbuffered::RingBufferedAdc; |
| 33 | 34 | ||
| 35 | #[cfg(adc_u5)] | ||
| 36 | use crate::pac::adc::vals::Adc4SampleTime; | ||
| 37 | #[cfg(adc_wba)] | ||
| 38 | use crate::pac::adc::vals::SampleTime as Adc4SampleTime; | ||
| 39 | |||
| 34 | #[cfg(any(adc_u5, adc_wba))] | 40 | #[cfg(any(adc_u5, adc_wba))] |
| 35 | #[path = "adc4.rs"] | 41 | #[path = "adc4.rs"] |
| 36 | pub mod adc4; | 42 | pub mod adc4; |
| @@ -43,10 +49,10 @@ pub use crate::pac::adc::vals::Res as Resolution; | |||
| 43 | pub use crate::pac::adc::vals::SampleTime; | 49 | pub use crate::pac::adc::vals::SampleTime; |
| 44 | use crate::peripherals; | 50 | use crate::peripherals; |
| 45 | 51 | ||
| 46 | dma_trait!(RxDma, AnyInstance); | 52 | dma_trait!(RxDma, Instance); |
| 47 | 53 | ||
| 48 | /// Analog to Digital driver. | 54 | /// Analog to Digital driver. |
| 49 | pub struct Adc<'d, T: AnyInstance> { | 55 | pub struct Adc<'d, T: Instance> { |
| 50 | #[allow(unused)] | 56 | #[allow(unused)] |
| 51 | adc: crate::Peri<'d, T>, | 57 | adc: crate::Peri<'d, T>, |
| 52 | } | 58 | } |
| @@ -65,79 +71,72 @@ impl State { | |||
| 65 | } | 71 | } |
| 66 | } | 72 | } |
| 67 | 73 | ||
| 68 | trait SealedInstance { | 74 | #[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))] |
| 69 | #[cfg(not(adc_wba))] | 75 | trait_set::trait_set! { |
| 70 | #[allow(unused)] | 76 | pub trait DefaultInstance = Instance; |
| 71 | fn regs() -> crate::pac::adc::Adc; | ||
| 72 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0)))] | ||
| 73 | #[allow(unused)] | ||
| 74 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | ||
| 75 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] | ||
| 76 | fn state() -> &'static State; | ||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | pub(crate) trait SealedAdcChannel<T> { | 79 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_g4, adc_c0))] |
| 80 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 80 | trait_set::trait_set! { |
| 81 | fn setup(&mut self) {} | 81 | pub trait DefaultInstance = Instance<Regs = crate::pac::adc::Adc>; |
| 82 | |||
| 83 | #[allow(unused)] | ||
| 84 | fn channel(&self) -> u8; | ||
| 85 | |||
| 86 | #[allow(unused)] | ||
| 87 | fn is_differential(&self) -> bool { | ||
| 88 | false | ||
| 89 | } | ||
| 90 | } | 82 | } |
| 91 | 83 | ||
| 92 | // Temporary patch for ADCs that have not implemented the standard iface yet | 84 | #[cfg(adc_wba)] |
| 93 | #[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1))] | ||
| 94 | trait_set::trait_set! { | 85 | trait_set::trait_set! { |
| 95 | pub trait AnyInstance = Instance; | 86 | pub trait DefaultInstance = Instance<Regs = crate::pac::adc::Adc4>; |
| 96 | } | 87 | } |
| 97 | 88 | ||
| 98 | #[cfg(any( | 89 | pub trait BasicAdcRegs { |
| 99 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | ||
| 100 | ))] | ||
| 101 | pub trait BasicAnyInstance { | ||
| 102 | type SampleTime; | 90 | type SampleTime; |
| 103 | } | 91 | } |
| 104 | 92 | ||
| 105 | #[cfg(any( | 93 | #[cfg(any( |
| 106 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | 94 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 |
| 107 | ))] | 95 | ))] |
| 108 | pub(self) trait SealedAnyInstance: BasicAnyInstance { | 96 | trait AdcRegs: BasicAdcRegs { |
| 109 | fn enable(); | 97 | fn enable(&self); |
| 110 | fn start(); | 98 | fn start(&self); |
| 111 | fn stop(); | 99 | fn stop(&self); |
| 112 | fn convert() -> u16; | 100 | fn convert(&self); |
| 113 | fn configure_dma(conversion_mode: ConversionMode); | 101 | fn configure_dma(&self, conversion_mode: ConversionMode); |
| 114 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); | 102 | fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); |
| 115 | #[allow(dead_code)] | 103 | fn data(&self) -> *mut u16; |
| 116 | fn dr() -> *mut u16; | ||
| 117 | } | 104 | } |
| 118 | 105 | ||
| 119 | // On chips without ADC4, AnyInstance is an Instance | ||
| 120 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4, adc_c0))] | ||
| 121 | #[allow(private_bounds)] | 106 | #[allow(private_bounds)] |
| 122 | pub trait AnyInstance: SealedAnyInstance + Instance {} | 107 | pub trait BasicInstance { |
| 123 | 108 | #[cfg(any( | |
| 124 | // On chips with ADC4, AnyInstance is an Instance or adc4::Instance | 109 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 |
| 125 | #[cfg(any(adc_v4, adc_u5, adc_wba))] | 110 | ))] |
| 126 | #[allow(private_bounds)] | 111 | type Regs: AdcRegs; |
| 127 | pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} | 112 | } |
| 128 | 113 | ||
| 129 | // Implement AnyInstance automatically for SealedAnyInstance | 114 | trait SealedInstance: BasicInstance { |
| 130 | #[cfg(any( | 115 | #[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))] |
| 131 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | 116 | fn regs() -> crate::pac::adc::Adc; |
| 132 | ))] | 117 | #[cfg(any( |
| 133 | impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T { | 118 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 |
| 134 | type SampleTime = SampleTime; | 119 | ))] |
| 120 | fn regs() -> Self::Regs; | ||
| 121 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0)))] | ||
| 122 | #[allow(unused)] | ||
| 123 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | ||
| 124 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] | ||
| 125 | fn state() -> &'static State; | ||
| 135 | } | 126 | } |
| 136 | 127 | ||
| 137 | #[cfg(any( | 128 | pub(crate) trait SealedAdcChannel<T> { |
| 138 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | 129 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] |
| 139 | ))] | 130 | fn setup(&mut self) {} |
| 140 | impl<T: SealedAnyInstance + Instance> AnyInstance for T {} | 131 | |
| 132 | #[allow(unused)] | ||
| 133 | fn channel(&self) -> u8; | ||
| 134 | |||
| 135 | #[allow(unused)] | ||
| 136 | fn is_differential(&self) -> bool { | ||
| 137 | false | ||
| 138 | } | ||
| 139 | } | ||
| 141 | 140 | ||
| 142 | #[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] | 141 | #[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] |
| 143 | /// Number of samples used for averaging. | 142 | /// Number of samples used for averaging. |
| @@ -183,28 +182,33 @@ pub enum RegularConversionMode { | |||
| 183 | Triggered(ConversionTrigger), | 182 | Triggered(ConversionTrigger), |
| 184 | } | 183 | } |
| 185 | 184 | ||
| 186 | impl<'d, T: AnyInstance> Adc<'d, T> { | 185 | impl<'d, T: Instance> Adc<'d, T> { |
| 187 | #[cfg(any( | 186 | #[cfg(any( |
| 188 | adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba, adc_c0 | 187 | adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v3, adc_v4, adc_wba, adc_c0 |
| 189 | ))] | 188 | ))] |
| 190 | /// Read an ADC pin. | 189 | /// Read an ADC pin. |
| 191 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 { | 190 | pub fn blocking_read( |
| 192 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 191 | &mut self, |
| 192 | channel: &mut impl AdcChannel<T>, | ||
| 193 | sample_time: <T::Regs as BasicAdcRegs>::SampleTime, | ||
| 194 | ) -> u16 { | ||
| 195 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] | ||
| 193 | channel.setup(); | 196 | channel.setup(); |
| 194 | 197 | ||
| 195 | // Ensure no conversions are ongoing | 198 | // Ensure no conversions are ongoing |
| 196 | T::stop(); | 199 | T::regs().stop(); |
| 197 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u5, adc_wba, adc_c0))] | 200 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u5, adc_wba, adc_c0))] |
| 198 | T::enable(); | 201 | T::regs().enable(); |
| 199 | T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); | 202 | T::regs().configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); |
| 200 | 203 | ||
| 201 | // On chips with differential channels, enable after configure_sequence to allow setting differential channels | 204 | // On chips with differential channels, enable after configure_sequence to allow setting differential channels |
| 202 | // | 205 | // |
| 203 | // TODO: If hardware allows, enable after configure_sequence on all chips | 206 | // TODO: If hardware allows, enable after configure_sequence on all chips |
| 204 | #[cfg(any(adc_g4, adc_h5))] | 207 | #[cfg(any(adc_g4, adc_h5))] |
| 205 | T::enable(); | 208 | T::regs().enable(); |
| 209 | T::regs().convert(); | ||
| 206 | 210 | ||
| 207 | T::convert() | 211 | unsafe { *T::regs().data() } |
| 208 | } | 212 | } |
| 209 | 213 | ||
| 210 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | 214 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] |
| @@ -241,10 +245,10 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 241 | /// in order or require the sequence to have the same sample time for all channnels, depending | 245 | /// in order or require the sequence to have the same sample time for all channnels, depending |
| 242 | /// on the number and properties of the channels in the sequence. This method will panic if | 246 | /// on the number and properties of the channels in the sequence. This method will panic if |
| 243 | /// the hardware cannot deliver the requested configuration. | 247 | /// the hardware cannot deliver the requested configuration. |
| 244 | pub async fn read( | 248 | pub async fn read<'a, 'b: 'a>( |
| 245 | &mut self, | 249 | &mut self, |
| 246 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, | 250 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, |
| 247 | sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, T::SampleTime)>, | 251 | sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<'b, T>, <T::Regs as BasicAdcRegs>::SampleTime)>, |
| 248 | readings: &mut [u16], | 252 | readings: &mut [u16], |
| 249 | ) { | 253 | ) { |
| 250 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); | 254 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); |
| @@ -258,11 +262,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 258 | ); | 262 | ); |
| 259 | 263 | ||
| 260 | // Ensure no conversions are ongoing | 264 | // Ensure no conversions are ongoing |
| 261 | T::stop(); | 265 | T::regs().stop(); |
| 262 | #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | 266 | #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] |
| 263 | T::enable(); | 267 | T::regs().enable(); |
| 264 | 268 | ||
| 265 | T::configure_sequence( | 269 | T::regs().configure_sequence( |
| 266 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | 270 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), |
| 267 | ); | 271 | ); |
| 268 | 272 | ||
| @@ -270,20 +274,20 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 270 | // | 274 | // |
| 271 | // TODO: If hardware allows, enable after configure_sequence on all chips | 275 | // TODO: If hardware allows, enable after configure_sequence on all chips |
| 272 | #[cfg(any(adc_g4, adc_h5))] | 276 | #[cfg(any(adc_g4, adc_h5))] |
| 273 | T::enable(); | 277 | T::regs().enable(); |
| 274 | T::configure_dma(ConversionMode::Singular); | 278 | T::regs().configure_dma(ConversionMode::Singular); |
| 275 | 279 | ||
| 276 | let request = rx_dma.request(); | 280 | let request = rx_dma.request(); |
| 277 | let transfer = | 281 | let transfer = |
| 278 | unsafe { crate::dma::Transfer::new_read(rx_dma, request, T::dr(), readings, Default::default()) }; | 282 | unsafe { crate::dma::Transfer::new_read(rx_dma, request, T::regs().data(), readings, Default::default()) }; |
| 279 | 283 | ||
| 280 | T::start(); | 284 | T::regs().start(); |
| 281 | 285 | ||
| 282 | // Wait for conversion sequence to finish. | 286 | // Wait for conversion sequence to finish. |
| 283 | transfer.await; | 287 | transfer.await; |
| 284 | 288 | ||
| 285 | // Ensure conversions are finished. | 289 | // Ensure conversions are finished. |
| 286 | T::stop(); | 290 | T::regs().stop(); |
| 287 | } | 291 | } |
| 288 | 292 | ||
| 289 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | 293 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] |
| @@ -313,11 +317,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 313 | /// in order or require the sequence to have the same sample time for all channnels, depending | 317 | /// in order or require the sequence to have the same sample time for all channnels, depending |
| 314 | /// on the number and properties of the channels in the sequence. This method will panic if | 318 | /// on the number and properties of the channels in the sequence. This method will panic if |
| 315 | /// the hardware cannot deliver the requested configuration. | 319 | /// the hardware cannot deliver the requested configuration. |
| 316 | pub fn into_ring_buffered<'a>( | 320 | pub fn into_ring_buffered<'a, 'b>( |
| 317 | self, | 321 | self, |
| 318 | dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>, | 322 | dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>, |
| 319 | dma_buf: &'a mut [u16], | 323 | dma_buf: &'a mut [u16], |
| 320 | sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, T::SampleTime)>, | 324 | sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<'b, T>, <T::Regs as BasicAdcRegs>::SampleTime)>, |
| 321 | mode: RegularConversionMode, | 325 | mode: RegularConversionMode, |
| 322 | ) -> RingBufferedAdc<'a, T> { | 326 | ) -> RingBufferedAdc<'a, T> { |
| 323 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); | 327 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); |
| @@ -327,11 +331,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 327 | "Asynchronous read sequence cannot be more than 16 in length" | 331 | "Asynchronous read sequence cannot be more than 16 in length" |
| 328 | ); | 332 | ); |
| 329 | // Ensure no conversions are ongoing | 333 | // Ensure no conversions are ongoing |
| 330 | T::stop(); | 334 | T::regs().stop(); |
| 331 | #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | 335 | #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] |
| 332 | T::enable(); | 336 | T::regs().enable(); |
| 333 | 337 | ||
| 334 | T::configure_sequence( | 338 | T::regs().configure_sequence( |
| 335 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | 339 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), |
| 336 | ); | 340 | ); |
| 337 | 341 | ||
| @@ -339,8 +343,8 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 339 | // | 343 | // |
| 340 | // TODO: If hardware allows, enable after configure_sequence on all chips | 344 | // TODO: If hardware allows, enable after configure_sequence on all chips |
| 341 | #[cfg(any(adc_g4, adc_h5))] | 345 | #[cfg(any(adc_g4, adc_h5))] |
| 342 | T::enable(); | 346 | T::regs().enable(); |
| 343 | T::configure_dma(ConversionMode::Repeated(mode)); | 347 | T::regs().configure_dma(ConversionMode::Repeated(mode)); |
| 344 | 348 | ||
| 345 | core::mem::forget(self); | 349 | core::mem::forget(self); |
| 346 | 350 | ||
| @@ -417,8 +421,11 @@ pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeri | |||
| 417 | #[allow(private_bounds)] | 421 | #[allow(private_bounds)] |
| 418 | pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { | 422 | pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { |
| 419 | #[allow(unused_mut)] | 423 | #[allow(unused_mut)] |
| 420 | fn degrade_adc(mut self) -> AnyAdcChannel<T> { | 424 | fn degrade_adc<'a>(mut self) -> AnyAdcChannel<'a, T> |
| 421 | #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 425 | where |
| 426 | Self: 'a, | ||
| 427 | { | ||
| 428 | #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] | ||
| 422 | self.setup(); | 429 | self.setup(); |
| 423 | 430 | ||
| 424 | AnyAdcChannel { | 431 | AnyAdcChannel { |
| @@ -433,14 +440,13 @@ pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { | |||
| 433 | /// | 440 | /// |
| 434 | /// This is useful in scenarios where you need the ADC channels to have the same type, such as | 441 | /// This is useful in scenarios where you need the ADC channels to have the same type, such as |
| 435 | /// storing them in an array. | 442 | /// storing them in an array. |
| 436 | pub struct AnyAdcChannel<T> { | 443 | pub struct AnyAdcChannel<'a, T> { |
| 437 | channel: u8, | 444 | channel: u8, |
| 438 | is_differential: bool, | 445 | is_differential: bool, |
| 439 | _phantom: PhantomData<T>, | 446 | _phantom: PhantomData<&'a mut T>, |
| 440 | } | 447 | } |
| 441 | impl_peripheral!(AnyAdcChannel<T: AnyInstance>); | 448 | impl<T: Instance> AdcChannel<T> for AnyAdcChannel<'_, T> {} |
| 442 | impl<T: AnyInstance> AdcChannel<T> for AnyAdcChannel<T> {} | 449 | impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<'_, T> { |
| 443 | impl<T: AnyInstance> SealedAdcChannel<T> for AnyAdcChannel<T> { | ||
| 444 | fn channel(&self) -> u8 { | 450 | fn channel(&self) -> u8 { |
| 445 | self.channel | 451 | self.channel |
| 446 | } | 452 | } |
| @@ -450,22 +456,41 @@ impl<T: AnyInstance> SealedAdcChannel<T> for AnyAdcChannel<T> { | |||
| 450 | } | 456 | } |
| 451 | } | 457 | } |
| 452 | 458 | ||
| 453 | impl<T> AnyAdcChannel<T> { | 459 | impl<T> AnyAdcChannel<'_, T> { |
| 454 | #[allow(unused)] | 460 | #[allow(unused)] |
| 455 | pub fn get_hw_channel(&self) -> u8 { | 461 | pub fn get_hw_channel(&self) -> u8 { |
| 456 | self.channel | 462 | self.channel |
| 457 | } | 463 | } |
| 458 | } | 464 | } |
| 465 | |||
| 466 | #[cfg(not(adc_wba))] | ||
| 467 | impl BasicAdcRegs for crate::pac::adc::Adc { | ||
| 468 | type SampleTime = SampleTime; | ||
| 469 | } | ||
| 470 | |||
| 471 | #[cfg(any(adc_wba, adc_u5))] | ||
| 472 | impl BasicAdcRegs for crate::pac::adc::Adc4 { | ||
| 473 | type SampleTime = Adc4SampleTime; | ||
| 474 | } | ||
| 475 | |||
| 459 | #[cfg(adc_wba)] | 476 | #[cfg(adc_wba)] |
| 460 | foreach_adc!( | 477 | foreach_adc!( |
| 461 | (ADC4, $common_inst:ident, $clock:ident) => { | 478 | (ADC4, $common_inst:ident, $clock:ident) => { |
| 462 | impl crate::adc::adc4::SealedInstance for peripherals::ADC4 { | 479 | impl crate::adc::BasicInstance for peripherals::ADC4 { |
| 463 | fn regs() -> crate::pac::adc::Adc4 { | 480 | type Regs = crate::pac::adc::Adc4; |
| 481 | } | ||
| 482 | |||
| 483 | impl crate::adc::SealedInstance for peripherals::ADC4 { | ||
| 484 | fn regs() -> Self::Regs { | ||
| 464 | crate::pac::ADC4 | 485 | crate::pac::ADC4 |
| 465 | } | 486 | } |
| 487 | |||
| 488 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | ||
| 489 | return crate::pac::$common_inst | ||
| 490 | } | ||
| 466 | } | 491 | } |
| 467 | 492 | ||
| 468 | impl crate::adc::adc4::Instance for peripherals::ADC4 { | 493 | impl crate::adc::Instance for peripherals::ADC4 { |
| 469 | type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; | 494 | type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; |
| 470 | } | 495 | } |
| 471 | }; | 496 | }; |
| @@ -490,20 +515,32 @@ foreach_adc!( | |||
| 490 | #[cfg(adc_u5)] | 515 | #[cfg(adc_u5)] |
| 491 | foreach_adc!( | 516 | foreach_adc!( |
| 492 | (ADC4, $common_inst:ident, $clock:ident) => { | 517 | (ADC4, $common_inst:ident, $clock:ident) => { |
| 493 | impl crate::adc::adc4::SealedInstance for peripherals::ADC4 { | 518 | impl crate::adc::BasicInstance for peripherals::ADC4 { |
| 494 | fn regs() -> crate::pac::adc::Adc4 { | 519 | type Regs = crate::pac::adc::Adc4; |
| 520 | } | ||
| 521 | |||
| 522 | impl crate::adc::SealedInstance for peripherals::ADC4 { | ||
| 523 | fn regs() -> Self::Regs { | ||
| 495 | crate::pac::ADC4 | 524 | crate::pac::ADC4 |
| 496 | } | 525 | } |
| 526 | |||
| 527 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | ||
| 528 | return crate::pac::$common_inst | ||
| 529 | } | ||
| 497 | } | 530 | } |
| 498 | 531 | ||
| 499 | impl crate::adc::adc4::Instance for peripherals::ADC4 { | 532 | impl crate::adc::Instance for peripherals::ADC4 { |
| 500 | type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; | 533 | type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; |
| 501 | } | 534 | } |
| 502 | }; | 535 | }; |
| 503 | 536 | ||
| 504 | ($inst:ident, $common_inst:ident, $clock:ident) => { | 537 | ($inst:ident, $common_inst:ident, $clock:ident) => { |
| 538 | impl crate::adc::BasicInstance for peripherals::$inst { | ||
| 539 | type Regs = crate::pac::adc::Adc; | ||
| 540 | } | ||
| 541 | |||
| 505 | impl crate::adc::SealedInstance for peripherals::$inst { | 542 | impl crate::adc::SealedInstance for peripherals::$inst { |
| 506 | fn regs() -> crate::pac::adc::Adc { | 543 | fn regs() -> Self::Regs { |
| 507 | crate::pac::$inst | 544 | crate::pac::$inst |
| 508 | } | 545 | } |
| 509 | 546 | ||
| @@ -521,14 +558,23 @@ foreach_adc!( | |||
| 521 | #[cfg(not(any(adc_u5, adc_wba)))] | 558 | #[cfg(not(any(adc_u5, adc_wba)))] |
| 522 | foreach_adc!( | 559 | foreach_adc!( |
| 523 | ($inst:ident, $common_inst:ident, $clock:ident) => { | 560 | ($inst:ident, $common_inst:ident, $clock:ident) => { |
| 561 | impl crate::adc::BasicInstance for peripherals::$inst { | ||
| 562 | #[cfg(any( | ||
| 563 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | ||
| 564 | ))] | ||
| 565 | type Regs = crate::pac::adc::Adc; | ||
| 566 | } | ||
| 567 | |||
| 524 | impl crate::adc::SealedInstance for peripherals::$inst { | 568 | impl crate::adc::SealedInstance for peripherals::$inst { |
| 525 | #[cfg(not(adc_wba))] | 569 | #[cfg(any( |
| 526 | fn regs() -> crate::pac::adc::Adc { | 570 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 |
| 571 | ))] | ||
| 572 | fn regs() -> Self::Regs { | ||
| 527 | crate::pac::$inst | 573 | crate::pac::$inst |
| 528 | } | 574 | } |
| 529 | 575 | ||
| 530 | #[cfg(adc_wba)] | 576 | #[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))] |
| 531 | fn regs() -> crate::pac::adc::Adc4 { | 577 | fn regs() -> crate::pac::adc::Adc { |
| 532 | crate::pac::$inst | 578 | crate::pac::$inst |
| 533 | } | 579 | } |
| 534 | 580 | ||
| @@ -554,7 +600,7 @@ macro_rules! impl_adc_pin { | |||
| 554 | ($inst:ident, $pin:ident, $ch:expr) => { | 600 | ($inst:ident, $pin:ident, $ch:expr) => { |
| 555 | impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {} | 601 | impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {} |
| 556 | impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> { | 602 | impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> { |
| 557 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 603 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] |
| 558 | fn setup(&mut self) { | 604 | fn setup(&mut self) { |
| 559 | <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self); | 605 | <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self); |
| 560 | } | 606 | } |
| @@ -582,7 +628,7 @@ macro_rules! impl_adc_pair { | |||
| 582 | crate::Peri<'_, crate::peripherals::$npin>, | 628 | crate::Peri<'_, crate::peripherals::$npin>, |
| 583 | ) | 629 | ) |
| 584 | { | 630 | { |
| 585 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 631 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] |
| 586 | fn setup(&mut self) { | 632 | fn setup(&mut self) { |
| 587 | <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(&mut self.0); | 633 | <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(&mut self.0); |
| 588 | <crate::peripherals::$npin as crate::gpio::SealedPin>::set_as_analog(&mut self.1); | 634 | <crate::peripherals::$npin as crate::gpio::SealedPin>::set_as_analog(&mut self.1); |
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs index 5437866d3..242a1a89c 100644 --- a/embassy-stm32/src/adc/ringbuffered.rs +++ b/embassy-stm32/src/adc/ringbuffered.rs | |||
| @@ -4,7 +4,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; | |||
| 4 | #[allow(unused_imports)] | 4 | #[allow(unused_imports)] |
| 5 | use embassy_hal_internal::Peri; | 5 | use embassy_hal_internal::Peri; |
| 6 | 6 | ||
| 7 | use crate::adc::AnyInstance; | 7 | use super::AdcRegs; |
| 8 | #[allow(unused_imports)] | 8 | #[allow(unused_imports)] |
| 9 | use crate::adc::{Instance, RxDma}; | 9 | use crate::adc::{Instance, RxDma}; |
| 10 | #[allow(unused_imports)] | 10 | #[allow(unused_imports)] |
| @@ -19,7 +19,7 @@ pub struct RingBufferedAdc<'d, T: Instance> { | |||
| 19 | ring_buf: ReadableRingBuffer<'d, u16>, | 19 | ring_buf: ReadableRingBuffer<'d, u16>, |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { | 22 | impl<'d, T: Instance> RingBufferedAdc<'d, T> { |
| 23 | pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self { | 23 | pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self { |
| 24 | //dma side setup | 24 | //dma side setup |
| 25 | let opts = TransferOptions { | 25 | let opts = TransferOptions { |
| @@ -31,8 +31,7 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { | |||
| 31 | // Safety: we forget the struct before this function returns. | 31 | // Safety: we forget the struct before this function returns. |
| 32 | let request = dma.request(); | 32 | let request = dma.request(); |
| 33 | 33 | ||
| 34 | let ring_buf = | 34 | let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, T::regs().data(), dma_buf, opts) }; |
| 35 | unsafe { ReadableRingBuffer::new(dma, request, T::regs().dr().as_ptr() as *mut u16, dma_buf, opts) }; | ||
| 36 | 35 | ||
| 37 | Self { | 36 | Self { |
| 38 | _phantom: PhantomData, | 37 | _phantom: PhantomData, |
| @@ -45,7 +44,7 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { | |||
| 45 | compiler_fence(Ordering::SeqCst); | 44 | compiler_fence(Ordering::SeqCst); |
| 46 | self.ring_buf.start(); | 45 | self.ring_buf.start(); |
| 47 | 46 | ||
| 48 | T::start(); | 47 | T::regs().start(); |
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | pub fn stop(&mut self) { | 50 | pub fn stop(&mut self) { |
| @@ -117,15 +116,15 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { | |||
| 117 | self.start(); | 116 | self.start(); |
| 118 | } | 117 | } |
| 119 | 118 | ||
| 120 | #[cfg(adc_v2)] | 119 | // #[cfg(adc_v2)] |
| 121 | { | 120 | // { |
| 122 | // Clear overrun flag if set. | 121 | // // Clear overrun flag if set. |
| 123 | if T::regs().sr().read().ovr() { | 122 | // if T::regs().sr().read().ovr() { |
| 124 | self.stop(); | 123 | // self.stop(); |
| 125 | 124 | // | |
| 126 | return Err(OverrunError); | 125 | // return Err(OverrunError); |
| 127 | } | 126 | // } |
| 128 | } | 127 | // } |
| 129 | 128 | ||
| 130 | self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError) | 129 | self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError) |
| 131 | } | 130 | } |
| @@ -143,15 +142,16 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { | |||
| 143 | self.start(); | 142 | self.start(); |
| 144 | } | 143 | } |
| 145 | 144 | ||
| 146 | #[cfg(adc_v2)] | 145 | // #[cfg(adc_v2)] |
| 147 | { | 146 | // { |
| 148 | // Clear overrun flag if set. | 147 | // // Clear overrun flag if set. |
| 149 | if T::regs().sr().read().ovr() { | 148 | // if T::regs().sr().read().ovr() { |
| 150 | self.stop(); | 149 | // self.stop(); |
| 150 | // | ||
| 151 | // return Err(OverrunError); | ||
| 152 | // } | ||
| 153 | // } | ||
| 151 | 154 | ||
| 152 | return Err(OverrunError); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | loop { | 155 | loop { |
| 156 | match self.ring_buf.read(buf) { | 156 | match self.ring_buf.read(buf) { |
| 157 | Ok((0, _)) => {} | 157 | Ok((0, _)) => {} |
| @@ -168,9 +168,9 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { | |||
| 168 | } | 168 | } |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | impl<T: Instance + AnyInstance> Drop for RingBufferedAdc<'_, T> { | 171 | impl<T: Instance> Drop for RingBufferedAdc<'_, T> { |
| 172 | fn drop(&mut self) { | 172 | fn drop(&mut self) { |
| 173 | T::stop(); | 173 | T::regs().stop(); |
| 174 | 174 | ||
| 175 | compiler_fence(Ordering::SeqCst); | 175 | compiler_fence(Ordering::SeqCst); |
| 176 | 176 | ||
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 3c4431ae0..b026383d5 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | use core::sync::atomic::{Ordering, compiler_fence}; | 1 | use core::sync::atomic::{Ordering, compiler_fence}; |
| 2 | 2 | ||
| 3 | use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; | 3 | use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; |
| 4 | use crate::adc::{Adc, Instance, Resolution, SampleTime}; | 4 | use crate::adc::{Adc, AdcRegs, Instance, Resolution, SampleTime}; |
| 5 | use crate::pac::adc::vals; | 5 | use crate::pac::adc::vals; |
| 6 | pub use crate::pac::adccommon::vals::Adcpre; | 6 | pub use crate::pac::adccommon::vals::Adcpre; |
| 7 | use crate::time::Hertz; | 7 | use crate::time::Hertz; |
| @@ -71,31 +71,31 @@ fn from_pclk2(freq: Hertz) -> Adcpre { | |||
| 71 | /// ADC configuration | 71 | /// ADC configuration |
| 72 | #[derive(Default)] | 72 | #[derive(Default)] |
| 73 | pub struct AdcConfig { | 73 | pub struct AdcConfig { |
| 74 | resolution: Option<Resolution>, | 74 | pub resolution: Option<Resolution>, |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | impl<T: Instance> super::SealedAnyInstance for T { | 77 | impl super::AdcRegs for crate::pac::adc::Adc { |
| 78 | fn dr() -> *mut u16 { | 78 | fn data(&self) -> *mut u16 { |
| 79 | T::regs().dr().as_ptr() as *mut u16 | 79 | crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | fn enable() { | 82 | fn enable(&self) { |
| 83 | T::regs().cr2().modify(|reg| { | 83 | self.cr2().modify(|reg| { |
| 84 | reg.set_adon(true); | 84 | reg.set_adon(true); |
| 85 | }); | 85 | }); |
| 86 | 86 | ||
| 87 | blocking_delay_us(3); | 87 | blocking_delay_us(3); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | fn start() { | 90 | fn start(&self) { |
| 91 | // Begin ADC conversions | 91 | // Begin ADC conversions |
| 92 | T::regs().cr2().modify(|reg| { | 92 | self.cr2().modify(|reg| { |
| 93 | reg.set_swstart(true); | 93 | reg.set_swstart(true); |
| 94 | }); | 94 | }); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | fn stop() { | 97 | fn stop(&self) { |
| 98 | let r = T::regs(); | 98 | let r = self; |
| 99 | 99 | ||
| 100 | // Stop ADC | 100 | // Stop ADC |
| 101 | r.cr2().modify(|reg| { | 101 | r.cr2().modify(|reg| { |
| @@ -114,36 +114,34 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 114 | w.set_ovrie(false); | 114 | w.set_ovrie(false); |
| 115 | }); | 115 | }); |
| 116 | 116 | ||
| 117 | clear_interrupt_flags(r); | 117 | clear_interrupt_flags(*r); |
| 118 | 118 | ||
| 119 | compiler_fence(Ordering::SeqCst); | 119 | compiler_fence(Ordering::SeqCst); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | fn convert() -> u16 { | 122 | fn convert(&self) { |
| 123 | // clear end of conversion flag | 123 | // clear end of conversion flag |
| 124 | T::regs().sr().modify(|reg| { | 124 | self.sr().modify(|reg| { |
| 125 | reg.set_eoc(false); | 125 | reg.set_eoc(false); |
| 126 | }); | 126 | }); |
| 127 | 127 | ||
| 128 | // Start conversion | 128 | // Start conversion |
| 129 | T::regs().cr2().modify(|reg| { | 129 | self.cr2().modify(|reg| { |
| 130 | reg.set_swstart(true); | 130 | reg.set_swstart(true); |
| 131 | }); | 131 | }); |
| 132 | 132 | ||
| 133 | while T::regs().sr().read().strt() == false { | 133 | while self.sr().read().strt() == false { |
| 134 | // spin //wait for actual start | 134 | // spin //wait for actual start |
| 135 | } | 135 | } |
| 136 | while T::regs().sr().read().eoc() == false { | 136 | while self.sr().read().eoc() == false { |
| 137 | // spin //wait for finish | 137 | // spin //wait for finish |
| 138 | } | 138 | } |
| 139 | |||
| 140 | T::regs().dr().read().0 as u16 | ||
| 141 | } | 139 | } |
| 142 | 140 | ||
| 143 | fn configure_dma(conversion_mode: ConversionMode) { | 141 | fn configure_dma(&self, conversion_mode: ConversionMode) { |
| 144 | match conversion_mode { | 142 | match conversion_mode { |
| 145 | ConversionMode::Repeated(_) => { | 143 | ConversionMode::Repeated(_) => { |
| 146 | let r = T::regs(); | 144 | let r = self; |
| 147 | 145 | ||
| 148 | // Clear all interrupts | 146 | // Clear all interrupts |
| 149 | r.sr().modify(|regs| { | 147 | r.sr().modify(|regs| { |
| @@ -177,25 +175,25 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 177 | } | 175 | } |
| 178 | } | 176 | } |
| 179 | 177 | ||
| 180 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | 178 | fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 181 | T::regs().cr2().modify(|reg| { | 179 | self.cr2().modify(|reg| { |
| 182 | reg.set_adon(true); | 180 | reg.set_adon(true); |
| 183 | }); | 181 | }); |
| 184 | 182 | ||
| 185 | // Check the sequence is long enough | 183 | // Check the sequence is long enough |
| 186 | T::regs().sqr1().modify(|r| { | 184 | self.sqr1().modify(|r| { |
| 187 | r.set_l((sequence.len() - 1).try_into().unwrap()); | 185 | r.set_l((sequence.len() - 1).try_into().unwrap()); |
| 188 | }); | 186 | }); |
| 189 | 187 | ||
| 190 | for (i, ((ch, _), sample_time)) in sequence.enumerate() { | 188 | for (i, ((ch, _), sample_time)) in sequence.enumerate() { |
| 191 | // Set the channel in the right sequence field. | 189 | // Set the channel in the right sequence field. |
| 192 | T::regs().sqr3().modify(|w| w.set_sq(i, ch)); | 190 | self.sqr3().modify(|w| w.set_sq(i, ch)); |
| 193 | 191 | ||
| 194 | let sample_time = sample_time.into(); | 192 | let sample_time = sample_time.into(); |
| 195 | if ch <= 9 { | 193 | if ch <= 9 { |
| 196 | T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); | 194 | self.smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); |
| 197 | } else { | 195 | } else { |
| 198 | T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | 196 | self.smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); |
| 199 | } | 197 | } |
| 200 | } | 198 | } |
| 201 | } | 199 | } |
| @@ -203,7 +201,7 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 203 | 201 | ||
| 204 | impl<'d, T> Adc<'d, T> | 202 | impl<'d, T> Adc<'d, T> |
| 205 | where | 203 | where |
| 206 | T: Instance + super::AnyInstance, | 204 | T: Instance<Regs = crate::pac::adc::Adc>, |
| 207 | { | 205 | { |
| 208 | pub fn new(adc: Peri<'d, T>) -> Self { | 206 | pub fn new(adc: Peri<'d, T>) -> Self { |
| 209 | Self::new_with_config(adc, Default::default()) | 207 | Self::new_with_config(adc, Default::default()) |
| @@ -214,7 +212,7 @@ where | |||
| 214 | 212 | ||
| 215 | let presc = from_pclk2(T::frequency()); | 213 | let presc = from_pclk2(T::frequency()); |
| 216 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc)); | 214 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc)); |
| 217 | T::enable(); | 215 | T::regs().enable(); |
| 218 | 216 | ||
| 219 | if let Some(resolution) = config.resolution { | 217 | if let Some(resolution) = config.resolution { |
| 220 | T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); | 218 | T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); |
| @@ -259,9 +257,7 @@ where | |||
| 259 | 257 | ||
| 260 | impl<'d, T: Instance> Drop for Adc<'d, T> { | 258 | impl<'d, T: Instance> Drop for Adc<'d, T> { |
| 261 | fn drop(&mut self) { | 259 | fn drop(&mut self) { |
| 262 | T::regs().cr2().modify(|reg| { | 260 | T::regs().stop(); |
| 263 | reg.set_adon(false); | ||
| 264 | }); | ||
| 265 | 261 | ||
| 266 | rcc::disable::<T>(); | 262 | rcc::disable::<T>(); |
| 267 | } | 263 | } |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index b270588c4..9cc44aa9a 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -146,63 +146,63 @@ pub struct AdcConfig { | |||
| 146 | pub averaging: Option<Averaging>, | 146 | pub averaging: Option<Averaging>, |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | impl<T: Instance> super::SealedAnyInstance for T { | 149 | impl super::AdcRegs for crate::pac::adc::Adc { |
| 150 | fn dr() -> *mut u16 { | 150 | fn data(&self) -> *mut u16 { |
| 151 | T::regs().dr().as_ptr() as *mut u16 | 151 | crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | // Enable ADC only when it is not already running. | 154 | // Enable ADC only when it is not already running. |
| 155 | fn enable() { | 155 | fn enable(&self) { |
| 156 | // Make sure bits are off | 156 | // Make sure bits are off |
| 157 | while T::regs().cr().read().addis() { | 157 | while self.cr().read().addis() { |
| 158 | // spin | 158 | // spin |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | if !T::regs().cr().read().aden() { | 161 | if !self.cr().read().aden() { |
| 162 | // Enable ADC | 162 | // Enable ADC |
| 163 | T::regs().isr().modify(|reg| { | 163 | self.isr().modify(|reg| { |
| 164 | reg.set_adrdy(true); | 164 | reg.set_adrdy(true); |
| 165 | }); | 165 | }); |
| 166 | T::regs().cr().modify(|reg| { | 166 | self.cr().modify(|reg| { |
| 167 | reg.set_aden(true); | 167 | reg.set_aden(true); |
| 168 | }); | 168 | }); |
| 169 | 169 | ||
| 170 | while !T::regs().isr().read().adrdy() { | 170 | while !self.isr().read().adrdy() { |
| 171 | // spin | 171 | // spin |
| 172 | } | 172 | } |
| 173 | } | 173 | } |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | fn start() { | 176 | fn start(&self) { |
| 177 | T::regs().cr().modify(|reg| { | 177 | self.cr().modify(|reg| { |
| 178 | reg.set_adstart(true); | 178 | reg.set_adstart(true); |
| 179 | }); | 179 | }); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | fn stop() { | 182 | fn stop(&self) { |
| 183 | // Ensure conversions are finished. | 183 | // Ensure conversions are finished. |
| 184 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | 184 | if self.cr().read().adstart() && !self.cr().read().addis() { |
| 185 | T::regs().cr().modify(|reg| { | 185 | self.cr().modify(|reg| { |
| 186 | reg.set_adstp(true); | 186 | reg.set_adstp(true); |
| 187 | }); | 187 | }); |
| 188 | while T::regs().cr().read().adstart() {} | 188 | while self.cr().read().adstart() {} |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | // Reset configuration. | 191 | // Reset configuration. |
| 192 | #[cfg(not(any(adc_g0, adc_u0)))] | 192 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 193 | T::regs().cfgr().modify(|reg| { | 193 | self.cfgr().modify(|reg| { |
| 194 | reg.set_cont(false); | 194 | reg.set_cont(false); |
| 195 | reg.set_dmaen(false); | 195 | reg.set_dmaen(false); |
| 196 | }); | 196 | }); |
| 197 | #[cfg(any(adc_g0, adc_u0))] | 197 | #[cfg(any(adc_g0, adc_u0))] |
| 198 | T::regs().cfgr1().modify(|reg| { | 198 | self.cfgr1().modify(|reg| { |
| 199 | reg.set_cont(false); | 199 | reg.set_cont(false); |
| 200 | reg.set_dmaen(false); | 200 | reg.set_dmaen(false); |
| 201 | }); | 201 | }); |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | /// Perform a single conversion. | 204 | /// Perform a single conversion. |
| 205 | fn convert() -> u16 { | 205 | fn convert(&self) { |
| 206 | // Some models are affected by an erratum: | 206 | // Some models are affected by an erratum: |
| 207 | // If we perform conversions slower than 1 kHz, the first read ADC value can be | 207 | // If we perform conversions slower than 1 kHz, the first read ADC value can be |
| 208 | // corrupted, so we discard it and measure again. | 208 | // corrupted, so we discard it and measure again. |
| @@ -216,36 +216,34 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 216 | let len = 1; | 216 | let len = 1; |
| 217 | 217 | ||
| 218 | for _ in 0..len { | 218 | for _ in 0..len { |
| 219 | T::regs().isr().modify(|reg| { | 219 | self.isr().modify(|reg| { |
| 220 | reg.set_eos(true); | 220 | reg.set_eos(true); |
| 221 | reg.set_eoc(true); | 221 | reg.set_eoc(true); |
| 222 | }); | 222 | }); |
| 223 | 223 | ||
| 224 | // Start conversion | 224 | // Start conversion |
| 225 | T::regs().cr().modify(|reg| { | 225 | self.cr().modify(|reg| { |
| 226 | reg.set_adstart(true); | 226 | reg.set_adstart(true); |
| 227 | }); | 227 | }); |
| 228 | 228 | ||
| 229 | while !T::regs().isr().read().eos() { | 229 | while !self.isr().read().eos() { |
| 230 | // spin | 230 | // spin |
| 231 | } | 231 | } |
| 232 | } | 232 | } |
| 233 | |||
| 234 | T::regs().dr().read().0 as u16 | ||
| 235 | } | 233 | } |
| 236 | 234 | ||
| 237 | fn configure_dma(conversion_mode: ConversionMode) { | 235 | fn configure_dma(&self, conversion_mode: ConversionMode) { |
| 238 | // Set continuous mode with oneshot dma. | 236 | // Set continuous mode with oneshot dma. |
| 239 | // Clear overrun flag before starting transfer. | 237 | // Clear overrun flag before starting transfer. |
| 240 | T::regs().isr().modify(|reg| { | 238 | self.isr().modify(|reg| { |
| 241 | reg.set_ovr(true); | 239 | reg.set_ovr(true); |
| 242 | }); | 240 | }); |
| 243 | 241 | ||
| 244 | #[cfg(not(any(adc_g0, adc_u0)))] | 242 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 245 | let regs = T::regs().cfgr(); | 243 | let regs = self.cfgr(); |
| 246 | 244 | ||
| 247 | #[cfg(any(adc_g0, adc_u0))] | 245 | #[cfg(any(adc_g0, adc_u0))] |
| 248 | let regs = T::regs().cfgr1(); | 246 | let regs = self.cfgr1(); |
| 249 | 247 | ||
| 250 | regs.modify(|reg| { | 248 | regs.modify(|reg| { |
| 251 | reg.set_discen(false); | 249 | reg.set_discen(false); |
| @@ -259,13 +257,13 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 259 | }); | 257 | }); |
| 260 | } | 258 | } |
| 261 | 259 | ||
| 262 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | 260 | fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 263 | #[cfg(adc_h5)] | 261 | #[cfg(adc_h5)] |
| 264 | T::regs().cr().modify(|w| w.set_aden(false)); | 262 | self.cr().modify(|w| w.set_aden(false)); |
| 265 | 263 | ||
| 266 | // Set sequence length | 264 | // Set sequence length |
| 267 | #[cfg(not(any(adc_g0, adc_u0)))] | 265 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 268 | T::regs().sqr1().modify(|w| { | 266 | self.sqr1().modify(|w| { |
| 269 | w.set_l(sequence.len() as u8 - 1); | 267 | w.set_l(sequence.len() as u8 - 1); |
| 270 | }); | 268 | }); |
| 271 | 269 | ||
| @@ -273,8 +271,8 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 273 | { | 271 | { |
| 274 | let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new(); | 272 | let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new(); |
| 275 | 273 | ||
| 276 | T::regs().chselr().write(|chselr| { | 274 | self.chselr().write(|chselr| { |
| 277 | T::regs().smpr().write(|smpr| { | 275 | self.smpr().write(|smpr| { |
| 278 | for ((channel, _), sample_time) in sequence { | 276 | for ((channel, _), sample_time) in sequence { |
| 279 | chselr.set_chsel(channel.into(), true); | 277 | chselr.set_chsel(channel.into(), true); |
| 280 | if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { | 278 | if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { |
| @@ -306,22 +304,22 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 306 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." | 304 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." |
| 307 | #[cfg(any(adc_h5, adc_h7rs))] | 305 | #[cfg(any(adc_h5, adc_h7rs))] |
| 308 | if channel == 0 { | 306 | if channel == 0 { |
| 309 | T::regs().or().modify(|reg| reg.set_op0(true)); | 307 | self.or().modify(|reg| reg.set_op0(true)); |
| 310 | } | 308 | } |
| 311 | 309 | ||
| 312 | // Configure channel | 310 | // Configure channel |
| 313 | cfg_if! { | 311 | cfg_if! { |
| 314 | if #[cfg(adc_u0)] { | 312 | if #[cfg(adc_u0)] { |
| 315 | // On G0 and U6 all channels use the same sampling time. | 313 | // On G0 and U6 all channels use the same sampling time. |
| 316 | T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); | 314 | self.smpr().modify(|reg| reg.set_smp1(sample_time.into())); |
| 317 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | 315 | } else if #[cfg(any(adc_h5, adc_h7rs))] { |
| 318 | match channel { | 316 | match channel { |
| 319 | 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), | 317 | 0..=9 => self.smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), |
| 320 | _ => T::regs().smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), | 318 | _ => self.smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), |
| 321 | } | 319 | } |
| 322 | } else { | 320 | } else { |
| 323 | let sample_time = sample_time.into(); | 321 | let sample_time = sample_time.into(); |
| 324 | T::regs() | 322 | self |
| 325 | .smpr(channel as usize / 10) | 323 | .smpr(channel as usize / 10) |
| 326 | .modify(|reg| reg.set_smp(channel as usize % 10, sample_time)); | 324 | .modify(|reg| reg.set_smp(channel as usize % 10, sample_time)); |
| 327 | } | 325 | } |
| @@ -331,9 +329,8 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 331 | { | 329 | { |
| 332 | use crate::pac::adc::vals::Pcsel; | 330 | use crate::pac::adc::vals::Pcsel; |
| 333 | 331 | ||
| 334 | T::regs().cfgr2().modify(|w| w.set_lshift(0)); | 332 | self.cfgr2().modify(|w| w.set_lshift(0)); |
| 335 | T::regs() | 333 | self.pcsel() |
| 336 | .pcsel() | ||
| 337 | .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); | 334 | .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); |
| 338 | } | 335 | } |
| 339 | 336 | ||
| @@ -341,22 +338,22 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 341 | #[cfg(not(any(adc_g0, adc_u0)))] | 338 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 342 | match _i { | 339 | match _i { |
| 343 | 0..=3 => { | 340 | 0..=3 => { |
| 344 | T::regs().sqr1().modify(|w| { | 341 | self.sqr1().modify(|w| { |
| 345 | w.set_sq(_i, channel); | 342 | w.set_sq(_i, channel); |
| 346 | }); | 343 | }); |
| 347 | } | 344 | } |
| 348 | 4..=8 => { | 345 | 4..=8 => { |
| 349 | T::regs().sqr2().modify(|w| { | 346 | self.sqr2().modify(|w| { |
| 350 | w.set_sq(_i - 4, channel); | 347 | w.set_sq(_i - 4, channel); |
| 351 | }); | 348 | }); |
| 352 | } | 349 | } |
| 353 | 9..=13 => { | 350 | 9..=13 => { |
| 354 | T::regs().sqr3().modify(|w| { | 351 | self.sqr3().modify(|w| { |
| 355 | w.set_sq(_i - 9, channel); | 352 | w.set_sq(_i - 9, channel); |
| 356 | }); | 353 | }); |
| 357 | } | 354 | } |
| 358 | 14..=15 => { | 355 | 14..=15 => { |
| 359 | T::regs().sqr4().modify(|w| { | 356 | self.sqr4().modify(|w| { |
| 360 | w.set_sq(_i - 14, channel); | 357 | w.set_sq(_i - 14, channel); |
| 361 | }); | 358 | }); |
| 362 | } | 359 | } |
| @@ -375,20 +372,20 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 375 | } | 372 | } |
| 376 | 373 | ||
| 377 | #[cfg(adc_h5)] | 374 | #[cfg(adc_h5)] |
| 378 | T::regs().difsel().write(|w| w.set_difsel(difsel)); | 375 | self.difsel().write(|w| w.set_difsel(difsel)); |
| 379 | 376 | ||
| 380 | // On G0 and U0 enabled channels are sampled from 0 to last channel. | 377 | // On G0 and U0 enabled channels are sampled from 0 to last channel. |
| 381 | // It is possible to add up to 8 sequences if CHSELRMOD = 1. | 378 | // It is possible to add up to 8 sequences if CHSELRMOD = 1. |
| 382 | // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. | 379 | // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. |
| 383 | #[cfg(adc_u0)] | 380 | #[cfg(adc_u0)] |
| 384 | T::regs().chselr().modify(|reg| { | 381 | self.chselr().modify(|reg| { |
| 385 | reg.set_chsel(channel_mask); | 382 | reg.set_chsel(channel_mask); |
| 386 | }); | 383 | }); |
| 387 | } | 384 | } |
| 388 | } | 385 | } |
| 389 | } | 386 | } |
| 390 | 387 | ||
| 391 | impl<'d, T: Instance> Adc<'d, T> { | 388 | impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> { |
| 392 | /// Enable the voltage regulator | 389 | /// Enable the voltage regulator |
| 393 | fn init_regulator() { | 390 | fn init_regulator() { |
| 394 | rcc::enable_and_reset::<T>(); | 391 | rcc::enable_and_reset::<T>(); |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index a3d9e6176..09fc2ab22 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -5,7 +5,7 @@ use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; | |||
| 5 | use pac::adccommon::vals::Presc; | 5 | use pac::adccommon::vals::Presc; |
| 6 | 6 | ||
| 7 | use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; | 7 | use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; |
| 8 | use crate::adc::ConversionMode; | 8 | use crate::adc::{AdcRegs, ConversionMode}; |
| 9 | use crate::time::Hertz; | 9 | use crate::time::Hertz; |
| 10 | use crate::{Peri, pac, rcc}; | 10 | use crate::{Peri, pac, rcc}; |
| 11 | 11 | ||
| @@ -80,65 +80,63 @@ pub struct AdcConfig { | |||
| 80 | pub averaging: Option<Averaging>, | 80 | pub averaging: Option<Averaging>, |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | impl<T: Instance> super::SealedAnyInstance for T { | 83 | impl AdcRegs for crate::pac::adc::Adc { |
| 84 | fn dr() -> *mut u16 { | 84 | fn data(&self) -> *mut u16 { |
| 85 | T::regs().dr().as_ptr() as *mut u16 | 85 | crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | fn enable() { | 88 | fn enable(&self) { |
| 89 | T::regs().isr().write(|w| w.set_adrdy(true)); | 89 | self.isr().write(|w| w.set_adrdy(true)); |
| 90 | T::regs().cr().modify(|w| w.set_aden(true)); | 90 | self.cr().modify(|w| w.set_aden(true)); |
| 91 | while !T::regs().isr().read().adrdy() {} | 91 | while !self.isr().read().adrdy() {} |
| 92 | T::regs().isr().write(|w| w.set_adrdy(true)); | 92 | self.isr().write(|w| w.set_adrdy(true)); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | fn start() { | 95 | fn start(&self) { |
| 96 | // Start conversion | 96 | // Start conversion |
| 97 | T::regs().cr().modify(|reg| { | 97 | self.cr().modify(|reg| { |
| 98 | reg.set_adstart(true); | 98 | reg.set_adstart(true); |
| 99 | }); | 99 | }); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | fn stop() { | 102 | fn stop(&self) { |
| 103 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | 103 | if self.cr().read().adstart() && !self.cr().read().addis() { |
| 104 | T::regs().cr().modify(|reg| { | 104 | self.cr().modify(|reg| { |
| 105 | reg.set_adstp(Adstp::STOP); | 105 | reg.set_adstp(Adstp::STOP); |
| 106 | }); | 106 | }); |
| 107 | while T::regs().cr().read().adstart() {} | 107 | while self.cr().read().adstart() {} |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | // Reset configuration. | 110 | // Reset configuration. |
| 111 | T::regs().cfgr().modify(|reg| { | 111 | self.cfgr().modify(|reg| { |
| 112 | reg.set_cont(false); | 112 | reg.set_cont(false); |
| 113 | reg.set_dmngt(Dmngt::from_bits(0)); | 113 | reg.set_dmngt(Dmngt::from_bits(0)); |
| 114 | }); | 114 | }); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | fn convert() -> u16 { | 117 | fn convert(&self) { |
| 118 | T::regs().isr().modify(|reg| { | 118 | self.isr().modify(|reg| { |
| 119 | reg.set_eos(true); | 119 | reg.set_eos(true); |
| 120 | reg.set_eoc(true); | 120 | reg.set_eoc(true); |
| 121 | }); | 121 | }); |
| 122 | 122 | ||
| 123 | // Start conversion | 123 | // Start conversion |
| 124 | T::regs().cr().modify(|reg| { | 124 | self.cr().modify(|reg| { |
| 125 | reg.set_adstart(true); | 125 | reg.set_adstart(true); |
| 126 | }); | 126 | }); |
| 127 | 127 | ||
| 128 | while !T::regs().isr().read().eos() { | 128 | while !self.isr().read().eos() { |
| 129 | // spin | 129 | // spin |
| 130 | } | 130 | } |
| 131 | |||
| 132 | T::regs().dr().read().0 as u16 | ||
| 133 | } | 131 | } |
| 134 | 132 | ||
| 135 | fn configure_dma(conversion_mode: ConversionMode) { | 133 | fn configure_dma(&self, conversion_mode: ConversionMode) { |
| 136 | match conversion_mode { | 134 | match conversion_mode { |
| 137 | ConversionMode::Singular => { | 135 | ConversionMode::Singular => { |
| 138 | T::regs().isr().modify(|reg| { | 136 | self.isr().modify(|reg| { |
| 139 | reg.set_ovr(true); | 137 | reg.set_ovr(true); |
| 140 | }); | 138 | }); |
| 141 | T::regs().cfgr().modify(|reg| { | 139 | self.cfgr().modify(|reg| { |
| 142 | reg.set_cont(true); | 140 | reg.set_cont(true); |
| 143 | reg.set_dmngt(Dmngt::DMA_ONE_SHOT); | 141 | reg.set_dmngt(Dmngt::DMA_ONE_SHOT); |
| 144 | }); | 142 | }); |
| @@ -148,9 +146,9 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 148 | } | 146 | } |
| 149 | } | 147 | } |
| 150 | 148 | ||
| 151 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | 149 | fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 152 | // Set sequence length | 150 | // Set sequence length |
| 153 | T::regs().sqr1().modify(|w| { | 151 | self.sqr1().modify(|w| { |
| 154 | w.set_l(sequence.len() as u8 - 1); | 152 | w.set_l(sequence.len() as u8 - 1); |
| 155 | }); | 153 | }); |
| 156 | 154 | ||
| @@ -158,39 +156,35 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 158 | for (i, ((channel, _), sample_time)) in sequence.enumerate() { | 156 | for (i, ((channel, _), sample_time)) in sequence.enumerate() { |
| 159 | let sample_time = sample_time.into(); | 157 | let sample_time = sample_time.into(); |
| 160 | if channel <= 9 { | 158 | if channel <= 9 { |
| 161 | T::regs().smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time)); | 159 | self.smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time)); |
| 162 | } else { | 160 | } else { |
| 163 | T::regs() | 161 | self.smpr(1).modify(|reg| reg.set_smp((channel - 10) as _, sample_time)); |
| 164 | .smpr(1) | ||
| 165 | .modify(|reg| reg.set_smp((channel - 10) as _, sample_time)); | ||
| 166 | } | 162 | } |
| 167 | 163 | ||
| 168 | #[cfg(any(stm32h7, stm32u5))] | 164 | #[cfg(any(stm32h7, stm32u5))] |
| 169 | { | 165 | { |
| 170 | T::regs().cfgr2().modify(|w| w.set_lshift(0)); | 166 | self.cfgr2().modify(|w| w.set_lshift(0)); |
| 171 | T::regs() | 167 | self.pcsel().modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); |
| 172 | .pcsel() | ||
| 173 | .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); | ||
| 174 | } | 168 | } |
| 175 | 169 | ||
| 176 | match i { | 170 | match i { |
| 177 | 0..=3 => { | 171 | 0..=3 => { |
| 178 | T::regs().sqr1().modify(|w| { | 172 | self.sqr1().modify(|w| { |
| 179 | w.set_sq(i, channel); | 173 | w.set_sq(i, channel); |
| 180 | }); | 174 | }); |
| 181 | } | 175 | } |
| 182 | 4..=8 => { | 176 | 4..=8 => { |
| 183 | T::regs().sqr2().modify(|w| { | 177 | self.sqr2().modify(|w| { |
| 184 | w.set_sq(i - 4, channel); | 178 | w.set_sq(i - 4, channel); |
| 185 | }); | 179 | }); |
| 186 | } | 180 | } |
| 187 | 9..=13 => { | 181 | 9..=13 => { |
| 188 | T::regs().sqr3().modify(|w| { | 182 | self.sqr3().modify(|w| { |
| 189 | w.set_sq(i - 9, channel); | 183 | w.set_sq(i - 9, channel); |
| 190 | }); | 184 | }); |
| 191 | } | 185 | } |
| 192 | 14..=15 => { | 186 | 14..=15 => { |
| 193 | T::regs().sqr4().modify(|w| { | 187 | self.sqr4().modify(|w| { |
| 194 | w.set_sq(i - 14, channel); | 188 | w.set_sq(i - 14, channel); |
| 195 | }); | 189 | }); |
| 196 | } | 190 | } |
| @@ -200,7 +194,7 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 200 | } | 194 | } |
| 201 | } | 195 | } |
| 202 | 196 | ||
| 203 | impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> { | 197 | impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> { |
| 204 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { | 198 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { |
| 205 | let s = Self::new(adc); | 199 | let s = Self::new(adc); |
| 206 | 200 | ||
| @@ -292,7 +286,7 @@ impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> { | |||
| 292 | 286 | ||
| 293 | blocking_delay_us(1); | 287 | blocking_delay_us(1); |
| 294 | 288 | ||
| 295 | T::enable(); | 289 | T::regs().enable(); |
| 296 | 290 | ||
| 297 | // single conversion mode, software trigger | 291 | // single conversion mode, software trigger |
| 298 | T::regs().cfgr().modify(|w| { | 292 | T::regs().cfgr().modify(|w| { |
diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs index bfd0570f8..afb18ec1a 100644 --- a/embassy-stm32/src/dma/gpdma/mod.rs +++ b/embassy-stm32/src/dma/gpdma/mod.rs | |||
| @@ -137,7 +137,6 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: c | |||
| 137 | 137 | ||
| 138 | impl AnyChannel { | 138 | impl AnyChannel { |
| 139 | /// Safety: Must be called with a matching set of parameters for a valid dma channel | 139 | /// Safety: Must be called with a matching set of parameters for a valid dma channel |
| 140 | #[cfg(not(stm32n6))] | ||
| 141 | pub(crate) unsafe fn on_irq(&self) { | 140 | pub(crate) unsafe fn on_irq(&self) { |
| 142 | let info = self.info(); | 141 | let info = self.info(); |
| 143 | #[cfg(feature = "_dual-core")] | 142 | #[cfg(feature = "_dual-core")] |
| @@ -238,6 +237,11 @@ impl AnyChannel { | |||
| 238 | // "Preceding reads and writes cannot be moved past subsequent writes." | 237 | // "Preceding reads and writes cannot be moved past subsequent writes." |
| 239 | fence(Ordering::SeqCst); | 238 | fence(Ordering::SeqCst); |
| 240 | 239 | ||
| 240 | if ch.cr().read().en() { | ||
| 241 | ch.cr().modify(|w| w.set_susp(true)); | ||
| 242 | while !ch.sr().read().suspf() {} | ||
| 243 | } | ||
| 244 | |||
| 241 | ch.cr().write(|w| w.set_reset(true)); | 245 | ch.cr().write(|w| w.set_reset(true)); |
| 242 | ch.fcr().write(|w| { | 246 | ch.fcr().write(|w| { |
| 243 | // Clear all irqs | 247 | // Clear all irqs |
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index efb324fa6..05d9c2e51 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -25,7 +25,7 @@ pub(crate) use util::*; | |||
| 25 | pub(crate) mod ringbuffer; | 25 | pub(crate) mod ringbuffer; |
| 26 | pub mod word; | 26 | pub mod word; |
| 27 | 27 | ||
| 28 | use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; | 28 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; |
| 29 | 29 | ||
| 30 | use crate::interrupt; | 30 | use crate::interrupt; |
| 31 | use crate::rcc::StoppablePeripheral; | 31 | use crate::rcc::StoppablePeripheral; |
| @@ -47,21 +47,10 @@ pub type Request = u8; | |||
| 47 | #[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] | 47 | #[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] |
| 48 | pub type Request = (); | 48 | pub type Request = (); |
| 49 | 49 | ||
| 50 | impl<'a> StoppablePeripheral for Peri<'a, AnyChannel> { | 50 | pub(crate) trait SealedChannel: StoppablePeripheral { |
| 51 | #[cfg(feature = "low-power")] | ||
| 52 | fn stop_mode(&self) -> crate::rcc::StopMode { | ||
| 53 | self.stop_mode | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | pub(crate) trait SealedChannel { | ||
| 58 | #[cfg(not(stm32n6))] | ||
| 59 | fn id(&self) -> u8; | 51 | fn id(&self) -> u8; |
| 60 | #[cfg(feature = "low-power")] | ||
| 61 | fn stop_mode(&self) -> crate::rcc::StopMode; | ||
| 62 | } | 52 | } |
| 63 | 53 | ||
| 64 | #[cfg(not(stm32n6))] | ||
| 65 | pub(crate) trait ChannelInterrupt { | 54 | pub(crate) trait ChannelInterrupt { |
| 66 | #[cfg_attr(not(feature = "rt"), allow(unused))] | 55 | #[cfg_attr(not(feature = "rt"), allow(unused))] |
| 67 | unsafe fn on_irq(); | 56 | unsafe fn on_irq(); |
| @@ -71,19 +60,21 @@ pub(crate) trait ChannelInterrupt { | |||
| 71 | #[allow(private_bounds)] | 60 | #[allow(private_bounds)] |
| 72 | pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {} | 61 | pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {} |
| 73 | 62 | ||
| 74 | #[cfg(not(stm32n6))] | ||
| 75 | macro_rules! dma_channel_impl { | 63 | macro_rules! dma_channel_impl { |
| 76 | ($channel_peri:ident, $index:expr, $stop_mode:ident) => { | 64 | ($channel_peri:ident, $index:expr, $stop_mode:ident) => { |
| 77 | impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { | 65 | impl crate::rcc::StoppablePeripheral for crate::peripherals::$channel_peri { |
| 78 | fn id(&self) -> u8 { | ||
| 79 | $index | ||
| 80 | } | ||
| 81 | |||
| 82 | #[cfg(feature = "low-power")] | 66 | #[cfg(feature = "low-power")] |
| 83 | fn stop_mode(&self) -> crate::rcc::StopMode { | 67 | fn stop_mode(&self) -> crate::rcc::StopMode { |
| 84 | crate::rcc::StopMode::$stop_mode | 68 | crate::rcc::StopMode::$stop_mode |
| 85 | } | 69 | } |
| 86 | } | 70 | } |
| 71 | |||
| 72 | impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { | ||
| 73 | fn id(&self) -> u8 { | ||
| 74 | $index | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 87 | impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri { | 78 | impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri { |
| 88 | unsafe fn on_irq() { | 79 | unsafe fn on_irq() { |
| 89 | crate::dma::AnyChannel { | 80 | crate::dma::AnyChannel { |
| @@ -102,7 +93,7 @@ macro_rules! dma_channel_impl { | |||
| 102 | Self { | 93 | Self { |
| 103 | id: crate::dma::SealedChannel::id(&val), | 94 | id: crate::dma::SealedChannel::id(&val), |
| 104 | #[cfg(feature = "low-power")] | 95 | #[cfg(feature = "low-power")] |
| 105 | stop_mode: crate::dma::SealedChannel::stop_mode(&val), | 96 | stop_mode: crate::rcc::StoppablePeripheral::stop_mode(&val), |
| 106 | } | 97 | } |
| 107 | } | 98 | } |
| 108 | } | 99 | } |
| @@ -123,17 +114,18 @@ impl AnyChannel { | |||
| 123 | } | 114 | } |
| 124 | } | 115 | } |
| 125 | 116 | ||
| 126 | impl SealedChannel for AnyChannel { | 117 | impl StoppablePeripheral for AnyChannel { |
| 127 | #[cfg(not(stm32n6))] | ||
| 128 | fn id(&self) -> u8 { | ||
| 129 | self.id | ||
| 130 | } | ||
| 131 | |||
| 132 | #[cfg(feature = "low-power")] | 118 | #[cfg(feature = "low-power")] |
| 133 | fn stop_mode(&self) -> crate::rcc::StopMode { | 119 | fn stop_mode(&self) -> crate::rcc::StopMode { |
| 134 | self.stop_mode | 120 | self.stop_mode |
| 135 | } | 121 | } |
| 136 | } | 122 | } |
| 123 | |||
| 124 | impl SealedChannel for AnyChannel { | ||
| 125 | fn id(&self) -> u8 { | ||
| 126 | self.id | ||
| 127 | } | ||
| 128 | } | ||
| 137 | impl Channel for AnyChannel {} | 129 | impl Channel for AnyChannel {} |
| 138 | 130 | ||
| 139 | const CHANNEL_COUNT: usize = crate::_generated::DMA_CHANNELS.len(); | 131 | const CHANNEL_COUNT: usize = crate::_generated::DMA_CHANNELS.len(); |
diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs index 3245887c1..304268963 100644 --- a/embassy-stm32/src/dma/util.rs +++ b/embassy-stm32/src/dma/util.rs | |||
| @@ -20,6 +20,16 @@ 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 | #[allow(dead_code)] | ||
| 24 | pub unsafe fn read_unchecked<'a, W: Word>( | ||
| 25 | &'a self, | ||
| 26 | peri_addr: *mut W, | ||
| 27 | buf: &'a mut [W], | ||
| 28 | options: TransferOptions, | ||
| 29 | ) -> Transfer<'a> { | ||
| 30 | Transfer::new_read(self.channel.clone_unchecked(), self.request, peri_addr, buf, options) | ||
| 31 | } | ||
| 32 | |||
| 23 | pub unsafe fn read_raw<'a, MW: Word, PW: Word>( | 33 | pub unsafe fn read_raw<'a, MW: Word, PW: Word>( |
| 24 | &'a mut self, | 34 | &'a mut self, |
| 25 | peri_addr: *mut PW, | 35 | peri_addr: *mut PW, |
| @@ -29,6 +39,16 @@ impl<'d> ChannelAndRequest<'d> { | |||
| 29 | Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options) | 39 | Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options) |
| 30 | } | 40 | } |
| 31 | 41 | ||
| 42 | #[allow(dead_code)] | ||
| 43 | pub unsafe fn read_raw_unchecked<'a, MW: Word, PW: Word>( | ||
| 44 | &'a self, | ||
| 45 | peri_addr: *mut PW, | ||
| 46 | buf: *mut [MW], | ||
| 47 | options: TransferOptions, | ||
| 48 | ) -> Transfer<'a> { | ||
| 49 | Transfer::new_read_raw(self.channel.clone_unchecked(), self.request, peri_addr, buf, options) | ||
| 50 | } | ||
| 51 | |||
| 32 | pub unsafe fn write<'a, W: Word>( | 52 | pub unsafe fn write<'a, W: Word>( |
| 33 | &'a mut self, | 53 | &'a mut self, |
| 34 | buf: &'a [W], | 54 | buf: &'a [W], |
| @@ -38,6 +58,16 @@ impl<'d> ChannelAndRequest<'d> { | |||
| 38 | Transfer::new_write(self.channel.reborrow(), self.request, buf, peri_addr, options) | 58 | Transfer::new_write(self.channel.reborrow(), self.request, buf, peri_addr, options) |
| 39 | } | 59 | } |
| 40 | 60 | ||
| 61 | #[allow(dead_code)] | ||
| 62 | pub unsafe fn write_unchecked<'a, W: Word>( | ||
| 63 | &'a self, | ||
| 64 | buf: &'a [W], | ||
| 65 | peri_addr: *mut W, | ||
| 66 | options: TransferOptions, | ||
| 67 | ) -> Transfer<'a> { | ||
| 68 | Transfer::new_write(self.channel.clone_unchecked(), self.request, buf, peri_addr, options) | ||
| 69 | } | ||
| 70 | |||
| 41 | pub unsafe fn write_raw<'a, MW: Word, PW: Word>( | 71 | pub unsafe fn write_raw<'a, MW: Word, PW: Word>( |
| 42 | &'a mut self, | 72 | &'a mut self, |
| 43 | buf: *const [MW], | 73 | buf: *const [MW], |
| @@ -48,6 +78,16 @@ impl<'d> ChannelAndRequest<'d> { | |||
| 48 | } | 78 | } |
| 49 | 79 | ||
| 50 | #[allow(dead_code)] | 80 | #[allow(dead_code)] |
| 81 | pub unsafe fn write_raw_unchecked<'a, MW: Word, PW: Word>( | ||
| 82 | &'a self, | ||
| 83 | buf: *const [MW], | ||
| 84 | peri_addr: *mut PW, | ||
| 85 | options: TransferOptions, | ||
| 86 | ) -> Transfer<'a> { | ||
| 87 | Transfer::new_write_raw(self.channel.clone_unchecked(), self.request, buf, peri_addr, options) | ||
| 88 | } | ||
| 89 | |||
| 90 | #[allow(dead_code)] | ||
| 51 | pub unsafe fn write_repeated<'a, W: Word>( | 91 | pub unsafe fn write_repeated<'a, W: Word>( |
| 52 | &'a mut self, | 92 | &'a mut self, |
| 53 | repeated: &'a W, | 93 | repeated: &'a W, |
| @@ -64,4 +104,22 @@ impl<'d> ChannelAndRequest<'d> { | |||
| 64 | options, | 104 | options, |
| 65 | ) | 105 | ) |
| 66 | } | 106 | } |
| 107 | |||
| 108 | #[allow(dead_code)] | ||
| 109 | pub unsafe fn write_repeated_unchecked<'a, W: Word>( | ||
| 110 | &'a self, | ||
| 111 | repeated: &'a W, | ||
| 112 | count: usize, | ||
| 113 | peri_addr: *mut W, | ||
| 114 | options: TransferOptions, | ||
| 115 | ) -> Transfer<'a> { | ||
| 116 | Transfer::new_write_repeated( | ||
| 117 | self.channel.clone_unchecked(), | ||
| 118 | self.request, | ||
| 119 | repeated, | ||
| 120 | count, | ||
| 121 | peri_addr, | ||
| 122 | options, | ||
| 123 | ) | ||
| 124 | } | ||
| 67 | } | 125 | } |
diff --git a/embassy-stm32/src/dma/word.rs b/embassy-stm32/src/dma/word.rs index fb1bde860..5c3bb8f7f 100644 --- a/embassy-stm32/src/dma/word.rs +++ b/embassy-stm32/src/dma/word.rs | |||
| @@ -31,6 +31,10 @@ pub trait Word: SealedWord + Default + Copy + 'static { | |||
| 31 | fn size() -> WordSize; | 31 | fn size() -> WordSize; |
| 32 | /// Amount of bits of this word size. | 32 | /// Amount of bits of this word size. |
| 33 | fn bits() -> usize; | 33 | fn bits() -> usize; |
| 34 | /// Maximum value of this type. | ||
| 35 | fn max() -> usize { | ||
| 36 | (1 << Self::bits()) - 1 | ||
| 37 | } | ||
| 34 | } | 38 | } |
| 35 | 39 | ||
| 36 | macro_rules! impl_word { | 40 | macro_rules! impl_word { |
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 7b7896d46..458174b5d 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs | |||
| @@ -74,7 +74,7 @@ unsafe fn on_irq() { | |||
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | #[cfg(feature = "low-power")] | 76 | #[cfg(feature = "low-power")] |
| 77 | crate::low_power::Executor::on_wakeup_irq(); | 77 | crate::low_power::Executor::on_wakeup_irq_or_event(); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | struct BitIter(u32); | 80 | struct BitIter(u32); |
diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs index b6ae24ee8..b731796f0 100644 --- a/embassy-stm32/src/fmt.rs +++ b/embassy-stm32/src/fmt.rs | |||
| @@ -207,6 +207,16 @@ macro_rules! error { | |||
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | #[cfg(feature = "defmt")] | 209 | #[cfg(feature = "defmt")] |
| 210 | trait_set::trait_set! { | ||
| 211 | pub trait Debuggable = Debug + defmt::Format; | ||
| 212 | } | ||
| 213 | |||
| 214 | #[cfg(not(feature = "defmt"))] | ||
| 215 | trait_set::trait_set! { | ||
| 216 | pub trait Debuggable = Debug; | ||
| 217 | } | ||
| 218 | |||
| 219 | #[cfg(feature = "defmt")] | ||
| 210 | #[collapse_debuginfo(yes)] | 220 | #[collapse_debuginfo(yes)] |
| 211 | macro_rules! unwrap { | 221 | macro_rules! unwrap { |
| 212 | ($($x:tt)*) => { | 222 | ($($x:tt)*) => { |
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index e7d4e9ad3..5de8bad2c 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs | |||
| @@ -684,7 +684,11 @@ fn set_as_analog(pin_port: PinNumber) { | |||
| 684 | }); | 684 | }); |
| 685 | 685 | ||
| 686 | #[cfg(gpio_v2)] | 686 | #[cfg(gpio_v2)] |
| 687 | r.moder().modify(|w| w.set_moder(n, vals::Moder::ANALOG)); | 687 | { |
| 688 | #[cfg(any(stm32l47x, stm32l48x))] | ||
| 689 | r.ascr().modify(|w| w.set_asc(n, true)); | ||
| 690 | r.moder().modify(|w| w.set_moder(n, vals::Moder::ANALOG)); | ||
| 691 | } | ||
| 688 | } | 692 | } |
| 689 | 693 | ||
| 690 | #[inline(never)] | 694 | #[inline(never)] |
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index ee60c3f44..0bf430ffc 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -226,7 +226,7 @@ impl<'d, M: Mode> I2c<'d, M, Master> { | |||
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | fn enable_and_init(&mut self, config: Config) { | 228 | fn enable_and_init(&mut self, config: Config) { |
| 229 | self.info.rcc.enable_and_reset(); | 229 | self.info.rcc.enable_and_reset_without_stop(); |
| 230 | self.init(config); | 230 | self.init(config); |
| 231 | } | 231 | } |
| 232 | } | 232 | } |
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 128a58db7..81a6d74c1 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -529,6 +529,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 529 | 529 | ||
| 530 | /// Write. | 530 | /// Write. |
| 531 | pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> { | 531 | pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> { |
| 532 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 532 | self.write_frame(address, write_buffer, FrameOptions::FirstAndLastFrame) | 533 | self.write_frame(address, write_buffer, FrameOptions::FirstAndLastFrame) |
| 533 | .await?; | 534 | .await?; |
| 534 | 535 | ||
| @@ -537,6 +538,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 537 | 538 | ||
| 538 | /// Read. | 539 | /// Read. |
| 539 | pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> { | 540 | pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> { |
| 541 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 540 | self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame) | 542 | self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame) |
| 541 | .await?; | 543 | .await?; |
| 542 | 544 | ||
| @@ -701,6 +703,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 701 | 703 | ||
| 702 | /// Write, restart, read. | 704 | /// Write, restart, read. |
| 703 | pub async fn write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> { | 705 | pub async fn write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> { |
| 706 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 704 | // Check empty read buffer before starting transaction. Otherwise, we would not generate the | 707 | // Check empty read buffer before starting transaction. Otherwise, we would not generate the |
| 705 | // stop condition below. | 708 | // stop condition below. |
| 706 | if read_buffer.is_empty() { | 709 | if read_buffer.is_empty() { |
| @@ -719,6 +722,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 719 | /// | 722 | /// |
| 720 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | 723 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction |
| 721 | pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | 724 | pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { |
| 725 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 722 | for (op, frame) in operation_frames(operations)? { | 726 | for (op, frame) in operation_frames(operations)? { |
| 723 | match op { | 727 | match op { |
| 724 | Operation::Read(read_buffer) => self.read_frame(address, read_buffer, frame).await?, | 728 | Operation::Read(read_buffer) => self.read_frame(address, read_buffer, frame).await?, |
| @@ -1357,6 +1361,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1357 | /// (Read/Write) and the matched address. This method will suspend until | 1361 | /// (Read/Write) and the matched address. This method will suspend until |
| 1358 | /// an address match occurs. | 1362 | /// an address match occurs. |
| 1359 | pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { | 1363 | pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { |
| 1364 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1360 | trace!("I2C slave: starting async listen for address match"); | 1365 | trace!("I2C slave: starting async listen for address match"); |
| 1361 | let state = self.state; | 1366 | let state = self.state; |
| 1362 | let info = self.info; | 1367 | let info = self.info; |
| @@ -1421,6 +1426,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1421 | /// | 1426 | /// |
| 1422 | /// Returns the number of bytes stored in the buffer (not total received). | 1427 | /// Returns the number of bytes stored in the buffer (not total received). |
| 1423 | pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 1428 | pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 1429 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1424 | trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len()); | 1430 | trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len()); |
| 1425 | 1431 | ||
| 1426 | if buffer.is_empty() { | 1432 | if buffer.is_empty() { |
| @@ -1454,6 +1460,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1454 | /// | 1460 | /// |
| 1455 | /// Returns the total number of bytes transmitted (data + padding). | 1461 | /// Returns the total number of bytes transmitted (data + padding). |
| 1456 | pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> { | 1462 | pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> { |
| 1463 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1457 | trace!("I2C slave: starting respond_to_read, data_len={}", data.len()); | 1464 | trace!("I2C slave: starting respond_to_read, data_len={}", data.len()); |
| 1458 | 1465 | ||
| 1459 | if data.is_empty() { | 1466 | if data.is_empty() { |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 933cca9cb..fe7782a7c 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -73,7 +73,7 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() { | |||
| 73 | // restore the clocks to their last configured state as | 73 | // restore the clocks to their last configured state as |
| 74 | // much is lost in STOP modes | 74 | // much is lost in STOP modes |
| 75 | #[cfg(all(feature = "low-power", stm32wlex))] | 75 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 76 | crate::low_power::Executor::on_wakeup_irq(); | 76 | crate::low_power::Executor::on_wakeup_irq_or_event(); |
| 77 | 77 | ||
| 78 | let regs = T::info().regs; | 78 | let regs = T::info().regs; |
| 79 | let isr = regs.isr().read(); | 79 | let isr = regs.isr().read(); |
| @@ -1075,6 +1075,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 1075 | 1075 | ||
| 1076 | /// Write. | 1076 | /// Write. |
| 1077 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { | 1077 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |
| 1078 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1078 | let timeout = self.timeout(); | 1079 | let timeout = self.timeout(); |
| 1079 | if write.is_empty() { | 1080 | if write.is_empty() { |
| 1080 | self.write_internal(address.into(), write, true, timeout) | 1081 | self.write_internal(address.into(), write, true, timeout) |
| @@ -1089,6 +1090,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 1089 | /// | 1090 | /// |
| 1090 | /// The buffers are concatenated in a single write transaction. | 1091 | /// The buffers are concatenated in a single write transaction. |
| 1091 | pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { | 1092 | pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { |
| 1093 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1092 | let timeout = self.timeout(); | 1094 | let timeout = self.timeout(); |
| 1093 | 1095 | ||
| 1094 | if write.is_empty() { | 1096 | if write.is_empty() { |
| @@ -1120,6 +1122,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 1120 | 1122 | ||
| 1121 | /// Read. | 1123 | /// Read. |
| 1122 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 1124 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 1125 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1123 | let timeout = self.timeout(); | 1126 | let timeout = self.timeout(); |
| 1124 | 1127 | ||
| 1125 | if buffer.is_empty() { | 1128 | if buffer.is_empty() { |
| @@ -1132,6 +1135,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 1132 | 1135 | ||
| 1133 | /// Write, restart, read. | 1136 | /// Write, restart, read. |
| 1134 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | 1137 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
| 1138 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1135 | let timeout = self.timeout(); | 1139 | let timeout = self.timeout(); |
| 1136 | 1140 | ||
| 1137 | if write.is_empty() { | 1141 | if write.is_empty() { |
| @@ -1157,6 +1161,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 1157 | /// | 1161 | /// |
| 1158 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | 1162 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction |
| 1159 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | 1163 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { |
| 1164 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1160 | if operations.is_empty() { | 1165 | if operations.is_empty() { |
| 1161 | return Err(Error::ZeroLengthTransfer); | 1166 | return Err(Error::ZeroLengthTransfer); |
| 1162 | } | 1167 | } |
| @@ -1741,6 +1746,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1741 | /// | 1746 | /// |
| 1742 | /// The listen method is an asynchronous method but it does not require DMA to be asynchronous. | 1747 | /// The listen method is an asynchronous method but it does not require DMA to be asynchronous. |
| 1743 | pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { | 1748 | pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { |
| 1749 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1744 | let state = self.state; | 1750 | let state = self.state; |
| 1745 | self.info.regs.cr1().modify(|reg| { | 1751 | self.info.regs.cr1().modify(|reg| { |
| 1746 | reg.set_addrie(true); | 1752 | reg.set_addrie(true); |
| @@ -1766,12 +1772,14 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1766 | /// | 1772 | /// |
| 1767 | /// Returns the total number of bytes received. | 1773 | /// Returns the total number of bytes received. |
| 1768 | pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 1774 | pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 1775 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1769 | let timeout = self.timeout(); | 1776 | let timeout = self.timeout(); |
| 1770 | timeout.with(self.read_dma_internal_slave(buffer, timeout)).await | 1777 | timeout.with(self.read_dma_internal_slave(buffer, timeout)).await |
| 1771 | } | 1778 | } |
| 1772 | 1779 | ||
| 1773 | /// Respond to a read request from an I2C master. | 1780 | /// Respond to a read request from an I2C master. |
| 1774 | pub async fn respond_to_read(&mut self, write: &[u8]) -> Result<SendStatus, Error> { | 1781 | pub async fn respond_to_read(&mut self, write: &[u8]) -> Result<SendStatus, Error> { |
| 1782 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1775 | let timeout = self.timeout(); | 1783 | let timeout = self.timeout(); |
| 1776 | timeout.with(self.write_dma_internal_slave(write, timeout)).await | 1784 | timeout.with(self.write_dma_internal_slave(write, timeout)).await |
| 1777 | } | 1785 | } |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index cdf3323fb..2388abe3c 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -88,7 +88,7 @@ foreach_interrupt! { | |||
| 88 | #[interrupt] | 88 | #[interrupt] |
| 89 | #[allow(non_snake_case)] | 89 | #[allow(non_snake_case)] |
| 90 | unsafe fn $irq() { | 90 | unsafe fn $irq() { |
| 91 | Executor::on_wakeup_irq(); | 91 | Executor::on_wakeup_irq_or_event(); |
| 92 | } | 92 | } |
| 93 | }; | 93 | }; |
| 94 | } | 94 | } |
| @@ -99,7 +99,7 @@ foreach_interrupt! { | |||
| 99 | #[interrupt] | 99 | #[interrupt] |
| 100 | #[allow(non_snake_case)] | 100 | #[allow(non_snake_case)] |
| 101 | unsafe fn $irq() { | 101 | unsafe fn $irq() { |
| 102 | Executor::on_wakeup_irq(); | 102 | Executor::on_wakeup_irq_or_event(); |
| 103 | } | 103 | } |
| 104 | }; | 104 | }; |
| 105 | } | 105 | } |
| @@ -164,22 +164,30 @@ impl Executor { | |||
| 164 | } | 164 | } |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | pub(crate) unsafe fn on_wakeup_irq() { | 167 | pub(crate) unsafe fn on_wakeup_irq_or_event() { |
| 168 | if !get_driver().is_stopped() { | ||
| 169 | return; | ||
| 170 | } | ||
| 171 | |||
| 168 | critical_section::with(|cs| { | 172 | critical_section::with(|cs| { |
| 169 | #[cfg(stm32wlex)] | 173 | #[cfg(stm32wlex)] |
| 170 | { | 174 | { |
| 171 | use crate::pac::rcc::vals::Sw; | 175 | let es = crate::pac::PWR.extscr().read(); |
| 172 | use crate::pac::{PWR, RCC}; | 176 | match (es.c1stopf(), es.c1stop2f()) { |
| 173 | use crate::rcc::init as init_rcc; | 177 | (true, false) => debug!("low power: wake from STOP1"), |
| 174 | 178 | (false, true) => debug!("low power: wake from STOP2"), | |
| 175 | let extscr = PWR.extscr().read(); | 179 | (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"), |
| 176 | if extscr.c1stop2f() || extscr.c1stopf() { | 180 | (false, false) => trace!("low power: stop mode not entered"), |
| 181 | }; | ||
| 182 | crate::pac::PWR.extscr().modify(|w| { | ||
| 183 | w.set_c1cssf(false); | ||
| 184 | }); | ||
| 185 | |||
| 186 | if es.c1stop2f() || es.c1stopf() { | ||
| 177 | // when we wake from any stop mode we need to re-initialize the rcc | 187 | // when we wake from any stop mode we need to re-initialize the rcc |
| 178 | while RCC.cfgr().read().sws() != Sw::MSI {} | 188 | crate::rcc::init(RCC_CONFIG.unwrap()); |
| 179 | |||
| 180 | init_rcc(RCC_CONFIG.unwrap()); | ||
| 181 | 189 | ||
| 182 | if extscr.c1stop2f() { | 190 | if es.c1stop2f() { |
| 183 | // when we wake from STOP2, we need to re-initialize the time driver | 191 | // when we wake from STOP2, we need to re-initialize the time driver |
| 184 | get_driver().init_timer(cs); | 192 | get_driver().init_timer(cs); |
| 185 | // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) | 193 | // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) |
| @@ -190,7 +198,8 @@ impl Executor { | |||
| 190 | } | 198 | } |
| 191 | } | 199 | } |
| 192 | get_driver().resume_time(cs); | 200 | get_driver().resume_time(cs); |
| 193 | trace!("low power: resume"); | 201 | |
| 202 | trace!("low power: resume time"); | ||
| 194 | }); | 203 | }); |
| 195 | } | 204 | } |
| 196 | 205 | ||
| @@ -201,10 +210,8 @@ impl Executor { | |||
| 201 | fn stop_mode(_cs: CriticalSection) -> Option<StopMode> { | 210 | fn stop_mode(_cs: CriticalSection) -> Option<StopMode> { |
| 202 | // We cannot enter standby because we will lose program state. | 211 | // We cannot enter standby because we will lose program state. |
| 203 | if unsafe { REFCOUNT_STOP2 == 0 && REFCOUNT_STOP1 == 0 } { | 212 | if unsafe { REFCOUNT_STOP2 == 0 && REFCOUNT_STOP1 == 0 } { |
| 204 | trace!("low power: stop 2"); | ||
| 205 | Some(StopMode::Stop2) | 213 | Some(StopMode::Stop2) |
| 206 | } else if unsafe { REFCOUNT_STOP1 == 0 } { | 214 | } else if unsafe { REFCOUNT_STOP1 == 0 } { |
| 207 | trace!("low power: stop 1"); | ||
| 208 | Some(StopMode::Stop1) | 215 | Some(StopMode::Stop1) |
| 209 | } else { | 216 | } else { |
| 210 | trace!("low power: not ready to stop (refcount_stop1: {})", unsafe { | 217 | trace!("low power: not ready to stop (refcount_stop1: {})", unsafe { |
| @@ -305,9 +312,11 @@ impl Executor { | |||
| 305 | get_driver().pause_time(cs).ok()?; | 312 | get_driver().pause_time(cs).ok()?; |
| 306 | self.configure_stop(cs, stop_mode).ok()?; | 313 | self.configure_stop(cs, stop_mode).ok()?; |
| 307 | 314 | ||
| 308 | Some(()) | 315 | Some(stop_mode) |
| 309 | }) | 316 | }) |
| 310 | .map(|_| { | 317 | .map(|stop_mode| { |
| 318 | trace!("low power: enter stop: {}", stop_mode); | ||
| 319 | |||
| 311 | #[cfg(not(feature = "low-power-debug-with-sleep"))] | 320 | #[cfg(not(feature = "low-power-debug-with-sleep"))] |
| 312 | Self::get_scb().set_sleepdeep(); | 321 | Self::get_scb().set_sleepdeep(); |
| 313 | }); | 322 | }); |
| @@ -338,20 +347,10 @@ impl Executor { | |||
| 338 | unsafe { | 347 | unsafe { |
| 339 | self.inner.poll(); | 348 | self.inner.poll(); |
| 340 | self.configure_pwr(); | 349 | self.configure_pwr(); |
| 350 | #[cfg(feature = "defmt")] | ||
| 351 | defmt::flush(); | ||
| 341 | asm!("wfe"); | 352 | asm!("wfe"); |
| 342 | #[cfg(stm32wlex)] | 353 | Self::on_wakeup_irq_or_event(); |
| 343 | { | ||
| 344 | let es = crate::pac::PWR.extscr().read(); | ||
| 345 | match (es.c1stopf(), es.c1stop2f()) { | ||
| 346 | (true, false) => debug!("low power: wake from STOP1"), | ||
| 347 | (false, true) => debug!("low power: wake from STOP2"), | ||
| 348 | (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"), | ||
| 349 | (false, false) => trace!("low power: stop mode not entered"), | ||
| 350 | }; | ||
| 351 | crate::pac::PWR.extscr().modify(|w| { | ||
| 352 | w.set_c1cssf(false); | ||
| 353 | }); | ||
| 354 | } | ||
| 355 | }; | 354 | }; |
| 356 | } | 355 | } |
| 357 | } | 356 | } |
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index bb4f4f1d0..1f47f4845 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs | |||
| @@ -111,7 +111,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { | |||
| 111 | config: Config, | 111 | config: Config, |
| 112 | fsel: FlashSelection, | 112 | fsel: FlashSelection, |
| 113 | ) -> Self { | 113 | ) -> Self { |
| 114 | rcc::enable_and_reset::<T>(); | 114 | rcc::enable_and_reset_without_stop::<T>(); |
| 115 | 115 | ||
| 116 | while T::REGS.sr().read().busy() {} | 116 | while T::REGS.sr().read().busy() {} |
| 117 | 117 | ||
| @@ -403,6 +403,7 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { | |||
| 403 | 403 | ||
| 404 | /// Async read data, using DMA. | 404 | /// Async read data, using DMA. |
| 405 | pub async fn read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) { | 405 | pub async fn read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) { |
| 406 | let _scoped_block_stop = T::RCC_INFO.block_stop(); | ||
| 406 | let transfer = self.start_read_transfer(transaction, buf); | 407 | let transfer = self.start_read_transfer(transaction, buf); |
| 407 | transfer.await; | 408 | transfer.await; |
| 408 | } | 409 | } |
| @@ -443,6 +444,7 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { | |||
| 443 | 444 | ||
| 444 | /// Async write data, using DMA. | 445 | /// Async write data, using DMA. |
| 445 | pub async fn write_dma(&mut self, buf: &[u8], transaction: TransferConfig) { | 446 | pub async fn write_dma(&mut self, buf: &[u8], transaction: TransferConfig) { |
| 447 | let _scoped_block_stop = T::RCC_INFO.block_stop(); | ||
| 446 | let transfer = self.start_write_transfer(transaction, buf); | 448 | let transfer = self.start_write_transfer(transaction, buf); |
| 447 | transfer.await; | 449 | transfer.await; |
| 448 | } | 450 | } |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 1dd634cfe..2a9a1595a 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -12,6 +12,7 @@ pub use bd::*; | |||
| 12 | #[cfg(any(mco, mco1, mco2))] | 12 | #[cfg(any(mco, mco1, mco2))] |
| 13 | mod mco; | 13 | mod mco; |
| 14 | use critical_section::CriticalSection; | 14 | use critical_section::CriticalSection; |
| 15 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 15 | #[cfg(any(mco, mco1, mco2))] | 16 | #[cfg(any(mco, mco1, mco2))] |
| 16 | pub use mco::*; | 17 | pub use mco::*; |
| 17 | 18 | ||
| @@ -172,7 +173,7 @@ pub(crate) struct RccInfo { | |||
| 172 | /// E.g. if `StopMode::Stop1` is selected, the peripheral prevents the chip from entering Stop1 mode. | 173 | /// E.g. if `StopMode::Stop1` is selected, the peripheral prevents the chip from entering Stop1 mode. |
| 173 | #[cfg(feature = "low-power")] | 174 | #[cfg(feature = "low-power")] |
| 174 | #[allow(dead_code)] | 175 | #[allow(dead_code)] |
| 175 | #[derive(Debug, Clone, Copy, PartialEq, Default)] | 176 | #[derive(Debug, Clone, Copy, PartialEq, Default, defmt::Format)] |
| 176 | pub enum StopMode { | 177 | pub enum StopMode { |
| 177 | #[default] | 178 | #[default] |
| 178 | /// Peripheral prevents chip from entering Stop1 or executor will enter Stop1 | 179 | /// Peripheral prevents chip from entering Stop1 or executor will enter Stop1 |
| @@ -381,12 +382,19 @@ pub(crate) trait StoppablePeripheral { | |||
| 381 | } | 382 | } |
| 382 | 383 | ||
| 383 | #[cfg(feature = "low-power")] | 384 | #[cfg(feature = "low-power")] |
| 384 | impl<'a> StoppablePeripheral for StopMode { | 385 | impl StoppablePeripheral for StopMode { |
| 385 | fn stop_mode(&self) -> StopMode { | 386 | fn stop_mode(&self) -> StopMode { |
| 386 | *self | 387 | *self |
| 387 | } | 388 | } |
| 388 | } | 389 | } |
| 389 | 390 | ||
| 391 | impl<'a, T: StoppablePeripheral + PeripheralType> StoppablePeripheral for Peri<'a, T> { | ||
| 392 | #[cfg(feature = "low-power")] | ||
| 393 | fn stop_mode(&self) -> StopMode { | ||
| 394 | T::stop_mode(&self) | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 390 | pub(crate) struct BusyPeripheral<T: StoppablePeripheral> { | 398 | pub(crate) struct BusyPeripheral<T: StoppablePeripheral> { |
| 391 | peripheral: T, | 399 | peripheral: T, |
| 392 | } | 400 | } |
| @@ -490,6 +498,16 @@ pub fn enable_and_reset<T: RccPeripheral>() { | |||
| 490 | T::RCC_INFO.enable_and_reset(); | 498 | T::RCC_INFO.enable_and_reset(); |
| 491 | } | 499 | } |
| 492 | 500 | ||
| 501 | /// Enables and resets peripheral `T` without incrementing the stop refcount. | ||
| 502 | /// | ||
| 503 | /// # Safety | ||
| 504 | /// | ||
| 505 | /// Peripheral must not be in use. | ||
| 506 | // TODO: should this be `unsafe`? | ||
| 507 | pub fn enable_and_reset_without_stop<T: RccPeripheral>() { | ||
| 508 | T::RCC_INFO.enable_and_reset_without_stop(); | ||
| 509 | } | ||
| 510 | |||
| 493 | /// Disables peripheral `T`. | 511 | /// Disables peripheral `T`. |
| 494 | /// | 512 | /// |
| 495 | /// # Safety | 513 | /// # Safety |
diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs index 866851bbd..178ec57d4 100644 --- a/embassy-stm32/src/rcc/n6.rs +++ b/embassy-stm32/src/rcc/n6.rs | |||
| @@ -1003,6 +1003,24 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 1003 | p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22)); | 1003 | p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22)); |
| 1004 | } | 1004 | } |
| 1005 | 1005 | ||
| 1006 | // TODO: ugly workaround for DMA accesses until RIF is properly implemented | ||
| 1007 | debug!("deactivating RIF"); | ||
| 1008 | const RISAF3_BASE_NS: *mut u32 = stm32_metapac::RNG.wrapping_byte_offset(0x8000) as _; // AHB3PERIPH_BASE_NS + 0x8000UL | ||
| 1009 | const RISAF3_REG0_CFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x40); | ||
| 1010 | const RISAF3_REG0_ENDR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x48); | ||
| 1011 | const RISAF3_REG0_CIDCFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x4C); | ||
| 1012 | const RISAF3_REG1_CFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x80); | ||
| 1013 | const RISAF3_REG1_ENDR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x88); | ||
| 1014 | const RISAF3_REG1_CIDCFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x8C); | ||
| 1015 | unsafe { | ||
| 1016 | *RISAF3_REG0_CIDCFGR = 0x000F000F; /* RW for everyone */ | ||
| 1017 | *RISAF3_REG0_ENDR = 0xFFFFFFFF; /* all-encompassing */ | ||
| 1018 | *RISAF3_REG0_CFGR = 0x00000101; /* enabled, secure, unprivileged for everyone */ | ||
| 1019 | *RISAF3_REG1_CIDCFGR = 0x00FF00FF; /* RW for everyone */ | ||
| 1020 | *RISAF3_REG1_ENDR = 0xFFFFFFFF; /* all-encompassing */ | ||
| 1021 | *RISAF3_REG1_CFGR = 0x00000001; /* enabled, non-secure, unprivileged*/ | ||
| 1022 | } | ||
| 1023 | |||
| 1006 | debug!("setting power supply config"); | 1024 | debug!("setting power supply config"); |
| 1007 | 1025 | ||
| 1008 | power_supply_config(config.supply_config); | 1026 | power_supply_config(config.supply_config); |
| @@ -1039,7 +1057,9 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 1039 | i2s_ckin: None, | 1057 | i2s_ckin: None, |
| 1040 | ic8: None, | 1058 | ic8: None, |
| 1041 | ic9: None, | 1059 | ic9: None, |
| 1060 | ic10: None, | ||
| 1042 | ic14: None, | 1061 | ic14: None, |
| 1062 | ic15: None, | ||
| 1043 | ic17: None, | 1063 | ic17: None, |
| 1044 | ic20: None, | 1064 | ic20: None, |
| 1045 | ); | 1065 | ); |
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index ce4bc43c3..579c34c13 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs | |||
| @@ -394,7 +394,8 @@ pub struct Config { | |||
| 394 | pub frame_length: u16, | 394 | pub frame_length: u16, |
| 395 | pub clock_strobe: ClockStrobe, | 395 | pub clock_strobe: ClockStrobe, |
| 396 | pub output_drive: OutputDrive, | 396 | pub output_drive: OutputDrive, |
| 397 | pub master_clock_divider: Option<MasterClockDivider>, | 397 | pub master_clock_divider: MasterClockDivider, |
| 398 | pub nodiv: bool, | ||
| 398 | pub is_high_impedance_on_inactive_slot: bool, | 399 | pub is_high_impedance_on_inactive_slot: bool, |
| 399 | pub fifo_threshold: FifoThreshold, | 400 | pub fifo_threshold: FifoThreshold, |
| 400 | pub companding: Companding, | 401 | pub companding: Companding, |
| @@ -423,7 +424,8 @@ impl Default for Config { | |||
| 423 | frame_sync_active_level_length: word::U7(16), | 424 | frame_sync_active_level_length: word::U7(16), |
| 424 | frame_sync_definition: FrameSyncDefinition::ChannelIdentification, | 425 | frame_sync_definition: FrameSyncDefinition::ChannelIdentification, |
| 425 | frame_length: 32, | 426 | frame_length: 32, |
| 426 | master_clock_divider: None, | 427 | master_clock_divider: MasterClockDivider::DIV1, |
| 428 | nodiv: false, | ||
| 427 | clock_strobe: ClockStrobe::Rising, | 429 | clock_strobe: ClockStrobe::Rising, |
| 428 | output_drive: OutputDrive::Immediately, | 430 | output_drive: OutputDrive::Immediately, |
| 429 | is_high_impedance_on_inactive_slot: false, | 431 | is_high_impedance_on_inactive_slot: false, |
| @@ -677,8 +679,8 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { | |||
| 677 | w.set_syncen(config.sync_input.syncen()); | 679 | w.set_syncen(config.sync_input.syncen()); |
| 678 | w.set_mono(config.stereo_mono.mono()); | 680 | w.set_mono(config.stereo_mono.mono()); |
| 679 | w.set_outdriv(config.output_drive.outdriv()); | 681 | w.set_outdriv(config.output_drive.outdriv()); |
| 680 | w.set_mckdiv(config.master_clock_divider.unwrap_or(MasterClockDivider::DIV1)); | 682 | w.set_mckdiv(config.master_clock_divider); |
| 681 | w.set_nodiv(config.master_clock_divider.is_none()); | 683 | w.set_nodiv(config.nodiv); |
| 682 | w.set_dmaen(true); | 684 | w.set_dmaen(true); |
| 683 | }); | 685 | }); |
| 684 | 686 | ||
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index e05131040..12086cd3a 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -4,16 +4,15 @@ | |||
| 4 | use core::default::Default; | 4 | use core::default::Default; |
| 5 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | 6 | use core::marker::PhantomData; |
| 7 | use core::ops::{Deref, DerefMut}; | 7 | use core::slice; |
| 8 | use core::task::Poll; | 8 | use core::task::Poll; |
| 9 | 9 | ||
| 10 | use embassy_hal_internal::drop::OnDrop; | ||
| 11 | use embassy_hal_internal::{Peri, PeripheralType}; | 10 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 12 | use embassy_sync::waitqueue::AtomicWaker; | 11 | use embassy_sync::waitqueue::AtomicWaker; |
| 13 | use sdio_host::common_cmd::{self, Resp, ResponseLen}; | 12 | use sdio_host::Cmd; |
| 14 | use sdio_host::emmc::{EMMC, ExtCSD}; | 13 | use sdio_host::common_cmd::{self, R1, R2, R3, Resp, ResponseLen, Rz}; |
| 15 | use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; | 14 | use sdio_host::sd::{BusWidth, CardStatus}; |
| 16 | use sdio_host::{Cmd, emmc_cmd, sd_cmd}; | 15 | use sdio_host::sd_cmd::{R6, R7}; |
| 17 | 16 | ||
| 18 | #[cfg(sdmmc_v1)] | 17 | #[cfg(sdmmc_v1)] |
| 19 | use crate::dma::ChannelAndRequest; | 18 | use crate::dma::ChannelAndRequest; |
| @@ -22,37 +21,27 @@ use crate::gpio::Pull; | |||
| 22 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; | 21 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; |
| 23 | use crate::interrupt::typelevel::Interrupt; | 22 | use crate::interrupt::typelevel::Interrupt; |
| 24 | use crate::pac::sdmmc::Sdmmc as RegBlock; | 23 | use crate::pac::sdmmc::Sdmmc as RegBlock; |
| 25 | use crate::rcc::{self, RccPeripheral}; | 24 | use crate::rcc::{self, RccInfo, RccPeripheral, SealedRccPeripheral}; |
| 25 | use crate::sdmmc::sd::Addressable; | ||
| 26 | use crate::time::Hertz; | 26 | use crate::time::Hertz; |
| 27 | use crate::{interrupt, peripherals}; | 27 | use crate::{interrupt, peripherals}; |
| 28 | 28 | ||
| 29 | /// Module for SD and EMMC cards | ||
| 30 | pub mod sd; | ||
| 31 | |||
| 32 | /// Module for SDIO interface | ||
| 33 | pub mod sdio; | ||
| 34 | |||
| 29 | /// Interrupt handler. | 35 | /// Interrupt handler. |
| 30 | pub struct InterruptHandler<T: Instance> { | 36 | pub struct InterruptHandler<T: Instance> { |
| 31 | _phantom: PhantomData<T>, | 37 | _phantom: PhantomData<T>, |
| 32 | } | 38 | } |
| 33 | 39 | ||
| 34 | impl<T: Instance> InterruptHandler<T> { | ||
| 35 | fn enable_interrupts() { | ||
| 36 | let regs = T::regs(); | ||
| 37 | regs.maskr().write(|w| { | ||
| 38 | w.set_dcrcfailie(true); | ||
| 39 | w.set_dtimeoutie(true); | ||
| 40 | w.set_dataendie(true); | ||
| 41 | w.set_dbckendie(true); | ||
| 42 | |||
| 43 | #[cfg(sdmmc_v1)] | ||
| 44 | w.set_stbiterre(true); | ||
| 45 | #[cfg(sdmmc_v2)] | ||
| 46 | w.set_dabortie(true); | ||
| 47 | }); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | 40 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 52 | unsafe fn on_interrupt() { | 41 | unsafe fn on_interrupt() { |
| 53 | T::state().wake(); | 42 | T::state().waker.wake(); |
| 54 | let status = T::regs().star().read(); | 43 | let status = T::info().regs.star().read(); |
| 55 | T::regs().maskr().modify(|w| { | 44 | T::info().regs.maskr().modify(|w| { |
| 56 | if status.dcrcfail() { | 45 | if status.dcrcfail() { |
| 57 | w.set_dcrcfailie(false) | 46 | w.set_dcrcfailie(false) |
| 58 | } | 47 | } |
| @@ -77,6 +66,57 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 77 | } | 66 | } |
| 78 | } | 67 | } |
| 79 | 68 | ||
| 69 | struct U128(pub u128); | ||
| 70 | |||
| 71 | trait TypedResp: Resp { | ||
| 72 | type Word: From<U128>; | ||
| 73 | } | ||
| 74 | |||
| 75 | impl From<U128> for () { | ||
| 76 | fn from(value: U128) -> Self { | ||
| 77 | match value.0 { | ||
| 78 | 0 => (), | ||
| 79 | _ => unreachable!(), | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | impl From<U128> for u32 { | ||
| 85 | fn from(value: U128) -> Self { | ||
| 86 | unwrap!(value.0.try_into()) | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | impl From<U128> for u128 { | ||
| 91 | fn from(value: U128) -> Self { | ||
| 92 | value.0 | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | impl TypedResp for Rz { | ||
| 97 | type Word = (); | ||
| 98 | } | ||
| 99 | |||
| 100 | impl TypedResp for R1 { | ||
| 101 | type Word = u32; | ||
| 102 | } | ||
| 103 | |||
| 104 | impl TypedResp for R2 { | ||
| 105 | type Word = u128; | ||
| 106 | } | ||
| 107 | |||
| 108 | impl TypedResp for R3 { | ||
| 109 | type Word = u32; | ||
| 110 | } | ||
| 111 | |||
| 112 | impl TypedResp for R6 { | ||
| 113 | type Word = u32; | ||
| 114 | } | ||
| 115 | |||
| 116 | impl TypedResp for R7 { | ||
| 117 | type Word = u32; | ||
| 118 | } | ||
| 119 | |||
| 80 | /// Frequency used for SD Card initialization. Must be no higher than 400 kHz. | 120 | /// Frequency used for SD Card initialization. Must be no higher than 400 kHz. |
| 81 | const SD_INIT_FREQ: Hertz = Hertz(400_000); | 121 | const SD_INIT_FREQ: Hertz = Hertz(400_000); |
| 82 | 122 | ||
| @@ -99,54 +139,14 @@ impl Default for Signalling { | |||
| 99 | } | 139 | } |
| 100 | } | 140 | } |
| 101 | 141 | ||
| 102 | /// Aligned data block for SDMMC transfers. | 142 | const fn slice8_mut(x: &mut [u32]) -> &mut [u8] { |
| 103 | /// | 143 | let len = x.len() * 4; |
| 104 | /// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements. | 144 | unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } |
| 105 | #[repr(align(4))] | ||
| 106 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 107 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 108 | pub struct DataBlock(pub [u8; 512]); | ||
| 109 | |||
| 110 | impl Deref for DataBlock { | ||
| 111 | type Target = [u8; 512]; | ||
| 112 | |||
| 113 | fn deref(&self) -> &Self::Target { | ||
| 114 | &self.0 | ||
| 115 | } | ||
| 116 | } | 145 | } |
| 117 | 146 | ||
| 118 | impl DerefMut for DataBlock { | 147 | const fn slice8_ref(x: &[u32]) -> &[u8] { |
| 119 | fn deref_mut(&mut self) -> &mut Self::Target { | 148 | let len = x.len() * 4; |
| 120 | &mut self.0 | 149 | unsafe { slice::from_raw_parts(x.as_ptr() as _, len) } |
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | /// Command Block buffer for SDMMC command transfers. | ||
| 125 | /// | ||
| 126 | /// This is a 16-word array, exposed so that DMA commpatible memory can be used if required. | ||
| 127 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 128 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 129 | pub struct CmdBlock(pub [u32; 16]); | ||
| 130 | |||
| 131 | impl CmdBlock { | ||
| 132 | /// Creates a new instance of CmdBlock | ||
| 133 | pub const fn new() -> Self { | ||
| 134 | Self([0u32; 16]) | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | impl Deref for CmdBlock { | ||
| 139 | type Target = [u32; 16]; | ||
| 140 | |||
| 141 | fn deref(&self) -> &Self::Target { | ||
| 142 | &self.0 | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | impl DerefMut for CmdBlock { | ||
| 147 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 148 | &mut self.0 | ||
| 149 | } | ||
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | /// Errors | 152 | /// Errors |
| @@ -181,42 +181,6 @@ pub enum Error { | |||
| 181 | StBitErr, | 181 | StBitErr, |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | #[derive(Clone, Copy, Debug, Default)] | ||
| 185 | /// SD Card | ||
| 186 | pub struct Card { | ||
| 187 | /// The type of this card | ||
| 188 | pub card_type: CardCapacity, | ||
| 189 | /// Operation Conditions Register | ||
| 190 | pub ocr: OCR<SD>, | ||
| 191 | /// Relative Card Address | ||
| 192 | pub rca: u16, | ||
| 193 | /// Card ID | ||
| 194 | pub cid: CID<SD>, | ||
| 195 | /// Card Specific Data | ||
| 196 | pub csd: CSD<SD>, | ||
| 197 | /// SD CARD Configuration Register | ||
| 198 | pub scr: SCR, | ||
| 199 | /// SD Status | ||
| 200 | pub status: SDStatus, | ||
| 201 | } | ||
| 202 | |||
| 203 | #[derive(Clone, Copy, Debug, Default)] | ||
| 204 | /// eMMC storage | ||
| 205 | pub struct Emmc { | ||
| 206 | /// The capacity of this card | ||
| 207 | pub capacity: CardCapacity, | ||
| 208 | /// Operation Conditions Register | ||
| 209 | pub ocr: OCR<EMMC>, | ||
| 210 | /// Relative Card Address | ||
| 211 | pub rca: u16, | ||
| 212 | /// Card ID | ||
| 213 | pub cid: CID<EMMC>, | ||
| 214 | /// Card Specific Data | ||
| 215 | pub csd: CSD<EMMC>, | ||
| 216 | /// Extended Card Specific Data | ||
| 217 | pub ext_csd: ExtCSD, | ||
| 218 | } | ||
| 219 | |||
| 220 | #[repr(u8)] | 184 | #[repr(u8)] |
| 221 | enum PowerCtrl { | 185 | enum PowerCtrl { |
| 222 | Off = 0b00, | 186 | Off = 0b00, |
| @@ -259,6 +223,55 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u8, Hertz), Error> { | |||
| 259 | Ok((false, clk_div, clk_f)) | 223 | Ok((false, clk_div, clk_f)) |
| 260 | } | 224 | } |
| 261 | 225 | ||
| 226 | fn bus_width_vals(bus_width: BusWidth) -> (u8, u32) { | ||
| 227 | match bus_width { | ||
| 228 | BusWidth::One => (0, 1u32), | ||
| 229 | BusWidth::Four => (1, 4u32), | ||
| 230 | BusWidth::Eight => (2, 8u32), | ||
| 231 | _ => panic!("Invalid Bus Width"), | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | #[repr(u8)] | ||
| 236 | enum BlockSize { | ||
| 237 | Size1 = 0b0000, | ||
| 238 | Size2 = 0b0001, | ||
| 239 | Size4 = 0b0010, | ||
| 240 | Size8 = 0b0011, | ||
| 241 | Size16 = 0b0100, | ||
| 242 | Size32 = 0b0101, | ||
| 243 | Size64 = 0b0110, | ||
| 244 | Size128 = 0b0111, | ||
| 245 | Size256 = 0b1000, | ||
| 246 | Size512 = 0b1001, | ||
| 247 | Size1024 = 0b1010, | ||
| 248 | Size2048 = 0b1011, | ||
| 249 | Size4096 = 0b1100, | ||
| 250 | Size8192 = 0b1101, | ||
| 251 | Size16384 = 0b1110, | ||
| 252 | } | ||
| 253 | |||
| 254 | const fn block_size(bytes: usize) -> BlockSize { | ||
| 255 | match bytes { | ||
| 256 | 1 => BlockSize::Size1, | ||
| 257 | 2 => BlockSize::Size2, | ||
| 258 | 4 => BlockSize::Size4, | ||
| 259 | 8 => BlockSize::Size8, | ||
| 260 | 16 => BlockSize::Size16, | ||
| 261 | 32 => BlockSize::Size32, | ||
| 262 | 64 => BlockSize::Size64, | ||
| 263 | 128 => BlockSize::Size128, | ||
| 264 | 256 => BlockSize::Size256, | ||
| 265 | 512 => BlockSize::Size512, | ||
| 266 | 1024 => BlockSize::Size1024, | ||
| 267 | 2048 => BlockSize::Size2048, | ||
| 268 | 4096 => BlockSize::Size4096, | ||
| 269 | 8192 => BlockSize::Size8192, | ||
| 270 | 16384 => BlockSize::Size16384, | ||
| 271 | _ => core::unreachable!(), | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 262 | /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to | 275 | /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to |
| 263 | /// `sdmmc_ck` in Hertz. | 276 | /// `sdmmc_ck` in Hertz. |
| 264 | /// | 277 | /// |
| @@ -286,6 +299,34 @@ struct Transfer<'a> { | |||
| 286 | _dummy: PhantomData<&'a ()>, | 299 | _dummy: PhantomData<&'a ()>, |
| 287 | } | 300 | } |
| 288 | 301 | ||
| 302 | struct WrappedTransfer<'a> { | ||
| 303 | _transfer: Transfer<'a>, | ||
| 304 | sdmmc: &'a Sdmmc<'a>, | ||
| 305 | defused: bool, | ||
| 306 | } | ||
| 307 | |||
| 308 | impl<'a> WrappedTransfer<'a> { | ||
| 309 | pub const fn new(_transfer: Transfer<'a>, sdmmc: &'a Sdmmc) -> Self { | ||
| 310 | Self { | ||
| 311 | _transfer, | ||
| 312 | sdmmc, | ||
| 313 | defused: false, | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | pub fn defuse(&mut self) { | ||
| 318 | self.defused = true; | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | impl<'a> Drop for WrappedTransfer<'a> { | ||
| 323 | fn drop(&mut self) { | ||
| 324 | if !self.defused { | ||
| 325 | self.sdmmc.on_drop(); | ||
| 326 | } | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 289 | #[cfg(all(sdmmc_v1, dma))] | 330 | #[cfg(all(sdmmc_v1, dma))] |
| 290 | const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions { | 331 | const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions { |
| 291 | pburst: crate::dma::Burst::Incr4, | 332 | pburst: crate::dma::Burst::Incr4, |
| @@ -323,64 +364,11 @@ impl Default for Config { | |||
| 323 | } | 364 | } |
| 324 | } | 365 | } |
| 325 | 366 | ||
| 326 | /// Peripheral that can be operated over SDMMC | ||
| 327 | #[derive(Clone, Copy, Debug)] | ||
| 328 | pub enum SdmmcPeripheral { | ||
| 329 | /// SD Card | ||
| 330 | SdCard(Card), | ||
| 331 | /// eMMC memory | ||
| 332 | Emmc(Emmc), | ||
| 333 | } | ||
| 334 | |||
| 335 | impl SdmmcPeripheral { | ||
| 336 | /// Get this peripheral's address on the SDMMC bus | ||
| 337 | fn get_address(&self) -> u16 { | ||
| 338 | match self { | ||
| 339 | Self::SdCard(c) => c.rca, | ||
| 340 | Self::Emmc(e) => e.rca, | ||
| 341 | } | ||
| 342 | } | ||
| 343 | /// Is this a standard or high capacity peripheral? | ||
| 344 | fn get_capacity(&self) -> CardCapacity { | ||
| 345 | match self { | ||
| 346 | Self::SdCard(c) => c.card_type, | ||
| 347 | Self::Emmc(e) => e.capacity, | ||
| 348 | } | ||
| 349 | } | ||
| 350 | /// Size in bytes | ||
| 351 | fn size(&self) -> u64 { | ||
| 352 | match self { | ||
| 353 | // SDHC / SDXC / SDUC | ||
| 354 | Self::SdCard(c) => u64::from(c.csd.block_count()) * 512, | ||
| 355 | // capacity > 2GB | ||
| 356 | Self::Emmc(e) => u64::from(e.ext_csd.sector_count()) * 512, | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | /// Get a mutable reference to the SD Card. | ||
| 361 | /// | ||
| 362 | /// Panics if there is another peripheral instead. | ||
| 363 | fn get_sd_card(&mut self) -> &mut Card { | ||
| 364 | match *self { | ||
| 365 | Self::SdCard(ref mut c) => c, | ||
| 366 | _ => unreachable!("SD only"), | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | /// Get a mutable reference to the eMMC. | ||
| 371 | /// | ||
| 372 | /// Panics if there is another peripheral instead. | ||
| 373 | fn get_emmc(&mut self) -> &mut Emmc { | ||
| 374 | match *self { | ||
| 375 | Self::Emmc(ref mut e) => e, | ||
| 376 | _ => unreachable!("eMMC only"), | ||
| 377 | } | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | /// Sdmmc device | 367 | /// Sdmmc device |
| 382 | pub struct Sdmmc<'d, T: Instance> { | 368 | pub struct Sdmmc<'d> { |
| 383 | _peri: Peri<'d, T>, | 369 | info: &'static Info, |
| 370 | state: &'static State, | ||
| 371 | ker_clk: Hertz, | ||
| 384 | #[cfg(sdmmc_v1)] | 372 | #[cfg(sdmmc_v1)] |
| 385 | dma: ChannelAndRequest<'d>, | 373 | dma: ChannelAndRequest<'d>, |
| 386 | 374 | ||
| @@ -400,12 +388,6 @@ pub struct Sdmmc<'d, T: Instance> { | |||
| 400 | clock: Hertz, | 388 | clock: Hertz, |
| 401 | /// Current signalling scheme to card | 389 | /// Current signalling scheme to card |
| 402 | signalling: Signalling, | 390 | signalling: Signalling, |
| 403 | /// Card | ||
| 404 | card: Option<SdmmcPeripheral>, | ||
| 405 | |||
| 406 | /// An optional buffer to be used for commands | ||
| 407 | /// This should be used if there are special memory location requirements for dma | ||
| 408 | cmd_block: Option<&'d mut CmdBlock>, | ||
| 409 | } | 391 | } |
| 410 | 392 | ||
| 411 | const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); | 393 | const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); |
| @@ -416,9 +398,9 @@ const CMD_AF: AfType = AfType::output_pull(OutputType::PushPull, Speed::VeryHigh | |||
| 416 | const DATA_AF: AfType = CMD_AF; | 398 | const DATA_AF: AfType = CMD_AF; |
| 417 | 399 | ||
| 418 | #[cfg(sdmmc_v1)] | 400 | #[cfg(sdmmc_v1)] |
| 419 | impl<'d, T: Instance> Sdmmc<'d, T> { | 401 | impl<'d> Sdmmc<'d> { |
| 420 | /// Create a new SDMMC driver, with 1 data lane. | 402 | /// Create a new SDMMC driver, with 1 data lane. |
| 421 | pub fn new_1bit( | 403 | pub fn new_1bit<T: Instance>( |
| 422 | sdmmc: Peri<'d, T>, | 404 | sdmmc: Peri<'d, T>, |
| 423 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 405 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 424 | dma: Peri<'d, impl SdmmcDma<T>>, | 406 | dma: Peri<'d, impl SdmmcDma<T>>, |
| @@ -451,7 +433,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 451 | } | 433 | } |
| 452 | 434 | ||
| 453 | /// Create a new SDMMC driver, with 4 data lanes. | 435 | /// Create a new SDMMC driver, with 4 data lanes. |
| 454 | pub fn new_4bit( | 436 | pub fn new_4bit<T: Instance>( |
| 455 | sdmmc: Peri<'d, T>, | 437 | sdmmc: Peri<'d, T>, |
| 456 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 438 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 457 | dma: Peri<'d, impl SdmmcDma<T>>, | 439 | dma: Peri<'d, impl SdmmcDma<T>>, |
| @@ -491,9 +473,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 491 | } | 473 | } |
| 492 | 474 | ||
| 493 | #[cfg(sdmmc_v1)] | 475 | #[cfg(sdmmc_v1)] |
| 494 | impl<'d, T: Instance> Sdmmc<'d, T> { | 476 | impl<'d> Sdmmc<'d> { |
| 495 | /// Create a new SDMMC driver, with 8 data lanes. | 477 | /// Create a new SDMMC driver, with 8 data lanes. |
| 496 | pub fn new_8bit( | 478 | pub fn new_8bit<T: Instance>( |
| 497 | sdmmc: Peri<'d, T>, | 479 | sdmmc: Peri<'d, T>, |
| 498 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 480 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 499 | dma: Peri<'d, impl SdmmcDma<T>>, | 481 | dma: Peri<'d, impl SdmmcDma<T>>, |
| @@ -541,9 +523,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 541 | } | 523 | } |
| 542 | 524 | ||
| 543 | #[cfg(sdmmc_v2)] | 525 | #[cfg(sdmmc_v2)] |
| 544 | impl<'d, T: Instance> Sdmmc<'d, T> { | 526 | impl<'d> Sdmmc<'d> { |
| 545 | /// Create a new SDMMC driver, with 1 data lane. | 527 | /// Create a new SDMMC driver, with 1 data lane. |
| 546 | pub fn new_1bit( | 528 | pub fn new_1bit<T: Instance>( |
| 547 | sdmmc: Peri<'d, T>, | 529 | sdmmc: Peri<'d, T>, |
| 548 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 530 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 549 | clk: Peri<'d, impl CkPin<T>>, | 531 | clk: Peri<'d, impl CkPin<T>>, |
| @@ -574,7 +556,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 574 | } | 556 | } |
| 575 | 557 | ||
| 576 | /// Create a new SDMMC driver, with 4 data lanes. | 558 | /// Create a new SDMMC driver, with 4 data lanes. |
| 577 | pub fn new_4bit( | 559 | pub fn new_4bit<T: Instance>( |
| 578 | sdmmc: Peri<'d, T>, | 560 | sdmmc: Peri<'d, T>, |
| 579 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 561 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 580 | clk: Peri<'d, impl CkPin<T>>, | 562 | clk: Peri<'d, impl CkPin<T>>, |
| @@ -612,9 +594,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 612 | } | 594 | } |
| 613 | 595 | ||
| 614 | #[cfg(sdmmc_v2)] | 596 | #[cfg(sdmmc_v2)] |
| 615 | impl<'d, T: Instance> Sdmmc<'d, T> { | 597 | impl<'d> Sdmmc<'d> { |
| 616 | /// Create a new SDMMC driver, with 8 data lanes. | 598 | /// Create a new SDMMC driver, with 8 data lanes. |
| 617 | pub fn new_8bit( | 599 | pub fn new_8bit<T: Instance>( |
| 618 | sdmmc: Peri<'d, T>, | 600 | sdmmc: Peri<'d, T>, |
| 619 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 601 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 620 | clk: Peri<'d, impl CkPin<T>>, | 602 | clk: Peri<'d, impl CkPin<T>>, |
| @@ -659,9 +641,24 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 659 | } | 641 | } |
| 660 | } | 642 | } |
| 661 | 643 | ||
| 662 | impl<'d, T: Instance> Sdmmc<'d, T> { | 644 | impl<'d> Sdmmc<'d> { |
| 663 | fn new_inner( | 645 | fn enable_interrupts(&self) { |
| 664 | sdmmc: Peri<'d, T>, | 646 | let regs = self.info.regs; |
| 647 | regs.maskr().write(|w| { | ||
| 648 | w.set_dcrcfailie(true); | ||
| 649 | w.set_dtimeoutie(true); | ||
| 650 | w.set_dataendie(true); | ||
| 651 | w.set_dbckendie(true); | ||
| 652 | |||
| 653 | #[cfg(sdmmc_v1)] | ||
| 654 | w.set_stbiterre(true); | ||
| 655 | #[cfg(sdmmc_v2)] | ||
| 656 | w.set_dabortie(true); | ||
| 657 | }); | ||
| 658 | } | ||
| 659 | |||
| 660 | fn new_inner<T: Instance>( | ||
| 661 | _sdmmc: Peri<'d, T>, | ||
| 665 | #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, | 662 | #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, |
| 666 | clk: Peri<'d, AnyPin>, | 663 | clk: Peri<'d, AnyPin>, |
| 667 | cmd: Peri<'d, AnyPin>, | 664 | cmd: Peri<'d, AnyPin>, |
| @@ -675,13 +672,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 675 | d7: Option<Peri<'d, AnyPin>>, | 672 | d7: Option<Peri<'d, AnyPin>>, |
| 676 | config: Config, | 673 | config: Config, |
| 677 | ) -> Self { | 674 | ) -> Self { |
| 678 | rcc::enable_and_reset::<T>(); | 675 | rcc::enable_and_reset_without_stop::<T>(); |
| 679 | 676 | ||
| 680 | T::Interrupt::unpend(); | 677 | T::Interrupt::unpend(); |
| 681 | unsafe { T::Interrupt::enable() }; | 678 | unsafe { T::Interrupt::enable() }; |
| 682 | 679 | ||
| 683 | let regs = T::regs(); | 680 | let info = T::info(); |
| 684 | regs.clkcr().write(|w| { | 681 | let state = T::state(); |
| 682 | let ker_clk = T::frequency(); | ||
| 683 | |||
| 684 | info.regs.clkcr().write(|w| { | ||
| 685 | w.set_pwrsav(false); | 685 | w.set_pwrsav(false); |
| 686 | w.set_negedge(false); | 686 | w.set_negedge(false); |
| 687 | 687 | ||
| @@ -698,10 +698,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 698 | 698 | ||
| 699 | // Power off, writen 00: Clock to the card is stopped; | 699 | // Power off, writen 00: Clock to the card is stopped; |
| 700 | // D[7:0], CMD, and CK are driven high. | 700 | // D[7:0], CMD, and CK are driven high. |
| 701 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); | 701 | info.regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); |
| 702 | 702 | ||
| 703 | Self { | 703 | Self { |
| 704 | _peri: sdmmc, | 704 | info, |
| 705 | state, | ||
| 706 | ker_clk, | ||
| 705 | #[cfg(sdmmc_v1)] | 707 | #[cfg(sdmmc_v1)] |
| 706 | dma, | 708 | dma, |
| 707 | 709 | ||
| @@ -719,15 +721,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 719 | config, | 721 | config, |
| 720 | clock: SD_INIT_FREQ, | 722 | clock: SD_INIT_FREQ, |
| 721 | signalling: Default::default(), | 723 | signalling: Default::default(), |
| 722 | card: None, | ||
| 723 | cmd_block: None, | ||
| 724 | } | 724 | } |
| 725 | } | 725 | } |
| 726 | 726 | ||
| 727 | /// Data transfer is in progress | 727 | /// Data transfer is in progress |
| 728 | #[inline] | 728 | #[inline] |
| 729 | fn data_active() -> bool { | 729 | fn data_active(&self) -> bool { |
| 730 | let regs = T::regs(); | 730 | let regs = self.info.regs; |
| 731 | 731 | ||
| 732 | let status = regs.star().read(); | 732 | let status = regs.star().read(); |
| 733 | #[cfg(sdmmc_v1)] | 733 | #[cfg(sdmmc_v1)] |
| @@ -738,8 +738,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 738 | 738 | ||
| 739 | /// Coammand transfer is in progress | 739 | /// Coammand transfer is in progress |
| 740 | #[inline] | 740 | #[inline] |
| 741 | fn cmd_active() -> bool { | 741 | fn cmd_active(&self) -> bool { |
| 742 | let regs = T::regs(); | 742 | let regs = self.info.regs; |
| 743 | 743 | ||
| 744 | let status = regs.star().read(); | 744 | let status = regs.star().read(); |
| 745 | #[cfg(sdmmc_v1)] | 745 | #[cfg(sdmmc_v1)] |
| @@ -750,8 +750,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 750 | 750 | ||
| 751 | /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) | 751 | /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) |
| 752 | #[inline] | 752 | #[inline] |
| 753 | fn wait_idle() { | 753 | fn wait_idle(&self) { |
| 754 | while Self::data_active() || Self::cmd_active() {} | 754 | while self.data_active() || self.cmd_active() {} |
| 755 | } | ||
| 756 | |||
| 757 | fn bus_width(&self) -> BusWidth { | ||
| 758 | match (self.d3.is_some(), self.d7.is_some()) { | ||
| 759 | (true, true) => BusWidth::Eight, | ||
| 760 | (true, false) => BusWidth::Four, | ||
| 761 | _ => BusWidth::One, | ||
| 762 | } | ||
| 755 | } | 763 | } |
| 756 | 764 | ||
| 757 | /// # Safety | 765 | /// # Safety |
| @@ -759,23 +767,25 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 759 | /// `buffer` must be valid for the whole transfer and word aligned | 767 | /// `buffer` must be valid for the whole transfer and word aligned |
| 760 | #[allow(unused_variables)] | 768 | #[allow(unused_variables)] |
| 761 | fn prepare_datapath_read<'a>( | 769 | fn prepare_datapath_read<'a>( |
| 762 | config: &Config, | 770 | &'a self, |
| 763 | #[cfg(sdmmc_v1)] dma: &'a mut ChannelAndRequest<'d>, | ||
| 764 | buffer: &'a mut [u32], | 771 | buffer: &'a mut [u32], |
| 765 | length_bytes: u32, | 772 | block_size: BlockSize, |
| 766 | block_size: u8, | 773 | byte_mode: bool, |
| 767 | ) -> Transfer<'a> { | 774 | ) -> WrappedTransfer<'a> { |
| 768 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 775 | let regs = self.info.regs; |
| 769 | let regs = T::regs(); | ||
| 770 | 776 | ||
| 771 | // Command AND Data state machines must be idle | 777 | // Command AND Data state machines must be idle |
| 772 | Self::wait_idle(); | 778 | self.wait_idle(); |
| 773 | Self::clear_interrupt_flags(); | 779 | self.clear_interrupt_flags(); |
| 774 | 780 | ||
| 775 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | 781 | regs.dlenr().write(|w| w.set_datalength(size_of_val(buffer) as u32)); |
| 776 | 782 | ||
| 783 | // SAFETY: No other functions use the dma | ||
| 777 | #[cfg(sdmmc_v1)] | 784 | #[cfg(sdmmc_v1)] |
| 778 | let transfer = unsafe { dma.read(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS) }; | 785 | let transfer = unsafe { |
| 786 | self.dma | ||
| 787 | .read_unchecked(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS) | ||
| 788 | }; | ||
| 779 | #[cfg(sdmmc_v2)] | 789 | #[cfg(sdmmc_v2)] |
| 780 | let transfer = { | 790 | let transfer = { |
| 781 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); | 791 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); |
| @@ -785,8 +795,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 785 | } | 795 | } |
| 786 | }; | 796 | }; |
| 787 | 797 | ||
| 798 | #[cfg(sdmmc_v2)] | ||
| 799 | let byte_mode = byte_mode as u8; | ||
| 800 | |||
| 788 | regs.dctrl().modify(|w| { | 801 | regs.dctrl().modify(|w| { |
| 789 | w.set_dblocksize(block_size); | 802 | w.set_dtmode(byte_mode); |
| 803 | w.set_dblocksize(block_size as u8); | ||
| 790 | w.set_dtdir(true); | 804 | w.set_dtdir(true); |
| 791 | #[cfg(sdmmc_v1)] | 805 | #[cfg(sdmmc_v1)] |
| 792 | { | 806 | { |
| @@ -795,26 +809,33 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 795 | } | 809 | } |
| 796 | }); | 810 | }); |
| 797 | 811 | ||
| 798 | transfer | 812 | self.enable_interrupts(); |
| 813 | |||
| 814 | WrappedTransfer::new(transfer, &self) | ||
| 799 | } | 815 | } |
| 800 | 816 | ||
| 801 | /// # Safety | 817 | /// # Safety |
| 802 | /// | 818 | /// |
| 803 | /// `buffer` must be valid for the whole transfer and word aligned | 819 | /// `buffer` must be valid for the whole transfer and word aligned |
| 804 | fn prepare_datapath_write<'a>(&'a mut self, buffer: &'a [u32], length_bytes: u32, block_size: u8) -> Transfer<'a> { | 820 | fn prepare_datapath_write<'a>( |
| 805 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 821 | &'a self, |
| 806 | let regs = T::regs(); | 822 | buffer: &'a [u32], |
| 823 | block_size: BlockSize, | ||
| 824 | byte_mode: bool, | ||
| 825 | ) -> WrappedTransfer<'a> { | ||
| 826 | let regs = self.info.regs; | ||
| 807 | 827 | ||
| 808 | // Command AND Data state machines must be idle | 828 | // Command AND Data state machines must be idle |
| 809 | Self::wait_idle(); | 829 | self.wait_idle(); |
| 810 | Self::clear_interrupt_flags(); | 830 | self.clear_interrupt_flags(); |
| 811 | 831 | ||
| 812 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | 832 | regs.dlenr().write(|w| w.set_datalength(size_of_val(buffer) as u32)); |
| 813 | 833 | ||
| 834 | // SAFETY: No other functions use the dma | ||
| 814 | #[cfg(sdmmc_v1)] | 835 | #[cfg(sdmmc_v1)] |
| 815 | let transfer = unsafe { | 836 | let transfer = unsafe { |
| 816 | self.dma | 837 | self.dma |
| 817 | .write(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS) | 838 | .write_unchecked(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS) |
| 818 | }; | 839 | }; |
| 819 | #[cfg(sdmmc_v2)] | 840 | #[cfg(sdmmc_v2)] |
| 820 | let transfer = { | 841 | let transfer = { |
| @@ -825,8 +846,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 825 | } | 846 | } |
| 826 | }; | 847 | }; |
| 827 | 848 | ||
| 849 | #[cfg(sdmmc_v2)] | ||
| 850 | let byte_mode = byte_mode as u8; | ||
| 851 | |||
| 828 | regs.dctrl().modify(|w| { | 852 | regs.dctrl().modify(|w| { |
| 829 | w.set_dblocksize(block_size); | 853 | w.set_dtmode(byte_mode); |
| 854 | w.set_dblocksize(block_size as u8); | ||
| 830 | w.set_dtdir(false); | 855 | w.set_dtdir(false); |
| 831 | #[cfg(sdmmc_v1)] | 856 | #[cfg(sdmmc_v1)] |
| 832 | { | 857 | { |
| @@ -835,12 +860,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 835 | } | 860 | } |
| 836 | }); | 861 | }); |
| 837 | 862 | ||
| 838 | transfer | 863 | self.enable_interrupts(); |
| 864 | |||
| 865 | WrappedTransfer::new(transfer, &self) | ||
| 839 | } | 866 | } |
| 840 | 867 | ||
| 841 | /// Stops the DMA datapath | 868 | /// Stops the DMA datapath |
| 842 | fn stop_datapath() { | 869 | fn stop_datapath(&self) { |
| 843 | let regs = T::regs(); | 870 | let regs = self.info.regs; |
| 844 | 871 | ||
| 845 | #[cfg(sdmmc_v1)] | 872 | #[cfg(sdmmc_v1)] |
| 846 | regs.dctrl().modify(|w| { | 873 | regs.dctrl().modify(|w| { |
| @@ -851,49 +878,58 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 851 | regs.idmactrlr().modify(|w| w.set_idmaen(false)); | 878 | regs.idmactrlr().modify(|w| w.set_idmaen(false)); |
| 852 | } | 879 | } |
| 853 | 880 | ||
| 881 | fn init_idle(&mut self) -> Result<(), Error> { | ||
| 882 | let regs = self.info.regs; | ||
| 883 | |||
| 884 | self.clkcr_set_clkdiv(SD_INIT_FREQ, BusWidth::One)?; | ||
| 885 | regs.dtimer() | ||
| 886 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 887 | |||
| 888 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | ||
| 889 | self.cmd(common_cmd::idle(), false) | ||
| 890 | } | ||
| 891 | |||
| 854 | /// Sets the CLKDIV field in CLKCR. Updates clock field in self | 892 | /// Sets the CLKDIV field in CLKCR. Updates clock field in self |
| 855 | fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> { | 893 | fn clkcr_set_clkdiv(&mut self, freq: Hertz, width: BusWidth) -> Result<(), Error> { |
| 856 | let regs = T::regs(); | 894 | let regs = self.info.regs; |
| 857 | |||
| 858 | let width_u32 = match width { | ||
| 859 | BusWidth::One => 1u32, | ||
| 860 | BusWidth::Four => 4u32, | ||
| 861 | BusWidth::Eight => 8u32, | ||
| 862 | _ => panic!("Invalid Bus Width"), | ||
| 863 | }; | ||
| 864 | 895 | ||
| 865 | let ker_ck = T::frequency(); | 896 | let (widbus, width_u32) = bus_width_vals(width); |
| 866 | let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; | 897 | let (_bypass, clkdiv, new_clock) = clk_div(self.ker_clk, freq.0)?; |
| 867 | 898 | ||
| 868 | // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 | 899 | // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 |
| 869 | // Section 55.5.8 | 900 | // Section 55.5.8 |
| 870 | let sdmmc_bus_bandwidth = new_clock.0 * width_u32; | 901 | let sdmmc_bus_bandwidth = new_clock.0 * width_u32; |
| 871 | assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); | 902 | assert!(self.ker_clk.0 > 3 * sdmmc_bus_bandwidth / 32); |
| 872 | self.clock = new_clock; | 903 | self.clock = new_clock; |
| 873 | 904 | ||
| 874 | // CPSMACT and DPSMACT must be 0 to set CLKDIV | 905 | // CPSMACT and DPSMACT must be 0 to set CLKDIV or WIDBUS |
| 875 | Self::wait_idle(); | 906 | self.wait_idle(); |
| 876 | regs.clkcr().modify(|w| { | 907 | regs.clkcr().modify(|w| { |
| 877 | w.set_clkdiv(clkdiv); | 908 | w.set_clkdiv(clkdiv); |
| 878 | #[cfg(sdmmc_v1)] | 909 | #[cfg(sdmmc_v1)] |
| 879 | w.set_bypass(_bypass); | 910 | w.set_bypass(_bypass); |
| 911 | w.set_widbus(widbus); | ||
| 880 | }); | 912 | }); |
| 881 | 913 | ||
| 882 | Ok(()) | 914 | Ok(()) |
| 883 | } | 915 | } |
| 884 | 916 | ||
| 917 | fn get_cid(&self) -> Result<u128, Error> { | ||
| 918 | self.cmd(common_cmd::all_send_cid(), false) // CMD2 | ||
| 919 | } | ||
| 920 | |||
| 921 | fn get_csd(&self, address: u16) -> Result<u128, Error> { | ||
| 922 | self.cmd(common_cmd::send_csd(address), false) | ||
| 923 | } | ||
| 924 | |||
| 885 | /// Query the card status (CMD13, returns R1) | 925 | /// Query the card status (CMD13, returns R1) |
| 886 | fn read_status<Ext>(&self, card: &SdmmcPeripheral) -> Result<CardStatus<Ext>, Error> | 926 | fn read_status<A: Addressable>(&self, card: &A) -> Result<CardStatus<A::Ext>, Error> |
| 887 | where | 927 | where |
| 888 | CardStatus<Ext>: From<u32>, | 928 | CardStatus<A::Ext>: From<u32>, |
| 889 | { | 929 | { |
| 890 | let regs = T::regs(); | ||
| 891 | let rca = card.get_address(); | 930 | let rca = card.get_address(); |
| 892 | 931 | ||
| 893 | Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 | 932 | Ok(self.cmd(common_cmd::card_status(rca, false), false)?.into()) // CMD13 |
| 894 | |||
| 895 | let r1 = regs.respr(0).read().cardstatus(); | ||
| 896 | Ok(r1.into()) | ||
| 897 | } | 933 | } |
| 898 | 934 | ||
| 899 | /// Select one card and place it into the _Tranfer State_ | 935 | /// Select one card and place it into the _Tranfer State_ |
| @@ -904,17 +940,23 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 904 | // Determine Relative Card Address (RCA) of given card | 940 | // Determine Relative Card Address (RCA) of given card |
| 905 | let rca = rca.unwrap_or(0); | 941 | let rca = rca.unwrap_or(0); |
| 906 | 942 | ||
| 907 | let r = Self::cmd(common_cmd::select_card(rca), false); | 943 | let resp = self.cmd(common_cmd::select_card(rca), false); |
| 908 | match (r, rca) { | 944 | |
| 909 | (Err(Error::Timeout), 0) => Ok(()), | 945 | if let Err(Error::Timeout) = resp |
| 910 | _ => r, | 946 | && rca == 0 |
| 947 | { | ||
| 948 | return Ok(()); | ||
| 911 | } | 949 | } |
| 950 | |||
| 951 | resp?; | ||
| 952 | |||
| 953 | Ok(()) | ||
| 912 | } | 954 | } |
| 913 | 955 | ||
| 914 | /// Clear flags in interrupt clear register | 956 | /// Clear flags in interrupt clear register |
| 915 | #[inline] | 957 | #[inline] |
| 916 | fn clear_interrupt_flags() { | 958 | fn clear_interrupt_flags(&self) { |
| 917 | let regs = T::regs(); | 959 | let regs = self.info.regs; |
| 918 | regs.icr().write(|w| { | 960 | regs.icr().write(|w| { |
| 919 | w.set_ccrcfailc(true); | 961 | w.set_ccrcfailc(true); |
| 920 | w.set_dcrcfailc(true); | 962 | w.set_dcrcfailc(true); |
| @@ -947,12 +989,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 947 | 989 | ||
| 948 | /// Send command to card | 990 | /// Send command to card |
| 949 | #[allow(unused_variables)] | 991 | #[allow(unused_variables)] |
| 950 | fn cmd<R: Resp>(cmd: Cmd<R>, data: bool) -> Result<(), Error> { | 992 | fn cmd<R: TypedResp>(&self, cmd: Cmd<R>, data: bool) -> Result<R::Word, Error> { |
| 951 | let regs = T::regs(); | 993 | let regs = self.info.regs; |
| 952 | 994 | ||
| 953 | Self::clear_interrupt_flags(); | 995 | self.clear_interrupt_flags(); |
| 954 | // CP state machine must be idle | 996 | // CP state machine must be idle |
| 955 | while Self::cmd_active() {} | 997 | while self.cmd_active() {} |
| 956 | 998 | ||
| 957 | // Command arg | 999 | // Command arg |
| 958 | regs.argr().write(|w| w.set_cmdarg(cmd.arg)); | 1000 | regs.argr().write(|w| w.set_cmdarg(cmd.arg)); |
| @@ -994,16 +1036,29 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 994 | } else if status.ccrcfail() { | 1036 | } else if status.ccrcfail() { |
| 995 | return Err(Error::Crc); | 1037 | return Err(Error::Crc); |
| 996 | } | 1038 | } |
| 997 | Ok(()) | 1039 | |
| 1040 | Ok(match R::LENGTH { | ||
| 1041 | ResponseLen::Zero => U128(0u128), | ||
| 1042 | ResponseLen::R48 => U128(self.info.regs.respr(0).read().cardstatus() as u128), | ||
| 1043 | ResponseLen::R136 => { | ||
| 1044 | let cid0 = self.info.regs.respr(0).read().cardstatus() as u128; | ||
| 1045 | let cid1 = self.info.regs.respr(1).read().cardstatus() as u128; | ||
| 1046 | let cid2 = self.info.regs.respr(2).read().cardstatus() as u128; | ||
| 1047 | let cid3 = self.info.regs.respr(3).read().cardstatus() as u128; | ||
| 1048 | |||
| 1049 | U128((cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3)) | ||
| 1050 | } | ||
| 1051 | } | ||
| 1052 | .into()) | ||
| 998 | } | 1053 | } |
| 999 | 1054 | ||
| 1000 | fn on_drop() { | 1055 | fn on_drop(&self) { |
| 1001 | let regs = T::regs(); | 1056 | let regs = self.info.regs; |
| 1002 | if Self::data_active() { | 1057 | if self.data_active() { |
| 1003 | Self::clear_interrupt_flags(); | 1058 | self.clear_interrupt_flags(); |
| 1004 | // Send abort | 1059 | // Send abort |
| 1005 | // CP state machine must be idle | 1060 | // CP state machine must be idle |
| 1006 | while Self::cmd_active() {} | 1061 | while self.cmd_active() {} |
| 1007 | 1062 | ||
| 1008 | // Command arg | 1063 | // Command arg |
| 1009 | regs.argr().write(|w| w.set_cmdarg(0)); | 1064 | regs.argr().write(|w| w.set_cmdarg(0)); |
| @@ -1023,22 +1078,22 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1023 | }); | 1078 | }); |
| 1024 | 1079 | ||
| 1025 | // Wait for the abort | 1080 | // Wait for the abort |
| 1026 | while Self::data_active() {} | 1081 | while self.data_active() {} |
| 1027 | } | 1082 | } |
| 1028 | regs.maskr().write(|_| ()); // disable irqs | 1083 | regs.maskr().write(|_| ()); // disable irqs |
| 1029 | Self::clear_interrupt_flags(); | 1084 | self.clear_interrupt_flags(); |
| 1030 | Self::stop_datapath(); | 1085 | self.stop_datapath(); |
| 1031 | } | 1086 | } |
| 1032 | 1087 | ||
| 1033 | /// Wait for a previously started datapath transfer to complete from an interrupt. | 1088 | /// Wait for a previously started datapath transfer to complete from an interrupt. |
| 1034 | #[inline] | 1089 | #[inline] |
| 1035 | #[allow(unused)] | 1090 | #[allow(unused)] |
| 1036 | async fn complete_datapath_transfer(block: bool) -> Result<(), Error> { | 1091 | async fn complete_datapath_transfer(&self, mut transfer: WrappedTransfer<'_>, block: bool) -> Result<(), Error> { |
| 1037 | let res = poll_fn(|cx| { | 1092 | let res = poll_fn(|cx| { |
| 1038 | // Compiler might not be sufficiently constrained here | 1093 | // Compiler might not be sufficiently constrained here |
| 1039 | // https://github.com/embassy-rs/embassy/issues/4723 | 1094 | // https://github.com/embassy-rs/embassy/issues/4723 |
| 1040 | T::state().register(cx.waker()); | 1095 | self.state.waker.register(cx.waker()); |
| 1041 | let status = T::regs().star().read(); | 1096 | let status = self.info.regs.star().read(); |
| 1042 | 1097 | ||
| 1043 | if status.dcrcfail() { | 1098 | if status.dcrcfail() { |
| 1044 | return Poll::Ready(Err(Error::Crc)); | 1099 | return Poll::Ready(Err(Error::Crc)); |
| @@ -1067,698 +1122,25 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1067 | }) | 1122 | }) |
| 1068 | .await; | 1123 | .await; |
| 1069 | 1124 | ||
| 1070 | Self::clear_interrupt_flags(); | 1125 | self.clear_interrupt_flags(); |
| 1071 | 1126 | self.stop_datapath(); | |
| 1072 | res | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | /// Read a data block. | ||
| 1076 | #[inline] | ||
| 1077 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | ||
| 1078 | let card_capacity = self.card()?.get_capacity(); | ||
| 1079 | |||
| 1080 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 1081 | let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 1082 | 1127 | ||
| 1083 | // Always read 1 block of 512 bytes | 1128 | transfer.defuse(); |
| 1084 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | 1129 | drop(transfer); |
| 1085 | let address = match card_capacity { | ||
| 1086 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1087 | _ => block_idx, | ||
| 1088 | }; | ||
| 1089 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1090 | 1130 | ||
| 1091 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1092 | |||
| 1093 | let transfer = Self::prepare_datapath_read( | ||
| 1094 | &self.config, | ||
| 1095 | #[cfg(sdmmc_v1)] | ||
| 1096 | &mut self.dma, | ||
| 1097 | buffer, | ||
| 1098 | 512, | ||
| 1099 | 9, | ||
| 1100 | ); | ||
| 1101 | InterruptHandler::<T>::enable_interrupts(); | ||
| 1102 | Self::cmd(common_cmd::read_single_block(address), true)?; | ||
| 1103 | |||
| 1104 | let res = Self::complete_datapath_transfer(true).await; | ||
| 1105 | |||
| 1106 | if res.is_ok() { | ||
| 1107 | on_drop.defuse(); | ||
| 1108 | Self::stop_datapath(); | ||
| 1109 | drop(transfer); | ||
| 1110 | } | ||
| 1111 | res | 1131 | res |
| 1112 | } | 1132 | } |
| 1113 | 1133 | ||
| 1114 | /// Read multiple data blocks. | ||
| 1115 | #[inline] | ||
| 1116 | pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { | ||
| 1117 | let card_capacity = self.card()?.get_capacity(); | ||
| 1118 | |||
| 1119 | // NOTE(unsafe) reinterpret buffer as &mut [u32] | ||
| 1120 | let buffer = unsafe { | ||
| 1121 | let ptr = blocks.as_mut_ptr() as *mut u32; | ||
| 1122 | let len = blocks.len() * 128; | ||
| 1123 | core::slice::from_raw_parts_mut(ptr, len) | ||
| 1124 | }; | ||
| 1125 | |||
| 1126 | // Always read 1 block of 512 bytes | ||
| 1127 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1128 | let address = match card_capacity { | ||
| 1129 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1130 | _ => block_idx, | ||
| 1131 | }; | ||
| 1132 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1133 | |||
| 1134 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1135 | |||
| 1136 | let transfer = Self::prepare_datapath_read( | ||
| 1137 | &self.config, | ||
| 1138 | #[cfg(sdmmc_v1)] | ||
| 1139 | &mut self.dma, | ||
| 1140 | buffer, | ||
| 1141 | 512 * blocks.len() as u32, | ||
| 1142 | 9, | ||
| 1143 | ); | ||
| 1144 | InterruptHandler::<T>::enable_interrupts(); | ||
| 1145 | |||
| 1146 | Self::cmd(common_cmd::read_multiple_blocks(address), true)?; | ||
| 1147 | |||
| 1148 | let res = Self::complete_datapath_transfer(false).await; | ||
| 1149 | |||
| 1150 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 | ||
| 1151 | Self::clear_interrupt_flags(); | ||
| 1152 | |||
| 1153 | if res.is_ok() { | ||
| 1154 | on_drop.defuse(); | ||
| 1155 | Self::stop_datapath(); | ||
| 1156 | drop(transfer); | ||
| 1157 | } | ||
| 1158 | res | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | /// Write a data block. | ||
| 1162 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | ||
| 1163 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | ||
| 1164 | |||
| 1165 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 1166 | let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; | ||
| 1167 | |||
| 1168 | // Always read 1 block of 512 bytes | ||
| 1169 | // cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1170 | let address = match card.get_capacity() { | ||
| 1171 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1172 | _ => block_idx, | ||
| 1173 | }; | ||
| 1174 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1175 | |||
| 1176 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1177 | |||
| 1178 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||
| 1179 | #[cfg(sdmmc_v1)] | ||
| 1180 | Self::cmd(common_cmd::write_single_block(address), true)?; | ||
| 1181 | |||
| 1182 | let transfer = self.prepare_datapath_write(buffer, 512, 9); | ||
| 1183 | InterruptHandler::<T>::enable_interrupts(); | ||
| 1184 | |||
| 1185 | #[cfg(sdmmc_v2)] | ||
| 1186 | Self::cmd(common_cmd::write_single_block(address), true)?; | ||
| 1187 | |||
| 1188 | let res = Self::complete_datapath_transfer(true).await; | ||
| 1189 | |||
| 1190 | match res { | ||
| 1191 | Ok(_) => { | ||
| 1192 | on_drop.defuse(); | ||
| 1193 | Self::stop_datapath(); | ||
| 1194 | drop(transfer); | ||
| 1195 | |||
| 1196 | // TODO: Make this configurable | ||
| 1197 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 1198 | |||
| 1199 | let card = self.card.as_ref().unwrap(); | ||
| 1200 | while timeout > 0 { | ||
| 1201 | let ready_for_data = match card { | ||
| 1202 | SdmmcPeripheral::Emmc(_) => self.read_status::<EMMC>(card)?.ready_for_data(), | ||
| 1203 | SdmmcPeripheral::SdCard(_) => self.read_status::<SD>(card)?.ready_for_data(), | ||
| 1204 | }; | ||
| 1205 | |||
| 1206 | if ready_for_data { | ||
| 1207 | return Ok(()); | ||
| 1208 | } | ||
| 1209 | timeout -= 1; | ||
| 1210 | } | ||
| 1211 | Err(Error::SoftwareTimeout) | ||
| 1212 | } | ||
| 1213 | Err(e) => Err(e), | ||
| 1214 | } | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | /// Write multiple data blocks. | ||
| 1218 | pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> { | ||
| 1219 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | ||
| 1220 | |||
| 1221 | // NOTE(unsafe) reinterpret buffer as &[u32] | ||
| 1222 | let buffer = unsafe { | ||
| 1223 | let ptr = blocks.as_ptr() as *const u32; | ||
| 1224 | let len = blocks.len() * 128; | ||
| 1225 | core::slice::from_raw_parts(ptr, len) | ||
| 1226 | }; | ||
| 1227 | |||
| 1228 | // Always read 1 block of 512 bytes | ||
| 1229 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1230 | let address = match card.get_capacity() { | ||
| 1231 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1232 | _ => block_idx, | ||
| 1233 | }; | ||
| 1234 | |||
| 1235 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1236 | |||
| 1237 | let block_count = blocks.len(); | ||
| 1238 | |||
| 1239 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1240 | |||
| 1241 | #[cfg(sdmmc_v1)] | ||
| 1242 | Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | ||
| 1243 | |||
| 1244 | // Setup write command | ||
| 1245 | let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); | ||
| 1246 | InterruptHandler::<T>::enable_interrupts(); | ||
| 1247 | |||
| 1248 | #[cfg(sdmmc_v2)] | ||
| 1249 | Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | ||
| 1250 | |||
| 1251 | let res = Self::complete_datapath_transfer(false).await; | ||
| 1252 | |||
| 1253 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 | ||
| 1254 | Self::clear_interrupt_flags(); | ||
| 1255 | |||
| 1256 | match res { | ||
| 1257 | Ok(_) => { | ||
| 1258 | on_drop.defuse(); | ||
| 1259 | Self::stop_datapath(); | ||
| 1260 | drop(transfer); | ||
| 1261 | |||
| 1262 | // TODO: Make this configurable | ||
| 1263 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 1264 | |||
| 1265 | // Try to read card status (ACMD13) | ||
| 1266 | while timeout > 0 { | ||
| 1267 | match self.read_sd_status().await { | ||
| 1268 | Ok(_) => return Ok(()), | ||
| 1269 | Err(Error::Timeout) => (), // Try again | ||
| 1270 | Err(e) => return Err(e), | ||
| 1271 | } | ||
| 1272 | timeout -= 1; | ||
| 1273 | } | ||
| 1274 | Err(Error::SoftwareTimeout) | ||
| 1275 | } | ||
| 1276 | Err(e) => Err(e), | ||
| 1277 | } | ||
| 1278 | } | ||
| 1279 | |||
| 1280 | /// Get a reference to the initialized card | ||
| 1281 | /// | ||
| 1282 | /// # Errors | ||
| 1283 | /// | ||
| 1284 | /// Returns Error::NoCard if [`init_sd_card`](#method.init_sd_card) or | ||
| 1285 | /// [`init_emmc`](#method.init_emmc) has not previously succeeded | ||
| 1286 | #[inline] | ||
| 1287 | pub fn card(&self) -> Result<&SdmmcPeripheral, Error> { | ||
| 1288 | self.card.as_ref().ok_or(Error::NoCard) | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | /// Get the current SDMMC bus clock | 1134 | /// Get the current SDMMC bus clock |
| 1292 | pub fn clock(&self) -> Hertz { | 1135 | pub fn clock(&self) -> Hertz { |
| 1293 | self.clock | 1136 | self.clock |
| 1294 | } | 1137 | } |
| 1295 | |||
| 1296 | /// Set a specific cmd buffer rather than using the default stack allocated one. | ||
| 1297 | /// This is required if stack RAM cannot be used with DMA and usually manifests | ||
| 1298 | /// itself as an indefinite wait on a dma transfer because the dma peripheral | ||
| 1299 | /// cannot access the memory. | ||
| 1300 | pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { | ||
| 1301 | self.cmd_block = Some(cmd_block) | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | async fn init_internal(&mut self, freq: Hertz, mut card: SdmmcPeripheral) -> Result<(), Error> { | ||
| 1305 | let regs = T::regs(); | ||
| 1306 | let ker_ck = T::frequency(); | ||
| 1307 | |||
| 1308 | let bus_width = match (self.d3.is_some(), self.d7.is_some()) { | ||
| 1309 | (true, true) => { | ||
| 1310 | if matches!(card, SdmmcPeripheral::SdCard(_)) { | ||
| 1311 | return Err(Error::BusWidth); | ||
| 1312 | } | ||
| 1313 | BusWidth::Eight | ||
| 1314 | } | ||
| 1315 | (true, false) => BusWidth::Four, | ||
| 1316 | _ => BusWidth::One, | ||
| 1317 | }; | ||
| 1318 | |||
| 1319 | // While the SD/SDIO card or eMMC is in identification mode, | ||
| 1320 | // the SDMMC_CK frequency must be no more than 400 kHz. | ||
| 1321 | let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); | ||
| 1322 | self.clock = init_clock; | ||
| 1323 | |||
| 1324 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 1325 | Self::wait_idle(); | ||
| 1326 | |||
| 1327 | regs.clkcr().modify(|w| { | ||
| 1328 | w.set_widbus(0); | ||
| 1329 | w.set_clkdiv(clkdiv); | ||
| 1330 | #[cfg(sdmmc_v1)] | ||
| 1331 | w.set_bypass(_bypass); | ||
| 1332 | }); | ||
| 1333 | regs.dtimer() | ||
| 1334 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 1335 | |||
| 1336 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | ||
| 1337 | Self::cmd(common_cmd::idle(), false)?; | ||
| 1338 | |||
| 1339 | match card { | ||
| 1340 | SdmmcPeripheral::SdCard(ref mut card) => { | ||
| 1341 | // Check if cards supports CMD8 (with pattern) | ||
| 1342 | Self::cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; | ||
| 1343 | let cic = CIC::from(regs.respr(0).read().cardstatus()); | ||
| 1344 | |||
| 1345 | if cic.pattern() != 0xAA { | ||
| 1346 | return Err(Error::UnsupportedCardVersion); | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | if cic.voltage_accepted() & 1 == 0 { | ||
| 1350 | return Err(Error::UnsupportedVoltage); | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | let ocr = loop { | ||
| 1354 | // Signal that next command is a app command | ||
| 1355 | Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55 | ||
| 1356 | |||
| 1357 | // 3.2-3.3V | ||
| 1358 | let voltage_window = 1 << 5; | ||
| 1359 | // Initialize card | ||
| 1360 | match Self::cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) { | ||
| 1361 | // ACMD41 | ||
| 1362 | Ok(_) => (), | ||
| 1363 | Err(Error::Crc) => (), | ||
| 1364 | Err(err) => return Err(err), | ||
| 1365 | } | ||
| 1366 | let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into(); | ||
| 1367 | if !ocr.is_busy() { | ||
| 1368 | // Power up done | ||
| 1369 | break ocr; | ||
| 1370 | } | ||
| 1371 | }; | ||
| 1372 | |||
| 1373 | if ocr.high_capacity() { | ||
| 1374 | // Card is SDHC or SDXC or SDUC | ||
| 1375 | card.card_type = CardCapacity::HighCapacity; | ||
| 1376 | } else { | ||
| 1377 | card.card_type = CardCapacity::StandardCapacity; | ||
| 1378 | } | ||
| 1379 | card.ocr = ocr; | ||
| 1380 | } | ||
| 1381 | SdmmcPeripheral::Emmc(ref mut emmc) => { | ||
| 1382 | let ocr = loop { | ||
| 1383 | let high_voltage = 0b0 << 7; | ||
| 1384 | let access_mode = 0b10 << 29; | ||
| 1385 | let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; | ||
| 1386 | // Initialize card | ||
| 1387 | match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) { | ||
| 1388 | Ok(_) => (), | ||
| 1389 | Err(Error::Crc) => (), | ||
| 1390 | Err(err) => return Err(err), | ||
| 1391 | } | ||
| 1392 | let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into(); | ||
| 1393 | if !ocr.is_busy() { | ||
| 1394 | // Power up done | ||
| 1395 | break ocr; | ||
| 1396 | } | ||
| 1397 | }; | ||
| 1398 | |||
| 1399 | emmc.capacity = if ocr.access_mode() == 0b10 { | ||
| 1400 | // Card is SDHC or SDXC or SDUC | ||
| 1401 | CardCapacity::HighCapacity | ||
| 1402 | } else { | ||
| 1403 | CardCapacity::StandardCapacity | ||
| 1404 | }; | ||
| 1405 | emmc.ocr = ocr; | ||
| 1406 | } | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2 | ||
| 1410 | let cid0 = regs.respr(0).read().cardstatus() as u128; | ||
| 1411 | let cid1 = regs.respr(1).read().cardstatus() as u128; | ||
| 1412 | let cid2 = regs.respr(2).read().cardstatus() as u128; | ||
| 1413 | let cid3 = regs.respr(3).read().cardstatus() as u128; | ||
| 1414 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | ||
| 1415 | |||
| 1416 | match card { | ||
| 1417 | SdmmcPeripheral::SdCard(ref mut card) => { | ||
| 1418 | card.cid = cid.into(); | ||
| 1419 | |||
| 1420 | Self::cmd(sd_cmd::send_relative_address(), false)?; | ||
| 1421 | let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus()); | ||
| 1422 | card.rca = rca.address(); | ||
| 1423 | } | ||
| 1424 | SdmmcPeripheral::Emmc(ref mut emmc) => { | ||
| 1425 | emmc.cid = cid.into(); | ||
| 1426 | |||
| 1427 | emmc.rca = 1u16.into(); | ||
| 1428 | Self::cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?; | ||
| 1429 | } | ||
| 1430 | } | ||
| 1431 | |||
| 1432 | Self::cmd(common_cmd::send_csd(card.get_address()), false)?; | ||
| 1433 | let csd0 = regs.respr(0).read().cardstatus() as u128; | ||
| 1434 | let csd1 = regs.respr(1).read().cardstatus() as u128; | ||
| 1435 | let csd2 = regs.respr(2).read().cardstatus() as u128; | ||
| 1436 | let csd3 = regs.respr(3).read().cardstatus() as u128; | ||
| 1437 | let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); | ||
| 1438 | |||
| 1439 | self.select_card(Some(card.get_address()))?; | ||
| 1440 | |||
| 1441 | let bus_width = match card { | ||
| 1442 | SdmmcPeripheral::SdCard(ref mut card) => { | ||
| 1443 | card.csd = csd.into(); | ||
| 1444 | |||
| 1445 | self.get_scr(card).await?; | ||
| 1446 | |||
| 1447 | if !card.scr.bus_width_four() { | ||
| 1448 | BusWidth::One | ||
| 1449 | } else { | ||
| 1450 | BusWidth::Four | ||
| 1451 | } | ||
| 1452 | } | ||
| 1453 | SdmmcPeripheral::Emmc(ref mut emmc) => { | ||
| 1454 | emmc.csd = csd.into(); | ||
| 1455 | |||
| 1456 | bus_width | ||
| 1457 | } | ||
| 1458 | }; | ||
| 1459 | |||
| 1460 | // Set bus width | ||
| 1461 | let widbus = match bus_width { | ||
| 1462 | BusWidth::Eight => 2, | ||
| 1463 | BusWidth::Four => 1, | ||
| 1464 | BusWidth::One => 0, | ||
| 1465 | _ => unreachable!(), | ||
| 1466 | }; | ||
| 1467 | |||
| 1468 | match card { | ||
| 1469 | SdmmcPeripheral::SdCard(ref mut card) => { | ||
| 1470 | let acmd_arg = match bus_width { | ||
| 1471 | BusWidth::Four if card.scr.bus_width_four() => 2, | ||
| 1472 | _ => 0, | ||
| 1473 | }; | ||
| 1474 | Self::cmd(common_cmd::app_cmd(card.rca), false)?; | ||
| 1475 | Self::cmd(sd_cmd::cmd6(acmd_arg), false)?; | ||
| 1476 | } | ||
| 1477 | SdmmcPeripheral::Emmc(_) => { | ||
| 1478 | // Write bus width to ExtCSD byte 183 | ||
| 1479 | Self::cmd( | ||
| 1480 | emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), | ||
| 1481 | false, | ||
| 1482 | )?; | ||
| 1483 | |||
| 1484 | // Wait for ready after R1b response | ||
| 1485 | loop { | ||
| 1486 | let status = self.read_status::<EMMC>(&card)?; | ||
| 1487 | |||
| 1488 | if status.ready_for_data() { | ||
| 1489 | break; | ||
| 1490 | } | ||
| 1491 | } | ||
| 1492 | } | ||
| 1493 | } | ||
| 1494 | |||
| 1495 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 1496 | Self::wait_idle(); | ||
| 1497 | |||
| 1498 | regs.clkcr().modify(|w| w.set_widbus(widbus)); | ||
| 1499 | |||
| 1500 | // Set Clock | ||
| 1501 | if freq.0 <= 25_000_000 { | ||
| 1502 | // Final clock frequency | ||
| 1503 | self.clkcr_set_clkdiv(freq.0, bus_width)?; | ||
| 1504 | } else { | ||
| 1505 | // Switch to max clock for SDR12 | ||
| 1506 | self.clkcr_set_clkdiv(25_000_000, bus_width)?; | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | self.card = Some(card); | ||
| 1510 | |||
| 1511 | match card { | ||
| 1512 | SdmmcPeripheral::SdCard(_) => { | ||
| 1513 | // Read status | ||
| 1514 | self.read_sd_status().await?; | ||
| 1515 | |||
| 1516 | if freq.0 > 25_000_000 { | ||
| 1517 | // Switch to SDR25 | ||
| 1518 | self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; | ||
| 1519 | |||
| 1520 | if self.signalling == Signalling::SDR25 { | ||
| 1521 | // Set final clock frequency | ||
| 1522 | self.clkcr_set_clkdiv(freq.0, bus_width)?; | ||
| 1523 | |||
| 1524 | if self.read_status::<SD>(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer { | ||
| 1525 | return Err(Error::SignalingSwitchFailed); | ||
| 1526 | } | ||
| 1527 | } | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | // Read status after signalling change | ||
| 1531 | self.read_sd_status().await?; | ||
| 1532 | } | ||
| 1533 | SdmmcPeripheral::Emmc(_) => { | ||
| 1534 | self.read_ext_csd().await?; | ||
| 1535 | } | ||
| 1536 | } | ||
| 1537 | |||
| 1538 | Ok(()) | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | /// Initializes card (if present) and sets the bus at the specified frequency. | ||
| 1542 | /// | ||
| 1543 | /// SD only. | ||
| 1544 | pub async fn init_sd_card(&mut self, freq: Hertz) -> Result<(), Error> { | ||
| 1545 | self.init_internal(freq, SdmmcPeripheral::SdCard(Card::default())).await | ||
| 1546 | } | ||
| 1547 | |||
| 1548 | /// Switch mode using CMD6. | ||
| 1549 | /// | ||
| 1550 | /// Attempt to set a new signalling mode. The selected | ||
| 1551 | /// signalling mode is returned. Expects the current clock | ||
| 1552 | /// frequency to be > 12.5MHz. | ||
| 1553 | /// | ||
| 1554 | /// SD only. | ||
| 1555 | async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> { | ||
| 1556 | let _ = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card(); | ||
| 1557 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not | ||
| 1558 | // necessary" | ||
| 1559 | |||
| 1560 | let set_function = 0x8000_0000 | ||
| 1561 | | match signalling { | ||
| 1562 | // See PLSS v7_10 Table 4-11 | ||
| 1563 | Signalling::DDR50 => 0xFF_FF04, | ||
| 1564 | Signalling::SDR104 => 0xFF_1F03, | ||
| 1565 | Signalling::SDR50 => 0xFF_1F02, | ||
| 1566 | Signalling::SDR25 => 0xFF_FF01, | ||
| 1567 | Signalling::SDR12 => 0xFF_FF00, | ||
| 1568 | }; | ||
| 1569 | |||
| 1570 | let status = match self.cmd_block.as_deref_mut() { | ||
| 1571 | Some(x) => x, | ||
| 1572 | None => &mut CmdBlock::new(), | ||
| 1573 | }; | ||
| 1574 | |||
| 1575 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 1576 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1577 | |||
| 1578 | let transfer = Self::prepare_datapath_read( | ||
| 1579 | &self.config, | ||
| 1580 | #[cfg(sdmmc_v1)] | ||
| 1581 | &mut self.dma, | ||
| 1582 | status.as_mut(), | ||
| 1583 | 64, | ||
| 1584 | 6, | ||
| 1585 | ); | ||
| 1586 | InterruptHandler::<T>::enable_interrupts(); | ||
| 1587 | Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 | ||
| 1588 | |||
| 1589 | let res = Self::complete_datapath_transfer(true).await; | ||
| 1590 | |||
| 1591 | // Host is allowed to use the new functions at least 8 | ||
| 1592 | // clocks after the end of the switch command | ||
| 1593 | // transaction. We know the current clock period is < 80ns, | ||
| 1594 | // so a total delay of 640ns is required here | ||
| 1595 | for _ in 0..300 { | ||
| 1596 | cortex_m::asm::nop(); | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | match res { | ||
| 1600 | Ok(_) => { | ||
| 1601 | on_drop.defuse(); | ||
| 1602 | Self::stop_datapath(); | ||
| 1603 | drop(transfer); | ||
| 1604 | |||
| 1605 | // Function Selection of Function Group 1 | ||
| 1606 | let selection = (u32::from_be(status[4]) >> 24) & 0xF; | ||
| 1607 | |||
| 1608 | match selection { | ||
| 1609 | 0 => Ok(Signalling::SDR12), | ||
| 1610 | 1 => Ok(Signalling::SDR25), | ||
| 1611 | 2 => Ok(Signalling::SDR50), | ||
| 1612 | 3 => Ok(Signalling::SDR104), | ||
| 1613 | 4 => Ok(Signalling::DDR50), | ||
| 1614 | _ => Err(Error::UnsupportedCardType), | ||
| 1615 | } | ||
| 1616 | } | ||
| 1617 | Err(e) => Err(e), | ||
| 1618 | } | ||
| 1619 | } | ||
| 1620 | |||
| 1621 | /// Reads the SCR register. | ||
| 1622 | /// | ||
| 1623 | /// SD only. | ||
| 1624 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { | ||
| 1625 | // Read the 64-bit SCR register | ||
| 1626 | Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16 | ||
| 1627 | Self::cmd(common_cmd::app_cmd(card.rca), false)?; | ||
| 1628 | |||
| 1629 | let cmd_block = match self.cmd_block.as_deref_mut() { | ||
| 1630 | Some(x) => x, | ||
| 1631 | None => &mut CmdBlock::new(), | ||
| 1632 | }; | ||
| 1633 | let scr = &mut cmd_block.0[..2]; | ||
| 1634 | |||
| 1635 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 1636 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1637 | |||
| 1638 | let transfer = Self::prepare_datapath_read( | ||
| 1639 | &self.config, | ||
| 1640 | #[cfg(sdmmc_v1)] | ||
| 1641 | &mut self.dma, | ||
| 1642 | scr, | ||
| 1643 | 8, | ||
| 1644 | 3, | ||
| 1645 | ); | ||
| 1646 | InterruptHandler::<T>::enable_interrupts(); | ||
| 1647 | Self::cmd(sd_cmd::send_scr(), true)?; | ||
| 1648 | |||
| 1649 | let res = Self::complete_datapath_transfer(true).await; | ||
| 1650 | |||
| 1651 | if res.is_ok() { | ||
| 1652 | on_drop.defuse(); | ||
| 1653 | Self::stop_datapath(); | ||
| 1654 | drop(transfer); | ||
| 1655 | |||
| 1656 | unsafe { | ||
| 1657 | let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); | ||
| 1658 | card.scr = SCR(u64::from_be_bytes(*scr_bytes)); | ||
| 1659 | } | ||
| 1660 | } | ||
| 1661 | res | ||
| 1662 | } | ||
| 1663 | |||
| 1664 | /// Reads the SD Status (ACMD13) | ||
| 1665 | /// | ||
| 1666 | /// SD only. | ||
| 1667 | async fn read_sd_status(&mut self) -> Result<(), Error> { | ||
| 1668 | let card = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card(); | ||
| 1669 | let rca = card.rca; | ||
| 1670 | |||
| 1671 | let cmd_block = match self.cmd_block.as_deref_mut() { | ||
| 1672 | Some(x) => x, | ||
| 1673 | None => &mut CmdBlock::new(), | ||
| 1674 | }; | ||
| 1675 | |||
| 1676 | Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16 | ||
| 1677 | Self::cmd(common_cmd::app_cmd(rca), false)?; // APP | ||
| 1678 | |||
| 1679 | let status = cmd_block; | ||
| 1680 | |||
| 1681 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 1682 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1683 | |||
| 1684 | let transfer = Self::prepare_datapath_read( | ||
| 1685 | &self.config, | ||
| 1686 | #[cfg(sdmmc_v1)] | ||
| 1687 | &mut self.dma, | ||
| 1688 | status.as_mut(), | ||
| 1689 | 64, | ||
| 1690 | 6, | ||
| 1691 | ); | ||
| 1692 | InterruptHandler::<T>::enable_interrupts(); | ||
| 1693 | Self::cmd(sd_cmd::sd_status(), true)?; | ||
| 1694 | |||
| 1695 | let res = Self::complete_datapath_transfer(true).await; | ||
| 1696 | |||
| 1697 | if res.is_ok() { | ||
| 1698 | on_drop.defuse(); | ||
| 1699 | Self::stop_datapath(); | ||
| 1700 | drop(transfer); | ||
| 1701 | |||
| 1702 | for byte in status.iter_mut() { | ||
| 1703 | *byte = u32::from_be(*byte); | ||
| 1704 | } | ||
| 1705 | card.status = status.0.into(); | ||
| 1706 | } | ||
| 1707 | res | ||
| 1708 | } | ||
| 1709 | |||
| 1710 | /// Initializes eMMC and sets the bus at the specified frequency. | ||
| 1711 | /// | ||
| 1712 | /// eMMC only. | ||
| 1713 | pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> { | ||
| 1714 | self.init_internal(freq, SdmmcPeripheral::Emmc(Emmc::default())).await | ||
| 1715 | } | ||
| 1716 | |||
| 1717 | /// Gets the EXT_CSD register. | ||
| 1718 | /// | ||
| 1719 | /// eMMC only. | ||
| 1720 | async fn read_ext_csd(&mut self) -> Result<(), Error> { | ||
| 1721 | let card = self.card.as_mut().ok_or(Error::NoCard)?.get_emmc(); | ||
| 1722 | |||
| 1723 | // Note: cmd_block can't be used because ExtCSD is too long to fit. | ||
| 1724 | let mut data_block = DataBlock([0u8; 512]); | ||
| 1725 | |||
| 1726 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 1727 | let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 1728 | |||
| 1729 | Self::cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16 | ||
| 1730 | |||
| 1731 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 1732 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1733 | |||
| 1734 | let transfer = Self::prepare_datapath_read( | ||
| 1735 | &self.config, | ||
| 1736 | #[cfg(sdmmc_v1)] | ||
| 1737 | &mut self.dma, | ||
| 1738 | buffer, | ||
| 1739 | 512, | ||
| 1740 | 9, | ||
| 1741 | ); | ||
| 1742 | InterruptHandler::<T>::enable_interrupts(); | ||
| 1743 | Self::cmd(emmc_cmd::send_ext_csd(), true)?; | ||
| 1744 | |||
| 1745 | let res = Self::complete_datapath_transfer(true).await; | ||
| 1746 | |||
| 1747 | if res.is_ok() { | ||
| 1748 | on_drop.defuse(); | ||
| 1749 | Self::stop_datapath(); | ||
| 1750 | drop(transfer); | ||
| 1751 | |||
| 1752 | card.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into(); | ||
| 1753 | } | ||
| 1754 | res | ||
| 1755 | } | ||
| 1756 | } | 1138 | } |
| 1757 | 1139 | ||
| 1758 | impl<'d, T: Instance> Drop for Sdmmc<'d, T> { | 1140 | impl<'d> Drop for Sdmmc<'d> { |
| 1759 | fn drop(&mut self) { | 1141 | fn drop(&mut self) { |
| 1760 | T::Interrupt::disable(); | 1142 | // T::Interrupt::disable(); |
| 1761 | Self::on_drop(); | 1143 | self.on_drop(); |
| 1762 | 1144 | ||
| 1763 | critical_section::with(|_| { | 1145 | critical_section::with(|_| { |
| 1764 | self.clk.set_as_disconnected(); | 1146 | self.clk.set_as_disconnected(); |
| @@ -1791,9 +1173,28 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> { | |||
| 1791 | 1173 | ||
| 1792 | ////////////////////////////////////////////////////// | 1174 | ////////////////////////////////////////////////////// |
| 1793 | 1175 | ||
| 1176 | type Regs = RegBlock; | ||
| 1177 | |||
| 1178 | struct Info { | ||
| 1179 | regs: Regs, | ||
| 1180 | rcc: RccInfo, | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | struct State { | ||
| 1184 | waker: AtomicWaker, | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | impl State { | ||
| 1188 | const fn new() -> Self { | ||
| 1189 | Self { | ||
| 1190 | waker: AtomicWaker::new(), | ||
| 1191 | } | ||
| 1192 | } | ||
| 1193 | } | ||
| 1194 | |||
| 1794 | trait SealedInstance { | 1195 | trait SealedInstance { |
| 1795 | fn regs() -> RegBlock; | 1196 | fn info() -> &'static Info; |
| 1796 | fn state() -> &'static AtomicWaker; | 1197 | fn state() -> &'static State; |
| 1797 | } | 1198 | } |
| 1798 | 1199 | ||
| 1799 | /// SDMMC instance trait. | 1200 | /// SDMMC instance trait. |
| @@ -1820,13 +1221,17 @@ dma_trait!(SdmmcDma, Instance); | |||
| 1820 | foreach_peripheral!( | 1221 | foreach_peripheral!( |
| 1821 | (sdmmc, $inst:ident) => { | 1222 | (sdmmc, $inst:ident) => { |
| 1822 | impl SealedInstance for peripherals::$inst { | 1223 | impl SealedInstance for peripherals::$inst { |
| 1823 | fn regs() -> RegBlock { | 1224 | fn info() -> &'static Info { |
| 1824 | crate::pac::$inst | 1225 | static INFO: Info = Info { |
| 1226 | regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }, | ||
| 1227 | rcc: crate::peripherals::$inst::RCC_INFO, | ||
| 1228 | }; | ||
| 1229 | &INFO | ||
| 1825 | } | 1230 | } |
| 1826 | 1231 | ||
| 1827 | fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker { | 1232 | fn state() -> &'static State { |
| 1828 | static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new(); | 1233 | static STATE: State = State::new(); |
| 1829 | &WAKER | 1234 | &STATE |
| 1830 | } | 1235 | } |
| 1831 | } | 1236 | } |
| 1832 | 1237 | ||
| @@ -1835,46 +1240,3 @@ foreach_peripheral!( | |||
| 1835 | } | 1240 | } |
| 1836 | }; | 1241 | }; |
| 1837 | ); | 1242 | ); |
| 1838 | |||
| 1839 | impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { | ||
| 1840 | type Error = Error; | ||
| 1841 | type Align = aligned::A4; | ||
| 1842 | |||
| 1843 | async fn read( | ||
| 1844 | &mut self, | ||
| 1845 | block_address: u32, | ||
| 1846 | buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>], | ||
| 1847 | ) -> Result<(), Self::Error> { | ||
| 1848 | // TODO: I think block_address needs to be adjusted by the partition start offset | ||
| 1849 | if buf.len() == 1 { | ||
| 1850 | let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) }; | ||
| 1851 | self.read_block(block_address, block).await?; | ||
| 1852 | } else { | ||
| 1853 | let blocks: &mut [DataBlock] = | ||
| 1854 | unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) }; | ||
| 1855 | self.read_blocks(block_address, blocks).await?; | ||
| 1856 | } | ||
| 1857 | Ok(()) | ||
| 1858 | } | ||
| 1859 | |||
| 1860 | async fn write( | ||
| 1861 | &mut self, | ||
| 1862 | block_address: u32, | ||
| 1863 | buf: &[aligned::Aligned<Self::Align, [u8; 512]>], | ||
| 1864 | ) -> Result<(), Self::Error> { | ||
| 1865 | // TODO: I think block_address needs to be adjusted by the partition start offset | ||
| 1866 | if buf.len() == 1 { | ||
| 1867 | let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) }; | ||
| 1868 | self.write_block(block_address, block).await?; | ||
| 1869 | } else { | ||
| 1870 | let blocks: &[DataBlock] = | ||
| 1871 | unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) }; | ||
| 1872 | self.write_blocks(block_address, blocks).await?; | ||
| 1873 | } | ||
| 1874 | Ok(()) | ||
| 1875 | } | ||
| 1876 | |||
| 1877 | async fn size(&mut self) -> Result<u64, Self::Error> { | ||
| 1878 | Ok(self.card()?.size()) | ||
| 1879 | } | ||
| 1880 | } | ||
diff --git a/embassy-stm32/src/sdmmc/sd.rs b/embassy-stm32/src/sdmmc/sd.rs new file mode 100644 index 000000000..6190226b8 --- /dev/null +++ b/embassy-stm32/src/sdmmc/sd.rs | |||
| @@ -0,0 +1,693 @@ | |||
| 1 | use core::default::Default; | ||
| 2 | use core::ops::{Deref, DerefMut}; | ||
| 3 | |||
| 4 | use sdio_host::emmc::{EMMC, ExtCSD}; | ||
| 5 | use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; | ||
| 6 | use sdio_host::{common_cmd, emmc_cmd, sd_cmd}; | ||
| 7 | |||
| 8 | use crate::sdmmc::{BlockSize, Error, Sdmmc, Signalling, block_size, bus_width_vals, slice8_mut, slice8_ref}; | ||
| 9 | use crate::time::{Hertz, mhz}; | ||
| 10 | |||
| 11 | /// Aligned data block for SDMMC transfers. | ||
| 12 | /// | ||
| 13 | /// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements. | ||
| 14 | #[repr(align(4))] | ||
| 15 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 16 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 17 | pub struct DataBlock(pub [u32; 128]); | ||
| 18 | |||
| 19 | impl DataBlock { | ||
| 20 | /// Create a new DataBlock | ||
| 21 | pub const fn new() -> Self { | ||
| 22 | DataBlock([0u32; 128]) | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | impl Deref for DataBlock { | ||
| 27 | type Target = [u8; 512]; | ||
| 28 | |||
| 29 | fn deref(&self) -> &Self::Target { | ||
| 30 | unwrap!(slice8_ref(&self.0[..]).try_into()) | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | impl DerefMut for DataBlock { | ||
| 35 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 36 | unwrap!(slice8_mut(&mut self.0[..]).try_into()) | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | /// Command Block buffer for SDMMC command transfers. | ||
| 41 | /// | ||
| 42 | /// This is a 16-word array, exposed so that DMA commpatible memory can be used if required. | ||
| 43 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 44 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 45 | pub struct CmdBlock(pub [u32; 16]); | ||
| 46 | |||
| 47 | impl CmdBlock { | ||
| 48 | /// Creates a new instance of CmdBlock | ||
| 49 | pub const fn new() -> Self { | ||
| 50 | Self([0u32; 16]) | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | impl Deref for CmdBlock { | ||
| 55 | type Target = [u32; 16]; | ||
| 56 | |||
| 57 | fn deref(&self) -> &Self::Target { | ||
| 58 | &self.0 | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | impl DerefMut for CmdBlock { | ||
| 63 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 64 | &mut self.0 | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Represents either an SD or EMMC card | ||
| 69 | pub trait Addressable: Sized + Clone { | ||
| 70 | /// Associated type | ||
| 71 | type Ext; | ||
| 72 | |||
| 73 | /// Get this peripheral's address on the SDMMC bus | ||
| 74 | fn get_address(&self) -> u16; | ||
| 75 | |||
| 76 | /// Is this a standard or high capacity peripheral? | ||
| 77 | fn get_capacity(&self) -> CardCapacity; | ||
| 78 | |||
| 79 | /// Size in bytes | ||
| 80 | fn size(&self) -> u64; | ||
| 81 | } | ||
| 82 | |||
| 83 | /// Storage Device | ||
| 84 | pub struct StorageDevice<'a, 'b, T: Addressable> { | ||
| 85 | info: T, | ||
| 86 | /// Inner member | ||
| 87 | pub sdmmc: &'a mut Sdmmc<'b>, | ||
| 88 | } | ||
| 89 | |||
| 90 | /// Card Storage Device | ||
| 91 | impl<'a, 'b> StorageDevice<'a, 'b, Card> { | ||
| 92 | /// Create a new SD card | ||
| 93 | pub async fn new_sd_card(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> { | ||
| 94 | let mut s = Self { | ||
| 95 | info: Card::default(), | ||
| 96 | sdmmc, | ||
| 97 | }; | ||
| 98 | |||
| 99 | s.acquire(cmd_block, freq).await?; | ||
| 100 | |||
| 101 | Ok(s) | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Initializes the card into a known state (or at least tries to). | ||
| 105 | async fn acquire(&mut self, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<(), Error> { | ||
| 106 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 107 | let regs = self.sdmmc.info.regs; | ||
| 108 | |||
| 109 | let _bus_width = match self.sdmmc.bus_width() { | ||
| 110 | BusWidth::Eight => return Err(Error::BusWidth), | ||
| 111 | bus_width => bus_width, | ||
| 112 | }; | ||
| 113 | |||
| 114 | // While the SD/SDIO card or eMMC is in identification mode, | ||
| 115 | // the SDMMC_CK frequency must be no more than 400 kHz. | ||
| 116 | self.sdmmc.init_idle()?; | ||
| 117 | |||
| 118 | // Check if cards supports CMD8 (with pattern) | ||
| 119 | self.sdmmc.cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; | ||
| 120 | let cic = CIC::from(regs.respr(0).read().cardstatus()); | ||
| 121 | |||
| 122 | if cic.pattern() != 0xAA { | ||
| 123 | return Err(Error::UnsupportedCardVersion); | ||
| 124 | } | ||
| 125 | |||
| 126 | if cic.voltage_accepted() & 1 == 0 { | ||
| 127 | return Err(Error::UnsupportedVoltage); | ||
| 128 | } | ||
| 129 | |||
| 130 | let ocr = loop { | ||
| 131 | // Signal that next command is a app command | ||
| 132 | self.sdmmc.cmd(common_cmd::app_cmd(0), false)?; // CMD55 | ||
| 133 | |||
| 134 | // 3.2-3.3V | ||
| 135 | let voltage_window = 1 << 5; | ||
| 136 | // Initialize card | ||
| 137 | match self | ||
| 138 | .sdmmc | ||
| 139 | .cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) | ||
| 140 | { | ||
| 141 | // ACMD41 | ||
| 142 | Ok(_) => (), | ||
| 143 | Err(Error::Crc) => (), | ||
| 144 | Err(err) => return Err(err), | ||
| 145 | } | ||
| 146 | |||
| 147 | let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into(); | ||
| 148 | if !ocr.is_busy() { | ||
| 149 | // Power up done | ||
| 150 | break ocr; | ||
| 151 | } | ||
| 152 | }; | ||
| 153 | |||
| 154 | if ocr.high_capacity() { | ||
| 155 | // Card is SDHC or SDXC or SDUC | ||
| 156 | self.info.card_type = CardCapacity::HighCapacity; | ||
| 157 | } else { | ||
| 158 | self.info.card_type = CardCapacity::StandardCapacity; | ||
| 159 | } | ||
| 160 | self.info.ocr = ocr; | ||
| 161 | |||
| 162 | self.info.cid = self.sdmmc.get_cid()?.into(); | ||
| 163 | |||
| 164 | self.sdmmc.cmd(sd_cmd::send_relative_address(), false)?; | ||
| 165 | let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus()); | ||
| 166 | self.info.rca = rca.address(); | ||
| 167 | |||
| 168 | self.info.csd = self.sdmmc.get_csd(self.info.get_address())?.into(); | ||
| 169 | self.sdmmc.select_card(Some(self.info.get_address()))?; | ||
| 170 | |||
| 171 | self.info.scr = self.get_scr(cmd_block).await?; | ||
| 172 | |||
| 173 | let (bus_width, acmd_arg) = if !self.info.scr.bus_width_four() { | ||
| 174 | (BusWidth::One, 0) | ||
| 175 | } else { | ||
| 176 | (BusWidth::Four, 2) | ||
| 177 | }; | ||
| 178 | |||
| 179 | self.sdmmc.cmd(common_cmd::app_cmd(self.info.rca), false)?; | ||
| 180 | self.sdmmc.cmd(sd_cmd::cmd6(acmd_arg), false)?; | ||
| 181 | |||
| 182 | self.sdmmc.clkcr_set_clkdiv(freq.clamp(mhz(0), mhz(25)), bus_width)?; | ||
| 183 | |||
| 184 | // Read status | ||
| 185 | self.info.status = self.read_sd_status(cmd_block).await?; | ||
| 186 | |||
| 187 | if freq > mhz(25) { | ||
| 188 | // Switch to SDR25 | ||
| 189 | self.sdmmc.signalling = self.switch_signalling_mode(cmd_block, Signalling::SDR25).await?; | ||
| 190 | |||
| 191 | if self.sdmmc.signalling == Signalling::SDR25 { | ||
| 192 | // Set final clock frequency | ||
| 193 | self.sdmmc.clkcr_set_clkdiv(freq, bus_width)?; | ||
| 194 | |||
| 195 | if self.sdmmc.read_status(&self.info)?.state() != CurrentState::Transfer { | ||
| 196 | return Err(Error::SignalingSwitchFailed); | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | // Read status after signalling change | ||
| 201 | self.read_sd_status(cmd_block).await?; | ||
| 202 | } | ||
| 203 | |||
| 204 | Ok(()) | ||
| 205 | } | ||
| 206 | |||
| 207 | /// Switch mode using CMD6. | ||
| 208 | /// | ||
| 209 | /// Attempt to set a new signalling mode. The selected | ||
| 210 | /// signalling mode is returned. Expects the current clock | ||
| 211 | /// frequency to be > 12.5MHz. | ||
| 212 | /// | ||
| 213 | /// SD only. | ||
| 214 | async fn switch_signalling_mode( | ||
| 215 | &self, | ||
| 216 | cmd_block: &mut CmdBlock, | ||
| 217 | signalling: Signalling, | ||
| 218 | ) -> Result<Signalling, Error> { | ||
| 219 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not | ||
| 220 | // necessary" | ||
| 221 | |||
| 222 | let set_function = 0x8000_0000 | ||
| 223 | | match signalling { | ||
| 224 | // See PLSS v7_10 Table 4-11 | ||
| 225 | Signalling::DDR50 => 0xFF_FF04, | ||
| 226 | Signalling::SDR104 => 0xFF_1F03, | ||
| 227 | Signalling::SDR50 => 0xFF_1F02, | ||
| 228 | Signalling::SDR25 => 0xFF_FF01, | ||
| 229 | Signalling::SDR12 => 0xFF_FF00, | ||
| 230 | }; | ||
| 231 | |||
| 232 | let buffer = &mut cmd_block.0[..64 / 4]; | ||
| 233 | |||
| 234 | let transfer = self | ||
| 235 | .sdmmc | ||
| 236 | .prepare_datapath_read(buffer, block_size(size_of_val(buffer)), false); | ||
| 237 | |||
| 238 | self.sdmmc.cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 | ||
| 239 | |||
| 240 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 241 | |||
| 242 | // Host is allowed to use the new functions at least 8 | ||
| 243 | // clocks after the end of the switch command | ||
| 244 | // transaction. We know the current clock period is < 80ns, | ||
| 245 | // so a total delay of 640ns is required here | ||
| 246 | for _ in 0..300 { | ||
| 247 | cortex_m::asm::nop(); | ||
| 248 | } | ||
| 249 | |||
| 250 | // Function Selection of Function Group 1 | ||
| 251 | let selection = (u32::from_be(cmd_block[4]) >> 24) & 0xF; | ||
| 252 | |||
| 253 | match selection { | ||
| 254 | 0 => Ok(Signalling::SDR12), | ||
| 255 | 1 => Ok(Signalling::SDR25), | ||
| 256 | 2 => Ok(Signalling::SDR50), | ||
| 257 | 3 => Ok(Signalling::SDR104), | ||
| 258 | 4 => Ok(Signalling::DDR50), | ||
| 259 | _ => Err(Error::UnsupportedCardType), | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | /// Reads the SCR register. | ||
| 264 | /// | ||
| 265 | /// SD only. | ||
| 266 | async fn get_scr(&self, cmd_block: &mut CmdBlock) -> Result<SCR, Error> { | ||
| 267 | // Read the 64-bit SCR register | ||
| 268 | self.sdmmc.cmd(common_cmd::set_block_length(8), false)?; // CMD16 | ||
| 269 | self.sdmmc.cmd(common_cmd::app_cmd(self.info.rca), false)?; | ||
| 270 | |||
| 271 | let scr = &mut cmd_block.0[..2]; | ||
| 272 | |||
| 273 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 274 | |||
| 275 | let transfer = self.sdmmc.prepare_datapath_read(scr, BlockSize::Size8, false); | ||
| 276 | self.sdmmc.cmd(sd_cmd::send_scr(), true)?; | ||
| 277 | |||
| 278 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 279 | |||
| 280 | Ok(SCR(u64::from_be_bytes(unwrap!(slice8_mut(scr).try_into())))) | ||
| 281 | } | ||
| 282 | |||
| 283 | /// Reads the SD Status (ACMD13) | ||
| 284 | /// | ||
| 285 | /// SD only. | ||
| 286 | async fn read_sd_status(&self, cmd_block: &mut CmdBlock) -> Result<SDStatus, Error> { | ||
| 287 | let rca = self.info.rca; | ||
| 288 | |||
| 289 | self.sdmmc.cmd(common_cmd::set_block_length(64), false)?; // CMD16 | ||
| 290 | self.sdmmc.cmd(common_cmd::app_cmd(rca), false)?; // APP | ||
| 291 | |||
| 292 | let buffer = &mut cmd_block.as_mut()[..64 / 4]; | ||
| 293 | |||
| 294 | let transfer = self | ||
| 295 | .sdmmc | ||
| 296 | .prepare_datapath_read(buffer, block_size(size_of_val(buffer)), false); | ||
| 297 | self.sdmmc.cmd(sd_cmd::sd_status(), true)?; | ||
| 298 | |||
| 299 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 300 | |||
| 301 | for byte in cmd_block.iter_mut() { | ||
| 302 | *byte = u32::from_be(*byte); | ||
| 303 | } | ||
| 304 | |||
| 305 | Ok(cmd_block.0.into()) | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | /// Emmc storage device | ||
| 310 | impl<'a, 'b> StorageDevice<'a, 'b, Emmc> { | ||
| 311 | /// Create a new EMMC card | ||
| 312 | pub async fn new_emmc(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> { | ||
| 313 | let mut s = Self { | ||
| 314 | info: Emmc::default(), | ||
| 315 | sdmmc, | ||
| 316 | }; | ||
| 317 | |||
| 318 | s.acquire(cmd_block, freq).await?; | ||
| 319 | |||
| 320 | Ok(s) | ||
| 321 | } | ||
| 322 | |||
| 323 | async fn acquire(&mut self, _cmd_block: &mut CmdBlock, freq: Hertz) -> Result<(), Error> { | ||
| 324 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 325 | let regs = self.sdmmc.info.regs; | ||
| 326 | |||
| 327 | let bus_width = self.sdmmc.bus_width(); | ||
| 328 | |||
| 329 | // While the SD/SDIO card or eMMC is in identification mode, | ||
| 330 | // the SDMMC_CK frequency must be no more than 400 kHz. | ||
| 331 | self.sdmmc.init_idle()?; | ||
| 332 | |||
| 333 | let ocr = loop { | ||
| 334 | let high_voltage = 0b0 << 7; | ||
| 335 | let access_mode = 0b10 << 29; | ||
| 336 | let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; | ||
| 337 | // Initialize card | ||
| 338 | match self.sdmmc.cmd(emmc_cmd::send_op_cond(op_cond), false) { | ||
| 339 | Ok(_) => (), | ||
| 340 | Err(Error::Crc) => (), | ||
| 341 | Err(err) => return Err(err), | ||
| 342 | } | ||
| 343 | let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into(); | ||
| 344 | if !ocr.is_busy() { | ||
| 345 | // Power up done | ||
| 346 | break ocr; | ||
| 347 | } | ||
| 348 | }; | ||
| 349 | |||
| 350 | self.info.capacity = if ocr.access_mode() == 0b10 { | ||
| 351 | // Card is SDHC or SDXC or SDUC | ||
| 352 | CardCapacity::HighCapacity | ||
| 353 | } else { | ||
| 354 | CardCapacity::StandardCapacity | ||
| 355 | }; | ||
| 356 | self.info.ocr = ocr; | ||
| 357 | |||
| 358 | self.info.cid = self.sdmmc.get_cid()?.into(); | ||
| 359 | |||
| 360 | self.info.rca = 1u16.into(); | ||
| 361 | self.sdmmc | ||
| 362 | .cmd(emmc_cmd::assign_relative_address(self.info.rca), false)?; | ||
| 363 | |||
| 364 | self.info.csd = self.sdmmc.get_csd(self.info.get_address())?.into(); | ||
| 365 | self.sdmmc.select_card(Some(self.info.get_address()))?; | ||
| 366 | |||
| 367 | let (widbus, _) = bus_width_vals(bus_width); | ||
| 368 | |||
| 369 | // Write bus width to ExtCSD byte 183 | ||
| 370 | self.sdmmc.cmd( | ||
| 371 | emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), | ||
| 372 | false, | ||
| 373 | )?; | ||
| 374 | |||
| 375 | // Wait for ready after R1b response | ||
| 376 | loop { | ||
| 377 | let status = self.sdmmc.read_status(&self.info)?; | ||
| 378 | |||
| 379 | if status.ready_for_data() { | ||
| 380 | break; | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | self.sdmmc.clkcr_set_clkdiv(freq.clamp(mhz(0), mhz(25)), bus_width)?; | ||
| 385 | self.info.ext_csd = self.read_ext_csd().await?; | ||
| 386 | |||
| 387 | Ok(()) | ||
| 388 | } | ||
| 389 | |||
| 390 | /// Gets the EXT_CSD register. | ||
| 391 | /// | ||
| 392 | /// eMMC only. | ||
| 393 | async fn read_ext_csd(&self) -> Result<ExtCSD, Error> { | ||
| 394 | // Note: cmd_block can't be used because ExtCSD is too long to fit. | ||
| 395 | let mut data_block = DataBlock::new(); | ||
| 396 | |||
| 397 | self.sdmmc | ||
| 398 | .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false) | ||
| 399 | .unwrap(); // CMD16 | ||
| 400 | |||
| 401 | let transfer = self | ||
| 402 | .sdmmc | ||
| 403 | .prepare_datapath_read(&mut data_block.0, block_size(size_of::<DataBlock>()), false); | ||
| 404 | self.sdmmc.cmd(emmc_cmd::send_ext_csd(), true)?; | ||
| 405 | |||
| 406 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 407 | |||
| 408 | Ok(data_block.0.into()) | ||
| 409 | } | ||
| 410 | } | ||
| 411 | |||
| 412 | /// Card or Emmc storage device | ||
| 413 | impl<'a, 'b, A: Addressable> StorageDevice<'a, 'b, A> { | ||
| 414 | /// Write a block | ||
| 415 | pub fn card(&self) -> A { | ||
| 416 | self.info.clone() | ||
| 417 | } | ||
| 418 | |||
| 419 | /// Read a data block. | ||
| 420 | #[inline] | ||
| 421 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | ||
| 422 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 423 | let card_capacity = self.info.get_capacity(); | ||
| 424 | |||
| 425 | // Always read 1 block of 512 bytes | ||
| 426 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 427 | let address = match card_capacity { | ||
| 428 | CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32, | ||
| 429 | _ => block_idx, | ||
| 430 | }; | ||
| 431 | self.sdmmc | ||
| 432 | .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16 | ||
| 433 | |||
| 434 | let transfer = self | ||
| 435 | .sdmmc | ||
| 436 | .prepare_datapath_read(&mut buffer.0, block_size(size_of::<DataBlock>()), false); | ||
| 437 | self.sdmmc.cmd(common_cmd::read_single_block(address), true)?; | ||
| 438 | |||
| 439 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 440 | |||
| 441 | Ok(()) | ||
| 442 | } | ||
| 443 | |||
| 444 | /// Read multiple data blocks. | ||
| 445 | #[inline] | ||
| 446 | pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { | ||
| 447 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 448 | let card_capacity = self.info.get_capacity(); | ||
| 449 | |||
| 450 | // NOTE(unsafe) reinterpret buffer as &mut [u32] | ||
| 451 | let buffer = unsafe { | ||
| 452 | core::slice::from_raw_parts_mut( | ||
| 453 | blocks.as_mut_ptr() as *mut u32, | ||
| 454 | blocks.len() * size_of::<DataBlock>() / size_of::<u32>(), | ||
| 455 | ) | ||
| 456 | }; | ||
| 457 | |||
| 458 | // Always read 1 block of 512 bytes | ||
| 459 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 460 | let address = match card_capacity { | ||
| 461 | CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32, | ||
| 462 | _ => block_idx, | ||
| 463 | }; | ||
| 464 | self.sdmmc | ||
| 465 | .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16 | ||
| 466 | |||
| 467 | let transfer = self | ||
| 468 | .sdmmc | ||
| 469 | .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), false); | ||
| 470 | self.sdmmc.cmd(common_cmd::read_multiple_blocks(address), true)?; | ||
| 471 | |||
| 472 | self.sdmmc.complete_datapath_transfer(transfer, false).await?; | ||
| 473 | |||
| 474 | self.sdmmc.cmd(common_cmd::stop_transmission(), false)?; // CMD12 | ||
| 475 | self.sdmmc.clear_interrupt_flags(); | ||
| 476 | |||
| 477 | Ok(()) | ||
| 478 | } | ||
| 479 | |||
| 480 | /// Write a data block. | ||
| 481 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> | ||
| 482 | where | ||
| 483 | CardStatus<A::Ext>: From<u32>, | ||
| 484 | { | ||
| 485 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 486 | |||
| 487 | // Always read 1 block of 512 bytes | ||
| 488 | // cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 489 | let address = match self.info.get_capacity() { | ||
| 490 | CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32, | ||
| 491 | _ => block_idx, | ||
| 492 | }; | ||
| 493 | self.sdmmc | ||
| 494 | .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16 | ||
| 495 | |||
| 496 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||
| 497 | #[cfg(sdmmc_v1)] | ||
| 498 | self.sdmmc.cmd(common_cmd::write_single_block(address), true)?; | ||
| 499 | |||
| 500 | let transfer = self | ||
| 501 | .sdmmc | ||
| 502 | .prepare_datapath_write(&buffer.0, block_size(size_of::<DataBlock>()), false); | ||
| 503 | |||
| 504 | #[cfg(sdmmc_v2)] | ||
| 505 | self.sdmmc.cmd(common_cmd::write_single_block(address), true)?; | ||
| 506 | |||
| 507 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 508 | |||
| 509 | // TODO: Make this configurable | ||
| 510 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 511 | |||
| 512 | while timeout > 0 { | ||
| 513 | let ready_for_data = self.sdmmc.read_status(&self.info)?.ready_for_data(); | ||
| 514 | if ready_for_data { | ||
| 515 | return Ok(()); | ||
| 516 | } | ||
| 517 | timeout -= 1; | ||
| 518 | } | ||
| 519 | |||
| 520 | Err(Error::SoftwareTimeout) | ||
| 521 | } | ||
| 522 | |||
| 523 | /// Write multiple data blocks. | ||
| 524 | pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> | ||
| 525 | where | ||
| 526 | CardStatus<A::Ext>: From<u32>, | ||
| 527 | { | ||
| 528 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 529 | |||
| 530 | // NOTE(unsafe) reinterpret buffer as &[u32] | ||
| 531 | let buffer = unsafe { | ||
| 532 | core::slice::from_raw_parts( | ||
| 533 | blocks.as_ptr() as *const u32, | ||
| 534 | blocks.len() * size_of::<DataBlock>() / size_of::<u32>(), | ||
| 535 | ) | ||
| 536 | }; | ||
| 537 | // Always read 1 block of 512 bytes | ||
| 538 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 539 | let address = match self.info.get_capacity() { | ||
| 540 | CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32, | ||
| 541 | _ => block_idx, | ||
| 542 | }; | ||
| 543 | |||
| 544 | self.sdmmc | ||
| 545 | .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16 | ||
| 546 | |||
| 547 | #[cfg(sdmmc_v1)] | ||
| 548 | self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | ||
| 549 | |||
| 550 | // Setup write command | ||
| 551 | let transfer = self | ||
| 552 | .sdmmc | ||
| 553 | .prepare_datapath_write(buffer, block_size(size_of::<DataBlock>()), false); | ||
| 554 | |||
| 555 | #[cfg(sdmmc_v2)] | ||
| 556 | self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | ||
| 557 | |||
| 558 | self.sdmmc.complete_datapath_transfer(transfer, false).await?; | ||
| 559 | |||
| 560 | self.sdmmc.cmd(common_cmd::stop_transmission(), false)?; // CMD12 | ||
| 561 | self.sdmmc.clear_interrupt_flags(); | ||
| 562 | |||
| 563 | // TODO: Make this configurable | ||
| 564 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 565 | |||
| 566 | while timeout > 0 { | ||
| 567 | let ready_for_data = self.sdmmc.read_status(&self.info)?.ready_for_data(); | ||
| 568 | |||
| 569 | if ready_for_data { | ||
| 570 | return Ok(()); | ||
| 571 | } | ||
| 572 | timeout -= 1; | ||
| 573 | } | ||
| 574 | Err(Error::SoftwareTimeout) | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | #[derive(Clone, Copy, Debug, Default)] | ||
| 579 | /// SD Card | ||
| 580 | pub struct Card { | ||
| 581 | /// The type of this card | ||
| 582 | pub card_type: CardCapacity, | ||
| 583 | /// Operation Conditions Register | ||
| 584 | pub ocr: OCR<SD>, | ||
| 585 | /// Relative Card Address | ||
| 586 | pub rca: u16, | ||
| 587 | /// Card ID | ||
| 588 | pub cid: CID<SD>, | ||
| 589 | /// Card Specific Data | ||
| 590 | pub csd: CSD<SD>, | ||
| 591 | /// SD CARD Configuration Register | ||
| 592 | pub scr: SCR, | ||
| 593 | /// SD Status | ||
| 594 | pub status: SDStatus, | ||
| 595 | } | ||
| 596 | |||
| 597 | impl Addressable for Card { | ||
| 598 | type Ext = SD; | ||
| 599 | |||
| 600 | /// Get this peripheral's address on the SDMMC bus | ||
| 601 | fn get_address(&self) -> u16 { | ||
| 602 | self.rca | ||
| 603 | } | ||
| 604 | |||
| 605 | /// Is this a standard or high capacity peripheral? | ||
| 606 | fn get_capacity(&self) -> CardCapacity { | ||
| 607 | self.card_type | ||
| 608 | } | ||
| 609 | |||
| 610 | /// Size in bytes | ||
| 611 | fn size(&self) -> u64 { | ||
| 612 | u64::from(self.csd.block_count()) * 512 | ||
| 613 | } | ||
| 614 | } | ||
| 615 | |||
| 616 | #[derive(Clone, Copy, Debug, Default)] | ||
| 617 | /// eMMC storage | ||
| 618 | pub struct Emmc { | ||
| 619 | /// The capacity of this card | ||
| 620 | pub capacity: CardCapacity, | ||
| 621 | /// Operation Conditions Register | ||
| 622 | pub ocr: OCR<EMMC>, | ||
| 623 | /// Relative Card Address | ||
| 624 | pub rca: u16, | ||
| 625 | /// Card ID | ||
| 626 | pub cid: CID<EMMC>, | ||
| 627 | /// Card Specific Data | ||
| 628 | pub csd: CSD<EMMC>, | ||
| 629 | /// Extended Card Specific Data | ||
| 630 | pub ext_csd: ExtCSD, | ||
| 631 | } | ||
| 632 | |||
| 633 | impl Addressable for Emmc { | ||
| 634 | type Ext = EMMC; | ||
| 635 | |||
| 636 | /// Get this peripheral's address on the SDMMC bus | ||
| 637 | fn get_address(&self) -> u16 { | ||
| 638 | self.rca | ||
| 639 | } | ||
| 640 | |||
| 641 | /// Is this a standard or high capacity peripheral? | ||
| 642 | fn get_capacity(&self) -> CardCapacity { | ||
| 643 | self.capacity | ||
| 644 | } | ||
| 645 | |||
| 646 | /// Size in bytes | ||
| 647 | fn size(&self) -> u64 { | ||
| 648 | u64::from(self.ext_csd.sector_count()) * 512 | ||
| 649 | } | ||
| 650 | } | ||
| 651 | |||
| 652 | impl<'d, 'e, A: Addressable> block_device_driver::BlockDevice<512> for StorageDevice<'d, 'e, A> { | ||
| 653 | type Error = Error; | ||
| 654 | type Align = aligned::A4; | ||
| 655 | |||
| 656 | async fn read( | ||
| 657 | &mut self, | ||
| 658 | block_address: u32, | ||
| 659 | buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>], | ||
| 660 | ) -> Result<(), Self::Error> { | ||
| 661 | // TODO: I think block_address needs to be adjusted by the partition start offset | ||
| 662 | if buf.len() == 1 { | ||
| 663 | let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut DataBlock) }; | ||
| 664 | self.read_block(block_address, block).await?; | ||
| 665 | } else { | ||
| 666 | let blocks: &mut [DataBlock] = | ||
| 667 | unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) }; | ||
| 668 | self.read_blocks(block_address, blocks).await?; | ||
| 669 | } | ||
| 670 | Ok(()) | ||
| 671 | } | ||
| 672 | |||
| 673 | async fn write( | ||
| 674 | &mut self, | ||
| 675 | block_address: u32, | ||
| 676 | buf: &[aligned::Aligned<Self::Align, [u8; 512]>], | ||
| 677 | ) -> Result<(), Self::Error> { | ||
| 678 | // TODO: I think block_address needs to be adjusted by the partition start offset | ||
| 679 | if buf.len() == 1 { | ||
| 680 | let block = unsafe { &*(&buf[0] as *const _ as *const DataBlock) }; | ||
| 681 | self.write_block(block_address, block).await?; | ||
| 682 | } else { | ||
| 683 | let blocks: &[DataBlock] = | ||
| 684 | unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) }; | ||
| 685 | self.write_blocks(block_address, blocks).await?; | ||
| 686 | } | ||
| 687 | Ok(()) | ||
| 688 | } | ||
| 689 | |||
| 690 | async fn size(&mut self) -> Result<u64, Self::Error> { | ||
| 691 | Ok(self.info.size()) | ||
| 692 | } | ||
| 693 | } | ||
diff --git a/embassy-stm32/src/sdmmc/sdio.rs b/embassy-stm32/src/sdmmc/sdio.rs new file mode 100644 index 000000000..1412b21fc --- /dev/null +++ b/embassy-stm32/src/sdmmc/sdio.rs | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | use core::ops::{Deref, DerefMut}; | ||
| 2 | |||
| 3 | use sdio_host::common_cmd::{R1, Rz, cmd}; | ||
| 4 | use sdio_host::sd::BusWidth; | ||
| 5 | use sdio_host::sd_cmd; | ||
| 6 | |||
| 7 | use crate::sdmmc::{Error, Sdmmc, block_size, slice8_mut, slice8_ref}; | ||
| 8 | use crate::time::Hertz; | ||
| 9 | |||
| 10 | /// Aligned data block for SDMMC transfers. | ||
| 11 | /// | ||
| 12 | /// This is a 64-byte array, aligned to 4 bytes to satisfy DMA requirements. | ||
| 13 | #[repr(align(4))] | ||
| 14 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 15 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 16 | pub struct DataBlock(pub [u32; 16]); | ||
| 17 | |||
| 18 | impl DataBlock { | ||
| 19 | /// Create a new DataBlock | ||
| 20 | pub const fn new() -> Self { | ||
| 21 | DataBlock([0u32; 16]) | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | impl Deref for DataBlock { | ||
| 26 | type Target = [u8; 64]; | ||
| 27 | |||
| 28 | fn deref(&self) -> &Self::Target { | ||
| 29 | unwrap!(slice8_ref(&self.0[..]).try_into()) | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | impl DerefMut for DataBlock { | ||
| 34 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 35 | unwrap!(slice8_mut(&mut self.0[..]).try_into()) | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | /// Storage Device | ||
| 40 | pub struct SerialDataInterface<'a, 'b> { | ||
| 41 | /// Inner member | ||
| 42 | pub sdmmc: &'a mut Sdmmc<'b>, | ||
| 43 | } | ||
| 44 | |||
| 45 | /// Card Storage Device | ||
| 46 | impl<'a, 'b> SerialDataInterface<'a, 'b> { | ||
| 47 | /// Create a new SD card | ||
| 48 | pub async fn new(sdmmc: &'a mut Sdmmc<'b>, freq: Hertz) -> Result<Self, Error> { | ||
| 49 | let mut s = Self { sdmmc }; | ||
| 50 | |||
| 51 | s.acquire(freq).await?; | ||
| 52 | |||
| 53 | Ok(s) | ||
| 54 | } | ||
| 55 | |||
| 56 | /// Initializes the card into a known state (or at least tries to). | ||
| 57 | async fn acquire(&mut self, _freq: Hertz) -> Result<(), Error> { | ||
| 58 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 59 | |||
| 60 | let _bus_width = match self.sdmmc.bus_width() { | ||
| 61 | BusWidth::Eight => return Err(Error::BusWidth), | ||
| 62 | bus_width => bus_width, | ||
| 63 | }; | ||
| 64 | |||
| 65 | // While the SD/SDIO card or eMMC is in identification mode, | ||
| 66 | // the SDMMC_CK frequency must be no more than 400 kHz. | ||
| 67 | self.sdmmc.init_idle()?; | ||
| 68 | |||
| 69 | self.sdmmc.cmd(cmd::<Rz>(5, 0), false)?; | ||
| 70 | |||
| 71 | // Get RCA | ||
| 72 | let rca = self.sdmmc.cmd(sd_cmd::send_relative_address(), false)?; | ||
| 73 | |||
| 74 | // Select the card with RCA | ||
| 75 | self.sdmmc.select_card(Some(rca.try_into().unwrap()))?; | ||
| 76 | |||
| 77 | Ok(()) | ||
| 78 | } | ||
| 79 | |||
| 80 | /// Set the bus to the 4-bit high-speed frequency | ||
| 81 | pub fn set_bus_to_high_speed(&mut self, frequency: Hertz) -> Result<(), Error> { | ||
| 82 | self.sdmmc.clkcr_set_clkdiv(frequency, BusWidth::Four)?; | ||
| 83 | |||
| 84 | Ok(()) | ||
| 85 | } | ||
| 86 | |||
| 87 | /// Run cmd52 | ||
| 88 | pub async fn cmd52(&mut self, arg: u32) -> Result<u32, Error> { | ||
| 89 | self.sdmmc.cmd(cmd::<R1>(52, arg), false) | ||
| 90 | } | ||
| 91 | |||
| 92 | /// Read in block mode using cmd53 | ||
| 93 | pub async fn cmd53_block_read(&mut self, arg: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { | ||
| 94 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 95 | |||
| 96 | // NOTE(unsafe) reinterpret buffer as &mut [u32] | ||
| 97 | let buffer = unsafe { | ||
| 98 | core::slice::from_raw_parts_mut( | ||
| 99 | blocks.as_mut_ptr() as *mut u32, | ||
| 100 | blocks.len() * size_of::<DataBlock>() / size_of::<u32>(), | ||
| 101 | ) | ||
| 102 | }; | ||
| 103 | |||
| 104 | let transfer = self | ||
| 105 | .sdmmc | ||
| 106 | .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), false); | ||
| 107 | self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; | ||
| 108 | |||
| 109 | self.sdmmc.complete_datapath_transfer(transfer, false).await?; | ||
| 110 | self.sdmmc.clear_interrupt_flags(); | ||
| 111 | |||
| 112 | Ok(()) | ||
| 113 | } | ||
| 114 | |||
| 115 | /// Read in multibyte mode using cmd53 | ||
| 116 | pub async fn cmd53_byte_read(&mut self, arg: u32, buffer: &mut [u32]) -> Result<(), Error> { | ||
| 117 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 118 | |||
| 119 | let transfer = self | ||
| 120 | .sdmmc | ||
| 121 | .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), true); | ||
| 122 | self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; | ||
| 123 | |||
| 124 | self.sdmmc.complete_datapath_transfer(transfer, false).await?; | ||
| 125 | self.sdmmc.clear_interrupt_flags(); | ||
| 126 | |||
| 127 | Ok(()) | ||
| 128 | } | ||
| 129 | |||
| 130 | /// Write in block mode using cmd53 | ||
| 131 | pub async fn cmd53_block_write(&mut self, arg: u32, blocks: &[DataBlock]) -> Result<(), Error> { | ||
| 132 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 133 | |||
| 134 | // NOTE(unsafe) reinterpret buffer as &mut [u32] | ||
| 135 | let buffer = unsafe { | ||
| 136 | core::slice::from_raw_parts_mut( | ||
| 137 | blocks.as_ptr() as *mut u32, | ||
| 138 | blocks.len() * size_of::<DataBlock>() / size_of::<u32>(), | ||
| 139 | ) | ||
| 140 | }; | ||
| 141 | |||
| 142 | #[cfg(sdmmc_v1)] | ||
| 143 | self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; | ||
| 144 | |||
| 145 | let transfer = self | ||
| 146 | .sdmmc | ||
| 147 | .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), false); | ||
| 148 | |||
| 149 | #[cfg(sdmmc_v2)] | ||
| 150 | self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; | ||
| 151 | |||
| 152 | self.sdmmc.complete_datapath_transfer(transfer, false).await?; | ||
| 153 | self.sdmmc.clear_interrupt_flags(); | ||
| 154 | |||
| 155 | Ok(()) | ||
| 156 | } | ||
| 157 | |||
| 158 | /// Write in multibyte mode using cmd53 | ||
| 159 | pub async fn cmd53_byte_write(&mut self, arg: u32, buffer: &[u32]) -> Result<(), Error> { | ||
| 160 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 161 | |||
| 162 | #[cfg(sdmmc_v1)] | ||
| 163 | self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; | ||
| 164 | |||
| 165 | let transfer = self | ||
| 166 | .sdmmc | ||
| 167 | .prepare_datapath_write(buffer, block_size(size_of::<DataBlock>()), true); | ||
| 168 | |||
| 169 | #[cfg(sdmmc_v2)] | ||
| 170 | self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; | ||
| 171 | |||
| 172 | self.sdmmc.complete_datapath_transfer(transfer, false).await?; | ||
| 173 | self.sdmmc.clear_interrupt_flags(); | ||
| 174 | |||
| 175 | Ok(()) | ||
| 176 | } | ||
| 177 | } | ||
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index abb80ed26..c90e0cef4 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -54,6 +54,16 @@ pub enum BitOrder { | |||
| 54 | MsbFirst, | 54 | MsbFirst, |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | /// SPI Direction. | ||
| 58 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
| 59 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 60 | pub enum Direction { | ||
| 61 | /// Transmit | ||
| 62 | Transmit, | ||
| 63 | /// Receive | ||
| 64 | Receive, | ||
| 65 | } | ||
| 66 | |||
| 57 | /// SPI configuration. | 67 | /// SPI configuration. |
| 58 | #[non_exhaustive] | 68 | #[non_exhaustive] |
| 59 | #[derive(Copy, Clone)] | 69 | #[derive(Copy, Clone)] |
| @@ -72,6 +82,10 @@ pub struct Config { | |||
| 72 | /// signal rise/fall speed (slew rate) - defaults to `Medium`. | 82 | /// signal rise/fall speed (slew rate) - defaults to `Medium`. |
| 73 | /// Increase for high SPI speeds. Change to `Low` to reduce ringing. | 83 | /// Increase for high SPI speeds. Change to `Low` to reduce ringing. |
| 74 | pub gpio_speed: Speed, | 84 | pub gpio_speed: Speed, |
| 85 | /// If True sets SSOE to zero even if SPI is in Master Mode. | ||
| 86 | /// NSS output enabled (SSM = 0, SSOE = 1): The NSS signal is driven low when the master starts the communication and is kept low until the SPI is disabled. | ||
| 87 | /// NSS output disabled (SSM = 0, SSOE = 0): For devices set as slave, the NSS pin acts as a classical NSS input: the slave is selected when NSS is low and deselected when NSS high. | ||
| 88 | pub nss_output_disable: bool, | ||
| 75 | } | 89 | } |
| 76 | 90 | ||
| 77 | impl Default for Config { | 91 | impl Default for Config { |
| @@ -82,6 +96,7 @@ impl Default for Config { | |||
| 82 | frequency: Hertz(1_000_000), | 96 | frequency: Hertz(1_000_000), |
| 83 | miso_pull: Pull::None, | 97 | miso_pull: Pull::None, |
| 84 | gpio_speed: Speed::VeryHigh, | 98 | gpio_speed: Speed::VeryHigh, |
| 99 | nss_output_disable: false, | ||
| 85 | } | 100 | } |
| 86 | } | 101 | } |
| 87 | } | 102 | } |
| @@ -215,13 +230,35 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 215 | let cpol = config.raw_polarity(); | 230 | let cpol = config.raw_polarity(); |
| 216 | let lsbfirst = config.raw_byte_order(); | 231 | let lsbfirst = config.raw_byte_order(); |
| 217 | 232 | ||
| 218 | self.info.rcc.enable_and_reset(); | 233 | self.info.rcc.enable_and_reset_without_stop(); |
| 234 | |||
| 235 | /* | ||
| 236 | - Software NSS management (SSM = 1) | ||
| 237 | The slave select information is driven internally by the value of the SSI bit in the | ||
| 238 | SPI_CR1 register. The external NSS pin remains free for other application uses. | ||
| 239 | |||
| 240 | - Hardware NSS management (SSM = 0) | ||
| 241 | Two configurations are possible depending on the NSS output configuration (SSOE bit | ||
| 242 | in register SPI_CR1). | ||
| 243 | |||
| 244 | -- NSS output enabled (SSM = 0, SSOE = 1) | ||
| 245 | This configuration is used only when the device operates in master mode. The | ||
| 246 | NSS signal is driven low when the master starts the communication and is kept | ||
| 247 | low until the SPI is disabled. | ||
| 248 | |||
| 249 | -- NSS output disabled (SSM = 0, SSOE = 0) | ||
| 250 | This configuration allows multimaster capability for devices operating in master | ||
| 251 | mode. For devices set as slave, the NSS pin acts as a classical NSS input: the | ||
| 252 | slave is selected when NSS is low and deselected when NSS high | ||
| 253 | */ | ||
| 254 | let ssm = self.nss.is_none(); | ||
| 219 | 255 | ||
| 220 | let regs = self.info.regs; | 256 | let regs = self.info.regs; |
| 221 | #[cfg(any(spi_v1, spi_v2))] | 257 | #[cfg(any(spi_v1, spi_v2))] |
| 222 | { | 258 | { |
| 259 | let ssoe = CM::MASTER == vals::Mstr::MASTER && !config.nss_output_disable; | ||
| 223 | regs.cr2().modify(|w| { | 260 | regs.cr2().modify(|w| { |
| 224 | w.set_ssoe(false); | 261 | w.set_ssoe(ssoe); |
| 225 | }); | 262 | }); |
| 226 | regs.cr1().modify(|w| { | 263 | regs.cr1().modify(|w| { |
| 227 | w.set_cpha(cpha); | 264 | w.set_cpha(cpha); |
| @@ -232,7 +269,7 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 232 | w.set_spe(true); | 269 | w.set_spe(true); |
| 233 | w.set_lsbfirst(lsbfirst); | 270 | w.set_lsbfirst(lsbfirst); |
| 234 | w.set_ssi(CM::MASTER == vals::Mstr::MASTER); | 271 | w.set_ssi(CM::MASTER == vals::Mstr::MASTER); |
| 235 | w.set_ssm(CM::MASTER == vals::Mstr::MASTER); | 272 | w.set_ssm(ssm); |
| 236 | w.set_crcen(false); | 273 | w.set_crcen(false); |
| 237 | w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); | 274 | w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); |
| 238 | // we're doing "fake rxonly", by actually writing one | 275 | // we're doing "fake rxonly", by actually writing one |
| @@ -244,11 +281,12 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 244 | } | 281 | } |
| 245 | #[cfg(spi_v3)] | 282 | #[cfg(spi_v3)] |
| 246 | { | 283 | { |
| 284 | let ssoe = CM::MASTER == vals::Mstr::MASTER && !config.nss_output_disable; | ||
| 247 | regs.cr2().modify(|w| { | 285 | regs.cr2().modify(|w| { |
| 248 | let (ds, frxth) = <u8 as SealedWord>::CONFIG; | 286 | let (ds, frxth) = <u8 as SealedWord>::CONFIG; |
| 249 | w.set_frxth(frxth); | 287 | w.set_frxth(frxth); |
| 250 | w.set_ds(ds); | 288 | w.set_ds(ds); |
| 251 | w.set_ssoe(false); | 289 | w.set_ssoe(ssoe); |
| 252 | }); | 290 | }); |
| 253 | regs.cr1().modify(|w| { | 291 | regs.cr1().modify(|w| { |
| 254 | w.set_cpha(cpha); | 292 | w.set_cpha(cpha); |
| @@ -258,7 +296,7 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 258 | w.set_br(br); | 296 | w.set_br(br); |
| 259 | w.set_lsbfirst(lsbfirst); | 297 | w.set_lsbfirst(lsbfirst); |
| 260 | w.set_ssi(CM::MASTER == vals::Mstr::MASTER); | 298 | w.set_ssi(CM::MASTER == vals::Mstr::MASTER); |
| 261 | w.set_ssm(CM::MASTER == vals::Mstr::MASTER); | 299 | w.set_ssm(ssm); |
| 262 | w.set_crcen(false); | 300 | w.set_crcen(false); |
| 263 | w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); | 301 | w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); |
| 264 | w.set_spe(true); | 302 | w.set_spe(true); |
| @@ -266,14 +304,14 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 266 | } | 304 | } |
| 267 | #[cfg(any(spi_v4, spi_v5, spi_v6))] | 305 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 268 | { | 306 | { |
| 307 | let ssoe = CM::MASTER == vals::Master::MASTER && !config.nss_output_disable; | ||
| 269 | regs.ifcr().write(|w| w.0 = 0xffff_ffff); | 308 | regs.ifcr().write(|w| w.0 = 0xffff_ffff); |
| 270 | regs.cfg2().modify(|w| { | 309 | regs.cfg2().modify(|w| { |
| 271 | //w.set_ssoe(true); | 310 | w.set_ssoe(ssoe); |
| 272 | w.set_ssoe(false); | ||
| 273 | w.set_cpha(cpha); | 311 | w.set_cpha(cpha); |
| 274 | w.set_cpol(cpol); | 312 | w.set_cpol(cpol); |
| 275 | w.set_lsbfirst(lsbfirst); | 313 | w.set_lsbfirst(lsbfirst); |
| 276 | w.set_ssm(CM::MASTER == vals::Master::MASTER); | 314 | w.set_ssm(ssm); |
| 277 | w.set_master(CM::MASTER); | 315 | w.set_master(CM::MASTER); |
| 278 | w.set_comm(vals::Comm::FULL_DUPLEX); | 316 | w.set_comm(vals::Comm::FULL_DUPLEX); |
| 279 | w.set_ssom(vals::Ssom::ASSERTED); | 317 | w.set_ssom(vals::Ssom::ASSERTED); |
| @@ -348,6 +386,20 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 348 | Ok(()) | 386 | Ok(()) |
| 349 | } | 387 | } |
| 350 | 388 | ||
| 389 | /// Set SPI direction | ||
| 390 | #[cfg(any(spi_v1, spi_v2, spi_v3))] | ||
| 391 | pub fn set_direction(&mut self, dir: Option<Direction>) { | ||
| 392 | let (bidimode, bidioe) = match dir { | ||
| 393 | Some(Direction::Transmit) => (vals::Bidimode::BIDIRECTIONAL, vals::Bidioe::TRANSMIT), | ||
| 394 | Some(Direction::Receive) => (vals::Bidimode::BIDIRECTIONAL, vals::Bidioe::RECEIVE), | ||
| 395 | None => (vals::Bidimode::UNIDIRECTIONAL, vals::Bidioe::TRANSMIT), | ||
| 396 | }; | ||
| 397 | self.info.regs.cr1().modify(|w| { | ||
| 398 | w.set_bidimode(bidimode); | ||
| 399 | w.set_bidioe(bidioe); | ||
| 400 | }); | ||
| 401 | } | ||
| 402 | |||
| 351 | /// Get current SPI configuration. | 403 | /// Get current SPI configuration. |
| 352 | pub fn get_current_config(&self) -> Config { | 404 | pub fn get_current_config(&self) -> Config { |
| 353 | #[cfg(any(spi_v1, spi_v2, spi_v3))] | 405 | #[cfg(any(spi_v1, spi_v2, spi_v3))] |
| @@ -357,6 +409,11 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 357 | #[cfg(any(spi_v4, spi_v5, spi_v6))] | 409 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 358 | let cfg1 = self.info.regs.cfg1().read(); | 410 | let cfg1 = self.info.regs.cfg1().read(); |
| 359 | 411 | ||
| 412 | #[cfg(any(spi_v1, spi_v2, spi_v3))] | ||
| 413 | let ssoe = self.info.regs.cr2().read().ssoe(); | ||
| 414 | #[cfg(any(spi_v4, spi_v5, spi_v6))] | ||
| 415 | let ssoe = cfg.ssoe(); | ||
| 416 | |||
| 360 | let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { | 417 | let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { |
| 361 | Polarity::IdleLow | 418 | Polarity::IdleLow |
| 362 | } else { | 419 | } else { |
| @@ -386,12 +443,16 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 386 | 443 | ||
| 387 | let frequency = compute_frequency(self.kernel_clock, br); | 444 | let frequency = compute_frequency(self.kernel_clock, br); |
| 388 | 445 | ||
| 446 | // NSS output disabled if SSOE=0 or if SSM=1 software slave management enabled | ||
| 447 | let nss_output_disable = !ssoe || cfg.ssm(); | ||
| 448 | |||
| 389 | Config { | 449 | Config { |
| 390 | mode: Mode { polarity, phase }, | 450 | mode: Mode { polarity, phase }, |
| 391 | bit_order, | 451 | bit_order, |
| 392 | frequency, | 452 | frequency, |
| 393 | miso_pull, | 453 | miso_pull, |
| 394 | gpio_speed: self.gpio_speed, | 454 | gpio_speed: self.gpio_speed, |
| 455 | nss_output_disable, | ||
| 395 | } | 456 | } |
| 396 | } | 457 | } |
| 397 | 458 | ||
| @@ -708,6 +769,30 @@ impl<'d> Spi<'d, Async, Master> { | |||
| 708 | ) | 769 | ) |
| 709 | } | 770 | } |
| 710 | 771 | ||
| 772 | /// Create a new SPI driver, in bidirectional mode, specifically in tranmit mode | ||
| 773 | #[cfg(any(spi_v1, spi_v2, spi_v3))] | ||
| 774 | pub fn new_bidi<T: Instance, #[cfg(afio)] A>( | ||
| 775 | peri: Peri<'d, T>, | ||
| 776 | sck: Peri<'d, if_afio!(impl SckPin<T, A>)>, | ||
| 777 | sdio: Peri<'d, if_afio!(impl MosiPin<T, A>)>, | ||
| 778 | tx_dma: Peri<'d, impl TxDma<T>>, | ||
| 779 | rx_dma: Peri<'d, impl RxDma<T>>, | ||
| 780 | config: Config, | ||
| 781 | ) -> Self { | ||
| 782 | let mut this = Self::new_inner( | ||
| 783 | peri, | ||
| 784 | new_pin!(sck, config.sck_af()), | ||
| 785 | new_pin!(sdio, AfType::output(OutputType::PushPull, config.gpio_speed)), | ||
| 786 | None, | ||
| 787 | None, | ||
| 788 | new_dma!(tx_dma), | ||
| 789 | new_dma!(rx_dma), | ||
| 790 | config, | ||
| 791 | ); | ||
| 792 | this.set_direction(Some(Direction::Transmit)); | ||
| 793 | this | ||
| 794 | } | ||
| 795 | |||
| 711 | /// Create a new SPI driver, in TX-only mode, without SCK pin. | 796 | /// Create a new SPI driver, in TX-only mode, without SCK pin. |
| 712 | /// | 797 | /// |
| 713 | /// This can be useful for bit-banging non-SPI protocols. | 798 | /// This can be useful for bit-banging non-SPI protocols. |
| @@ -763,6 +848,7 @@ impl<'d> Spi<'d, Async, Master> { | |||
| 763 | impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> { | 848 | impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> { |
| 764 | /// SPI write, using DMA. | 849 | /// SPI write, using DMA. |
| 765 | pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> { | 850 | pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> { |
| 851 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 766 | if data.is_empty() { | 852 | if data.is_empty() { |
| 767 | return Ok(()); | 853 | return Ok(()); |
| 768 | } | 854 | } |
| @@ -794,6 +880,7 @@ impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> { | |||
| 794 | /// SPI read, using DMA. | 880 | /// SPI read, using DMA. |
| 795 | #[cfg(any(spi_v4, spi_v5, spi_v6))] | 881 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 796 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { | 882 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { |
| 883 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 797 | if data.is_empty() { | 884 | if data.is_empty() { |
| 798 | return Ok(()); | 885 | return Ok(()); |
| 799 | } | 886 | } |
| @@ -881,6 +968,7 @@ impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> { | |||
| 881 | /// SPI read, using DMA. | 968 | /// SPI read, using DMA. |
| 882 | #[cfg(any(spi_v1, spi_v2, spi_v3))] | 969 | #[cfg(any(spi_v1, spi_v2, spi_v3))] |
| 883 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { | 970 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { |
| 971 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 884 | if data.is_empty() { | 972 | if data.is_empty() { |
| 885 | return Ok(()); | 973 | return Ok(()); |
| 886 | } | 974 | } |
| @@ -928,6 +1016,7 @@ impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> { | |||
| 928 | } | 1016 | } |
| 929 | 1017 | ||
| 930 | async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> { | 1018 | async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> { |
| 1019 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 931 | assert_eq!(read.len(), write.len()); | 1020 | assert_eq!(read.len(), write.len()); |
| 932 | if read.len() == 0 { | 1021 | if read.len() == 0 { |
| 933 | return Ok(()); | 1022 | return Ok(()); |
| @@ -979,6 +1068,8 @@ impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> { | |||
| 979 | /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. | 1068 | /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. |
| 980 | /// If `write` is shorter it is padded with zero bytes. | 1069 | /// If `write` is shorter it is padded with zero bytes. |
| 981 | pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { | 1070 | pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { |
| 1071 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1072 | |||
| 982 | self.transfer_inner(read, write).await | 1073 | self.transfer_inner(read, write).await |
| 983 | } | 1074 | } |
| 984 | 1075 | ||
| @@ -986,6 +1077,8 @@ impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> { | |||
| 986 | /// | 1077 | /// |
| 987 | /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. | 1078 | /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. |
| 988 | pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { | 1079 | pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { |
| 1080 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1081 | |||
| 989 | self.transfer_inner(data, data).await | 1082 | self.transfer_inner(data, data).await |
| 990 | } | 1083 | } |
| 991 | } | 1084 | } |
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs index 532877f70..88a28ee3d 100644 --- a/embassy-stm32/src/time.rs +++ b/embassy-stm32/src/time.rs | |||
| @@ -4,7 +4,7 @@ use core::fmt::Display; | |||
| 4 | use core::ops::{Div, Mul}; | 4 | use core::ops::{Div, Mul}; |
| 5 | 5 | ||
| 6 | /// Hertz | 6 | /// Hertz |
| 7 | #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] | 7 | #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default)] |
| 8 | pub struct Hertz(pub u32); | 8 | pub struct Hertz(pub u32); |
| 9 | 9 | ||
| 10 | impl Display for Hertz { | 10 | impl Display for Hertz { |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index cfcf5f3fd..ed5d902bd 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -329,6 +329,12 @@ impl RtcDriver { | |||
| 329 | regs_gp16().cr1().modify(|w| w.set_cen(true)); | 329 | regs_gp16().cr1().modify(|w| w.set_cen(true)); |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | #[cfg(feature = "low-power")] | ||
| 333 | /// Returns whether time is currently stopped | ||
| 334 | pub(crate) fn is_stopped(&self) -> bool { | ||
| 335 | !regs_gp16().cr1().read().cen() | ||
| 336 | } | ||
| 337 | |||
| 332 | fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { | 338 | fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { |
| 333 | let r = regs_gp16(); | 339 | let r = regs_gp16(); |
| 334 | 340 | ||
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 77f19a37b..620d7858e 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -2,16 +2,17 @@ | |||
| 2 | 2 | ||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | 4 | ||
| 5 | pub use stm32_metapac::timer::vals::{Ckd, Mms2, Ossi, Ossr}; | ||
| 6 | |||
| 7 | use super::low_level::{CountingMode, OutputPolarity, Timer}; | 5 | use super::low_level::{CountingMode, OutputPolarity, Timer}; |
| 8 | use super::simple_pwm::PwmPin; | 6 | use super::simple_pwm::PwmPin; |
| 9 | use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; | 7 | use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; |
| 10 | use crate::Peri; | 8 | use crate::Peri; |
| 11 | use crate::gpio::{AnyPin, OutputType}; | 9 | use crate::dma::word::Word; |
| 10 | use crate::gpio::{AfType, AnyPin, OutputType}; | ||
| 11 | pub use crate::pac::timer::vals::{Ccds, Ckd, Mms2, Ossi, Ossr}; | ||
| 12 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 13 | use crate::timer::TimerChannel; | 13 | use crate::timer::TimerChannel; |
| 14 | use crate::timer::low_level::OutputCompareMode; | 14 | use crate::timer::low_level::OutputCompareMode; |
| 15 | use crate::timer::simple_pwm::PwmPinConfig; | ||
| 15 | 16 | ||
| 16 | /// Complementary PWM pin wrapper. | 17 | /// Complementary PWM pin wrapper. |
| 17 | /// | 18 | /// |
| @@ -27,9 +28,27 @@ impl<'d, T: AdvancedInstance4Channel, C: TimerChannel, #[cfg(afio)] A> if_afio!( | |||
| 27 | pub fn new(pin: Peri<'d, if_afio!(impl TimerComplementaryPin<T, C, A>)>, output_type: OutputType) -> Self { | 28 | pub fn new(pin: Peri<'d, if_afio!(impl TimerComplementaryPin<T, C, A>)>, output_type: OutputType) -> Self { |
| 28 | critical_section::with(|_| { | 29 | critical_section::with(|_| { |
| 29 | pin.set_low(); | 30 | pin.set_low(); |
| 30 | set_as_af!( | 31 | set_as_af!(pin, AfType::output(output_type, crate::gpio::Speed::VeryHigh)); |
| 31 | pin, | 32 | }); |
| 32 | crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh) | 33 | ComplementaryPwmPin { |
| 34 | pin: pin.into(), | ||
| 35 | phantom: PhantomData, | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | /// Create a new PWM pin instance with config. | ||
| 40 | pub fn new_with_config( | ||
| 41 | pin: Peri<'d, if_afio!(impl TimerComplementaryPin<T, C, A>)>, | ||
| 42 | pin_config: PwmPinConfig, | ||
| 43 | ) -> Self { | ||
| 44 | critical_section::with(|_| { | ||
| 45 | pin.set_low(); | ||
| 46 | #[cfg(gpio_v1)] | ||
| 47 | set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed)); | ||
| 48 | #[cfg(gpio_v2)] | ||
| 49 | pin.set_as_af( | ||
| 50 | pin.af_num(), | ||
| 51 | AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), | ||
| 33 | ); | 52 | ); |
| 34 | }); | 53 | }); |
| 35 | ComplementaryPwmPin { | 54 | ComplementaryPwmPin { |
| @@ -176,20 +195,20 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 176 | /// Get max duty value. | 195 | /// Get max duty value. |
| 177 | /// | 196 | /// |
| 178 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 197 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 179 | pub fn get_max_duty(&self) -> u16 { | 198 | pub fn get_max_duty(&self) -> u32 { |
| 180 | if self.inner.get_counting_mode().is_center_aligned() { | 199 | if self.inner.get_counting_mode().is_center_aligned() { |
| 181 | self.inner.get_max_compare_value() as u16 | 200 | self.inner.get_max_compare_value().into() |
| 182 | } else { | 201 | } else { |
| 183 | self.inner.get_max_compare_value() as u16 + 1 | 202 | self.inner.get_max_compare_value().into() + 1 |
| 184 | } | 203 | } |
| 185 | } | 204 | } |
| 186 | 205 | ||
| 187 | /// Set the duty for a given channel. | 206 | /// Set the duty for a given channel. |
| 188 | /// | 207 | /// |
| 189 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | 208 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. |
| 190 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 209 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { |
| 191 | assert!(duty <= self.get_max_duty()); | 210 | assert!(duty <= self.get_max_duty()); |
| 192 | self.inner.set_compare_value(channel, duty as _) | 211 | self.inner.set_compare_value(channel, unwrap!(duty.try_into())) |
| 193 | } | 212 | } |
| 194 | 213 | ||
| 195 | /// Set the output polarity for a given channel. | 214 | /// Set the output polarity for a given channel. |
| @@ -219,9 +238,34 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 219 | /// Generate a sequence of PWM waveform | 238 | /// Generate a sequence of PWM waveform |
| 220 | /// | 239 | /// |
| 221 | /// Note: | 240 | /// Note: |
| 241 | /// The DMA channel provided does not need to correspond to the requested channel. | ||
| 242 | pub async fn waveform<C: TimerChannel, W: Word + Into<T::Word>>( | ||
| 243 | &mut self, | ||
| 244 | dma: Peri<'_, impl super::Dma<T, C>>, | ||
| 245 | channel: Channel, | ||
| 246 | duty: &[W], | ||
| 247 | ) { | ||
| 248 | self.inner.enable_channel(channel, true); | ||
| 249 | self.inner.enable_channel(C::CHANNEL, true); | ||
| 250 | self.inner.clamp_compare_value::<W>(channel); | ||
| 251 | self.inner.set_cc_dma_selection(Ccds::ON_UPDATE); | ||
| 252 | self.inner.set_cc_dma_enable_state(C::CHANNEL, true); | ||
| 253 | self.inner.setup_channel_update_dma(dma, channel, duty).await; | ||
| 254 | self.inner.set_cc_dma_enable_state(C::CHANNEL, false); | ||
| 255 | } | ||
| 256 | |||
| 257 | /// Generate a sequence of PWM waveform | ||
| 258 | /// | ||
| 259 | /// Note: | ||
| 222 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. | 260 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. |
| 223 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { | 261 | pub async fn waveform_up<W: Word + Into<T::Word>>( |
| 262 | &mut self, | ||
| 263 | dma: Peri<'_, impl super::UpDma<T>>, | ||
| 264 | channel: Channel, | ||
| 265 | duty: &[W], | ||
| 266 | ) { | ||
| 224 | self.inner.enable_channel(channel, true); | 267 | self.inner.enable_channel(channel, true); |
| 268 | self.inner.clamp_compare_value::<W>(channel); | ||
| 225 | self.inner.enable_update_dma(true); | 269 | self.inner.enable_update_dma(true); |
| 226 | self.inner.setup_update_dma(dma, channel, duty).await; | 270 | self.inner.setup_update_dma(dma, channel, duty).await; |
| 227 | self.inner.enable_update_dma(false); | 271 | self.inner.enable_update_dma(false); |
| @@ -256,13 +300,21 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 256 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 300 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 257 | /// switch this timer by using `time-driver-timX` feature. | 301 | /// switch this timer by using `time-driver-timX` feature. |
| 258 | /// | 302 | /// |
| 259 | pub async fn waveform_up_multi_channel( | 303 | pub async fn waveform_up_multi_channel<W: Word + Into<T::Word>>( |
| 260 | &mut self, | 304 | &mut self, |
| 261 | dma: Peri<'_, impl super::UpDma<T>>, | 305 | dma: Peri<'_, impl super::UpDma<T>>, |
| 262 | starting_channel: Channel, | 306 | starting_channel: Channel, |
| 263 | ending_channel: Channel, | 307 | ending_channel: Channel, |
| 264 | duty: &[u16], | 308 | duty: &[W], |
| 265 | ) { | 309 | ) { |
| 310 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | ||
| 311 | .iter() | ||
| 312 | .filter(|ch| ch.index() >= starting_channel.index()) | ||
| 313 | .filter(|ch| ch.index() <= ending_channel.index()) | ||
| 314 | .for_each(|ch| { | ||
| 315 | self.inner.enable_channel(*ch, true); | ||
| 316 | self.inner.clamp_compare_value::<W>(*ch); | ||
| 317 | }); | ||
| 266 | self.inner.enable_update_dma(true); | 318 | self.inner.enable_update_dma(true); |
| 267 | self.inner | 319 | self.inner |
| 268 | .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) | 320 | .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) |
| @@ -291,20 +343,20 @@ impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm< | |||
| 291 | } | 343 | } |
| 292 | 344 | ||
| 293 | fn get_duty(&self, channel: Self::Channel) -> Self::Duty { | 345 | fn get_duty(&self, channel: Self::Channel) -> Self::Duty { |
| 294 | self.inner.get_compare_value(channel) as u16 | 346 | unwrap!(self.inner.get_compare_value(channel).try_into()) |
| 295 | } | 347 | } |
| 296 | 348 | ||
| 297 | fn get_max_duty(&self) -> Self::Duty { | 349 | fn get_max_duty(&self) -> Self::Duty { |
| 298 | if self.inner.get_counting_mode().is_center_aligned() { | 350 | if self.inner.get_counting_mode().is_center_aligned() { |
| 299 | self.inner.get_max_compare_value() as u16 | 351 | unwrap!(self.inner.get_max_compare_value().try_into()) |
| 300 | } else { | 352 | } else { |
| 301 | self.inner.get_max_compare_value() as u16 + 1 | 353 | unwrap!(self.inner.get_max_compare_value().try_into()) + 1 |
| 302 | } | 354 | } |
| 303 | } | 355 | } |
| 304 | 356 | ||
| 305 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { | 357 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { |
| 306 | assert!(duty <= self.get_max_duty()); | 358 | assert!(duty <= unwrap!(self.get_max_duty().try_into())); |
| 307 | self.inner.set_compare_value(channel, duty as u32) | 359 | self.inner.set_compare_value(channel, unwrap!(duty.try_into())) |
| 308 | } | 360 | } |
| 309 | 361 | ||
| 310 | fn set_period<P>(&mut self, period: P) | 362 | fn set_period<P>(&mut self, period: P) |
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index 9cf0f8c34..3e1482b67 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs | |||
| @@ -97,7 +97,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { | |||
| 97 | 97 | ||
| 98 | /// Get capture value for a channel. | 98 | /// Get capture value for a channel. |
| 99 | pub fn get_capture_value(&self, channel: Channel) -> u32 { | 99 | pub fn get_capture_value(&self, channel: Channel) -> u32 { |
| 100 | self.inner.get_capture_value(channel) | 100 | self.inner.get_capture_value(channel).into() |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /// Get input interrupt. | 103 | /// Get input interrupt. |
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index aba08081f..82e936f3a 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -13,7 +13,7 @@ use embassy_hal_internal::Peri; | |||
| 13 | pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource}; | 13 | pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource}; |
| 14 | 14 | ||
| 15 | use super::*; | 15 | use super::*; |
| 16 | use crate::dma::{Transfer, WritableRingBuffer}; | 16 | use crate::dma::{self, Transfer, WritableRingBuffer}; |
| 17 | use crate::pac::timer::vals; | 17 | use crate::pac::timer::vals; |
| 18 | use crate::rcc; | 18 | use crate::rcc; |
| 19 | use crate::time::Hertz; | 19 | use crate::time::Hertz; |
| @@ -268,6 +268,11 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 268 | unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } | 268 | unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | #[cfg(stm32l0)] | ||
| 272 | fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp16 { | ||
| 273 | unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) } | ||
| 274 | } | ||
| 275 | |||
| 271 | /// Start the timer. | 276 | /// Start the timer. |
| 272 | pub fn start(&self) { | 277 | pub fn start(&self) { |
| 273 | self.regs_core().cr1().modify(|r| r.set_cen(true)); | 278 | self.regs_core().cr1().modify(|r| r.set_cen(true)); |
| @@ -296,7 +301,12 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 296 | 301 | ||
| 297 | /// get the capability of the timer | 302 | /// get the capability of the timer |
| 298 | pub fn bits(&self) -> TimerBits { | 303 | pub fn bits(&self) -> TimerBits { |
| 299 | T::BITS | 304 | match T::Word::bits() { |
| 305 | 16 => TimerBits::Bits16, | ||
| 306 | #[cfg(not(stm32l0))] | ||
| 307 | 32 => TimerBits::Bits32, | ||
| 308 | _ => unreachable!(), | ||
| 309 | } | ||
| 300 | } | 310 | } |
| 301 | 311 | ||
| 302 | /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. | 312 | /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. |
| @@ -306,18 +316,10 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 306 | /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved | 316 | /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved |
| 307 | /// because it needs to count up and down. | 317 | /// because it needs to count up and down. |
| 308 | pub fn set_frequency(&self, frequency: Hertz) { | 318 | pub fn set_frequency(&self, frequency: Hertz) { |
| 309 | match T::BITS { | 319 | self.set_frequency_internal(frequency, T::Word::bits()); |
| 310 | TimerBits::Bits16 => { | ||
| 311 | self.set_frequency_internal(frequency, 16); | ||
| 312 | } | ||
| 313 | #[cfg(not(stm32l0))] | ||
| 314 | TimerBits::Bits32 => { | ||
| 315 | self.set_frequency_internal(frequency, 32); | ||
| 316 | } | ||
| 317 | } | ||
| 318 | } | 320 | } |
| 319 | 321 | ||
| 320 | pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) { | 322 | pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: usize) { |
| 321 | let f = frequency.0; | 323 | let f = frequency.0; |
| 322 | assert!(f > 0); | 324 | assert!(f > 0); |
| 323 | let timer_f = T::frequency().0; | 325 | let timer_f = T::frequency().0; |
| @@ -326,25 +328,15 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 326 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into()); | 328 | let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into()); |
| 327 | let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1); | 329 | let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1); |
| 328 | 330 | ||
| 329 | match T::BITS { | 331 | // the timer counts `0..=arr`, we want it to count `0..divide_by` |
| 330 | TimerBits::Bits16 => { | 332 | let arr: T::Word = unwrap!(T::Word::try_from(divide_by - 1)); |
| 331 | // the timer counts `0..=arr`, we want it to count `0..divide_by` | ||
| 332 | let arr = unwrap!(u16::try_from(divide_by - 1)); | ||
| 333 | |||
| 334 | let regs = self.regs_core(); | ||
| 335 | regs.psc().write_value(psc); | ||
| 336 | regs.arr().write(|r| r.set_arr(arr)); | ||
| 337 | } | ||
| 338 | #[cfg(not(stm32l0))] | ||
| 339 | TimerBits::Bits32 => { | ||
| 340 | // the timer counts `0..=arr`, we want it to count `0..divide_by` | ||
| 341 | let arr: u32 = unwrap!(u32::try_from(divide_by - 1)); | ||
| 342 | 333 | ||
| 343 | let regs = self.regs_gp32_unchecked(); | 334 | let regs = self.regs_gp32_unchecked(); |
| 344 | regs.psc().write_value(psc); | 335 | regs.psc().write_value(psc); |
| 345 | regs.arr().write_value(arr); | 336 | #[cfg(stm32l0)] |
| 346 | } | 337 | regs.arr().write(|r| r.set_arr(unwrap!(arr.try_into()))); |
| 347 | } | 338 | #[cfg(not(stm32l0))] |
| 339 | regs.arr().write_value(arr.into()); | ||
| 348 | } | 340 | } |
| 349 | 341 | ||
| 350 | /// Set tick frequency. | 342 | /// Set tick frequency. |
| @@ -393,23 +385,14 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 393 | pub fn get_frequency(&self) -> Hertz { | 385 | pub fn get_frequency(&self) -> Hertz { |
| 394 | let timer_f = T::frequency(); | 386 | let timer_f = T::frequency(); |
| 395 | 387 | ||
| 396 | match T::BITS { | 388 | let regs = self.regs_gp32_unchecked(); |
| 397 | TimerBits::Bits16 => { | 389 | #[cfg(not(stm32l0))] |
| 398 | let regs = self.regs_core(); | 390 | let arr = regs.arr().read(); |
| 399 | let arr = regs.arr().read().arr(); | 391 | #[cfg(stm32l0)] |
| 400 | let psc = regs.psc().read(); | 392 | let arr = regs.arr().read().arr(); |
| 393 | let psc = regs.psc().read(); | ||
| 401 | 394 | ||
| 402 | timer_f / arr / (psc + 1) | 395 | timer_f / arr / (psc + 1) |
| 403 | } | ||
| 404 | #[cfg(not(stm32l0))] | ||
| 405 | TimerBits::Bits32 => { | ||
| 406 | let regs = self.regs_gp32_unchecked(); | ||
| 407 | let arr = regs.arr().read(); | ||
| 408 | let psc = regs.psc().read(); | ||
| 409 | |||
| 410 | timer_f / arr / (psc + 1) | ||
| 411 | } | ||
| 412 | } | ||
| 413 | } | 396 | } |
| 414 | 397 | ||
| 415 | /// Get the clock frequency of the timer (before prescaler is applied). | 398 | /// Get the clock frequency of the timer (before prescaler is applied). |
| @@ -469,42 +452,29 @@ impl<'d, T: GeneralInstance1Channel> Timer<'d, T> { | |||
| 469 | } | 452 | } |
| 470 | 453 | ||
| 471 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | 454 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. |
| 472 | pub fn get_max_compare_value(&self) -> u32 { | 455 | pub fn get_max_compare_value(&self) -> T::Word { |
| 473 | match T::BITS { | 456 | #[cfg(not(stm32l0))] |
| 474 | TimerBits::Bits16 => self.regs_1ch().arr().read().arr() as u32, | 457 | return unwrap!(self.regs_gp32_unchecked().arr().read().try_into()); |
| 475 | #[cfg(not(stm32l0))] | 458 | #[cfg(stm32l0)] |
| 476 | TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(), | 459 | return unwrap!(self.regs_gp32_unchecked().arr().read().arr().try_into()); |
| 477 | } | ||
| 478 | } | 460 | } |
| 479 | 461 | ||
| 480 | /// Set the max compare value. | 462 | /// Set the max compare value. |
| 481 | /// | 463 | /// |
| 482 | /// An update event is generated to load the new value. The update event is | 464 | /// An update event is generated to load the new value. The update event is |
| 483 | /// generated such that it will not cause an interrupt or DMA request. | 465 | /// generated such that it will not cause an interrupt or DMA request. |
| 484 | pub fn set_max_compare_value(&self, ticks: u32) { | 466 | pub fn set_max_compare_value(&self, ticks: T::Word) { |
| 485 | match T::BITS { | 467 | let arr = ticks; |
| 486 | TimerBits::Bits16 => { | ||
| 487 | let arr = unwrap!(u16::try_from(ticks)); | ||
| 488 | 468 | ||
| 489 | let regs = self.regs_1ch(); | 469 | let regs = self.regs_gp32_unchecked(); |
| 490 | regs.arr().write(|r| r.set_arr(arr)); | 470 | #[cfg(not(stm32l0))] |
| 471 | regs.arr().write_value(arr.into()); | ||
| 472 | #[cfg(stm32l0)] | ||
| 473 | regs.arr().write(|r| r.set_arr(unwrap!(arr.try_into()))); | ||
| 491 | 474 | ||
| 492 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); | 475 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); |
| 493 | regs.egr().write(|r| r.set_ug(true)); | 476 | regs.egr().write(|r| r.set_ug(true)); |
| 494 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); | 477 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); |
| 495 | } | ||
| 496 | #[cfg(not(stm32l0))] | ||
| 497 | TimerBits::Bits32 => { | ||
| 498 | let arr = ticks; | ||
| 499 | |||
| 500 | let regs = self.regs_gp32_unchecked(); | ||
| 501 | regs.arr().write_value(arr); | ||
| 502 | |||
| 503 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); | ||
| 504 | regs.egr().write(|r| r.set_ug(true)); | ||
| 505 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); | ||
| 506 | } | ||
| 507 | } | ||
| 508 | } | 478 | } |
| 509 | } | 479 | } |
| 510 | 480 | ||
| @@ -638,35 +608,44 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 638 | } | 608 | } |
| 639 | 609 | ||
| 640 | /// Set compare value for a channel. | 610 | /// Set compare value for a channel. |
| 641 | pub fn set_compare_value(&self, channel: Channel, value: u32) { | 611 | pub fn set_compare_value(&self, channel: Channel, value: T::Word) { |
| 642 | match T::BITS { | 612 | #[cfg(not(stm32l0))] |
| 643 | TimerBits::Bits16 => { | 613 | self.regs_gp32_unchecked() |
| 644 | let value = unwrap!(u16::try_from(value)); | 614 | .ccr(channel.index()) |
| 645 | self.regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); | 615 | .write_value(value.into()); |
| 646 | } | 616 | #[cfg(stm32l0)] |
| 647 | #[cfg(not(stm32l0))] | 617 | self.regs_gp16() |
| 648 | TimerBits::Bits32 => { | 618 | .ccr(channel.index()) |
| 649 | self.regs_gp32_unchecked().ccr(channel.index()).write_value(value); | 619 | .modify(|w| w.set_ccr(unwrap!(value.try_into()))); |
| 650 | } | ||
| 651 | } | ||
| 652 | } | 620 | } |
| 653 | 621 | ||
| 654 | /// Get compare value for a channel. | 622 | /// Get compare value for a channel. |
| 655 | pub fn get_compare_value(&self, channel: Channel) -> u32 { | 623 | pub fn get_compare_value(&self, channel: Channel) -> T::Word { |
| 656 | match T::BITS { | 624 | #[cfg(not(stm32l0))] |
| 657 | TimerBits::Bits16 => self.regs_gp16().ccr(channel.index()).read().ccr() as u32, | 625 | return unwrap!(self.regs_gp32_unchecked().ccr(channel.index()).read().try_into()); |
| 658 | #[cfg(not(stm32l0))] | 626 | #[cfg(stm32l0)] |
| 659 | TimerBits::Bits32 => self.regs_gp32_unchecked().ccr(channel.index()).read(), | 627 | return unwrap!(self.regs_gp32_unchecked().ccr(channel.index()).read().ccr().try_into()); |
| 660 | } | 628 | } |
| 629 | |||
| 630 | pub(crate) fn clamp_compare_value<W: Word>(&mut self, channel: Channel) { | ||
| 631 | self.set_compare_value( | ||
| 632 | channel, | ||
| 633 | unwrap!( | ||
| 634 | self.get_compare_value(channel) | ||
| 635 | .into() | ||
| 636 | .clamp(0, W::max() as u32) | ||
| 637 | .try_into() | ||
| 638 | ), | ||
| 639 | ); | ||
| 661 | } | 640 | } |
| 662 | 641 | ||
| 663 | /// Setup a ring buffer for the channel | 642 | /// Setup a ring buffer for the channel |
| 664 | pub fn setup_ring_buffer<'a>( | 643 | pub fn setup_ring_buffer<'a, W: Word + Into<T::Word>>( |
| 665 | &mut self, | 644 | &mut self, |
| 666 | dma: Peri<'a, impl super::UpDma<T>>, | 645 | dma: Peri<'a, impl super::UpDma<T>>, |
| 667 | channel: Channel, | 646 | channel: Channel, |
| 668 | dma_buf: &'a mut [u16], | 647 | dma_buf: &'a mut [W], |
| 669 | ) -> WritableRingBuffer<'a, u16> { | 648 | ) -> WritableRingBuffer<'a, W> { |
| 670 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 649 | #[allow(clippy::let_unit_value)] // eg. stm32f334 |
| 671 | let req = dma.request(); | 650 | let req = dma.request(); |
| 672 | 651 | ||
| @@ -686,7 +665,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 686 | WritableRingBuffer::new( | 665 | WritableRingBuffer::new( |
| 687 | dma, | 666 | dma, |
| 688 | req, | 667 | req, |
| 689 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, | 668 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut W, |
| 690 | dma_buf, | 669 | dma_buf, |
| 691 | dma_transfer_option, | 670 | dma_transfer_option, |
| 692 | ) | 671 | ) |
| @@ -697,15 +676,35 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 697 | /// | 676 | /// |
| 698 | /// Note: | 677 | /// Note: |
| 699 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. | 678 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. |
| 700 | pub fn setup_update_dma<'a>( | 679 | pub fn setup_update_dma<'a, W: Word + Into<T::Word>>( |
| 701 | &mut self, | 680 | &mut self, |
| 702 | dma: Peri<'a, impl super::UpDma<T>>, | 681 | dma: Peri<'a, impl super::UpDma<T>>, |
| 703 | channel: Channel, | 682 | channel: Channel, |
| 704 | duty: &'a [u16], | 683 | duty: &'a [W], |
| 705 | ) -> Transfer<'a> { | 684 | ) -> Transfer<'a> { |
| 706 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 685 | self.setup_update_dma_inner(dma.request(), dma, channel, duty) |
| 707 | let req = dma.request(); | 686 | } |
| 708 | 687 | ||
| 688 | /// Generate a sequence of PWM waveform | ||
| 689 | /// | ||
| 690 | /// Note: | ||
| 691 | /// The DMA channel provided does not need to correspond to the requested channel. | ||
| 692 | pub fn setup_channel_update_dma<'a, C: TimerChannel, W: Word + Into<T::Word>>( | ||
| 693 | &mut self, | ||
| 694 | dma: Peri<'a, impl super::Dma<T, C>>, | ||
| 695 | channel: Channel, | ||
| 696 | duty: &'a [W], | ||
| 697 | ) -> Transfer<'a> { | ||
| 698 | self.setup_update_dma_inner(dma.request(), dma, channel, duty) | ||
| 699 | } | ||
| 700 | |||
| 701 | fn setup_update_dma_inner<'a, W: Word + Into<T::Word>>( | ||
| 702 | &mut self, | ||
| 703 | request: dma::Request, | ||
| 704 | dma: Peri<'a, impl dma::Channel>, | ||
| 705 | channel: Channel, | ||
| 706 | duty: &'a [W], | ||
| 707 | ) -> Transfer<'a> { | ||
| 709 | unsafe { | 708 | unsafe { |
| 710 | #[cfg(not(any(bdma, gpdma)))] | 709 | #[cfg(not(any(bdma, gpdma)))] |
| 711 | use crate::dma::{Burst, FifoThreshold}; | 710 | use crate::dma::{Burst, FifoThreshold}; |
| @@ -719,29 +718,13 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 719 | ..Default::default() | 718 | ..Default::default() |
| 720 | }; | 719 | }; |
| 721 | 720 | ||
| 722 | match self.bits() { | 721 | Transfer::new_write( |
| 723 | TimerBits::Bits16 => Transfer::new_write( | 722 | dma, |
| 724 | dma, | 723 | request, |
| 725 | req, | 724 | duty, |
| 726 | duty, | 725 | self.regs_gp16().ccr(channel.index()).as_ptr() as *mut W, |
| 727 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, | 726 | dma_transfer_option, |
| 728 | dma_transfer_option, | 727 | ) |
| 729 | ), | ||
| 730 | #[cfg(not(any(stm32l0)))] | ||
| 731 | TimerBits::Bits32 => { | ||
| 732 | #[cfg(not(any(bdma, gpdma)))] | ||
| 733 | panic!("unsupported timer bits"); | ||
| 734 | |||
| 735 | #[cfg(any(bdma, gpdma))] | ||
| 736 | Transfer::new_write( | ||
| 737 | dma, | ||
| 738 | req, | ||
| 739 | duty, | ||
| 740 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32, | ||
| 741 | dma_transfer_option, | ||
| 742 | ) | ||
| 743 | } | ||
| 744 | } | ||
| 745 | } | 728 | } |
| 746 | } | 729 | } |
| 747 | 730 | ||
| @@ -774,12 +757,12 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 774 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 757 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 775 | /// switch this timer by using `time-driver-timX` feature. | 758 | /// switch this timer by using `time-driver-timX` feature. |
| 776 | /// | 759 | /// |
| 777 | pub fn setup_update_dma_burst<'a>( | 760 | pub fn setup_update_dma_burst<'a, W: Word + Into<T::Word>>( |
| 778 | &mut self, | 761 | &mut self, |
| 779 | dma: Peri<'a, impl super::UpDma<T>>, | 762 | dma: Peri<'a, impl super::UpDma<T>>, |
| 780 | starting_channel: Channel, | 763 | starting_channel: Channel, |
| 781 | ending_channel: Channel, | 764 | ending_channel: Channel, |
| 782 | duty: &'a [u16], | 765 | duty: &'a [W], |
| 783 | ) -> Transfer<'a> { | 766 | ) -> Transfer<'a> { |
| 784 | let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; | 767 | let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; |
| 785 | let start_ch_index = starting_channel.index(); | 768 | let start_ch_index = starting_channel.index(); |
| @@ -815,14 +798,14 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 815 | dma, | 798 | dma, |
| 816 | req, | 799 | req, |
| 817 | duty, | 800 | duty, |
| 818 | self.regs_gp16().dmar().as_ptr() as *mut u16, | 801 | self.regs_gp16().dmar().as_ptr() as *mut W, |
| 819 | dma_transfer_option, | 802 | dma_transfer_option, |
| 820 | ) | 803 | ) |
| 821 | } | 804 | } |
| 822 | } | 805 | } |
| 823 | 806 | ||
| 824 | /// Get capture value for a channel. | 807 | /// Get capture value for a channel. |
| 825 | pub fn get_capture_value(&self, channel: Channel) -> u32 { | 808 | pub fn get_capture_value(&self, channel: Channel) -> T::Word { |
| 826 | self.get_compare_value(channel) | 809 | self.get_compare_value(channel) |
| 827 | } | 810 | } |
| 828 | 811 | ||
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 3fa363881..998e3a6f4 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -15,6 +15,8 @@ pub mod qei; | |||
| 15 | pub mod ringbuffered; | 15 | pub mod ringbuffered; |
| 16 | pub mod simple_pwm; | 16 | pub mod simple_pwm; |
| 17 | 17 | ||
| 18 | use crate::dma::word::Word; | ||
| 19 | use crate::fmt::Debuggable; | ||
| 18 | use crate::interrupt; | 20 | use crate::interrupt; |
| 19 | use crate::rcc::RccPeripheral; | 21 | use crate::rcc::RccPeripheral; |
| 20 | 22 | ||
| @@ -163,7 +165,12 @@ pub trait CoreInstance: SealedInstance + 'static { | |||
| 163 | type UpdateInterrupt: interrupt::typelevel::Interrupt; | 165 | type UpdateInterrupt: interrupt::typelevel::Interrupt; |
| 164 | 166 | ||
| 165 | /// Amount of bits this timer has. | 167 | /// Amount of bits this timer has. |
| 166 | const BITS: TimerBits; | 168 | type Word: Word |
| 169 | + TryInto<u16, Error: Debuggable> | ||
| 170 | + From<u16> | ||
| 171 | + TryFrom<u32, Error: Debuggable> | ||
| 172 | + Into<u32> | ||
| 173 | + TryFrom<u64, Error: Debuggable>; | ||
| 167 | 174 | ||
| 168 | /// Registers for this timer. | 175 | /// Registers for this timer. |
| 169 | /// | 176 | /// |
| @@ -241,7 +248,7 @@ dma_trait!(Dma, GeneralInstance4Channel, TimerChannel); | |||
| 241 | 248 | ||
| 242 | #[allow(unused)] | 249 | #[allow(unused)] |
| 243 | macro_rules! impl_core_timer { | 250 | macro_rules! impl_core_timer { |
| 244 | ($inst:ident, $bits:expr) => { | 251 | ($inst:ident, $bits:ident) => { |
| 245 | impl SealedInstance for crate::peripherals::$inst { | 252 | impl SealedInstance for crate::peripherals::$inst { |
| 246 | fn state() -> &'static State { | 253 | fn state() -> &'static State { |
| 247 | static STATE: State = State::new(); | 254 | static STATE: State = State::new(); |
| @@ -251,8 +258,7 @@ macro_rules! impl_core_timer { | |||
| 251 | 258 | ||
| 252 | impl CoreInstance for crate::peripherals::$inst { | 259 | impl CoreInstance for crate::peripherals::$inst { |
| 253 | type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP; | 260 | type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP; |
| 254 | 261 | type Word = $bits; | |
| 255 | const BITS: TimerBits = $bits; | ||
| 256 | 262 | ||
| 257 | fn regs() -> *mut () { | 263 | fn regs() -> *mut () { |
| 258 | crate::pac::$inst.as_ptr() | 264 | crate::pac::$inst.as_ptr() |
| @@ -306,13 +312,13 @@ macro_rules! impl_general_4ch_blank_sealed { | |||
| 306 | 312 | ||
| 307 | foreach_interrupt! { | 313 | foreach_interrupt! { |
| 308 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { | 314 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { |
| 309 | impl_core_timer!($inst, TimerBits::Bits16); | 315 | impl_core_timer!($inst, u16); |
| 310 | impl BasicNoCr2Instance for crate::peripherals::$inst {} | 316 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 311 | impl BasicInstance for crate::peripherals::$inst {} | 317 | impl BasicInstance for crate::peripherals::$inst {} |
| 312 | }; | 318 | }; |
| 313 | 319 | ||
| 314 | ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { | 320 | ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { |
| 315 | impl_core_timer!($inst, TimerBits::Bits16); | 321 | impl_core_timer!($inst, u16); |
| 316 | impl BasicNoCr2Instance for crate::peripherals::$inst {} | 322 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 317 | impl BasicInstance for crate::peripherals::$inst {} | 323 | impl BasicInstance for crate::peripherals::$inst {} |
| 318 | impl_general_1ch!($inst); | 324 | impl_general_1ch!($inst); |
| @@ -322,7 +328,7 @@ foreach_interrupt! { | |||
| 322 | }; | 328 | }; |
| 323 | 329 | ||
| 324 | ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { | 330 | ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { |
| 325 | impl_core_timer!($inst, TimerBits::Bits16); | 331 | impl_core_timer!($inst, u16); |
| 326 | impl BasicNoCr2Instance for crate::peripherals::$inst {} | 332 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 327 | impl BasicInstance for crate::peripherals::$inst {} | 333 | impl BasicInstance for crate::peripherals::$inst {} |
| 328 | impl_general_1ch!($inst); | 334 | impl_general_1ch!($inst); |
| @@ -332,7 +338,7 @@ foreach_interrupt! { | |||
| 332 | }; | 338 | }; |
| 333 | 339 | ||
| 334 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { | 340 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { |
| 335 | impl_core_timer!($inst, TimerBits::Bits16); | 341 | impl_core_timer!($inst, u16); |
| 336 | impl BasicNoCr2Instance for crate::peripherals::$inst {} | 342 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 337 | impl BasicInstance for crate::peripherals::$inst {} | 343 | impl BasicInstance for crate::peripherals::$inst {} |
| 338 | impl_general_1ch!($inst); | 344 | impl_general_1ch!($inst); |
| @@ -342,7 +348,7 @@ foreach_interrupt! { | |||
| 342 | }; | 348 | }; |
| 343 | 349 | ||
| 344 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { | 350 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { |
| 345 | impl_core_timer!($inst, TimerBits::Bits32); | 351 | impl_core_timer!($inst, u32); |
| 346 | impl BasicNoCr2Instance for crate::peripherals::$inst {} | 352 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 347 | impl BasicInstance for crate::peripherals::$inst {} | 353 | impl BasicInstance for crate::peripherals::$inst {} |
| 348 | impl_general_1ch!($inst); | 354 | impl_general_1ch!($inst); |
| @@ -353,7 +359,7 @@ foreach_interrupt! { | |||
| 353 | }; | 359 | }; |
| 354 | 360 | ||
| 355 | ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { | 361 | ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { |
| 356 | impl_core_timer!($inst, TimerBits::Bits16); | 362 | impl_core_timer!($inst, u16); |
| 357 | impl BasicNoCr2Instance for crate::peripherals::$inst {} | 363 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 358 | impl BasicInstance for crate::peripherals::$inst {} | 364 | impl BasicInstance for crate::peripherals::$inst {} |
| 359 | impl_general_1ch!($inst); | 365 | impl_general_1ch!($inst); |
| @@ -366,7 +372,7 @@ foreach_interrupt! { | |||
| 366 | }; | 372 | }; |
| 367 | 373 | ||
| 368 | ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { | 374 | ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { |
| 369 | impl_core_timer!($inst, TimerBits::Bits16); | 375 | impl_core_timer!($inst, u16); |
| 370 | impl BasicNoCr2Instance for crate::peripherals::$inst {} | 376 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 371 | impl BasicInstance for crate::peripherals::$inst {} | 377 | impl BasicInstance for crate::peripherals::$inst {} |
| 372 | impl_general_1ch!($inst); | 378 | impl_general_1ch!($inst); |
| @@ -379,7 +385,7 @@ foreach_interrupt! { | |||
| 379 | }; | 385 | }; |
| 380 | 386 | ||
| 381 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { | 387 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { |
| 382 | impl_core_timer!($inst, TimerBits::Bits16); | 388 | impl_core_timer!($inst, u16); |
| 383 | impl BasicNoCr2Instance for crate::peripherals::$inst {} | 389 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 384 | impl BasicInstance for crate::peripherals::$inst {} | 390 | impl BasicInstance for crate::peripherals::$inst {} |
| 385 | impl_general_1ch!($inst); | 391 | impl_general_1ch!($inst); |
| @@ -400,7 +406,7 @@ pub struct UpdateInterruptHandler<T: CoreInstance> { | |||
| 400 | impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { | 406 | impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { |
| 401 | unsafe fn on_interrupt() { | 407 | unsafe fn on_interrupt() { |
| 402 | #[cfg(feature = "low-power")] | 408 | #[cfg(feature = "low-power")] |
| 403 | crate::low_power::Executor::on_wakeup_irq(); | 409 | crate::low_power::Executor::on_wakeup_irq_or_event(); |
| 404 | 410 | ||
| 405 | let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); | 411 | let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); |
| 406 | 412 | ||
| @@ -430,7 +436,7 @@ impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompare | |||
| 430 | { | 436 | { |
| 431 | unsafe fn on_interrupt() { | 437 | unsafe fn on_interrupt() { |
| 432 | #[cfg(feature = "low-power")] | 438 | #[cfg(feature = "low-power")] |
| 433 | crate::low_power::Executor::on_wakeup_irq(); | 439 | crate::low_power::Executor::on_wakeup_irq_or_event(); |
| 434 | 440 | ||
| 435 | let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); | 441 | let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); |
| 436 | 442 | ||
diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs index fe8681356..989e1d630 100644 --- a/embassy-stm32/src/timer/one_pulse.rs +++ b/embassy-stm32/src/timer/one_pulse.rs | |||
| @@ -199,7 +199,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { | |||
| 199 | fn new_inner(&mut self, freq: Hertz, pulse_end: u32, counting_mode: CountingMode) { | 199 | fn new_inner(&mut self, freq: Hertz, pulse_end: u32, counting_mode: CountingMode) { |
| 200 | self.inner.set_counting_mode(counting_mode); | 200 | self.inner.set_counting_mode(counting_mode); |
| 201 | self.inner.set_tick_freq(freq); | 201 | self.inner.set_tick_freq(freq); |
| 202 | self.inner.set_max_compare_value(pulse_end); | 202 | self.inner.set_max_compare_value(unwrap!(pulse_end.try_into())); |
| 203 | self.inner.regs_core().cr1().modify(|r| r.set_opm(true)); | 203 | self.inner.regs_core().cr1().modify(|r| r.set_opm(true)); |
| 204 | // Required for advanced timers, see GeneralInstance4Channel for details | 204 | // Required for advanced timers, see GeneralInstance4Channel for details |
| 205 | self.inner.enable_outputs(); | 205 | self.inner.enable_outputs(); |
| @@ -211,14 +211,14 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { | |||
| 211 | 211 | ||
| 212 | /// Get the end of the pulse in ticks from the trigger. | 212 | /// Get the end of the pulse in ticks from the trigger. |
| 213 | pub fn pulse_end(&self) -> u32 { | 213 | pub fn pulse_end(&self) -> u32 { |
| 214 | let max = self.inner.get_max_compare_value(); | 214 | let max: u32 = self.inner.get_max_compare_value().into(); |
| 215 | assert!(max < u32::MAX); | 215 | assert!(max < u32::MAX); |
| 216 | max + 1 | 216 | max + 1 |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | /// Set the end of the pulse in ticks from the trigger. | 219 | /// Set the end of the pulse in ticks from the trigger. |
| 220 | pub fn set_pulse_end(&mut self, ticks: u32) { | 220 | pub fn set_pulse_end(&mut self, ticks: u32) { |
| 221 | self.inner.set_max_compare_value(ticks) | 221 | self.inner.set_max_compare_value(unwrap!(ticks.try_into())) |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | /// Reset the timer on each trigger | 224 | /// Reset the timer on each trigger |
| @@ -327,7 +327,7 @@ pub struct OnePulseChannel<'d, T: GeneralInstance4Channel> { | |||
| 327 | impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> { | 327 | impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> { |
| 328 | /// Get the end of the pulse in ticks from the trigger. | 328 | /// Get the end of the pulse in ticks from the trigger. |
| 329 | pub fn pulse_end(&self) -> u32 { | 329 | pub fn pulse_end(&self) -> u32 { |
| 330 | let max = self.inner.get_max_compare_value(); | 330 | let max: u32 = self.inner.get_max_compare_value().into(); |
| 331 | assert!(max < u32::MAX); | 331 | assert!(max < u32::MAX); |
| 332 | max + 1 | 332 | max + 1 |
| 333 | } | 333 | } |
| @@ -339,13 +339,13 @@ impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> { | |||
| 339 | 339 | ||
| 340 | /// Get the start of the pulse in ticks from the trigger. | 340 | /// Get the start of the pulse in ticks from the trigger. |
| 341 | pub fn pulse_delay(&mut self) -> u32 { | 341 | pub fn pulse_delay(&mut self) -> u32 { |
| 342 | self.inner.get_compare_value(self.channel) | 342 | self.inner.get_compare_value(self.channel).into() |
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | /// Set the start of the pulse in ticks from the trigger. | 345 | /// Set the start of the pulse in ticks from the trigger. |
| 346 | pub fn set_pulse_delay(&mut self, delay: u32) { | 346 | pub fn set_pulse_delay(&mut self, delay: u32) { |
| 347 | assert!(delay <= self.pulse_end()); | 347 | assert!(delay <= self.pulse_end()); |
| 348 | self.inner.set_compare_value(self.channel, delay); | 348 | self.inner.set_compare_value(self.channel, unwrap!(delay.try_into())); |
| 349 | } | 349 | } |
| 350 | 350 | ||
| 351 | /// Set the pulse width in ticks. | 351 | /// Set the pulse width in ticks. |
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs index 057ab011a..f2f00927d 100644 --- a/embassy-stm32/src/timer/pwm_input.rs +++ b/embassy-stm32/src/timer/pwm_input.rs | |||
| @@ -91,16 +91,18 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { | |||
| 91 | 91 | ||
| 92 | /// Get the period tick count | 92 | /// Get the period tick count |
| 93 | pub fn get_period_ticks(&self) -> u32 { | 93 | pub fn get_period_ticks(&self) -> u32 { |
| 94 | self.inner.get_capture_value(self.channel) | 94 | self.inner.get_capture_value(self.channel).into() |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | /// Get the pulse width tick count | 97 | /// Get the pulse width tick count |
| 98 | pub fn get_width_ticks(&self) -> u32 { | 98 | pub fn get_width_ticks(&self) -> u32 { |
| 99 | self.inner.get_capture_value(match self.channel { | 99 | self.inner |
| 100 | Channel::Ch1 => Channel::Ch2, | 100 | .get_capture_value(match self.channel { |
| 101 | Channel::Ch2 => Channel::Ch1, | 101 | Channel::Ch1 => Channel::Ch2, |
| 102 | _ => panic!("Invalid channel for PWM input"), | 102 | Channel::Ch2 => Channel::Ch1, |
| 103 | }) | 103 | _ => panic!("Invalid channel for PWM input"), |
| 104 | }) | ||
| 105 | .into() | ||
| 104 | } | 106 | } |
| 105 | 107 | ||
| 106 | /// Get the duty cycle in 100% | 108 | /// Get the duty cycle in 100% |
diff --git a/embassy-stm32/src/timer/ringbuffered.rs b/embassy-stm32/src/timer/ringbuffered.rs index e8f97bf59..fbb6b19ea 100644 --- a/embassy-stm32/src/timer/ringbuffered.rs +++ b/embassy-stm32/src/timer/ringbuffered.rs | |||
| @@ -7,6 +7,7 @@ use super::low_level::Timer; | |||
| 7 | use super::{Channel, GeneralInstance4Channel}; | 7 | use super::{Channel, GeneralInstance4Channel}; |
| 8 | use crate::dma::WritableRingBuffer; | 8 | use crate::dma::WritableRingBuffer; |
| 9 | use crate::dma::ringbuffer::Error; | 9 | use crate::dma::ringbuffer::Error; |
| 10 | use crate::dma::word::Word; | ||
| 10 | 11 | ||
| 11 | /// A PWM channel that uses a DMA ring buffer for continuous waveform generation. | 12 | /// A PWM channel that uses a DMA ring buffer for continuous waveform generation. |
| 12 | /// | 13 | /// |
| @@ -23,17 +24,17 @@ use crate::dma::ringbuffer::Error; | |||
| 23 | /// channel.start(); // Start DMA transfer | 24 | /// channel.start(); // Start DMA transfer |
| 24 | /// channel.write(&[100, 200, 300]).ok(); // Update duty cycles | 25 | /// channel.write(&[100, 200, 300]).ok(); // Update duty cycles |
| 25 | /// ``` | 26 | /// ``` |
| 26 | pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel> { | 27 | pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel, W: Word + Into<T::Word>> { |
| 27 | timer: ManuallyDrop<Timer<'d, T>>, | 28 | timer: ManuallyDrop<Timer<'d, T>>, |
| 28 | ring_buf: WritableRingBuffer<'d, u16>, | 29 | ring_buf: WritableRingBuffer<'d, W>, |
| 29 | channel: Channel, | 30 | channel: Channel, |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> { | 33 | impl<'d, T: GeneralInstance4Channel, W: Word + Into<T::Word>> RingBufferedPwmChannel<'d, T, W> { |
| 33 | pub(crate) fn new( | 34 | pub(crate) fn new( |
| 34 | timer: ManuallyDrop<Timer<'d, T>>, | 35 | timer: ManuallyDrop<Timer<'d, T>>, |
| 35 | channel: Channel, | 36 | channel: Channel, |
| 36 | ring_buf: WritableRingBuffer<'d, u16>, | 37 | ring_buf: WritableRingBuffer<'d, W>, |
| 37 | ) -> Self { | 38 | ) -> Self { |
| 38 | Self { | 39 | Self { |
| 39 | timer, | 40 | timer, |
| @@ -55,18 +56,18 @@ impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> { | |||
| 55 | } | 56 | } |
| 56 | 57 | ||
| 57 | /// Write elements directly to the raw buffer. This can be used to fill the buffer before starting the DMA transfer. | 58 | /// Write elements directly to the raw buffer. This can be used to fill the buffer before starting the DMA transfer. |
| 58 | pub fn write_immediate(&mut self, buf: &[u16]) -> Result<(usize, usize), Error> { | 59 | pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { |
| 59 | self.ring_buf.write_immediate(buf) | 60 | self.ring_buf.write_immediate(buf) |
| 60 | } | 61 | } |
| 61 | 62 | ||
| 62 | /// Write elements from the ring buffer | 63 | /// Write elements from the ring buffer |
| 63 | /// Return a tuple of the length written and the length remaining in the buffer | 64 | /// Return a tuple of the length written and the length remaining in the buffer |
| 64 | pub fn write(&mut self, buf: &[u16]) -> Result<(usize, usize), Error> { | 65 | pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { |
| 65 | self.ring_buf.write(buf) | 66 | self.ring_buf.write(buf) |
| 66 | } | 67 | } |
| 67 | 68 | ||
| 68 | /// Write an exact number of elements to the ringbuffer. | 69 | /// Write an exact number of elements to the ringbuffer. |
| 69 | pub async fn write_exact(&mut self, buffer: &[u16]) -> Result<usize, Error> { | 70 | pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, Error> { |
| 70 | self.ring_buf.write_exact(buffer).await | 71 | self.ring_buf.write_exact(buffer).await |
| 71 | } | 72 | } |
| 72 | 73 | ||
| @@ -140,7 +141,7 @@ impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> { | |||
| 140 | /// | 141 | /// |
| 141 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 142 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 142 | pub fn max_duty_cycle(&self) -> u16 { | 143 | pub fn max_duty_cycle(&self) -> u16 { |
| 143 | let max = self.timer.get_max_compare_value(); | 144 | let max: u32 = self.timer.get_max_compare_value().into(); |
| 144 | assert!(max < u16::MAX as u32); | 145 | assert!(max < u16::MAX as u32); |
| 145 | max as u16 + 1 | 146 | max as u16 + 1 |
| 146 | } | 147 | } |
| @@ -155,15 +156,3 @@ impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> { | |||
| 155 | self.timer.set_output_compare_mode(self.channel, mode); | 156 | self.timer.set_output_compare_mode(self.channel, mode); |
| 156 | } | 157 | } |
| 157 | } | 158 | } |
| 158 | |||
| 159 | /// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`]. | ||
| 160 | pub struct RingBufferedPwmChannels<'d, T: GeneralInstance4Channel> { | ||
| 161 | /// Channel 1 | ||
| 162 | pub ch1: RingBufferedPwmChannel<'d, T>, | ||
| 163 | /// Channel 2 | ||
| 164 | pub ch2: RingBufferedPwmChannel<'d, T>, | ||
| 165 | /// Channel 3 | ||
| 166 | pub ch3: RingBufferedPwmChannel<'d, T>, | ||
| 167 | /// Channel 4 | ||
| 168 | pub ch4: RingBufferedPwmChannel<'d, T>, | ||
| 169 | } | ||
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 484e9fd81..9a5f0fd1d 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -7,9 +7,11 @@ use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; | |||
| 7 | use super::ringbuffered::RingBufferedPwmChannel; | 7 | use super::ringbuffered::RingBufferedPwmChannel; |
| 8 | use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; | 8 | use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; |
| 9 | use crate::Peri; | 9 | use crate::Peri; |
| 10 | use crate::dma::word::Word; | ||
| 10 | #[cfg(gpio_v2)] | 11 | #[cfg(gpio_v2)] |
| 11 | use crate::gpio::Pull; | 12 | use crate::gpio::Pull; |
| 12 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; | 13 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; |
| 14 | use crate::pac::timer::vals::Ccds; | ||
| 13 | use crate::time::Hertz; | 15 | use crate::time::Hertz; |
| 14 | 16 | ||
| 15 | /// PWM pin wrapper. | 17 | /// PWM pin wrapper. |
| @@ -98,18 +100,16 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { | |||
| 98 | /// Get max duty value. | 100 | /// Get max duty value. |
| 99 | /// | 101 | /// |
| 100 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 102 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 101 | pub fn max_duty_cycle(&self) -> u16 { | 103 | pub fn max_duty_cycle(&self) -> u32 { |
| 102 | let max = self.timer.get_max_compare_value(); | 104 | self.timer.get_max_compare_value().into() + 1 |
| 103 | assert!(max < u16::MAX as u32); | ||
| 104 | max as u16 + 1 | ||
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | /// Set the duty for a given channel. | 107 | /// Set the duty for a given channel. |
| 108 | /// | 108 | /// |
| 109 | /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included. | 109 | /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included. |
| 110 | pub fn set_duty_cycle(&mut self, duty: u16) { | 110 | pub fn set_duty_cycle(&mut self, duty: u32) { |
| 111 | assert!(duty <= (*self).max_duty_cycle()); | 111 | assert!(duty <= (*self).max_duty_cycle()); |
| 112 | self.timer.set_compare_value(self.channel, duty.into()) | 112 | self.timer.set_compare_value(self.channel, unwrap!(duty.try_into())) |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | /// Set the duty cycle to 0%, or always inactive. | 115 | /// Set the duty cycle to 0%, or always inactive. |
| @@ -126,21 +126,21 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { | |||
| 126 | /// | 126 | /// |
| 127 | /// The caller is responsible for ensuring that `num` is less than or equal to `denom`, | 127 | /// The caller is responsible for ensuring that `num` is less than or equal to `denom`, |
| 128 | /// and that `denom` is not zero. | 128 | /// and that `denom` is not zero. |
| 129 | pub fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) { | 129 | pub fn set_duty_cycle_fraction(&mut self, num: u32, denom: u32) { |
| 130 | assert!(denom != 0); | 130 | assert!(denom != 0); |
| 131 | assert!(num <= denom); | 131 | assert!(num <= denom); |
| 132 | let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom); | 132 | let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom); |
| 133 | 133 | ||
| 134 | // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16) | 134 | // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16) |
| 135 | #[allow(clippy::cast_possible_truncation)] | 135 | #[allow(clippy::cast_possible_truncation)] |
| 136 | self.set_duty_cycle(duty as u16); | 136 | self.set_duty_cycle(unwrap!(duty.try_into())); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | /// Set the duty cycle to `percent / 100` | 139 | /// Set the duty cycle to `percent / 100` |
| 140 | /// | 140 | /// |
| 141 | /// The caller is responsible for ensuring that `percent` is less than or equal to 100. | 141 | /// The caller is responsible for ensuring that `percent` is less than or equal to 100. |
| 142 | pub fn set_duty_cycle_percent(&mut self, percent: u8) { | 142 | pub fn set_duty_cycle_percent(&mut self, percent: u8) { |
| 143 | self.set_duty_cycle_fraction(u16::from(percent), 100) | 143 | self.set_duty_cycle_fraction(percent as u32, 100) |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | /// Get the duty for a given channel. | 146 | /// Get the duty for a given channel. |
| @@ -171,13 +171,14 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { | |||
| 171 | /// | 171 | /// |
| 172 | /// # Panics | 172 | /// # Panics |
| 173 | /// Panics if `dma_buf` is empty or longer than 65535 elements. | 173 | /// Panics if `dma_buf` is empty or longer than 65535 elements. |
| 174 | pub fn into_ring_buffered_channel( | 174 | pub fn into_ring_buffered_channel<W: Word + Into<T::Word>>( |
| 175 | mut self, | 175 | mut self, |
| 176 | tx_dma: Peri<'d, impl super::UpDma<T>>, | 176 | tx_dma: Peri<'d, impl super::UpDma<T>>, |
| 177 | dma_buf: &'d mut [u16], | 177 | dma_buf: &'d mut [W], |
| 178 | ) -> RingBufferedPwmChannel<'d, T> { | 178 | ) -> RingBufferedPwmChannel<'d, T, W> { |
| 179 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); | 179 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); |
| 180 | 180 | ||
| 181 | self.timer.clamp_compare_value::<W>(self.channel); | ||
| 181 | self.timer.enable_update_dma(true); | 182 | self.timer.enable_update_dma(true); |
| 182 | 183 | ||
| 183 | RingBufferedPwmChannel::new( | 184 | RingBufferedPwmChannel::new( |
| @@ -332,10 +333,27 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 332 | /// Get max duty value. | 333 | /// Get max duty value. |
| 333 | /// | 334 | /// |
| 334 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 335 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 335 | pub fn max_duty_cycle(&self) -> u16 { | 336 | pub fn max_duty_cycle(&self) -> u32 { |
| 336 | let max = self.inner.get_max_compare_value(); | 337 | self.inner.get_max_compare_value().into() + 1 |
| 337 | assert!(max < u16::MAX as u32); | 338 | } |
| 338 | max as u16 + 1 | 339 | |
| 340 | /// Generate a sequence of PWM waveform | ||
| 341 | /// | ||
| 342 | /// Note: | ||
| 343 | /// The DMA channel provided does not need to correspond to the requested channel. | ||
| 344 | pub async fn waveform<C: TimerChannel, W: Word + Into<T::Word>>( | ||
| 345 | &mut self, | ||
| 346 | dma: Peri<'_, impl super::Dma<T, C>>, | ||
| 347 | channel: Channel, | ||
| 348 | duty: &[W], | ||
| 349 | ) { | ||
| 350 | self.inner.enable_channel(channel, true); | ||
| 351 | self.inner.enable_channel(C::CHANNEL, true); | ||
| 352 | self.inner.clamp_compare_value::<W>(channel); | ||
| 353 | self.inner.set_cc_dma_selection(Ccds::ON_UPDATE); | ||
| 354 | self.inner.set_cc_dma_enable_state(C::CHANNEL, true); | ||
| 355 | self.inner.setup_channel_update_dma(dma, channel, duty).await; | ||
| 356 | self.inner.set_cc_dma_enable_state(C::CHANNEL, false); | ||
| 339 | } | 357 | } |
| 340 | 358 | ||
| 341 | /// Generate a sequence of PWM waveform | 359 | /// Generate a sequence of PWM waveform |
| @@ -344,8 +362,14 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 344 | /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. | 362 | /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. |
| 345 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 363 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 346 | /// switch this timer by using `time-driver-timX` feature. | 364 | /// switch this timer by using `time-driver-timX` feature. |
| 347 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { | 365 | pub async fn waveform_up<W: Word + Into<T::Word>>( |
| 366 | &mut self, | ||
| 367 | dma: Peri<'_, impl super::UpDma<T>>, | ||
| 368 | channel: Channel, | ||
| 369 | duty: &[W], | ||
| 370 | ) { | ||
| 348 | self.inner.enable_channel(channel, true); | 371 | self.inner.enable_channel(channel, true); |
| 372 | self.inner.clamp_compare_value::<W>(channel); | ||
| 349 | self.inner.enable_update_dma(true); | 373 | self.inner.enable_update_dma(true); |
| 350 | self.inner.setup_update_dma(dma, channel, duty).await; | 374 | self.inner.setup_update_dma(dma, channel, duty).await; |
| 351 | self.inner.enable_update_dma(false); | 375 | self.inner.enable_update_dma(false); |
| @@ -380,13 +404,21 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 380 | /// Also be aware that embassy timers use one of timers internally. It is possible to | 404 | /// Also be aware that embassy timers use one of timers internally. It is possible to |
| 381 | /// switch this timer by using `time-driver-timX` feature. | 405 | /// switch this timer by using `time-driver-timX` feature. |
| 382 | /// | 406 | /// |
| 383 | pub async fn waveform_up_multi_channel( | 407 | pub async fn waveform_up_multi_channel<W: Word + Into<T::Word>>( |
| 384 | &mut self, | 408 | &mut self, |
| 385 | dma: Peri<'_, impl super::UpDma<T>>, | 409 | dma: Peri<'_, impl super::UpDma<T>>, |
| 386 | starting_channel: Channel, | 410 | starting_channel: Channel, |
| 387 | ending_channel: Channel, | 411 | ending_channel: Channel, |
| 388 | duty: &[u16], | 412 | duty: &[W], |
| 389 | ) { | 413 | ) { |
| 414 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | ||
| 415 | .iter() | ||
| 416 | .filter(|ch| ch.index() >= starting_channel.index()) | ||
| 417 | .filter(|ch| ch.index() <= ending_channel.index()) | ||
| 418 | .for_each(|ch| { | ||
| 419 | self.inner.enable_channel(*ch, true); | ||
| 420 | self.inner.clamp_compare_value::<W>(*ch); | ||
| 421 | }); | ||
| 390 | self.inner.enable_update_dma(true); | 422 | self.inner.enable_update_dma(true); |
| 391 | self.inner | 423 | self.inner |
| 392 | .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) | 424 | .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) |
| @@ -401,11 +433,11 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePw | |||
| 401 | 433 | ||
| 402 | impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> { | 434 | impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> { |
| 403 | fn max_duty_cycle(&self) -> u16 { | 435 | fn max_duty_cycle(&self) -> u16 { |
| 404 | self.max_duty_cycle() | 436 | unwrap!(self.max_duty_cycle().try_into()) |
| 405 | } | 437 | } |
| 406 | 438 | ||
| 407 | fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { | 439 | fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { |
| 408 | self.set_duty_cycle(duty); | 440 | self.set_duty_cycle(duty.into()); |
| 409 | Ok(()) | 441 | Ok(()) |
| 410 | } | 442 | } |
| 411 | 443 | ||
| @@ -420,7 +452,7 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for Simpl | |||
| 420 | } | 452 | } |
| 421 | 453 | ||
| 422 | fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> { | 454 | fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> { |
| 423 | self.set_duty_cycle_fraction(num, denom); | 455 | self.set_duty_cycle_fraction(num.into(), denom.into()); |
| 424 | Ok(()) | 456 | Ok(()) |
| 425 | } | 457 | } |
| 426 | 458 | ||
| @@ -448,16 +480,16 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> { | |||
| 448 | } | 480 | } |
| 449 | 481 | ||
| 450 | fn get_duty(&self, channel: Self::Channel) -> Self::Duty { | 482 | fn get_duty(&self, channel: Self::Channel) -> Self::Duty { |
| 451 | self.inner.get_compare_value(channel) | 483 | self.inner.get_compare_value(channel).into() |
| 452 | } | 484 | } |
| 453 | 485 | ||
| 454 | fn get_max_duty(&self) -> Self::Duty { | 486 | fn get_max_duty(&self) -> Self::Duty { |
| 455 | self.inner.get_max_compare_value() + 1 | 487 | self.inner.get_max_compare_value().into() + 1 |
| 456 | } | 488 | } |
| 457 | 489 | ||
| 458 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { | 490 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { |
| 459 | assert!(duty <= self.max_duty_cycle() as u32); | 491 | assert!(duty <= self.max_duty_cycle() as u32); |
| 460 | self.inner.set_compare_value(channel, duty) | 492 | self.inner.set_compare_value(channel, unwrap!(duty.try_into())) |
| 461 | } | 493 | } |
| 462 | 494 | ||
| 463 | fn set_period<P>(&mut self, period: P) | 495 | fn set_period<P>(&mut self, period: P) |
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 8047d6005..d2c361c61 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -491,7 +491,7 @@ impl<'d> UartTx<'d, Async> { | |||
| 491 | 491 | ||
| 492 | /// Initiate an asynchronous UART write | 492 | /// Initiate an asynchronous UART write |
| 493 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 493 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 494 | let _ = self.info.rcc.block_stop(); | 494 | let _scoped_block_stop = self.info.rcc.block_stop(); |
| 495 | 495 | ||
| 496 | let r = self.info.regs; | 496 | let r = self.info.regs; |
| 497 | 497 | ||
| @@ -510,7 +510,7 @@ impl<'d> UartTx<'d, Async> { | |||
| 510 | 510 | ||
| 511 | /// Wait until transmission complete | 511 | /// Wait until transmission complete |
| 512 | pub async fn flush(&mut self) -> Result<(), Error> { | 512 | pub async fn flush(&mut self) -> Result<(), Error> { |
| 513 | let _ = self.info.rcc.block_stop(); | 513 | let _scoped_block_stop = self.info.rcc.block_stop(); |
| 514 | 514 | ||
| 515 | flush(&self.info, &self.state).await | 515 | flush(&self.info, &self.state).await |
| 516 | } | 516 | } |
| @@ -730,7 +730,7 @@ impl<'d> UartRx<'d, Async> { | |||
| 730 | 730 | ||
| 731 | /// Initiate an asynchronous UART read | 731 | /// Initiate an asynchronous UART read |
| 732 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 732 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 733 | let _ = self.info.rcc.block_stop(); | 733 | let _scoped_block_stop = self.info.rcc.block_stop(); |
| 734 | 734 | ||
| 735 | self.inner_read(buffer, false).await?; | 735 | self.inner_read(buffer, false).await?; |
| 736 | 736 | ||
| @@ -739,7 +739,7 @@ impl<'d> UartRx<'d, Async> { | |||
| 739 | 739 | ||
| 740 | /// Initiate an asynchronous read with idle line detection enabled | 740 | /// Initiate an asynchronous read with idle line detection enabled |
| 741 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 741 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 742 | let _ = self.info.rcc.block_stop(); | 742 | let _scoped_block_stop = self.info.rcc.block_stop(); |
| 743 | 743 | ||
| 744 | self.inner_read(buffer, true).await | 744 | self.inner_read(buffer, true).await |
| 745 | } | 745 | } |
