Merge pull request #1570 from embassy-rs/update-metapac2
stm32: update stm32-metapac.
This commit is contained in:
		| @@ -20,13 +20,13 @@ fn main() -> ! { | ||||
|     let led = Output::new(p.PB14, Level::Low, Speed::Low); | ||||
|     let mut button = Input::new(p.PC13, Pull::Up); | ||||
|  | ||||
|     cortex_m::interrupt::free(|cs| unsafe { | ||||
|     cortex_m::interrupt::free(|cs| { | ||||
|         enable_interrupt(&mut button); | ||||
|  | ||||
|         LED.borrow(cs).borrow_mut().replace(led); | ||||
|         BUTTON.borrow(cs).borrow_mut().replace(button); | ||||
|  | ||||
|         NVIC::unmask(pac::Interrupt::EXTI15_10); | ||||
|         unsafe { NVIC::unmask(pac::Interrupt::EXTI15_10) }; | ||||
|     }); | ||||
|  | ||||
|     loop { | ||||
| @@ -64,25 +64,21 @@ const PORT: u8 = 2; | ||||
| const PIN: usize = 13; | ||||
| fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool { | ||||
|     let exti = pac::EXTI; | ||||
|     unsafe { | ||||
|         let pin = PIN; | ||||
|         let lines = exti.pr(0).read(); | ||||
|         lines.line(pin) | ||||
|     } | ||||
|     let pin = PIN; | ||||
|     let lines = exti.pr(0).read(); | ||||
|     lines.line(pin) | ||||
| } | ||||
|  | ||||
| fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { | ||||
|     let exti = pac::EXTI; | ||||
|     unsafe { | ||||
|         let pin = PIN; | ||||
|         let mut lines = exti.pr(0).read(); | ||||
|         lines.set_line(pin, true); | ||||
|         exti.pr(0).write_value(lines); | ||||
|     } | ||||
|     let pin = PIN; | ||||
|     let mut lines = exti.pr(0).read(); | ||||
|     lines.set_line(pin, true); | ||||
|     exti.pr(0).write_value(lines); | ||||
| } | ||||
|  | ||||
| fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { | ||||
|     cortex_m::interrupt::free(|_| unsafe { | ||||
|     cortex_m::interrupt::free(|_| { | ||||
|         let rcc = pac::RCC; | ||||
|         rcc.apb2enr().modify(|w| w.set_syscfgen(true)); | ||||
|  | ||||
|   | ||||
| @@ -68,29 +68,23 @@ where | ||||
|     } | ||||
|     async fn set_nss_low(&mut self) -> Result<(), RadioError> { | ||||
|         let pwr = pac::PWR; | ||||
|         unsafe { | ||||
|             pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW)); | ||||
|         } | ||||
|         pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW)); | ||||
|         Ok(()) | ||||
|     } | ||||
|     async fn set_nss_high(&mut self) -> Result<(), RadioError> { | ||||
|         let pwr = pac::PWR; | ||||
|         unsafe { | ||||
|             pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH)); | ||||
|         } | ||||
|         pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH)); | ||||
|         Ok(()) | ||||
|     } | ||||
|     async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> { | ||||
|         let rcc = pac::RCC; | ||||
|         unsafe { | ||||
|             rcc.csr().modify(|w| w.set_rfrst(true)); | ||||
|             rcc.csr().modify(|w| w.set_rfrst(false)); | ||||
|         } | ||||
|         rcc.csr().modify(|w| w.set_rfrst(true)); | ||||
|         rcc.csr().modify(|w| w.set_rfrst(false)); | ||||
|         Ok(()) | ||||
|     } | ||||
|     async fn wait_on_busy(&mut self) -> Result<(), RadioError> { | ||||
|         let pwr = pac::PWR; | ||||
|         while unsafe { pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY } {} | ||||
|         while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {} | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -57,7 +57,7 @@ sdio-host = "0.5.0" | ||||
| embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | ||||
| critical-section = "1.1" | ||||
| atomic-polyfill = "1.0.1" | ||||
| stm32-metapac = "9" | ||||
| stm32-metapac = "10" | ||||
| vcell = "0.1.3" | ||||
| bxcan = "0.7.0" | ||||
| nb = "1.0.0" | ||||
| @@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] } | ||||
| [build-dependencies] | ||||
| proc-macro2 = "1.0.36" | ||||
| quote = "1.0.15" | ||||
| stm32-metapac = { version = "9", default-features = false, features = ["metadata"]} | ||||
| stm32-metapac = { version = "10", default-features = false, features = ["metadata"]} | ||||
|  | ||||
| [features] | ||||
| default = ["rt"] | ||||
|   | ||||
| @@ -322,7 +322,7 @@ fn main() { | ||||
|                     let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); | ||||
|                     let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); | ||||
|                     quote! { | ||||
|                         critical_section::with(|_| unsafe { | ||||
|                         critical_section::with(|_| { | ||||
|                             crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); | ||||
|                             crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); | ||||
|                         }); | ||||
| @@ -353,13 +353,13 @@ fn main() { | ||||
|                         }) | ||||
|                     } | ||||
|                     fn enable() { | ||||
|                         critical_section::with(|_| unsafe { | ||||
|                         critical_section::with(|_| { | ||||
|                             crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); | ||||
|                             #after_enable | ||||
|                         }) | ||||
|                     } | ||||
|                     fn disable() { | ||||
|                         critical_section::with(|_| unsafe { | ||||
|                         critical_section::with(|_| { | ||||
|                             crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); | ||||
|                         }) | ||||
|                     } | ||||
|   | ||||
| @@ -32,26 +32,22 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|         into_ref!(adc); | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
|         unsafe { | ||||
|             T::regs().cr2().modify(|reg| reg.set_adon(true)); | ||||
|         } | ||||
|         T::regs().cr2().modify(|reg| reg.set_adon(true)); | ||||
|  | ||||
|         // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) | ||||
|         // for at least two ADC clock cycles | ||||
|         delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1); | ||||
|  | ||||
|         unsafe { | ||||
|             // Reset calibration | ||||
|             T::regs().cr2().modify(|reg| reg.set_rstcal(true)); | ||||
|             while T::regs().cr2().read().rstcal() { | ||||
|                 // spin | ||||
|             } | ||||
|         // Reset calibration | ||||
|         T::regs().cr2().modify(|reg| reg.set_rstcal(true)); | ||||
|         while T::regs().cr2().read().rstcal() { | ||||
|             // spin | ||||
|         } | ||||
|  | ||||
|             // Calibrate | ||||
|             T::regs().cr2().modify(|reg| reg.set_cal(true)); | ||||
|             while T::regs().cr2().read().cal() { | ||||
|                 // spin | ||||
|             } | ||||
|         // Calibrate | ||||
|         T::regs().cr2().modify(|reg| reg.set_cal(true)); | ||||
|         while T::regs().cr2().read().cal() { | ||||
|             // spin | ||||
|         } | ||||
|  | ||||
|         // One cycle after calibration | ||||
| @@ -81,20 +77,16 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|     } | ||||
|  | ||||
|     pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref { | ||||
|         unsafe { | ||||
|             T::regs().cr2().modify(|reg| { | ||||
|                 reg.set_tsvrefe(true); | ||||
|             }) | ||||
|         } | ||||
|         T::regs().cr2().modify(|reg| { | ||||
|             reg.set_tsvrefe(true); | ||||
|         }); | ||||
|         Vref {} | ||||
|     } | ||||
|  | ||||
|     pub fn enable_temperature(&self) -> Temperature { | ||||
|         unsafe { | ||||
|             T::regs().cr2().modify(|reg| { | ||||
|                 reg.set_tsvrefe(true); | ||||
|             }) | ||||
|         } | ||||
|         T::regs().cr2().modify(|reg| { | ||||
|             reg.set_tsvrefe(true); | ||||
|         }); | ||||
|         Temperature {} | ||||
|     } | ||||
|  | ||||
| @@ -104,41 +96,37 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|  | ||||
|     /// Perform a single conversion. | ||||
|     fn convert(&mut self) -> u16 { | ||||
|         unsafe { | ||||
|             T::regs().cr2().modify(|reg| { | ||||
|                 reg.set_adon(true); | ||||
|                 reg.set_swstart(true); | ||||
|             }); | ||||
|             while T::regs().cr2().read().swstart() {} | ||||
|             while !T::regs().sr().read().eoc() {} | ||||
|         T::regs().cr2().modify(|reg| { | ||||
|             reg.set_adon(true); | ||||
|             reg.set_swstart(true); | ||||
|         }); | ||||
|         while T::regs().cr2().read().swstart() {} | ||||
|         while !T::regs().sr().read().eoc() {} | ||||
|  | ||||
|             T::regs().dr().read().0 as u16 | ||||
|         } | ||||
|         T::regs().dr().read().0 as u16 | ||||
|     } | ||||
|  | ||||
|     pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | ||||
|         unsafe { | ||||
|             Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||||
|             T::regs().cr1().modify(|reg| { | ||||
|                 reg.set_scan(false); | ||||
|                 reg.set_discen(false); | ||||
|             }); | ||||
|             T::regs().sqr1().modify(|reg| reg.set_l(0)); | ||||
|         Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||||
|         T::regs().cr1().modify(|reg| { | ||||
|             reg.set_scan(false); | ||||
|             reg.set_discen(false); | ||||
|         }); | ||||
|         T::regs().sqr1().modify(|reg| reg.set_l(0)); | ||||
|  | ||||
|             T::regs().cr2().modify(|reg| { | ||||
|                 reg.set_cont(false); | ||||
|                 reg.set_exttrig(true); | ||||
|                 reg.set_swstart(false); | ||||
|                 reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr2().modify(|reg| { | ||||
|             reg.set_cont(false); | ||||
|             reg.set_exttrig(true); | ||||
|             reg.set_swstart(false); | ||||
|             reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART); | ||||
|         }); | ||||
|  | ||||
|         // Configure the channel to sample | ||||
|         unsafe { T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())) } | ||||
|         T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())); | ||||
|         self.convert() | ||||
|     } | ||||
|  | ||||
|     unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||||
|     fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||||
|         let sample_time = sample_time.into(); | ||||
|         if ch <= 9 { | ||||
|             T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); | ||||
|   | ||||
| @@ -57,18 +57,14 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|         // | ||||
|         // 6.3.20 Vbat monitoring characteristics | ||||
|         // ts_vbat ≥ 4μs | ||||
|         unsafe { | ||||
|             T::regs().ccr().modify(|reg| reg.set_vbaten(true)); | ||||
|         } | ||||
|         T::regs().ccr().modify(|reg| reg.set_vbaten(true)); | ||||
|         Vbat | ||||
|     } | ||||
|  | ||||
|     pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref { | ||||
|         // Table 28. Embedded internal reference voltage | ||||
|         // tstart = 10μs | ||||
|         unsafe { | ||||
|             T::regs().ccr().modify(|reg| reg.set_vrefen(true)); | ||||
|         } | ||||
|         T::regs().ccr().modify(|reg| reg.set_vrefen(true)); | ||||
|         delay.delay_us(10); | ||||
|         Vref | ||||
|     } | ||||
| @@ -79,27 +75,23 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|         // 6.3.19 Temperature sensor characteristics | ||||
|         // tstart ≤ 10μs | ||||
|         // ts_temp ≥ 4μs | ||||
|         unsafe { | ||||
|             T::regs().ccr().modify(|reg| reg.set_tsen(true)); | ||||
|         } | ||||
|         T::regs().ccr().modify(|reg| reg.set_tsen(true)); | ||||
|         delay.delay_us(10); | ||||
|         Temperature | ||||
|     } | ||||
|  | ||||
|     fn calibrate(&self) { | ||||
|         unsafe { | ||||
|             // A.7.1 ADC calibration code example | ||||
|             if T::regs().cr().read().aden() { | ||||
|                 T::regs().cr().modify(|reg| reg.set_addis(true)); | ||||
|             } | ||||
|             while T::regs().cr().read().aden() { | ||||
|                 // spin | ||||
|             } | ||||
|             T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); | ||||
|             T::regs().cr().modify(|reg| reg.set_adcal(true)); | ||||
|             while T::regs().cr().read().adcal() { | ||||
|                 // spin | ||||
|             } | ||||
|         // A.7.1 ADC calibration code example | ||||
|         if T::regs().cr().read().aden() { | ||||
|             T::regs().cr().modify(|reg| reg.set_addis(true)); | ||||
|         } | ||||
|         while T::regs().cr().read().aden() { | ||||
|             // spin | ||||
|         } | ||||
|         T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); | ||||
|         T::regs().cr().modify(|reg| reg.set_adcal(true)); | ||||
|         while T::regs().cr().read().adcal() { | ||||
|             // spin | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -108,9 +100,7 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|     } | ||||
|  | ||||
|     pub fn set_resolution(&mut self, resolution: Resolution) { | ||||
|         unsafe { | ||||
|             T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||||
|         } | ||||
|         T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||||
|     } | ||||
|  | ||||
|     pub fn read<P>(&mut self, pin: &mut P) -> u16 | ||||
| @@ -118,18 +108,16 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|         P: AdcPin<T> + crate::gpio::sealed::Pin, | ||||
|     { | ||||
|         let channel = pin.channel(); | ||||
|         unsafe { | ||||
|             pin.set_as_analog(); | ||||
|             self.read_channel(channel) | ||||
|         } | ||||
|         pin.set_as_analog(); | ||||
|         self.read_channel(channel) | ||||
|     } | ||||
|  | ||||
|     pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { | ||||
|         let channel = channel.channel(); | ||||
|         unsafe { self.read_channel(channel) } | ||||
|         self.read_channel(channel) | ||||
|     } | ||||
|  | ||||
|     unsafe fn read_channel(&mut self, channel: u8) -> u16 { | ||||
|     fn read_channel(&mut self, channel: u8) -> u16 { | ||||
|         // A.7.2 ADC enable sequence code example | ||||
|         if T::regs().isr().read().adrdy() { | ||||
|             T::regs().isr().modify(|reg| reg.set_adrdy(true)); | ||||
|   | ||||
| @@ -100,13 +100,10 @@ where | ||||
|         T::reset(); | ||||
|  | ||||
|         let presc = Prescaler::from_pclk2(T::frequency()); | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); | ||||
|  | ||||
|             T::regs().cr2().modify(|reg| { | ||||
|                 reg.set_adon(crate::pac::adc::vals::Adon::ENABLED); | ||||
|             }); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); | ||||
|         T::regs().cr2().modify(|reg| { | ||||
|             reg.set_adon(crate::pac::adc::vals::Adon::ENABLED); | ||||
|         }); | ||||
|  | ||||
|         delay.delay_us(ADC_POWERUP_TIME_US); | ||||
|  | ||||
| @@ -121,19 +118,15 @@ where | ||||
|     } | ||||
|  | ||||
|     pub fn set_resolution(&mut self, resolution: Resolution) { | ||||
|         unsafe { | ||||
|             T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); | ||||
|         } | ||||
|         T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); | ||||
|     } | ||||
|  | ||||
|     /// Enables internal voltage reference and returns [VrefInt], which can be used in | ||||
|     /// [Adc::read_internal()] to perform conversion. | ||||
|     pub fn enable_vrefint(&self) -> VrefInt { | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|reg| { | ||||
|                 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); | ||||
|             }); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|reg| { | ||||
|             reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); | ||||
|         }); | ||||
|  | ||||
|         VrefInt {} | ||||
|     } | ||||
| @@ -144,11 +137,9 @@ where | ||||
|     /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled, | ||||
|     /// temperature sensor will return vbat value. | ||||
|     pub fn enable_temperature(&self) -> Temperature { | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|reg| { | ||||
|                 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); | ||||
|             }); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|reg| { | ||||
|             reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); | ||||
|         }); | ||||
|  | ||||
|         Temperature {} | ||||
|     } | ||||
| @@ -156,37 +147,33 @@ where | ||||
|     /// Enables vbat input and returns [Vbat], which can be used in | ||||
|     /// [Adc::read_internal()] to perform conversion. | ||||
|     pub fn enable_vbat(&self) -> Vbat { | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|reg| { | ||||
|                 reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED); | ||||
|             }); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|reg| { | ||||
|             reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED); | ||||
|         }); | ||||
|  | ||||
|         Vbat {} | ||||
|     } | ||||
|  | ||||
|     /// Perform a single conversion. | ||||
|     fn convert(&mut self) -> u16 { | ||||
|         unsafe { | ||||
|             // clear end of conversion flag | ||||
|             T::regs().sr().modify(|reg| { | ||||
|                 reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE); | ||||
|             }); | ||||
|         // clear end of conversion flag | ||||
|         T::regs().sr().modify(|reg| { | ||||
|             reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE); | ||||
|         }); | ||||
|  | ||||
|             // Start conversion | ||||
|             T::regs().cr2().modify(|reg| { | ||||
|                 reg.set_swstart(true); | ||||
|             }); | ||||
|         // Start conversion | ||||
|         T::regs().cr2().modify(|reg| { | ||||
|             reg.set_swstart(true); | ||||
|         }); | ||||
|  | ||||
|             while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED { | ||||
|                 // spin //wait for actual start | ||||
|             } | ||||
|             while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE { | ||||
|                 // spin //wait for finish | ||||
|             } | ||||
|  | ||||
|             T::regs().dr().read().0 as u16 | ||||
|         while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED { | ||||
|             // spin //wait for actual start | ||||
|         } | ||||
|         while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE { | ||||
|             // spin //wait for finish | ||||
|         } | ||||
|  | ||||
|         T::regs().dr().read().0 as u16 | ||||
|     } | ||||
|  | ||||
|     pub fn read<P>(&mut self, pin: &mut P) -> u16 | ||||
| @@ -194,18 +181,16 @@ where | ||||
|         P: AdcPin<T>, | ||||
|         P: crate::gpio::sealed::Pin, | ||||
|     { | ||||
|         unsafe { | ||||
|             pin.set_as_analog(); | ||||
|         pin.set_as_analog(); | ||||
|  | ||||
|             self.read_channel(pin.channel()) | ||||
|         } | ||||
|         self.read_channel(pin.channel()) | ||||
|     } | ||||
|  | ||||
|     pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { | ||||
|         unsafe { self.read_channel(channel.channel()) } | ||||
|         self.read_channel(channel.channel()) | ||||
|     } | ||||
|  | ||||
|     unsafe fn read_channel(&mut self, channel: u8) -> u16 { | ||||
|     fn read_channel(&mut self, channel: u8) -> u16 { | ||||
|         // Configure ADC | ||||
|  | ||||
|         // Select channel | ||||
| @@ -219,7 +204,7 @@ where | ||||
|         val | ||||
|     } | ||||
|  | ||||
|     unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||||
|     fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||||
|         let sample_time = sample_time.into(); | ||||
|         if ch <= 9 { | ||||
|             T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); | ||||
|   | ||||
| @@ -12,7 +12,7 @@ pub const VREF_CALIB_MV: u32 = 3000; | ||||
| /// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock | ||||
| /// configuration. | ||||
| fn enable() { | ||||
|     critical_section::with(|_| unsafe { | ||||
|     critical_section::with(|_| { | ||||
|         #[cfg(stm32h7)] | ||||
|         crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); | ||||
|         #[cfg(stm32g0)] | ||||
| @@ -62,29 +62,25 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|     pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { | ||||
|         into_ref!(adc); | ||||
|         enable(); | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 #[cfg(not(adc_g0))] | ||||
|                 reg.set_deeppwd(false); | ||||
|                 reg.set_advregen(true); | ||||
|             }); | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             #[cfg(not(adc_g0))] | ||||
|             reg.set_deeppwd(false); | ||||
|             reg.set_advregen(true); | ||||
|         }); | ||||
|  | ||||
|             #[cfg(adc_g0)] | ||||
|             T::regs().cfgr1().modify(|reg| { | ||||
|                 reg.set_chselrmod(false); | ||||
|             }); | ||||
|         } | ||||
|         #[cfg(adc_g0)] | ||||
|         T::regs().cfgr1().modify(|reg| { | ||||
|             reg.set_chselrmod(false); | ||||
|         }); | ||||
|  | ||||
|         delay.delay_us(20); | ||||
|  | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 reg.set_adcal(true); | ||||
|             }); | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             reg.set_adcal(true); | ||||
|         }); | ||||
|  | ||||
|             while T::regs().cr().read().adcal() { | ||||
|                 // spin | ||||
|             } | ||||
|         while T::regs().cr().read().adcal() { | ||||
|             // spin | ||||
|         } | ||||
|  | ||||
|         delay.delay_us(1); | ||||
| @@ -96,11 +92,9 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|     } | ||||
|  | ||||
|     pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|reg| { | ||||
|                 reg.set_vrefen(true); | ||||
|             }); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|reg| { | ||||
|             reg.set_vrefen(true); | ||||
|         }); | ||||
|  | ||||
|         // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us | ||||
|         // to stabilize the internal voltage reference, we wait a little more. | ||||
| @@ -112,21 +106,17 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|     } | ||||
|  | ||||
|     pub fn enable_temperature(&self) -> Temperature { | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|reg| { | ||||
|                 reg.set_ch17sel(true); | ||||
|             }); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|reg| { | ||||
|             reg.set_ch17sel(true); | ||||
|         }); | ||||
|  | ||||
|         Temperature {} | ||||
|     } | ||||
|  | ||||
|     pub fn enable_vbat(&self) -> Vbat { | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|reg| { | ||||
|                 reg.set_ch18sel(true); | ||||
|             }); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|reg| { | ||||
|             reg.set_ch18sel(true); | ||||
|         }); | ||||
|  | ||||
|         Vbat {} | ||||
|     } | ||||
| @@ -136,12 +126,10 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|     } | ||||
|  | ||||
|     pub fn set_resolution(&mut self, resolution: Resolution) { | ||||
|         unsafe { | ||||
|             #[cfg(not(stm32g0))] | ||||
|             T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||||
|             #[cfg(stm32g0)] | ||||
|             T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||||
|         } | ||||
|         #[cfg(not(stm32g0))] | ||||
|         T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||||
|         #[cfg(stm32g0)] | ||||
|         T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
| @@ -155,77 +143,73 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|  | ||||
|     /// Perform a single conversion. | ||||
|     fn convert(&mut self) -> u16 { | ||||
|         unsafe { | ||||
|             T::regs().isr().modify(|reg| { | ||||
|                 reg.set_eos(true); | ||||
|                 reg.set_eoc(true); | ||||
|             }); | ||||
|         T::regs().isr().modify(|reg| { | ||||
|             reg.set_eos(true); | ||||
|             reg.set_eoc(true); | ||||
|         }); | ||||
|  | ||||
|             // Start conversion | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 reg.set_adstart(true); | ||||
|             }); | ||||
|         // Start conversion | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             reg.set_adstart(true); | ||||
|         }); | ||||
|  | ||||
|             while !T::regs().isr().read().eos() { | ||||
|                 // spin | ||||
|             } | ||||
|  | ||||
|             T::regs().dr().read().0 as u16 | ||||
|         while !T::regs().isr().read().eos() { | ||||
|             // spin | ||||
|         } | ||||
|  | ||||
|         T::regs().dr().read().0 as u16 | ||||
|     } | ||||
|  | ||||
|     pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | ||||
|         unsafe { | ||||
|             // Make sure bits are off | ||||
|             while T::regs().cr().read().addis() { | ||||
|                 // spin | ||||
|             } | ||||
|  | ||||
|             // Enable ADC | ||||
|             T::regs().isr().modify(|reg| { | ||||
|                 reg.set_adrdy(true); | ||||
|             }); | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 reg.set_aden(true); | ||||
|             }); | ||||
|  | ||||
|             while !T::regs().isr().read().adrdy() { | ||||
|                 // spin | ||||
|             } | ||||
|  | ||||
|             // Configure channel | ||||
|             Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||||
|  | ||||
|             // Select channel | ||||
|             #[cfg(not(stm32g0))] | ||||
|             T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); | ||||
|             #[cfg(stm32g0)] | ||||
|             T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); | ||||
|  | ||||
|             // Some models are affected by an erratum: | ||||
|             // If we perform conversions slower than 1 kHz, the first read ADC value can be | ||||
|             // corrupted, so we discard it and measure again. | ||||
|             // | ||||
|             // STM32L471xx: Section 2.7.3 | ||||
|             // STM32G4: Section 2.7.3 | ||||
|             #[cfg(any(rcc_l4, rcc_g4))] | ||||
|             let _ = self.convert(); | ||||
|  | ||||
|             let val = self.convert(); | ||||
|  | ||||
|             T::regs().cr().modify(|reg| reg.set_addis(true)); | ||||
|  | ||||
|             val | ||||
|         // Make sure bits are off | ||||
|         while T::regs().cr().read().addis() { | ||||
|             // spin | ||||
|         } | ||||
|  | ||||
|         // Enable ADC | ||||
|         T::regs().isr().modify(|reg| { | ||||
|             reg.set_adrdy(true); | ||||
|         }); | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             reg.set_aden(true); | ||||
|         }); | ||||
|  | ||||
|         while !T::regs().isr().read().adrdy() { | ||||
|             // spin | ||||
|         } | ||||
|  | ||||
|         // Configure channel | ||||
|         Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||||
|  | ||||
|         // Select channel | ||||
|         #[cfg(not(stm32g0))] | ||||
|         T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); | ||||
|         #[cfg(stm32g0)] | ||||
|         T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); | ||||
|  | ||||
|         // Some models are affected by an erratum: | ||||
|         // If we perform conversions slower than 1 kHz, the first read ADC value can be | ||||
|         // corrupted, so we discard it and measure again. | ||||
|         // | ||||
|         // STM32L471xx: Section 2.7.3 | ||||
|         // STM32G4: Section 2.7.3 | ||||
|         #[cfg(any(rcc_l4, rcc_g4))] | ||||
|         let _ = self.convert(); | ||||
|  | ||||
|         let val = self.convert(); | ||||
|  | ||||
|         T::regs().cr().modify(|reg| reg.set_addis(true)); | ||||
|  | ||||
|         val | ||||
|     } | ||||
|  | ||||
|     #[cfg(stm32g0)] | ||||
|     unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { | ||||
|     fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { | ||||
|         T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(stm32g0))] | ||||
|     unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||||
|     fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||||
|         let sample_time = sample_time.into(); | ||||
|         if ch <= 9 { | ||||
|             T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); | ||||
|   | ||||
| @@ -46,8 +46,8 @@ foreach_peripheral!( | ||||
|     (adc, ADC1) => { | ||||
|         impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 { | ||||
|             fn frequency() -> crate::time::Hertz { | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                     match crate::rcc::get_freqs().adc { | ||||
|                 critical_section::with(|_| { | ||||
|                     match unsafe { crate::rcc::get_freqs() }.adc { | ||||
|                         Some(ck) => ck, | ||||
|                         None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") | ||||
|                     } | ||||
| @@ -55,7 +55,7 @@ foreach_peripheral!( | ||||
|             } | ||||
|  | ||||
|             fn enable() { | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) | ||||
|                 }); | ||||
|                 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); | ||||
| @@ -63,7 +63,7 @@ foreach_peripheral!( | ||||
|  | ||||
|             fn disable() { | ||||
|                 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | ||||
|                     critical_section::with(|_| unsafe { | ||||
|                     critical_section::with(|_| { | ||||
|                         crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); | ||||
|                     }) | ||||
|                 } | ||||
| @@ -72,7 +72,7 @@ foreach_peripheral!( | ||||
|  | ||||
|             fn reset() { | ||||
|                 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | ||||
|                     critical_section::with(|_| unsafe { | ||||
|                     critical_section::with(|_| { | ||||
|                         crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); | ||||
|                         crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); | ||||
|                     }); | ||||
| @@ -85,8 +85,8 @@ foreach_peripheral!( | ||||
|     (adc, ADC2) => { | ||||
|         impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 { | ||||
|             fn frequency() -> crate::time::Hertz { | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                     match crate::rcc::get_freqs().adc { | ||||
|                 critical_section::with(|_| { | ||||
|                     match unsafe { crate::rcc::get_freqs() }.adc { | ||||
|                         Some(ck) => ck, | ||||
|                         None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") | ||||
|                     } | ||||
| @@ -94,7 +94,7 @@ foreach_peripheral!( | ||||
|             } | ||||
|  | ||||
|             fn enable() { | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) | ||||
|                 }); | ||||
|                 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); | ||||
| @@ -102,7 +102,7 @@ foreach_peripheral!( | ||||
|  | ||||
|             fn disable() { | ||||
|                 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | ||||
|                     critical_section::with(|_| unsafe { | ||||
|                     critical_section::with(|_| { | ||||
|                         crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); | ||||
|                     }) | ||||
|                 } | ||||
| @@ -111,7 +111,7 @@ foreach_peripheral!( | ||||
|  | ||||
|             fn reset() { | ||||
|                 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | ||||
|                     critical_section::with(|_| unsafe { | ||||
|                     critical_section::with(|_| { | ||||
|                         crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); | ||||
|                         crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); | ||||
|                     }); | ||||
| @@ -124,8 +124,8 @@ foreach_peripheral!( | ||||
|     (adc, ADC3) => { | ||||
|         impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 { | ||||
|             fn frequency() -> crate::time::Hertz { | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                     match crate::rcc::get_freqs().adc { | ||||
|                 critical_section::with(|_| { | ||||
|                     match unsafe { crate::rcc::get_freqs() }.adc { | ||||
|                         Some(ck) => ck, | ||||
|                         None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") | ||||
|                     } | ||||
| @@ -133,22 +133,22 @@ foreach_peripheral!( | ||||
|             } | ||||
|  | ||||
|             fn enable() { | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true)) | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             fn disable() { | ||||
|                     critical_section::with(|_| unsafe { | ||||
|                         crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false)); | ||||
|                     }) | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false)); | ||||
|                 }) | ||||
|             } | ||||
|  | ||||
|             fn reset() { | ||||
|                     critical_section::with(|_| unsafe { | ||||
|                         crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true)); | ||||
|                         crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false)); | ||||
|                     }); | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true)); | ||||
|                     crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false)); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -232,9 +232,7 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|  | ||||
|         let prescaler = Prescaler::from_ker_ck(T::frequency()); | ||||
|  | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | ||||
|  | ||||
|         let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | ||||
|         info!("ADC frequency set to {} Hz", frequency.0); | ||||
| @@ -251,9 +249,7 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|         } else { | ||||
|             Boost::LT50 | ||||
|         }; | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|w| w.set_boost(boost)); | ||||
|         } | ||||
|         T::regs().cr().modify(|w| w.set_boost(boost)); | ||||
|  | ||||
|         let mut s = Self { | ||||
|             adc, | ||||
| @@ -272,84 +268,68 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|     } | ||||
|  | ||||
|     fn power_up(&mut self, delay: &mut impl DelayUs<u16>) { | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 reg.set_deeppwd(false); | ||||
|                 reg.set_advregen(true); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             reg.set_deeppwd(false); | ||||
|             reg.set_advregen(true); | ||||
|         }); | ||||
|  | ||||
|         delay.delay_us(10); | ||||
|     } | ||||
|  | ||||
|     fn configure_differential_inputs(&mut self) { | ||||
|         unsafe { | ||||
|             T::regs().difsel().modify(|w| { | ||||
|                 for n in 0..20 { | ||||
|                     w.set_difsel(n, Difsel::SINGLEENDED); | ||||
|                 } | ||||
|             }) | ||||
|         }; | ||||
|         T::regs().difsel().modify(|w| { | ||||
|             for n in 0..20 { | ||||
|                 w.set_difsel(n, Difsel::SINGLEENDED); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     fn calibrate(&mut self) { | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|w| { | ||||
|                 w.set_adcaldif(Adcaldif::SINGLEENDED); | ||||
|                 w.set_adcallin(true); | ||||
|             }); | ||||
|         T::regs().cr().modify(|w| { | ||||
|             w.set_adcaldif(Adcaldif::SINGLEENDED); | ||||
|             w.set_adcallin(true); | ||||
|         }); | ||||
|  | ||||
|             T::regs().cr().modify(|w| w.set_adcal(true)); | ||||
|         T::regs().cr().modify(|w| w.set_adcal(true)); | ||||
|  | ||||
|             while T::regs().cr().read().adcal() {} | ||||
|         } | ||||
|         while T::regs().cr().read().adcal() {} | ||||
|     } | ||||
|  | ||||
|     fn enable(&mut self) { | ||||
|         unsafe { | ||||
|             T::regs().isr().write(|w| w.set_adrdy(true)); | ||||
|             T::regs().cr().modify(|w| w.set_aden(true)); | ||||
|             while !T::regs().isr().read().adrdy() {} | ||||
|             T::regs().isr().write(|w| w.set_adrdy(true)); | ||||
|         } | ||||
|         T::regs().isr().write(|w| w.set_adrdy(true)); | ||||
|         T::regs().cr().modify(|w| w.set_aden(true)); | ||||
|         while !T::regs().isr().read().adrdy() {} | ||||
|         T::regs().isr().write(|w| w.set_adrdy(true)); | ||||
|     } | ||||
|  | ||||
|     fn configure(&mut self) { | ||||
|         // single conversion mode, software trigger | ||||
|         unsafe { | ||||
|             T::regs().cfgr().modify(|w| { | ||||
|                 w.set_cont(false); | ||||
|                 w.set_exten(Exten::DISABLED); | ||||
|             }) | ||||
|         } | ||||
|         T::regs().cfgr().modify(|w| { | ||||
|             w.set_cont(false); | ||||
|             w.set_exten(Exten::DISABLED); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn enable_vrefint(&self) -> VrefInt { | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|reg| { | ||||
|                 reg.set_vrefen(true); | ||||
|             }); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|reg| { | ||||
|             reg.set_vrefen(true); | ||||
|         }); | ||||
|  | ||||
|         VrefInt {} | ||||
|     } | ||||
|  | ||||
|     pub fn enable_temperature(&self) -> Temperature { | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|reg| { | ||||
|                 reg.set_vsenseen(true); | ||||
|             }); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|reg| { | ||||
|             reg.set_vsenseen(true); | ||||
|         }); | ||||
|  | ||||
|         Temperature {} | ||||
|     } | ||||
|  | ||||
|     pub fn enable_vbat(&self) -> Vbat { | ||||
|         unsafe { | ||||
|             T::common_regs().ccr().modify(|reg| { | ||||
|                 reg.set_vbaten(true); | ||||
|             }); | ||||
|         } | ||||
|         T::common_regs().ccr().modify(|reg| { | ||||
|             reg.set_vbaten(true); | ||||
|         }); | ||||
|  | ||||
|         Vbat {} | ||||
|     } | ||||
| @@ -359,30 +339,26 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|     } | ||||
|  | ||||
|     pub fn set_resolution(&mut self, resolution: Resolution) { | ||||
|         unsafe { | ||||
|             T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||||
|         } | ||||
|         T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||||
|     } | ||||
|  | ||||
|     /// Perform a single conversion. | ||||
|     fn convert(&mut self) -> u16 { | ||||
|         unsafe { | ||||
|             T::regs().isr().modify(|reg| { | ||||
|                 reg.set_eos(true); | ||||
|                 reg.set_eoc(true); | ||||
|             }); | ||||
|         T::regs().isr().modify(|reg| { | ||||
|             reg.set_eos(true); | ||||
|             reg.set_eoc(true); | ||||
|         }); | ||||
|  | ||||
|             // Start conversion | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 reg.set_adstart(true); | ||||
|             }); | ||||
|         // Start conversion | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             reg.set_adstart(true); | ||||
|         }); | ||||
|  | ||||
|             while !T::regs().isr().read().eos() { | ||||
|                 // spin | ||||
|             } | ||||
|  | ||||
|             T::regs().dr().read().0 as u16 | ||||
|         while !T::regs().isr().read().eos() { | ||||
|             // spin | ||||
|         } | ||||
|  | ||||
|         T::regs().dr().read().0 as u16 | ||||
|     } | ||||
|  | ||||
|     pub fn read<P>(&mut self, pin: &mut P) -> u16 | ||||
| @@ -390,18 +366,16 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|         P: AdcPin<T>, | ||||
|         P: crate::gpio::sealed::Pin, | ||||
|     { | ||||
|         unsafe { | ||||
|             pin.set_as_analog(); | ||||
|         pin.set_as_analog(); | ||||
|  | ||||
|             self.read_channel(pin.channel()) | ||||
|         } | ||||
|         self.read_channel(pin.channel()) | ||||
|     } | ||||
|  | ||||
|     pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { | ||||
|         unsafe { self.read_channel(channel.channel()) } | ||||
|         self.read_channel(channel.channel()) | ||||
|     } | ||||
|  | ||||
|     unsafe fn read_channel(&mut self, channel: u8) -> u16 { | ||||
|     fn read_channel(&mut self, channel: u8) -> u16 { | ||||
|         // Configure channel | ||||
|         Self::set_channel_sample_time(channel, self.sample_time); | ||||
|  | ||||
| @@ -417,7 +391,7 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|         self.convert() | ||||
|     } | ||||
|  | ||||
|     unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||||
|     fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||||
|         let sample_time = sample_time.into(); | ||||
|         if ch <= 9 { | ||||
|             T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); | ||||
|   | ||||
| @@ -20,10 +20,8 @@ impl<'d, T: Instance> Can<'d, T> { | ||||
|     ) -> Self { | ||||
|         into_ref!(peri, rx, tx); | ||||
|  | ||||
|         unsafe { | ||||
|             rx.set_as_af(rx.af_num(), AFType::Input); | ||||
|             tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||
|         } | ||||
|         rx.set_as_af(rx.af_num(), AFType::Input); | ||||
|         tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||
|  | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
| @@ -42,10 +40,8 @@ impl<'d, T: Instance> Can<'d, T> { | ||||
|     ) -> Self { | ||||
|         into_ref!(peri, rx, tx); | ||||
|  | ||||
|         unsafe { | ||||
|             rx.set_as_af(rx.af_num(), AFType::Input); | ||||
|             tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||
|         } | ||||
|         rx.set_as_af(rx.af_num(), AFType::Input); | ||||
|         tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||
|  | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
| @@ -60,7 +56,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> { | ||||
|     fn drop(&mut self) { | ||||
|         // Cannot call `free()` because it moves the instance. | ||||
|         // Manually reset the peripheral. | ||||
|         unsafe { T::regs().mcr().write(|w| w.set_reset(true)) } | ||||
|         T::regs().mcr().write(|w| w.set_reset(true)); | ||||
|         T::disable(); | ||||
|     } | ||||
| } | ||||
| @@ -98,7 +94,7 @@ unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { | ||||
| foreach_peripheral!( | ||||
|     (can, $inst:ident) => { | ||||
|         impl sealed::Instance for peripherals::$inst { | ||||
|             const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.0 as *mut _; | ||||
|             const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; | ||||
|  | ||||
|             fn regs() -> &'static crate::pac::can::Can { | ||||
|                 &crate::pac::$inst | ||||
|   | ||||
| @@ -27,26 +27,24 @@ impl<'d> Crc<'d> { | ||||
|  | ||||
|     /// Resets the CRC unit to default value (0xFFFF_FFFF) | ||||
|     pub fn reset(&mut self) { | ||||
|         unsafe { PAC_CRC.cr().write(|w| w.set_reset(true)) }; | ||||
|         PAC_CRC.cr().write(|w| w.set_reset(true)); | ||||
|     } | ||||
|  | ||||
|     /// Feeds a word to the peripheral and returns the current CRC value | ||||
|     pub fn feed_word(&mut self, word: u32) -> u32 { | ||||
|         // write a single byte to the device, and return the result | ||||
|         unsafe { | ||||
|             PAC_CRC.dr().write_value(word); | ||||
|         } | ||||
|         PAC_CRC.dr().write_value(word); | ||||
|         self.read() | ||||
|     } | ||||
|     /// Feed a slice of words to the peripheral and return the result. | ||||
|     pub fn feed_words(&mut self, words: &[u32]) -> u32 { | ||||
|         for word in words { | ||||
|             unsafe { PAC_CRC.dr().write_value(*word) } | ||||
|             PAC_CRC.dr().write_value(*word); | ||||
|         } | ||||
|  | ||||
|         self.read() | ||||
|     } | ||||
|     pub fn read(&self) -> u32 { | ||||
|         unsafe { PAC_CRC.dr().read() } | ||||
|         PAC_CRC.dr().read() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -85,95 +85,79 @@ impl<'d> Crc<'d> { | ||||
|     } | ||||
|  | ||||
|     pub fn reset(&mut self) { | ||||
|         unsafe { | ||||
|             PAC_CRC.cr().modify(|w| w.set_reset(true)); | ||||
|         } | ||||
|         PAC_CRC.cr().modify(|w| w.set_reset(true)); | ||||
|     } | ||||
|  | ||||
|     /// Reconfigures the CRC peripheral. Doesn't reset. | ||||
|     fn reconfigure(&mut self) { | ||||
|         unsafe { | ||||
|             // Init CRC value | ||||
|             PAC_CRC.init().write_value(self._config.crc_init_value); | ||||
|             #[cfg(crc_v3)] | ||||
|             PAC_CRC.pol().write_value(self._config.crc_poly); | ||||
|         // Init CRC value | ||||
|         PAC_CRC.init().write_value(self._config.crc_init_value); | ||||
|         #[cfg(crc_v3)] | ||||
|         PAC_CRC.pol().write_value(self._config.crc_poly); | ||||
|  | ||||
|             // configure CR components | ||||
|             // (reverse I/O, polysize, poly) | ||||
|             PAC_CRC.cr().write(|w| { | ||||
|                 // configure reverse output | ||||
|                 w.set_rev_out(match self._config.reverse_out { | ||||
|                     true => vals::RevOut::REVERSED, | ||||
|                     false => vals::RevOut::NORMAL, | ||||
|                 }); | ||||
|                 // configure reverse input | ||||
|                 w.set_rev_in(match self._config.reverse_in { | ||||
|                     InputReverseConfig::None => vals::RevIn::NORMAL, | ||||
|                     InputReverseConfig::Byte => vals::RevIn::BYTE, | ||||
|                     InputReverseConfig::Halfword => vals::RevIn::HALFWORD, | ||||
|                     InputReverseConfig::Word => vals::RevIn::WORD, | ||||
|                 }); | ||||
|                 // configure the polynomial. | ||||
|                 #[cfg(crc_v3)] | ||||
|                 w.set_polysize(match self._config.poly_size { | ||||
|                     PolySize::Width7 => vals::Polysize::POLYSIZE7, | ||||
|                     PolySize::Width8 => vals::Polysize::POLYSIZE8, | ||||
|                     PolySize::Width16 => vals::Polysize::POLYSIZE16, | ||||
|                     PolySize::Width32 => vals::Polysize::POLYSIZE32, | ||||
|                 }); | ||||
|             }) | ||||
|         } | ||||
|         // configure CR components | ||||
|         // (reverse I/O, polysize, poly) | ||||
|         PAC_CRC.cr().write(|w| { | ||||
|             // configure reverse output | ||||
|             w.set_rev_out(match self._config.reverse_out { | ||||
|                 true => vals::RevOut::REVERSED, | ||||
|                 false => vals::RevOut::NORMAL, | ||||
|             }); | ||||
|             // configure reverse input | ||||
|             w.set_rev_in(match self._config.reverse_in { | ||||
|                 InputReverseConfig::None => vals::RevIn::NORMAL, | ||||
|                 InputReverseConfig::Byte => vals::RevIn::BYTE, | ||||
|                 InputReverseConfig::Halfword => vals::RevIn::HALFWORD, | ||||
|                 InputReverseConfig::Word => vals::RevIn::WORD, | ||||
|             }); | ||||
|             // configure the polynomial. | ||||
|             #[cfg(crc_v3)] | ||||
|             w.set_polysize(match self._config.poly_size { | ||||
|                 PolySize::Width7 => vals::Polysize::POLYSIZE7, | ||||
|                 PolySize::Width8 => vals::Polysize::POLYSIZE8, | ||||
|                 PolySize::Width16 => vals::Polysize::POLYSIZE16, | ||||
|                 PolySize::Width32 => vals::Polysize::POLYSIZE32, | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         self.reset(); | ||||
|     } | ||||
|  | ||||
|     /// Feeds a byte into the CRC peripheral. Returns the computed checksum. | ||||
|     pub fn feed_byte(&mut self, byte: u8) -> u32 { | ||||
|         unsafe { | ||||
|             PAC_CRC.dr8().write_value(byte); | ||||
|             PAC_CRC.dr().read() | ||||
|         } | ||||
|         PAC_CRC.dr8().write_value(byte); | ||||
|         PAC_CRC.dr().read() | ||||
|     } | ||||
|  | ||||
|     /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. | ||||
|     pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 { | ||||
|         for byte in bytes { | ||||
|             unsafe { | ||||
|                 PAC_CRC.dr8().write_value(*byte); | ||||
|             } | ||||
|             PAC_CRC.dr8().write_value(*byte); | ||||
|         } | ||||
|         unsafe { PAC_CRC.dr().read() } | ||||
|         PAC_CRC.dr().read() | ||||
|     } | ||||
|     /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. | ||||
|     pub fn feed_halfword(&mut self, halfword: u16) -> u32 { | ||||
|         unsafe { | ||||
|             PAC_CRC.dr16().write_value(halfword); | ||||
|             PAC_CRC.dr().read() | ||||
|         } | ||||
|         PAC_CRC.dr16().write_value(halfword); | ||||
|         PAC_CRC.dr().read() | ||||
|     } | ||||
|     /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. | ||||
|     pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { | ||||
|         for halfword in halfwords { | ||||
|             unsafe { | ||||
|                 PAC_CRC.dr16().write_value(*halfword); | ||||
|             } | ||||
|             PAC_CRC.dr16().write_value(*halfword); | ||||
|         } | ||||
|         unsafe { PAC_CRC.dr().read() } | ||||
|         PAC_CRC.dr().read() | ||||
|     } | ||||
|     /// Feeds a words into the CRC peripheral. Returns the computed checksum. | ||||
|     pub fn feed_word(&mut self, word: u32) -> u32 { | ||||
|         unsafe { | ||||
|             PAC_CRC.dr().write_value(word as u32); | ||||
|             PAC_CRC.dr().read() | ||||
|         } | ||||
|         PAC_CRC.dr().write_value(word as u32); | ||||
|         PAC_CRC.dr().read() | ||||
|     } | ||||
|     /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. | ||||
|     pub fn feed_words(&mut self, words: &[u32]) -> u32 { | ||||
|         for word in words { | ||||
|             unsafe { | ||||
|                 PAC_CRC.dr().write_value(*word as u32); | ||||
|             } | ||||
|             PAC_CRC.dr().write_value(*word as u32); | ||||
|         } | ||||
|         unsafe { PAC_CRC.dr().read() } | ||||
|         PAC_CRC.dr().read() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -121,13 +121,11 @@ impl<'d, T: Instance> Dac<'d, T> { | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
|  | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 for ch in 0..channels { | ||||
|                     reg.set_en(ch as usize, true); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             for ch in 0..channels { | ||||
|                 reg.set_en(ch as usize, true); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         Self { channels, _peri: peri } | ||||
|     } | ||||
| @@ -143,11 +141,9 @@ impl<'d, T: Instance> Dac<'d, T> { | ||||
|  | ||||
|     fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { | ||||
|         self.check_channel_exists(ch)?; | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 reg.set_en(ch.index(), on); | ||||
|             }) | ||||
|         } | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             reg.set_en(ch.index(), on); | ||||
|         }); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @@ -162,56 +158,42 @@ impl<'d, T: Instance> Dac<'d, T> { | ||||
|     pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { | ||||
|         self.check_channel_exists(Channel::Ch1)?; | ||||
|         unwrap!(self.disable_channel(Channel::Ch1)); | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 reg.set_tsel1(trigger.tsel()); | ||||
|             }) | ||||
|         } | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             reg.set_tsel1(trigger.tsel()); | ||||
|         }); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { | ||||
|         self.check_channel_exists(Channel::Ch2)?; | ||||
|         unwrap!(self.disable_channel(Channel::Ch2)); | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 reg.set_tsel2(trigger.tsel()); | ||||
|             }) | ||||
|         } | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             reg.set_tsel2(trigger.tsel()); | ||||
|         }); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { | ||||
|         self.check_channel_exists(ch)?; | ||||
|         unsafe { | ||||
|             T::regs().swtrigr().write(|reg| { | ||||
|                 reg.set_swtrig(ch.index(), true); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().swtrigr().write(|reg| { | ||||
|             reg.set_swtrig(ch.index(), true); | ||||
|         }); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn trigger_all(&mut self) { | ||||
|         unsafe { | ||||
|             T::regs().swtrigr().write(|reg| { | ||||
|                 reg.set_swtrig(Channel::Ch1.index(), true); | ||||
|                 reg.set_swtrig(Channel::Ch2.index(), true); | ||||
|             }) | ||||
|         } | ||||
|         T::regs().swtrigr().write(|reg| { | ||||
|             reg.set_swtrig(Channel::Ch1.index(), true); | ||||
|             reg.set_swtrig(Channel::Ch2.index(), true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { | ||||
|         self.check_channel_exists(ch)?; | ||||
|         match value { | ||||
|             Value::Bit8(v) => unsafe { | ||||
|                 T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)); | ||||
|             }, | ||||
|             Value::Bit12(v, Alignment::Left) => unsafe { | ||||
|                 T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)); | ||||
|             }, | ||||
|             Value::Bit12(v, Alignment::Right) => unsafe { | ||||
|                 T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)); | ||||
|             }, | ||||
|             Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)), | ||||
|             Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)), | ||||
|             Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)), | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| @@ -239,20 +221,20 @@ foreach_peripheral!( | ||||
|             } | ||||
|  | ||||
|             fn reset() { | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); | ||||
|                     crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); | ||||
|                 }) | ||||
|             } | ||||
|  | ||||
|             fn enable() { | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); | ||||
|                 }) | ||||
|             } | ||||
|  | ||||
|             fn disable() { | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)); | ||||
|                 }) | ||||
|             } | ||||
|   | ||||
| @@ -96,8 +96,7 @@ impl Default for Config { | ||||
| macro_rules! config_pins { | ||||
|     ($($pin:ident),*) => { | ||||
|         into_ref!($($pin),*); | ||||
|         // NOTE(unsafe) Exclusive access to the registers | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             $( | ||||
|                 $pin.set_as_af($pin.af_num(), AFType::Input); | ||||
|                 $pin.set_speed(Speed::VeryHigh); | ||||
| @@ -334,17 +333,15 @@ where | ||||
|         T::reset(); | ||||
|         T::enable(); | ||||
|  | ||||
|         unsafe { | ||||
|             peri.regs().cr().modify(|r| { | ||||
|                 r.set_cm(true); // disable continuous mode (snapshot mode) | ||||
|                 r.set_ess(use_embedded_synchronization); | ||||
|                 r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge); | ||||
|                 r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High); | ||||
|                 r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High); | ||||
|                 r.set_fcrc(0x00); // capture every frame | ||||
|                 r.set_edm(edm); // extended data mode | ||||
|             }); | ||||
|         } | ||||
|         peri.regs().cr().modify(|r| { | ||||
|             r.set_cm(true); // disable continuous mode (snapshot mode) | ||||
|             r.set_ess(use_embedded_synchronization); | ||||
|             r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge); | ||||
|             r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High); | ||||
|             r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High); | ||||
|             r.set_fcrc(0x00); // capture every frame | ||||
|             r.set_edm(edm); // extended data mode | ||||
|         }); | ||||
|  | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
| @@ -352,7 +349,7 @@ where | ||||
|         Self { inner: peri, dma } | ||||
|     } | ||||
|  | ||||
|     unsafe fn toggle(enable: bool) { | ||||
|     fn toggle(enable: bool) { | ||||
|         crate::pac::DCMI.cr().modify(|r| { | ||||
|             r.set_enable(enable); | ||||
|             r.set_capture(enable); | ||||
| @@ -360,23 +357,19 @@ where | ||||
|     } | ||||
|  | ||||
|     fn enable_irqs() { | ||||
|         unsafe { | ||||
|             crate::pac::DCMI.ier().modify(|r| { | ||||
|                 r.set_err_ie(true); | ||||
|                 r.set_ovr_ie(true); | ||||
|                 r.set_frame_ie(true); | ||||
|             }); | ||||
|         } | ||||
|         crate::pac::DCMI.ier().modify(|r| { | ||||
|             r.set_err_ie(true); | ||||
|             r.set_ovr_ie(true); | ||||
|             r.set_frame_ie(true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     fn clear_interrupt_flags() { | ||||
|         unsafe { | ||||
|             crate::pac::DCMI.icr().write(|r| { | ||||
|                 r.set_ovr_isc(true); | ||||
|                 r.set_err_isc(true); | ||||
|                 r.set_frame_isc(true); | ||||
|             }) | ||||
|         } | ||||
|         crate::pac::DCMI.icr().write(|r| { | ||||
|             r.set_ovr_isc(true); | ||||
|             r.set_err_isc(true); | ||||
|             r.set_frame_isc(true); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer. | ||||
| @@ -392,41 +385,30 @@ where | ||||
|             return self.capture_giant(buffer).await; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> { | ||||
|         let r = self.inner.regs(); | ||||
|         let src = r.dr().ptr() as *mut u32; | ||||
|         let src = r.dr().as_ptr() as *mut u32; | ||||
|         let request = self.dma.request(); | ||||
|         let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) }; | ||||
|  | ||||
|         Self::clear_interrupt_flags(); | ||||
|         Self::enable_irqs(); | ||||
|  | ||||
|         unsafe { Self::toggle(true) }; | ||||
|         Self::toggle(true); | ||||
|  | ||||
|         let result = poll_fn(|cx| { | ||||
|             STATE.waker.register(cx.waker()); | ||||
|  | ||||
|             let ris = unsafe { crate::pac::DCMI.ris().read() }; | ||||
|             let ris = crate::pac::DCMI.ris().read(); | ||||
|             if ris.err_ris() { | ||||
|                 unsafe { | ||||
|                     crate::pac::DCMI.icr().write(|r| { | ||||
|                         r.set_err_isc(true); | ||||
|                     }) | ||||
|                 }; | ||||
|                 crate::pac::DCMI.icr().write(|r| r.set_err_isc(true)); | ||||
|                 Poll::Ready(Err(Error::PeripheralError)) | ||||
|             } else if ris.ovr_ris() { | ||||
|                 unsafe { | ||||
|                     crate::pac::DCMI.icr().write(|r| { | ||||
|                         r.set_ovr_isc(true); | ||||
|                     }) | ||||
|                 }; | ||||
|                 crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true)); | ||||
|                 Poll::Ready(Err(Error::Overrun)) | ||||
|             } else if ris.frame_ris() { | ||||
|                 unsafe { | ||||
|                     crate::pac::DCMI.icr().write(|r| { | ||||
|                         r.set_frame_isc(true); | ||||
|                     }) | ||||
|                 }; | ||||
|                 crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true)); | ||||
|                 Poll::Ready(Ok(())) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
| @@ -435,7 +417,7 @@ where | ||||
|  | ||||
|         let (_, result) = embassy_futures::join::join(dma_read, result).await; | ||||
|  | ||||
|         unsafe { Self::toggle(false) }; | ||||
|         Self::toggle(false); | ||||
|  | ||||
|         result | ||||
|     } | ||||
| @@ -468,7 +450,7 @@ where | ||||
|         let request = channel.request(); | ||||
|  | ||||
|         let r = self.inner.regs(); | ||||
|         let src = r.dr().ptr() as *mut u32; | ||||
|         let src = r.dr().as_ptr() as *mut u32; | ||||
|  | ||||
|         let mut transfer = unsafe { | ||||
|             crate::dma::DoubleBuffered::new_read( | ||||
| @@ -526,38 +508,26 @@ where | ||||
|         let result = poll_fn(|cx| { | ||||
|             STATE.waker.register(cx.waker()); | ||||
|  | ||||
|             let ris = unsafe { crate::pac::DCMI.ris().read() }; | ||||
|             let ris = crate::pac::DCMI.ris().read(); | ||||
|             if ris.err_ris() { | ||||
|                 unsafe { | ||||
|                     crate::pac::DCMI.icr().write(|r| { | ||||
|                         r.set_err_isc(true); | ||||
|                     }) | ||||
|                 }; | ||||
|                 crate::pac::DCMI.icr().write(|r| r.set_err_isc(true)); | ||||
|                 Poll::Ready(Err(Error::PeripheralError)) | ||||
|             } else if ris.ovr_ris() { | ||||
|                 unsafe { | ||||
|                     crate::pac::DCMI.icr().write(|r| { | ||||
|                         r.set_ovr_isc(true); | ||||
|                     }) | ||||
|                 }; | ||||
|                 crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true)); | ||||
|                 Poll::Ready(Err(Error::Overrun)) | ||||
|             } else if ris.frame_ris() { | ||||
|                 unsafe { | ||||
|                     crate::pac::DCMI.icr().write(|r| { | ||||
|                         r.set_frame_isc(true); | ||||
|                     }) | ||||
|                 }; | ||||
|                 crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true)); | ||||
|                 Poll::Ready(Ok(())) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         unsafe { Self::toggle(true) }; | ||||
|         Self::toggle(true); | ||||
|  | ||||
|         let (_, result) = embassy_futures::join::join(dma_result, result).await; | ||||
|  | ||||
|         unsafe { Self::toggle(false) }; | ||||
|         Self::toggle(false); | ||||
|  | ||||
|         result | ||||
|     } | ||||
|   | ||||
| @@ -107,7 +107,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index | ||||
|     let cr = dma.ch(channel_num).cr(); | ||||
|  | ||||
|     if isr.teif(channel_num) { | ||||
|         panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num); | ||||
|         panic!("DMA: error on BDMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num); | ||||
|     } | ||||
|  | ||||
|     if isr.htif(channel_num) && cr.read().htie() { | ||||
| @@ -291,29 +291,25 @@ impl<'a, C: Channel> Transfer<'a, C> { | ||||
|     } | ||||
|  | ||||
|     fn clear_irqs(&mut self) { | ||||
|         unsafe { | ||||
|             self.channel.regs().ifcr().write(|w| { | ||||
|                 w.set_tcif(self.channel.num(), true); | ||||
|                 w.set_teif(self.channel.num(), true); | ||||
|             }) | ||||
|         } | ||||
|         self.channel.regs().ifcr().write(|w| { | ||||
|             w.set_tcif(self.channel.num(), true); | ||||
|             w.set_teif(self.channel.num(), true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn request_stop(&mut self) { | ||||
|         let ch = self.channel.regs().ch(self.channel.num()); | ||||
|  | ||||
|         // Disable the channel. Keep the IEs enabled so the irqs still fire. | ||||
|         unsafe { | ||||
|             ch.cr().write(|w| { | ||||
|                 w.set_teie(true); | ||||
|                 w.set_tcie(true); | ||||
|             }) | ||||
|         } | ||||
|         ch.cr().write(|w| { | ||||
|             w.set_teie(true); | ||||
|             w.set_tcie(true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn is_running(&mut self) -> bool { | ||||
|         let ch = self.channel.regs().ch(self.channel.num()); | ||||
|         let en = unsafe { ch.cr().read() }.en(); | ||||
|         let en = ch.cr().read().en(); | ||||
|         let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; | ||||
|         en && !tcif | ||||
|     } | ||||
| @@ -322,7 +318,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | ||||
|     /// Note: this will be zero for transfers that completed without cancellation. | ||||
|     pub fn get_remaining_transfers(&self) -> u16 { | ||||
|         let ch = self.channel.regs().ch(self.channel.num()); | ||||
|         unsafe { ch.ndtr().read() }.ndt() | ||||
|         ch.ndtr().read().ndt() | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_wait(mut self) { | ||||
| @@ -366,7 +362,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>); | ||||
| impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { | ||||
|     fn get_remaining_transfers(&self) -> usize { | ||||
|         let ch = self.0.regs().ch(self.0.num()); | ||||
|         unsafe { ch.ndtr().read() }.ndt() as usize | ||||
|         ch.ndtr().read().ndt() as usize | ||||
|     } | ||||
|  | ||||
|     fn get_complete_count(&self) -> usize { | ||||
| @@ -442,7 +438,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> { | ||||
|  | ||||
|     pub fn start(&mut self) { | ||||
|         let ch = self.channel.regs().ch(self.channel.num()); | ||||
|         unsafe { ch.cr().write_value(self.cr) } | ||||
|         ch.cr().write_value(self.cr) | ||||
|     } | ||||
|  | ||||
|     pub fn clear(&mut self) { | ||||
| @@ -469,31 +465,27 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> { | ||||
|  | ||||
|     fn clear_irqs(&mut self) { | ||||
|         let dma = self.channel.regs(); | ||||
|         unsafe { | ||||
|             dma.ifcr().write(|w| { | ||||
|                 w.set_htif(self.channel.num(), true); | ||||
|                 w.set_tcif(self.channel.num(), true); | ||||
|                 w.set_teif(self.channel.num(), true); | ||||
|             }) | ||||
|         } | ||||
|         dma.ifcr().write(|w| { | ||||
|             w.set_htif(self.channel.num(), true); | ||||
|             w.set_tcif(self.channel.num(), true); | ||||
|             w.set_teif(self.channel.num(), true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn request_stop(&mut self) { | ||||
|         let ch = self.channel.regs().ch(self.channel.num()); | ||||
|  | ||||
|         // Disable the channel. Keep the IEs enabled so the irqs still fire. | ||||
|         unsafe { | ||||
|             ch.cr().write(|w| { | ||||
|                 w.set_teie(true); | ||||
|                 w.set_htie(true); | ||||
|                 w.set_tcie(true); | ||||
|             }) | ||||
|         } | ||||
|         ch.cr().write(|w| { | ||||
|             w.set_teie(true); | ||||
|             w.set_htie(true); | ||||
|             w.set_tcie(true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn is_running(&mut self) -> bool { | ||||
|         let ch = self.channel.regs().ch(self.channel.num()); | ||||
|         unsafe { ch.cr().read() }.en() | ||||
|         ch.cr().read().en() | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -183,7 +183,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index: | ||||
|     let isr = dma.isr(channel_num / 4).read(); | ||||
|  | ||||
|     if isr.teif(channel_num % 4) { | ||||
|         panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num); | ||||
|         panic!("DMA: error on DMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num); | ||||
|     } | ||||
|  | ||||
|     if isr.htif(channel_num % 4) && cr.read().htie() { | ||||
| @@ -387,36 +387,32 @@ impl<'a, C: Channel> Transfer<'a, C> { | ||||
|         let isrn = self.channel.num() / 4; | ||||
|         let isrbit = self.channel.num() % 4; | ||||
|  | ||||
|         unsafe { | ||||
|             self.channel.regs().ifcr(isrn).write(|w| { | ||||
|                 w.set_tcif(isrbit, true); | ||||
|                 w.set_teif(isrbit, true); | ||||
|             }) | ||||
|         } | ||||
|         self.channel.regs().ifcr(isrn).write(|w| { | ||||
|             w.set_tcif(isrbit, true); | ||||
|             w.set_teif(isrbit, true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn request_stop(&mut self) { | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|  | ||||
|         // Disable the channel. Keep the IEs enabled so the irqs still fire. | ||||
|         unsafe { | ||||
|             ch.cr().write(|w| { | ||||
|                 w.set_teie(true); | ||||
|                 w.set_tcie(true); | ||||
|             }) | ||||
|         } | ||||
|         ch.cr().write(|w| { | ||||
|             w.set_teie(true); | ||||
|             w.set_tcie(true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn is_running(&mut self) -> bool { | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|         unsafe { ch.cr().read() }.en() | ||||
|         ch.cr().read().en() | ||||
|     } | ||||
|  | ||||
|     /// Gets the total remaining transfers for the channel | ||||
|     /// Note: this will be zero for transfers that completed without cancellation. | ||||
|     pub fn get_remaining_transfers(&self) -> u16 { | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|         unsafe { ch.ndtr().read() }.ndt() | ||||
|         ch.ndtr().read().ndt() | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_wait(mut self) { | ||||
| @@ -537,13 +533,11 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | ||||
|         let isrn = channel_number / 4; | ||||
|         let isrbit = channel_number % 4; | ||||
|  | ||||
|         unsafe { | ||||
|             dma.ifcr(isrn).write(|w| { | ||||
|                 w.set_htif(isrbit, true); | ||||
|                 w.set_tcif(isrbit, true); | ||||
|                 w.set_teif(isrbit, true); | ||||
|             }) | ||||
|         } | ||||
|         dma.ifcr(isrn).write(|w| { | ||||
|             w.set_htif(isrbit, true); | ||||
|             w.set_tcif(isrbit, true); | ||||
|             w.set_teif(isrbit, true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { | ||||
| @@ -558,7 +552,7 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | ||||
|  | ||||
|     pub fn is_buffer0_accessible(&mut self) -> bool { | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|         unsafe { ch.cr().read() }.ct() == vals::Ct::MEMORY1 | ||||
|         ch.cr().read().ct() == vals::Ct::MEMORY1 | ||||
|     } | ||||
|  | ||||
|     pub fn set_waker(&mut self, waker: &Waker) { | ||||
| @@ -569,24 +563,22 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|  | ||||
|         // Disable the channel. Keep the IEs enabled so the irqs still fire. | ||||
|         unsafe { | ||||
|             ch.cr().write(|w| { | ||||
|                 w.set_teie(true); | ||||
|                 w.set_tcie(true); | ||||
|             }) | ||||
|         } | ||||
|         ch.cr().write(|w| { | ||||
|             w.set_teie(true); | ||||
|             w.set_tcie(true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn is_running(&mut self) -> bool { | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|         unsafe { ch.cr().read() }.en() | ||||
|         ch.cr().read().en() | ||||
|     } | ||||
|  | ||||
|     /// Gets the total remaining transfers for the channel | ||||
|     /// Note: this will be zero for transfers that completed without cancellation. | ||||
|     pub fn get_remaining_transfers(&self) -> u16 { | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|         unsafe { ch.ndtr().read() }.ndt() | ||||
|         ch.ndtr().read().ndt() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -607,7 +599,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>); | ||||
| impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { | ||||
|     fn get_remaining_transfers(&self) -> usize { | ||||
|         let ch = self.0.regs().st(self.0.num()); | ||||
|         unsafe { ch.ndtr().read() }.ndt() as usize | ||||
|         ch.ndtr().read().ndt() as usize | ||||
|     } | ||||
|  | ||||
|     fn get_complete_count(&self) -> usize { | ||||
| @@ -698,7 +690,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> { | ||||
|  | ||||
|     pub fn start(&mut self) { | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|         unsafe { ch.cr().write_value(self.cr) } | ||||
|         ch.cr().write_value(self.cr); | ||||
|     } | ||||
|  | ||||
|     pub fn clear(&mut self) { | ||||
| @@ -729,31 +721,27 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> { | ||||
|         let isrn = channel_number / 4; | ||||
|         let isrbit = channel_number % 4; | ||||
|  | ||||
|         unsafe { | ||||
|             dma.ifcr(isrn).write(|w| { | ||||
|                 w.set_htif(isrbit, true); | ||||
|                 w.set_tcif(isrbit, true); | ||||
|                 w.set_teif(isrbit, true); | ||||
|             }) | ||||
|         } | ||||
|         dma.ifcr(isrn).write(|w| { | ||||
|             w.set_htif(isrbit, true); | ||||
|             w.set_tcif(isrbit, true); | ||||
|             w.set_teif(isrbit, true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn request_stop(&mut self) { | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|  | ||||
|         // Disable the channel. Keep the IEs enabled so the irqs still fire. | ||||
|         unsafe { | ||||
|             ch.cr().write(|w| { | ||||
|                 w.set_teie(true); | ||||
|                 w.set_htie(true); | ||||
|                 w.set_tcie(true); | ||||
|             }) | ||||
|         } | ||||
|         ch.cr().write(|w| { | ||||
|             w.set_teie(true); | ||||
|             w.set_htie(true); | ||||
|             w.set_tcie(true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn is_running(&mut self) -> bool { | ||||
|         let ch = self.channel.regs().st(self.channel.num()); | ||||
|         unsafe { ch.cr().read() }.en() | ||||
|         ch.cr().read().en() | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| use crate::{pac, peripherals}; | ||||
|  | ||||
| pub(crate) unsafe fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) { | ||||
| pub(crate) fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) { | ||||
|     let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); | ||||
|     ch_mux_regs.write(|reg| { | ||||
|         reg.set_nbreq(0); | ||||
|   | ||||
| @@ -92,13 +92,15 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in | ||||
|     if sr.dtef() { | ||||
|         panic!( | ||||
|             "DMA: data transfer error on DMA@{:08x} channel {}", | ||||
|             dma.0 as u32, channel_num | ||||
|             dma.as_ptr() as u32, | ||||
|             channel_num | ||||
|         ); | ||||
|     } | ||||
|     if sr.usef() { | ||||
|         panic!( | ||||
|             "DMA: user settings error on DMA@{:08x} channel {}", | ||||
|             dma.0 as u32, channel_num | ||||
|             dma.as_ptr() as u32, | ||||
|             channel_num | ||||
|         ); | ||||
|     } | ||||
|  | ||||
| @@ -298,26 +300,24 @@ impl<'a, C: Channel> Transfer<'a, C> { | ||||
|         let ch = self.channel.regs().ch(self.channel.num()); | ||||
|  | ||||
|         // Disable the channel. Keep the IEs enabled so the irqs still fire. | ||||
|         unsafe { | ||||
|             ch.cr().write(|w| { | ||||
|                 w.set_tcie(true); | ||||
|                 w.set_useie(true); | ||||
|                 w.set_dteie(true); | ||||
|                 w.set_suspie(true); | ||||
|             }) | ||||
|         } | ||||
|         ch.cr().write(|w| { | ||||
|             w.set_tcie(true); | ||||
|             w.set_useie(true); | ||||
|             w.set_dteie(true); | ||||
|             w.set_suspie(true); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     pub fn is_running(&mut self) -> bool { | ||||
|         let ch = self.channel.regs().ch(self.channel.num()); | ||||
|         !unsafe { ch.sr().read() }.tcf() | ||||
|         !ch.sr().read().tcf() | ||||
|     } | ||||
|  | ||||
|     /// Gets the total remaining transfers for the channel | ||||
|     /// Note: this will be zero for transfers that completed without cancellation. | ||||
|     pub fn get_remaining_transfers(&self) -> u16 { | ||||
|         let ch = self.channel.regs().ch(self.channel.num()); | ||||
|         unsafe { ch.br1().read() }.bndt() | ||||
|         ch.br1().read().bndt() | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_wait(mut self) { | ||||
|   | ||||
| @@ -29,18 +29,16 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl | ||||
|         WAKER.wake(); | ||||
|  | ||||
|         // TODO: Check and clear more flags | ||||
|         unsafe { | ||||
|             let dma = ETH.ethernet_dma(); | ||||
|         let dma = ETH.ethernet_dma(); | ||||
|  | ||||
|             dma.dmasr().modify(|w| { | ||||
|                 w.set_ts(true); | ||||
|                 w.set_rs(true); | ||||
|                 w.set_nis(true); | ||||
|             }); | ||||
|             // Delay two peripheral's clock | ||||
|             dma.dmasr().read(); | ||||
|             dma.dmasr().read(); | ||||
|         } | ||||
|         dma.dmasr().modify(|w| { | ||||
|             w.set_ts(true); | ||||
|             w.set_rs(true); | ||||
|             w.set_nis(true); | ||||
|         }); | ||||
|         // Delay two peripheral's clock | ||||
|         dma.dmasr().read(); | ||||
|         dma.dmasr().read(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -59,7 +57,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> { | ||||
| #[cfg(eth_v1a)] | ||||
| macro_rules! config_in_pins { | ||||
|     ($($pin:ident),*) => { | ||||
|         // NOTE(unsafe) Exclusive access to the registers | ||||
|         critical_section::with(|_| { | ||||
|             $( | ||||
|                 // TODO properly create a set_as_input function | ||||
| @@ -72,7 +69,6 @@ macro_rules! config_in_pins { | ||||
| #[cfg(eth_v1a)] | ||||
| macro_rules! config_af_pins { | ||||
|     ($($pin:ident),*) => { | ||||
|         // NOTE(unsafe) Exclusive access to the registers | ||||
|         critical_section::with(|_| { | ||||
|             $( | ||||
|                 // We are lucky here, this configures to max speed (50MHz) | ||||
| @@ -85,7 +81,6 @@ macro_rules! config_af_pins { | ||||
| #[cfg(any(eth_v1b, eth_v1c))] | ||||
| macro_rules! config_pins { | ||||
|     ($($pin:ident),*) => { | ||||
|         // NOTE(unsafe) Exclusive access to the registers | ||||
|         critical_section::with(|_| { | ||||
|             $( | ||||
|                 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); | ||||
| @@ -116,222 +111,208 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | ||||
|     ) -> Self { | ||||
|         into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | ||||
|  | ||||
|         unsafe { | ||||
|             // Enable the necessary Clocks | ||||
|             // NOTE(unsafe) We have exclusive access to the registers | ||||
|             #[cfg(eth_v1a)] | ||||
|             critical_section::with(|_| { | ||||
|                 RCC.apb2enr().modify(|w| w.set_afioen(true)); | ||||
|         // Enable the necessary Clocks | ||||
|         #[cfg(eth_v1a)] | ||||
|         critical_section::with(|_| { | ||||
|             RCC.apb2enr().modify(|w| w.set_afioen(true)); | ||||
|  | ||||
|                 // Select RMII (Reduced Media Independent Interface) | ||||
|                 // Must be done prior to enabling peripheral clock | ||||
|                 AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true)); | ||||
|             // Select RMII (Reduced Media Independent Interface) | ||||
|             // Must be done prior to enabling peripheral clock | ||||
|             AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true)); | ||||
|  | ||||
|                 RCC.ahbenr().modify(|w| { | ||||
|                     w.set_ethen(true); | ||||
|                     w.set_ethtxen(true); | ||||
|                     w.set_ethrxen(true); | ||||
|                 }); | ||||
|             RCC.ahbenr().modify(|w| { | ||||
|                 w.set_ethen(true); | ||||
|                 w.set_ethtxen(true); | ||||
|                 w.set_ethrxen(true); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         #[cfg(any(eth_v1b, eth_v1c))] | ||||
|         critical_section::with(|_| { | ||||
|             RCC.apb2enr().modify(|w| w.set_syscfgen(true)); | ||||
|             RCC.ahb1enr().modify(|w| { | ||||
|                 w.set_ethen(true); | ||||
|                 w.set_ethtxen(true); | ||||
|                 w.set_ethrxen(true); | ||||
|             }); | ||||
|  | ||||
|             #[cfg(any(eth_v1b, eth_v1c))] | ||||
|             critical_section::with(|_| { | ||||
|                 RCC.apb2enr().modify(|w| w.set_syscfgen(true)); | ||||
|                 RCC.ahb1enr().modify(|w| { | ||||
|                     w.set_ethen(true); | ||||
|                     w.set_ethtxen(true); | ||||
|                     w.set_ethrxen(true); | ||||
|                 }); | ||||
|             // RMII (Reduced Media Independent Interface) | ||||
|             SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true)); | ||||
|         }); | ||||
|  | ||||
|                 // RMII (Reduced Media Independent Interface) | ||||
|                 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true)); | ||||
|             }); | ||||
|  | ||||
|             #[cfg(eth_v1a)] | ||||
|             { | ||||
|                 config_in_pins!(ref_clk, rx_d0, rx_d1); | ||||
|                 config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en); | ||||
|             } | ||||
|  | ||||
|             #[cfg(any(eth_v1b, eth_v1c))] | ||||
|             config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | ||||
|  | ||||
|             // NOTE(unsafe) We have exclusive access to the registers | ||||
|             let dma = ETH.ethernet_dma(); | ||||
|             let mac = ETH.ethernet_mac(); | ||||
|  | ||||
|             // Reset and wait | ||||
|             dma.dmabmr().modify(|w| w.set_sr(true)); | ||||
|             while dma.dmabmr().read().sr() {} | ||||
|  | ||||
|             mac.maccr().modify(|w| { | ||||
|                 w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times | ||||
|                 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping | ||||
|                 w.set_fes(Fes::FES100); // fast ethernet speed | ||||
|                 w.set_dm(Dm::FULLDUPLEX); // full duplex | ||||
|                                           // TODO: Carrier sense ? ECRSFD | ||||
|             }); | ||||
|  | ||||
|             // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, | ||||
|             // so the LR write must happen after the HR write. | ||||
|             mac.maca0hr() | ||||
|                 .modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); | ||||
|             mac.maca0lr().write(|w| { | ||||
|                 w.set_maca0l( | ||||
|                     u32::from(mac_addr[0]) | ||||
|                         | (u32::from(mac_addr[1]) << 8) | ||||
|                         | (u32::from(mac_addr[2]) << 16) | ||||
|                         | (u32::from(mac_addr[3]) << 24), | ||||
|                 ) | ||||
|             }); | ||||
|  | ||||
|             // pause time | ||||
|             mac.macfcr().modify(|w| w.set_pt(0x100)); | ||||
|  | ||||
|             // Transfer and Forward, Receive and Forward | ||||
|             dma.dmaomr().modify(|w| { | ||||
|                 w.set_tsf(Tsf::STOREFORWARD); | ||||
|                 w.set_rsf(Rsf::STOREFORWARD); | ||||
|             }); | ||||
|  | ||||
|             dma.dmabmr().modify(|w| { | ||||
|                 w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ? | ||||
|             }); | ||||
|  | ||||
|             // TODO MTU size setting not found for v1 ethernet, check if correct | ||||
|  | ||||
|             // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called | ||||
|             let hclk = crate::rcc::get_freqs().ahb1; | ||||
|             let hclk_mhz = hclk.0 / 1_000_000; | ||||
|  | ||||
|             // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||||
|             let clock_range = match hclk_mhz { | ||||
|                 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."), | ||||
|                 25..=34 => Cr::CR_20_35,     // Divide by 16 | ||||
|                 35..=59 => Cr::CR_35_60,     // Divide by 26 | ||||
|                 60..=99 => Cr::CR_60_100,    // Divide by 42 | ||||
|                 100..=149 => Cr::CR_100_150, // Divide by 62 | ||||
|                 150..=216 => Cr::CR_150_168, // Divide by 102 | ||||
|                 _ => { | ||||
|                     panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             let pins = [ | ||||
|                 ref_clk.map_into(), | ||||
|                 mdio.map_into(), | ||||
|                 mdc.map_into(), | ||||
|                 crs.map_into(), | ||||
|                 rx_d0.map_into(), | ||||
|                 rx_d1.map_into(), | ||||
|                 tx_d0.map_into(), | ||||
|                 tx_d1.map_into(), | ||||
|                 tx_en.map_into(), | ||||
|             ]; | ||||
|  | ||||
|             let mut this = Self { | ||||
|                 _peri: peri, | ||||
|                 pins, | ||||
|                 _phy: phy, | ||||
|                 clock_range, | ||||
|                 phy_addr, | ||||
|                 mac_addr, | ||||
|                 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), | ||||
|                 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | ||||
|             }; | ||||
|  | ||||
|             fence(Ordering::SeqCst); | ||||
|  | ||||
|             let mac = ETH.ethernet_mac(); | ||||
|             let dma = ETH.ethernet_dma(); | ||||
|  | ||||
|             mac.maccr().modify(|w| { | ||||
|                 w.set_re(true); | ||||
|                 w.set_te(true); | ||||
|             }); | ||||
|             dma.dmaomr().modify(|w| { | ||||
|                 w.set_ftf(Ftf::FLUSH); // flush transmit fifo (queue) | ||||
|                 w.set_st(St::STARTED); // start transmitting channel | ||||
|                 w.set_sr(DmaomrSr::STARTED); // start receiving channel | ||||
|             }); | ||||
|  | ||||
|             this.rx.demand_poll(); | ||||
|  | ||||
|             // Enable interrupts | ||||
|             dma.dmaier().modify(|w| { | ||||
|                 w.set_nise(true); | ||||
|                 w.set_rie(true); | ||||
|                 w.set_tie(true); | ||||
|             }); | ||||
|  | ||||
|             P::phy_reset(&mut this); | ||||
|             P::phy_init(&mut this); | ||||
|  | ||||
|             interrupt::ETH.unpend(); | ||||
|             interrupt::ETH.enable(); | ||||
|  | ||||
|             this | ||||
|         #[cfg(eth_v1a)] | ||||
|         { | ||||
|             config_in_pins!(ref_clk, rx_d0, rx_d1); | ||||
|             config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en); | ||||
|         } | ||||
|  | ||||
|         #[cfg(any(eth_v1b, eth_v1c))] | ||||
|         config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | ||||
|  | ||||
|         let dma = ETH.ethernet_dma(); | ||||
|         let mac = ETH.ethernet_mac(); | ||||
|  | ||||
|         // Reset and wait | ||||
|         dma.dmabmr().modify(|w| w.set_sr(true)); | ||||
|         while dma.dmabmr().read().sr() {} | ||||
|  | ||||
|         mac.maccr().modify(|w| { | ||||
|             w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times | ||||
|             w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping | ||||
|             w.set_fes(Fes::FES100); // fast ethernet speed | ||||
|             w.set_dm(Dm::FULLDUPLEX); // full duplex | ||||
|                                       // TODO: Carrier sense ? ECRSFD | ||||
|         }); | ||||
|  | ||||
|         // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, | ||||
|         // so the LR write must happen after the HR write. | ||||
|         mac.maca0hr() | ||||
|             .modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); | ||||
|         mac.maca0lr().write(|w| { | ||||
|             w.set_maca0l( | ||||
|                 u32::from(mac_addr[0]) | ||||
|                     | (u32::from(mac_addr[1]) << 8) | ||||
|                     | (u32::from(mac_addr[2]) << 16) | ||||
|                     | (u32::from(mac_addr[3]) << 24), | ||||
|             ) | ||||
|         }); | ||||
|  | ||||
|         // pause time | ||||
|         mac.macfcr().modify(|w| w.set_pt(0x100)); | ||||
|  | ||||
|         // Transfer and Forward, Receive and Forward | ||||
|         dma.dmaomr().modify(|w| { | ||||
|             w.set_tsf(Tsf::STOREFORWARD); | ||||
|             w.set_rsf(Rsf::STOREFORWARD); | ||||
|         }); | ||||
|  | ||||
|         dma.dmabmr().modify(|w| { | ||||
|             w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ? | ||||
|         }); | ||||
|  | ||||
|         // TODO MTU size setting not found for v1 ethernet, check if correct | ||||
|  | ||||
|         // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called | ||||
|         let hclk = unsafe { crate::rcc::get_freqs() }.ahb1; | ||||
|         let hclk_mhz = hclk.0 / 1_000_000; | ||||
|  | ||||
|         // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||||
|         let clock_range = match hclk_mhz { | ||||
|             0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."), | ||||
|             25..=34 => Cr::CR_20_35,     // Divide by 16 | ||||
|             35..=59 => Cr::CR_35_60,     // Divide by 26 | ||||
|             60..=99 => Cr::CR_60_100,    // Divide by 42 | ||||
|             100..=149 => Cr::CR_100_150, // Divide by 62 | ||||
|             150..=216 => Cr::CR_150_168, // Divide by 102 | ||||
|             _ => { | ||||
|                 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let pins = [ | ||||
|             ref_clk.map_into(), | ||||
|             mdio.map_into(), | ||||
|             mdc.map_into(), | ||||
|             crs.map_into(), | ||||
|             rx_d0.map_into(), | ||||
|             rx_d1.map_into(), | ||||
|             tx_d0.map_into(), | ||||
|             tx_d1.map_into(), | ||||
|             tx_en.map_into(), | ||||
|         ]; | ||||
|  | ||||
|         let mut this = Self { | ||||
|             _peri: peri, | ||||
|             pins, | ||||
|             _phy: phy, | ||||
|             clock_range, | ||||
|             phy_addr, | ||||
|             mac_addr, | ||||
|             tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), | ||||
|             rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | ||||
|         }; | ||||
|  | ||||
|         fence(Ordering::SeqCst); | ||||
|  | ||||
|         let mac = ETH.ethernet_mac(); | ||||
|         let dma = ETH.ethernet_dma(); | ||||
|  | ||||
|         mac.maccr().modify(|w| { | ||||
|             w.set_re(true); | ||||
|             w.set_te(true); | ||||
|         }); | ||||
|         dma.dmaomr().modify(|w| { | ||||
|             w.set_ftf(Ftf::FLUSH); // flush transmit fifo (queue) | ||||
|             w.set_st(St::STARTED); // start transmitting channel | ||||
|             w.set_sr(DmaomrSr::STARTED); // start receiving channel | ||||
|         }); | ||||
|  | ||||
|         this.rx.demand_poll(); | ||||
|  | ||||
|         // Enable interrupts | ||||
|         dma.dmaier().modify(|w| { | ||||
|             w.set_nise(true); | ||||
|             w.set_rie(true); | ||||
|             w.set_tie(true); | ||||
|         }); | ||||
|  | ||||
|         P::phy_reset(&mut this); | ||||
|         P::phy_init(&mut this); | ||||
|  | ||||
|         interrupt::ETH.unpend(); | ||||
|         unsafe { interrupt::ETH.enable() }; | ||||
|  | ||||
|         this | ||||
|     } | ||||
| } | ||||
|  | ||||
| unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { | ||||
|     fn smi_read(&mut self, reg: u8) -> u16 { | ||||
|         // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` | ||||
|         unsafe { | ||||
|             let mac = ETH.ethernet_mac(); | ||||
|         let mac = ETH.ethernet_mac(); | ||||
|  | ||||
|             mac.macmiiar().modify(|w| { | ||||
|                 w.set_pa(self.phy_addr); | ||||
|                 w.set_mr(reg); | ||||
|                 w.set_mw(Mw::READ); // read operation | ||||
|                 w.set_cr(self.clock_range); | ||||
|                 w.set_mb(MbProgress::BUSY); // indicate that operation is in progress | ||||
|             }); | ||||
|             while mac.macmiiar().read().mb() == MbProgress::BUSY {} | ||||
|             mac.macmiidr().read().md() | ||||
|         } | ||||
|         mac.macmiiar().modify(|w| { | ||||
|             w.set_pa(self.phy_addr); | ||||
|             w.set_mr(reg); | ||||
|             w.set_mw(Mw::READ); // read operation | ||||
|             w.set_cr(self.clock_range); | ||||
|             w.set_mb(MbProgress::BUSY); // indicate that operation is in progress | ||||
|         }); | ||||
|         while mac.macmiiar().read().mb() == MbProgress::BUSY {} | ||||
|         mac.macmiidr().read().md() | ||||
|     } | ||||
|  | ||||
|     fn smi_write(&mut self, reg: u8, val: u16) { | ||||
|         // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` | ||||
|         unsafe { | ||||
|             let mac = ETH.ethernet_mac(); | ||||
|         let mac = ETH.ethernet_mac(); | ||||
|  | ||||
|             mac.macmiidr().write(|w| w.set_md(val)); | ||||
|             mac.macmiiar().modify(|w| { | ||||
|                 w.set_pa(self.phy_addr); | ||||
|                 w.set_mr(reg); | ||||
|                 w.set_mw(Mw::WRITE); // write | ||||
|                 w.set_cr(self.clock_range); | ||||
|                 w.set_mb(MbProgress::BUSY); | ||||
|             }); | ||||
|             while mac.macmiiar().read().mb() == MbProgress::BUSY {} | ||||
|         } | ||||
|         mac.macmiidr().write(|w| w.set_md(val)); | ||||
|         mac.macmiiar().modify(|w| { | ||||
|             w.set_pa(self.phy_addr); | ||||
|             w.set_mr(reg); | ||||
|             w.set_mw(Mw::WRITE); // write | ||||
|             w.set_cr(self.clock_range); | ||||
|             w.set_mb(MbProgress::BUSY); | ||||
|         }); | ||||
|         while mac.macmiiar().read().mb() == MbProgress::BUSY {} | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { | ||||
|     fn drop(&mut self) { | ||||
|         // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers | ||||
|         unsafe { | ||||
|             let dma = ETH.ethernet_dma(); | ||||
|             let mac = ETH.ethernet_mac(); | ||||
|         let dma = ETH.ethernet_dma(); | ||||
|         let mac = ETH.ethernet_mac(); | ||||
|  | ||||
|             // Disable the TX DMA and wait for any previous transmissions to be completed | ||||
|             dma.dmaomr().modify(|w| w.set_st(St::STOPPED)); | ||||
|         // Disable the TX DMA and wait for any previous transmissions to be completed | ||||
|         dma.dmaomr().modify(|w| w.set_st(St::STOPPED)); | ||||
|  | ||||
|             // Disable MAC transmitter and receiver | ||||
|             mac.maccr().modify(|w| { | ||||
|                 w.set_re(false); | ||||
|                 w.set_te(false); | ||||
|             }); | ||||
|         // Disable MAC transmitter and receiver | ||||
|         mac.maccr().modify(|w| { | ||||
|             w.set_re(false); | ||||
|             w.set_te(false); | ||||
|         }); | ||||
|  | ||||
|             dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED)); | ||||
|         } | ||||
|         dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED)); | ||||
|  | ||||
|         // NOTE(unsafe) Exclusive access to the regs | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             for pin in self.pins.iter_mut() { | ||||
|                 pin.set_as_disconnected(); | ||||
|             } | ||||
|   | ||||
| @@ -146,12 +146,9 @@ impl<'a> RDesRing<'a> { | ||||
|         } | ||||
|  | ||||
|         // Register rx descriptor start | ||||
|         // NOTE (unsafe) Used for atomic writes | ||||
|         unsafe { | ||||
|             ETH.ethernet_dma() | ||||
|                 .dmardlar() | ||||
|                 .write(|w| w.0 = descriptors.as_ptr() as u32); | ||||
|         }; | ||||
|         ETH.ethernet_dma() | ||||
|             .dmardlar() | ||||
|             .write(|w| w.0 = descriptors.as_ptr() as u32); | ||||
|         // We already have fences in `set_owned`, which is called in `setup` | ||||
|  | ||||
|         Self { | ||||
| @@ -162,12 +159,12 @@ impl<'a> RDesRing<'a> { | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn demand_poll(&self) { | ||||
|         unsafe { ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)) }; | ||||
|         ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)); | ||||
|     } | ||||
|  | ||||
|     /// Get current `RunningState` | ||||
|     fn running_state(&self) -> RunningState { | ||||
|         match unsafe { ETH.ethernet_dma().dmasr().read().rps() } { | ||||
|         match ETH.ethernet_dma().dmasr().read().rps() { | ||||
|             //  Reset or Stop Receive Command issued | ||||
|             Rps::STOPPED => RunningState::Stopped, | ||||
|             //  Fetching receive transfer descriptor | ||||
|   | ||||
| @@ -120,12 +120,9 @@ impl<'a> TDesRing<'a> { | ||||
|         } | ||||
|  | ||||
|         // Register txdescriptor start | ||||
|         // NOTE (unsafe) Used for atomic writes | ||||
|         unsafe { | ||||
|             ETH.ethernet_dma() | ||||
|                 .dmatdlar() | ||||
|                 .write(|w| w.0 = descriptors.as_ptr() as u32); | ||||
|         } | ||||
|         ETH.ethernet_dma() | ||||
|             .dmatdlar() | ||||
|             .write(|w| w.0 = descriptors.as_ptr() as u32); | ||||
|  | ||||
|         Self { | ||||
|             descriptors, | ||||
| @@ -169,6 +166,6 @@ impl<'a> TDesRing<'a> { | ||||
|             self.index = 0 | ||||
|         } | ||||
|         // Request the DMA engine to poll the latest tx descriptor | ||||
|         unsafe { ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) } | ||||
|         ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -73,14 +73,10 @@ impl<'a> TDesRing<'a> { | ||||
|  | ||||
|         // Initialize the pointers in the DMA engine. (There will be a memory barrier later | ||||
|         // before the DMA engine is enabled.) | ||||
|         // NOTE (unsafe) Used for atomic writes | ||||
|         unsafe { | ||||
|             let dma = ETH.ethernet_dma(); | ||||
|  | ||||
|             dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32); | ||||
|             dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1)); | ||||
|             dma.dmactx_dtpr().write(|w| w.0 = 0); | ||||
|         } | ||||
|         let dma = ETH.ethernet_dma(); | ||||
|         dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32); | ||||
|         dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1)); | ||||
|         dma.dmactx_dtpr().write(|w| w.0 = 0); | ||||
|  | ||||
|         Self { | ||||
|             descriptors, | ||||
| @@ -129,8 +125,7 @@ impl<'a> TDesRing<'a> { | ||||
|         } | ||||
|  | ||||
|         // signal DMA it can try again. | ||||
|         // NOTE(unsafe) Atomic write | ||||
|         unsafe { ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0) } | ||||
|         ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -199,13 +194,10 @@ impl<'a> RDesRing<'a> { | ||||
|             desc.set_ready(buffers[i].0.as_mut_ptr()); | ||||
|         } | ||||
|  | ||||
|         unsafe { | ||||
|             let dma = ETH.ethernet_dma(); | ||||
|  | ||||
|             dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32); | ||||
|             dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1)); | ||||
|             dma.dmacrx_dtpr().write(|w| w.0 = 0); | ||||
|         } | ||||
|         let dma = ETH.ethernet_dma(); | ||||
|         dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32); | ||||
|         dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1)); | ||||
|         dma.dmacrx_dtpr().write(|w| w.0 = 0); | ||||
|  | ||||
|         Self { | ||||
|             descriptors, | ||||
| @@ -254,8 +246,7 @@ impl<'a> RDesRing<'a> { | ||||
|         fence(Ordering::Release); | ||||
|  | ||||
|         // signal DMA it can try again. | ||||
|         // NOTE(unsafe) Atomic write | ||||
|         unsafe { ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0) } | ||||
|         ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0); | ||||
|  | ||||
|         // Increment index. | ||||
|         self.index += 1; | ||||
|   | ||||
| @@ -20,18 +20,16 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl | ||||
|         WAKER.wake(); | ||||
|  | ||||
|         // TODO: Check and clear more flags | ||||
|         unsafe { | ||||
|             let dma = ETH.ethernet_dma(); | ||||
|         let dma = ETH.ethernet_dma(); | ||||
|  | ||||
|             dma.dmacsr().modify(|w| { | ||||
|                 w.set_ti(true); | ||||
|                 w.set_ri(true); | ||||
|                 w.set_nis(true); | ||||
|             }); | ||||
|             // Delay two peripheral's clock | ||||
|             dma.dmacsr().read(); | ||||
|             dma.dmacsr().read(); | ||||
|         } | ||||
|         dma.dmacsr().modify(|w| { | ||||
|             w.set_ti(true); | ||||
|             w.set_ri(true); | ||||
|             w.set_nis(true); | ||||
|         }); | ||||
|         // Delay two peripheral's clock | ||||
|         dma.dmacsr().read(); | ||||
|         dma.dmacsr().read(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -50,7 +48,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> { | ||||
|  | ||||
| macro_rules! config_pins { | ||||
|     ($($pin:ident),*) => { | ||||
|         // NOTE(unsafe) Exclusive access to the registers | ||||
|         critical_section::with(|_| { | ||||
|             $( | ||||
|                 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); | ||||
| @@ -80,239 +77,225 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | ||||
|     ) -> Self { | ||||
|         into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | ||||
|  | ||||
|         unsafe { | ||||
|             // Enable the necessary Clocks | ||||
|             // NOTE(unsafe) We have exclusive access to the registers | ||||
|             #[cfg(not(rcc_h5))] | ||||
|             critical_section::with(|_| { | ||||
|                 crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true)); | ||||
|                 crate::pac::RCC.ahb1enr().modify(|w| { | ||||
|                     w.set_eth1macen(true); | ||||
|                     w.set_eth1txen(true); | ||||
|                     w.set_eth1rxen(true); | ||||
|                 }); | ||||
|  | ||||
|                 // RMII | ||||
|                 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); | ||||
|         // Enable the necessary Clocks | ||||
|         #[cfg(not(rcc_h5))] | ||||
|         critical_section::with(|_| { | ||||
|             crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true)); | ||||
|             crate::pac::RCC.ahb1enr().modify(|w| { | ||||
|                 w.set_eth1macen(true); | ||||
|                 w.set_eth1txen(true); | ||||
|                 w.set_eth1rxen(true); | ||||
|             }); | ||||
|  | ||||
|             #[cfg(rcc_h5)] | ||||
|             critical_section::with(|_| { | ||||
|                 crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true)); | ||||
|             // RMII | ||||
|             crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); | ||||
|         }); | ||||
|  | ||||
|                 crate::pac::RCC.ahb1enr().modify(|w| { | ||||
|                     w.set_ethen(true); | ||||
|                     w.set_ethtxen(true); | ||||
|                     w.set_ethrxen(true); | ||||
|                 }); | ||||
|         #[cfg(rcc_h5)] | ||||
|         critical_section::with(|_| { | ||||
|             crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true)); | ||||
|  | ||||
|                 // RMII | ||||
|                 crate::pac::SBS | ||||
|                     .pmcr() | ||||
|                     .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4)); | ||||
|             crate::pac::RCC.ahb1enr().modify(|w| { | ||||
|                 w.set_ethen(true); | ||||
|                 w.set_ethtxen(true); | ||||
|                 w.set_ethrxen(true); | ||||
|             }); | ||||
|  | ||||
|             config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | ||||
|             // RMII | ||||
|             crate::pac::SBS | ||||
|                 .pmcr() | ||||
|                 .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4)); | ||||
|         }); | ||||
|  | ||||
|             // NOTE(unsafe) We have exclusive access to the registers | ||||
|             let dma = ETH.ethernet_dma(); | ||||
|             let mac = ETH.ethernet_mac(); | ||||
|             let mtl = ETH.ethernet_mtl(); | ||||
|         config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | ||||
|  | ||||
|             // Reset and wait | ||||
|             dma.dmamr().modify(|w| w.set_swr(true)); | ||||
|             while dma.dmamr().read().swr() {} | ||||
|         let dma = ETH.ethernet_dma(); | ||||
|         let mac = ETH.ethernet_mac(); | ||||
|         let mtl = ETH.ethernet_mtl(); | ||||
|  | ||||
|             mac.maccr().modify(|w| { | ||||
|                 w.set_ipg(0b000); // 96 bit times | ||||
|                 w.set_acs(true); | ||||
|                 w.set_fes(true); | ||||
|                 w.set_dm(true); | ||||
|                 // TODO: Carrier sense ? ECRSFD | ||||
|             }); | ||||
|         // Reset and wait | ||||
|         dma.dmamr().modify(|w| w.set_swr(true)); | ||||
|         while dma.dmamr().read().swr() {} | ||||
|  | ||||
|             // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, | ||||
|             // so the LR write must happen after the HR write. | ||||
|             mac.maca0hr() | ||||
|                 .modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); | ||||
|             mac.maca0lr().write(|w| { | ||||
|                 w.set_addrlo( | ||||
|                     u32::from(mac_addr[0]) | ||||
|                         | (u32::from(mac_addr[1]) << 8) | ||||
|                         | (u32::from(mac_addr[2]) << 16) | ||||
|                         | (u32::from(mac_addr[3]) << 24), | ||||
|                 ) | ||||
|             }); | ||||
|         mac.maccr().modify(|w| { | ||||
|             w.set_ipg(0b000); // 96 bit times | ||||
|             w.set_acs(true); | ||||
|             w.set_fes(true); | ||||
|             w.set_dm(true); | ||||
|             // TODO: Carrier sense ? ECRSFD | ||||
|         }); | ||||
|  | ||||
|             mac.macqtx_fcr().modify(|w| w.set_pt(0x100)); | ||||
|         // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, | ||||
|         // so the LR write must happen after the HR write. | ||||
|         mac.maca0hr() | ||||
|             .modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); | ||||
|         mac.maca0lr().write(|w| { | ||||
|             w.set_addrlo( | ||||
|                 u32::from(mac_addr[0]) | ||||
|                     | (u32::from(mac_addr[1]) << 8) | ||||
|                     | (u32::from(mac_addr[2]) << 16) | ||||
|                     | (u32::from(mac_addr[3]) << 24), | ||||
|             ) | ||||
|         }); | ||||
|  | ||||
|             // disable all MMC RX interrupts | ||||
|             mac.mmc_rx_interrupt_mask().write(|w| { | ||||
|                 w.set_rxcrcerpim(true); | ||||
|                 w.set_rxalgnerpim(true); | ||||
|                 w.set_rxucgpim(true); | ||||
|                 w.set_rxlpiuscim(true); | ||||
|                 w.set_rxlpitrcim(true) | ||||
|             }); | ||||
|         mac.macqtx_fcr().modify(|w| w.set_pt(0x100)); | ||||
|  | ||||
|             // disable all MMC TX interrupts | ||||
|             mac.mmc_tx_interrupt_mask().write(|w| { | ||||
|                 w.set_txscolgpim(true); | ||||
|                 w.set_txmcolgpim(true); | ||||
|                 w.set_txgpktim(true); | ||||
|                 w.set_txlpiuscim(true); | ||||
|                 w.set_txlpitrcim(true); | ||||
|             }); | ||||
|         // disable all MMC RX interrupts | ||||
|         mac.mmc_rx_interrupt_mask().write(|w| { | ||||
|             w.set_rxcrcerpim(true); | ||||
|             w.set_rxalgnerpim(true); | ||||
|             w.set_rxucgpim(true); | ||||
|             w.set_rxlpiuscim(true); | ||||
|             w.set_rxlpitrcim(true) | ||||
|         }); | ||||
|  | ||||
|             mtl.mtlrx_qomr().modify(|w| w.set_rsf(true)); | ||||
|             mtl.mtltx_qomr().modify(|w| w.set_tsf(true)); | ||||
|         // disable all MMC TX interrupts | ||||
|         mac.mmc_tx_interrupt_mask().write(|w| { | ||||
|             w.set_txscolgpim(true); | ||||
|             w.set_txmcolgpim(true); | ||||
|             w.set_txgpktim(true); | ||||
|             w.set_txlpiuscim(true); | ||||
|             w.set_txlpitrcim(true); | ||||
|         }); | ||||
|  | ||||
|             dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ? | ||||
|             dma.dmacrx_cr().modify(|w| { | ||||
|                 w.set_rxpbl(1); // 32 ? | ||||
|                 w.set_rbsz(MTU as u16); | ||||
|             }); | ||||
|         mtl.mtlrx_qomr().modify(|w| w.set_rsf(true)); | ||||
|         mtl.mtltx_qomr().modify(|w| w.set_tsf(true)); | ||||
|  | ||||
|             // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called | ||||
|             let hclk = crate::rcc::get_freqs().ahb1; | ||||
|             let hclk_mhz = hclk.0 / 1_000_000; | ||||
|         dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ? | ||||
|         dma.dmacrx_cr().modify(|w| { | ||||
|             w.set_rxpbl(1); // 32 ? | ||||
|             w.set_rbsz(MTU as u16); | ||||
|         }); | ||||
|  | ||||
|             // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||||
|             let clock_range = match hclk_mhz { | ||||
|                 0..=34 => 2,    // Divide by 16 | ||||
|                 35..=59 => 3,   // Divide by 26 | ||||
|                 60..=99 => 0,   // Divide by 42 | ||||
|                 100..=149 => 1, // Divide by 62 | ||||
|                 150..=249 => 4, // Divide by 102 | ||||
|                 250..=310 => 5, // Divide by 124 | ||||
|                 _ => { | ||||
|                     panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||||
|                 } | ||||
|             }; | ||||
|         // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called | ||||
|         let hclk = unsafe { crate::rcc::get_freqs() }.ahb1; | ||||
|         let hclk_mhz = hclk.0 / 1_000_000; | ||||
|  | ||||
|             let pins = [ | ||||
|                 ref_clk.map_into(), | ||||
|                 mdio.map_into(), | ||||
|                 mdc.map_into(), | ||||
|                 crs.map_into(), | ||||
|                 rx_d0.map_into(), | ||||
|                 rx_d1.map_into(), | ||||
|                 tx_d0.map_into(), | ||||
|                 tx_d1.map_into(), | ||||
|                 tx_en.map_into(), | ||||
|             ]; | ||||
|         // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||||
|         let clock_range = match hclk_mhz { | ||||
|             0..=34 => 2,    // Divide by 16 | ||||
|             35..=59 => 3,   // Divide by 26 | ||||
|             60..=99 => 0,   // Divide by 42 | ||||
|             100..=149 => 1, // Divide by 62 | ||||
|             150..=249 => 4, // Divide by 102 | ||||
|             250..=310 => 5, // Divide by 124 | ||||
|             _ => { | ||||
|                 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|             let mut this = Self { | ||||
|                 _peri: peri, | ||||
|                 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), | ||||
|                 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | ||||
|                 pins, | ||||
|                 _phy: phy, | ||||
|                 clock_range, | ||||
|                 phy_addr, | ||||
|                 mac_addr, | ||||
|             }; | ||||
|         let pins = [ | ||||
|             ref_clk.map_into(), | ||||
|             mdio.map_into(), | ||||
|             mdc.map_into(), | ||||
|             crs.map_into(), | ||||
|             rx_d0.map_into(), | ||||
|             rx_d1.map_into(), | ||||
|             tx_d0.map_into(), | ||||
|             tx_d1.map_into(), | ||||
|             tx_en.map_into(), | ||||
|         ]; | ||||
|  | ||||
|             fence(Ordering::SeqCst); | ||||
|         let mut this = Self { | ||||
|             _peri: peri, | ||||
|             tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), | ||||
|             rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | ||||
|             pins, | ||||
|             _phy: phy, | ||||
|             clock_range, | ||||
|             phy_addr, | ||||
|             mac_addr, | ||||
|         }; | ||||
|  | ||||
|             let mac = ETH.ethernet_mac(); | ||||
|             let mtl = ETH.ethernet_mtl(); | ||||
|             let dma = ETH.ethernet_dma(); | ||||
|         fence(Ordering::SeqCst); | ||||
|  | ||||
|             mac.maccr().modify(|w| { | ||||
|                 w.set_re(true); | ||||
|                 w.set_te(true); | ||||
|             }); | ||||
|             mtl.mtltx_qomr().modify(|w| w.set_ftq(true)); | ||||
|         let mac = ETH.ethernet_mac(); | ||||
|         let mtl = ETH.ethernet_mtl(); | ||||
|         let dma = ETH.ethernet_dma(); | ||||
|  | ||||
|             dma.dmactx_cr().modify(|w| w.set_st(true)); | ||||
|             dma.dmacrx_cr().modify(|w| w.set_sr(true)); | ||||
|         mac.maccr().modify(|w| { | ||||
|             w.set_re(true); | ||||
|             w.set_te(true); | ||||
|         }); | ||||
|         mtl.mtltx_qomr().modify(|w| w.set_ftq(true)); | ||||
|  | ||||
|             // Enable interrupts | ||||
|             dma.dmacier().modify(|w| { | ||||
|                 w.set_nie(true); | ||||
|                 w.set_rie(true); | ||||
|                 w.set_tie(true); | ||||
|             }); | ||||
|         dma.dmactx_cr().modify(|w| w.set_st(true)); | ||||
|         dma.dmacrx_cr().modify(|w| w.set_sr(true)); | ||||
|  | ||||
|             P::phy_reset(&mut this); | ||||
|             P::phy_init(&mut this); | ||||
|         // Enable interrupts | ||||
|         dma.dmacier().modify(|w| { | ||||
|             w.set_nie(true); | ||||
|             w.set_rie(true); | ||||
|             w.set_tie(true); | ||||
|         }); | ||||
|  | ||||
|             interrupt::ETH.unpend(); | ||||
|             interrupt::ETH.enable(); | ||||
|         P::phy_reset(&mut this); | ||||
|         P::phy_init(&mut this); | ||||
|  | ||||
|             this | ||||
|         } | ||||
|         interrupt::ETH.unpend(); | ||||
|         unsafe { interrupt::ETH.enable() }; | ||||
|  | ||||
|         this | ||||
|     } | ||||
| } | ||||
|  | ||||
| unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { | ||||
|     fn smi_read(&mut self, reg: u8) -> u16 { | ||||
|         // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` | ||||
|         unsafe { | ||||
|             let mac = ETH.ethernet_mac(); | ||||
|         let mac = ETH.ethernet_mac(); | ||||
|  | ||||
|             mac.macmdioar().modify(|w| { | ||||
|                 w.set_pa(self.phy_addr); | ||||
|                 w.set_rda(reg); | ||||
|                 w.set_goc(0b11); // read | ||||
|                 w.set_cr(self.clock_range); | ||||
|                 w.set_mb(true); | ||||
|             }); | ||||
|             while mac.macmdioar().read().mb() {} | ||||
|             mac.macmdiodr().read().md() | ||||
|         } | ||||
|         mac.macmdioar().modify(|w| { | ||||
|             w.set_pa(self.phy_addr); | ||||
|             w.set_rda(reg); | ||||
|             w.set_goc(0b11); // read | ||||
|             w.set_cr(self.clock_range); | ||||
|             w.set_mb(true); | ||||
|         }); | ||||
|         while mac.macmdioar().read().mb() {} | ||||
|         mac.macmdiodr().read().md() | ||||
|     } | ||||
|  | ||||
|     fn smi_write(&mut self, reg: u8, val: u16) { | ||||
|         // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` | ||||
|         unsafe { | ||||
|             let mac = ETH.ethernet_mac(); | ||||
|         let mac = ETH.ethernet_mac(); | ||||
|  | ||||
|             mac.macmdiodr().write(|w| w.set_md(val)); | ||||
|             mac.macmdioar().modify(|w| { | ||||
|                 w.set_pa(self.phy_addr); | ||||
|                 w.set_rda(reg); | ||||
|                 w.set_goc(0b01); // write | ||||
|                 w.set_cr(self.clock_range); | ||||
|                 w.set_mb(true); | ||||
|             }); | ||||
|             while mac.macmdioar().read().mb() {} | ||||
|         } | ||||
|         mac.macmdiodr().write(|w| w.set_md(val)); | ||||
|         mac.macmdioar().modify(|w| { | ||||
|             w.set_pa(self.phy_addr); | ||||
|             w.set_rda(reg); | ||||
|             w.set_goc(0b01); // write | ||||
|             w.set_cr(self.clock_range); | ||||
|             w.set_mb(true); | ||||
|         }); | ||||
|         while mac.macmdioar().read().mb() {} | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { | ||||
|     fn drop(&mut self) { | ||||
|         // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers | ||||
|         unsafe { | ||||
|             let dma = ETH.ethernet_dma(); | ||||
|             let mac = ETH.ethernet_mac(); | ||||
|             let mtl = ETH.ethernet_mtl(); | ||||
|         let dma = ETH.ethernet_dma(); | ||||
|         let mac = ETH.ethernet_mac(); | ||||
|         let mtl = ETH.ethernet_mtl(); | ||||
|  | ||||
|             // Disable the TX DMA and wait for any previous transmissions to be completed | ||||
|             dma.dmactx_cr().modify(|w| w.set_st(false)); | ||||
|             while { | ||||
|                 let txqueue = mtl.mtltx_qdr().read(); | ||||
|                 txqueue.trcsts() == 0b01 || txqueue.txqsts() | ||||
|             } {} | ||||
|         // Disable the TX DMA and wait for any previous transmissions to be completed | ||||
|         dma.dmactx_cr().modify(|w| w.set_st(false)); | ||||
|         while { | ||||
|             let txqueue = mtl.mtltx_qdr().read(); | ||||
|             txqueue.trcsts() == 0b01 || txqueue.txqsts() | ||||
|         } {} | ||||
|  | ||||
|             // Disable MAC transmitter and receiver | ||||
|             mac.maccr().modify(|w| { | ||||
|                 w.set_re(false); | ||||
|                 w.set_te(false); | ||||
|             }); | ||||
|         // Disable MAC transmitter and receiver | ||||
|         mac.maccr().modify(|w| { | ||||
|             w.set_re(false); | ||||
|             w.set_te(false); | ||||
|         }); | ||||
|  | ||||
|             // Wait for previous receiver transfers to be completed and then disable the RX DMA | ||||
|             while { | ||||
|                 let rxqueue = mtl.mtlrx_qdr().read(); | ||||
|                 rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0 | ||||
|             } {} | ||||
|             dma.dmacrx_cr().modify(|w| w.set_sr(false)); | ||||
|         } | ||||
|         // Wait for previous receiver transfers to be completed and then disable the RX DMA | ||||
|         while { | ||||
|             let rxqueue = mtl.mtlrx_qdr().read(); | ||||
|             rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0 | ||||
|         } {} | ||||
|         dma.dmacrx_cr().modify(|w| w.set_sr(false)); | ||||
|  | ||||
|         // NOTE(unsafe) Exclusive access to the regs | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             for pin in self.pins.iter_mut() { | ||||
|                 pin.set_as_disconnected(); | ||||
|             } | ||||
|   | ||||
| @@ -206,7 +206,7 @@ struct ExtiInputFuture<'a> { | ||||
|  | ||||
| impl<'a> ExtiInputFuture<'a> { | ||||
|     fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             let pin = pin as usize; | ||||
|             exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); | ||||
|             EXTI.rtsr(0).modify(|w| w.set_line(pin, rising)); | ||||
| @@ -233,7 +233,7 @@ impl<'a> ExtiInputFuture<'a> { | ||||
|  | ||||
| impl<'a> Drop for ExtiInputFuture<'a> { | ||||
|     fn drop(&mut self) { | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             let pin = self.pin as _; | ||||
|             cpu_regs().imr(0).modify(|w| w.set_line(pin, false)); | ||||
|         }); | ||||
| @@ -246,7 +246,7 @@ impl<'a> Future for ExtiInputFuture<'a> { | ||||
|     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||||
|         EXTI_WAKERS[self.pin as usize].register(cx.waker()); | ||||
|  | ||||
|         let imr = unsafe { cpu_regs().imr(0).read() }; | ||||
|         let imr = cpu_regs().imr(0).read(); | ||||
|         if !imr.line(self.pin as _) { | ||||
|             Poll::Ready(()) | ||||
|         } else { | ||||
|   | ||||
| @@ -192,7 +192,7 @@ impl FlashSector { | ||||
|  | ||||
| #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] | ||||
| pub(crate) fn is_default_layout() -> bool { | ||||
|     unsafe { !pac::FLASH.optcr().read().db1m() } | ||||
|     !pac::FLASH.optcr().read().db1m() | ||||
| } | ||||
|  | ||||
| #[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))] | ||||
| @@ -336,7 +336,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | ||||
|     ret | ||||
| } | ||||
|  | ||||
| pub(crate) unsafe fn clear_all_err() { | ||||
| pub(crate) fn clear_all_err() { | ||||
|     pac::FLASH.sr().write(|w| { | ||||
|         w.set_pgserr(true); | ||||
|         w.set_pgperr(true); | ||||
| @@ -345,7 +345,7 @@ pub(crate) unsafe fn clear_all_err() { | ||||
|     }); | ||||
| } | ||||
|  | ||||
| pub(crate) async unsafe fn wait_ready() -> Result<(), Error> { | ||||
| pub(crate) async fn wait_ready() -> Result<(), Error> { | ||||
|     use core::task::Poll; | ||||
|  | ||||
|     use futures::future::poll_fn; | ||||
| @@ -391,10 +391,10 @@ fn save_data_cache_state() { | ||||
|     let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2; | ||||
|     if dual_bank { | ||||
|         // Disable data cache during write/erase if there are two banks, see errata 2.2.12 | ||||
|         let dcen = unsafe { pac::FLASH.acr().read().dcen() }; | ||||
|         let dcen = pac::FLASH.acr().read().dcen(); | ||||
|         DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed); | ||||
|         if dcen { | ||||
|             unsafe { pac::FLASH.acr().modify(|w| w.set_dcen(false)) }; | ||||
|             pac::FLASH.acr().modify(|w| w.set_dcen(false)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -405,12 +405,10 @@ fn restore_data_cache_state() { | ||||
|         // Restore data cache if it was enabled | ||||
|         let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed); | ||||
|         if dcen { | ||||
|             unsafe { | ||||
|                 // Reset data cache before we enable it again | ||||
|                 pac::FLASH.acr().modify(|w| w.set_dcrst(true)); | ||||
|                 pac::FLASH.acr().modify(|w| w.set_dcrst(false)); | ||||
|                 pac::FLASH.acr().modify(|w| w.set_dcen(true)) | ||||
|             }; | ||||
|             // Reset data cache before we enable it again | ||||
|             pac::FLASH.acr().modify(|w| w.set_dcrst(true)); | ||||
|             pac::FLASH.acr().modify(|w| w.set_dcrst(false)); | ||||
|             pac::FLASH.acr().modify(|w| w.set_dcen(true)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -445,7 +443,7 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) { | ||||
|         feature = "stm32f439vi", | ||||
|         feature = "stm32f439zi", | ||||
|     ))] | ||||
|     if second_bank_read && unsafe { pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() } { | ||||
|     if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { | ||||
|         panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); | ||||
|     } | ||||
|  | ||||
| @@ -479,11 +477,9 @@ fn pa12_is_output_pull_low() -> bool { | ||||
|     use pac::gpio::vals; | ||||
|     use pac::GPIOA; | ||||
|     const PIN: usize = 12; | ||||
|     unsafe { | ||||
|         GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT | ||||
|             && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN | ||||
|             && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW | ||||
|     } | ||||
|     GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT | ||||
|         && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN | ||||
|         && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
|   | ||||
| @@ -16,7 +16,7 @@ unsafe impl<'d, T> stm32_fmc::FmcPeripheral for Fmc<'d, T> | ||||
| where | ||||
|     T: Instance, | ||||
| { | ||||
|     const REGISTERS: *const () = T::REGS.0 as *const _; | ||||
|     const REGISTERS: *const () = T::REGS.as_ptr() as *const _; | ||||
|  | ||||
|     fn enable(&mut self) { | ||||
|         <T as crate::rcc::sealed::RccPeripheral>::enable(); | ||||
| @@ -28,9 +28,7 @@ where | ||||
|         // fsmc v1, v2 and v3 does not have the fmcen bit | ||||
|         // This is a "not" because it is expected that all future versions have this bit | ||||
|         #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))] | ||||
|         unsafe { | ||||
|             T::REGS.bcr1().modify(|r| r.set_fmcen(true)) | ||||
|         }; | ||||
|         T::REGS.bcr1().modify(|r| r.set_fmcen(true)); | ||||
|     } | ||||
|  | ||||
|     fn source_clock_hz(&self) -> u32 { | ||||
| @@ -67,7 +65,7 @@ macro_rules! fmc_sdram_constructor { | ||||
|             chip: CHIP | ||||
|         ) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> { | ||||
|  | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             config_pins!( | ||||
|                 $($addr_pin_name),*, | ||||
|                 $($ba_pin_name),*, | ||||
|   | ||||
| @@ -46,7 +46,7 @@ impl<'d, T: Pin> Flex<'d, T> { | ||||
|     /// Put the pin into input mode. | ||||
|     #[inline] | ||||
|     pub fn set_as_input(&mut self, pull: Pull) { | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             let r = self.pin.block(); | ||||
|             let n = self.pin.pin() as usize; | ||||
|             #[cfg(gpio_v1)] | ||||
| @@ -84,7 +84,7 @@ impl<'d, T: Pin> Flex<'d, T> { | ||||
|     /// at a specific level, call `set_high`/`set_low` on the pin first. | ||||
|     #[inline] | ||||
|     pub fn set_as_output(&mut self, speed: Speed) { | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             let r = self.pin.block(); | ||||
|             let n = self.pin.pin() as usize; | ||||
|             #[cfg(gpio_v1)] | ||||
| @@ -116,7 +116,7 @@ impl<'d, T: Pin> Flex<'d, T> { | ||||
|     /// at a specific level, call `set_high`/`set_low` on the pin first. | ||||
|     #[inline] | ||||
|     pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) { | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             let r = self.pin.block(); | ||||
|             let n = self.pin.pin() as usize; | ||||
|             #[cfg(gpio_v1)] | ||||
| @@ -147,7 +147,7 @@ impl<'d, T: Pin> Flex<'d, T> { | ||||
|  | ||||
|     #[inline] | ||||
|     pub fn is_low(&self) -> bool { | ||||
|         let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as _) }; | ||||
|         let state = self.pin.block().idr().read().idr(self.pin.pin() as _); | ||||
|         state == vals::Idr::LOW | ||||
|     } | ||||
|  | ||||
| @@ -164,7 +164,7 @@ impl<'d, T: Pin> Flex<'d, T> { | ||||
|     /// Is the output pin set as low? | ||||
|     #[inline] | ||||
|     pub fn is_set_low(&self) -> bool { | ||||
|         let state = unsafe { self.pin.block().odr().read().odr(self.pin.pin() as _) }; | ||||
|         let state = self.pin.block().odr().read().odr(self.pin.pin() as _); | ||||
|         state == vals::Odr::LOW | ||||
|     } | ||||
|  | ||||
| @@ -207,7 +207,7 @@ impl<'d, T: Pin> Flex<'d, T> { | ||||
| impl<'d, T: Pin> Drop for Flex<'d, T> { | ||||
|     #[inline] | ||||
|     fn drop(&mut self) { | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             let r = self.pin.block(); | ||||
|             let n = self.pin.pin() as usize; | ||||
|             #[cfg(gpio_v1)] | ||||
| @@ -534,29 +534,25 @@ pub(crate) mod sealed { | ||||
|         /// Set the output as high. | ||||
|         #[inline] | ||||
|         fn set_high(&self) { | ||||
|             unsafe { | ||||
|                 let n = self._pin() as _; | ||||
|                 self.block().bsrr().write(|w| w.set_bs(n, true)); | ||||
|             } | ||||
|             let n = self._pin() as _; | ||||
|             self.block().bsrr().write(|w| w.set_bs(n, true)); | ||||
|         } | ||||
|  | ||||
|         /// Set the output as low. | ||||
|         #[inline] | ||||
|         fn set_low(&self) { | ||||
|             unsafe { | ||||
|                 let n = self._pin() as _; | ||||
|                 self.block().bsrr().write(|w| w.set_br(n, true)); | ||||
|             } | ||||
|             let n = self._pin() as _; | ||||
|             self.block().bsrr().write(|w| w.set_br(n, true)); | ||||
|         } | ||||
|  | ||||
|         #[inline] | ||||
|         unsafe fn set_as_af(&self, af_num: u8, af_type: AFType) { | ||||
|         fn set_as_af(&self, af_num: u8, af_type: AFType) { | ||||
|             self.set_as_af_pull(af_num, af_type, Pull::None); | ||||
|         } | ||||
|  | ||||
|         #[cfg(gpio_v1)] | ||||
|         #[inline] | ||||
|         unsafe fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) { | ||||
|         fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) { | ||||
|             // F1 uses the AFIO register for remapping. | ||||
|             // For now, this is not implemented, so af_num is ignored | ||||
|             // _af_num should be zero here, since it is not set by stm32-data | ||||
| @@ -599,7 +595,7 @@ pub(crate) mod sealed { | ||||
|  | ||||
|         #[cfg(gpio_v2)] | ||||
|         #[inline] | ||||
|         unsafe fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) { | ||||
|         fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) { | ||||
|             let pin = self._pin() as usize; | ||||
|             let block = self.block(); | ||||
|             block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num)); | ||||
| @@ -614,7 +610,7 @@ pub(crate) mod sealed { | ||||
|         } | ||||
|  | ||||
|         #[inline] | ||||
|         unsafe fn set_as_analog(&self) { | ||||
|         fn set_as_analog(&self) { | ||||
|             let pin = self._pin() as usize; | ||||
|             let block = self.block(); | ||||
|             #[cfg(gpio_v1)] | ||||
| @@ -635,12 +631,12 @@ pub(crate) mod sealed { | ||||
|         /// This is currently the same as set_as_analog but is semantically different really. | ||||
|         /// Drivers should set_as_disconnected pins when dropped. | ||||
|         #[inline] | ||||
|         unsafe fn set_as_disconnected(&self) { | ||||
|         fn set_as_disconnected(&self) { | ||||
|             self.set_as_analog(); | ||||
|         } | ||||
|  | ||||
|         #[inline] | ||||
|         unsafe fn set_speed(&self, speed: Speed) { | ||||
|         fn set_speed(&self, speed: Speed) { | ||||
|             let pin = self._pin() as usize; | ||||
|  | ||||
|             #[cfg(gpio_v1)] | ||||
|   | ||||
| @@ -68,53 +68,45 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
|  | ||||
|         unsafe { | ||||
|             scl.set_as_af_pull( | ||||
|                 scl.af_num(), | ||||
|                 AFType::OutputOpenDrain, | ||||
|                 match config.scl_pullup { | ||||
|                     true => Pull::Up, | ||||
|                     false => Pull::None, | ||||
|                 }, | ||||
|             ); | ||||
|             sda.set_as_af_pull( | ||||
|                 sda.af_num(), | ||||
|                 AFType::OutputOpenDrain, | ||||
|                 match config.sda_pullup { | ||||
|                     true => Pull::Up, | ||||
|                     false => Pull::None, | ||||
|                 }, | ||||
|             ); | ||||
|         } | ||||
|         scl.set_as_af_pull( | ||||
|             scl.af_num(), | ||||
|             AFType::OutputOpenDrain, | ||||
|             match config.scl_pullup { | ||||
|                 true => Pull::Up, | ||||
|                 false => Pull::None, | ||||
|             }, | ||||
|         ); | ||||
|         sda.set_as_af_pull( | ||||
|             sda.af_num(), | ||||
|             AFType::OutputOpenDrain, | ||||
|             match config.sda_pullup { | ||||
|                 true => Pull::Up, | ||||
|                 false => Pull::None, | ||||
|             }, | ||||
|         ); | ||||
|  | ||||
|         unsafe { | ||||
|             T::regs().cr1().modify(|reg| { | ||||
|                 reg.set_pe(false); | ||||
|                 //reg.set_anfoff(false); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr1().modify(|reg| { | ||||
|             reg.set_pe(false); | ||||
|             //reg.set_anfoff(false); | ||||
|         }); | ||||
|  | ||||
|         let timings = Timings::new(T::frequency(), freq.into()); | ||||
|  | ||||
|         unsafe { | ||||
|             T::regs().cr2().modify(|reg| { | ||||
|                 reg.set_freq(timings.freq); | ||||
|             }); | ||||
|             T::regs().ccr().modify(|reg| { | ||||
|                 reg.set_f_s(timings.mode.f_s()); | ||||
|                 reg.set_duty(timings.duty.duty()); | ||||
|                 reg.set_ccr(timings.ccr); | ||||
|             }); | ||||
|             T::regs().trise().modify(|reg| { | ||||
|                 reg.set_trise(timings.trise); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr2().modify(|reg| { | ||||
|             reg.set_freq(timings.freq); | ||||
|         }); | ||||
|         T::regs().ccr().modify(|reg| { | ||||
|             reg.set_f_s(timings.mode.f_s()); | ||||
|             reg.set_duty(timings.duty.duty()); | ||||
|             reg.set_ccr(timings.ccr); | ||||
|         }); | ||||
|         T::regs().trise().modify(|reg| { | ||||
|             reg.set_trise(timings.trise); | ||||
|         }); | ||||
|  | ||||
|         unsafe { | ||||
|             T::regs().cr1().modify(|reg| { | ||||
|                 reg.set_pe(true); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr1().modify(|reg| { | ||||
|             reg.set_pe(true); | ||||
|         }); | ||||
|  | ||||
|         Self { | ||||
|             phantom: PhantomData, | ||||
| @@ -123,7 +115,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { | ||||
|     fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { | ||||
|         // Note that flags should only be cleared once they have been registered. If flags are | ||||
|         // cleared otherwise, there may be an inherent race condition and flags may be missed. | ||||
|         let sr1 = T::regs().sr1().read(); | ||||
| @@ -162,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         Ok(sr1) | ||||
|     } | ||||
|  | ||||
|     unsafe fn write_bytes( | ||||
|     fn write_bytes( | ||||
|         &mut self, | ||||
|         addr: u8, | ||||
|         bytes: &[u8], | ||||
| @@ -211,7 +203,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | ||||
|     fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | ||||
|         // Wait until we're ready for sending | ||||
|         while { | ||||
|             // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | ||||
| @@ -234,7 +226,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { | ||||
|     fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { | ||||
|         while { | ||||
|             // Check for any potential error conditions. | ||||
|             self.check_and_clear_error_flags()?; | ||||
| @@ -256,56 +248,52 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|     ) -> Result<(), Error> { | ||||
|         if let Some((last, buffer)) = buffer.split_last_mut() { | ||||
|             // Send a START condition and set ACK bit | ||||
|             unsafe { | ||||
|                 T::regs().cr1().modify(|reg| { | ||||
|                     reg.set_start(true); | ||||
|                     reg.set_ack(true); | ||||
|                 }); | ||||
|             } | ||||
|             T::regs().cr1().modify(|reg| { | ||||
|                 reg.set_start(true); | ||||
|                 reg.set_ack(true); | ||||
|             }); | ||||
|  | ||||
|             // Wait until START condition was generated | ||||
|             while unsafe { !self.check_and_clear_error_flags()?.start() } { | ||||
|             while !self.check_and_clear_error_flags()?.start() { | ||||
|                 check_timeout()?; | ||||
|             } | ||||
|  | ||||
|             // Also wait until signalled we're master and everything is waiting for us | ||||
|             while { | ||||
|                 let sr2 = unsafe { T::regs().sr2().read() }; | ||||
|                 let sr2 = T::regs().sr2().read(); | ||||
|                 !sr2.msl() && !sr2.busy() | ||||
|             } { | ||||
|                 check_timeout()?; | ||||
|             } | ||||
|  | ||||
|             // Set up current address, we're trying to talk to | ||||
|             unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) } | ||||
|             T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)); | ||||
|  | ||||
|             // Wait until address was sent | ||||
|             // Wait for the address to be acknowledged | ||||
|             while unsafe { !self.check_and_clear_error_flags()?.addr() } { | ||||
|             while !self.check_and_clear_error_flags()?.addr() { | ||||
|                 check_timeout()?; | ||||
|             } | ||||
|  | ||||
|             // Clear condition by reading SR2 | ||||
|             let _ = unsafe { T::regs().sr2().read() }; | ||||
|             let _ = T::regs().sr2().read(); | ||||
|  | ||||
|             // Receive bytes into buffer | ||||
|             for c in buffer { | ||||
|                 *c = unsafe { self.recv_byte(&check_timeout)? }; | ||||
|                 *c = self.recv_byte(&check_timeout)?; | ||||
|             } | ||||
|  | ||||
|             // Prepare to send NACK then STOP after next byte | ||||
|             unsafe { | ||||
|                 T::regs().cr1().modify(|reg| { | ||||
|                     reg.set_ack(false); | ||||
|                     reg.set_stop(true); | ||||
|                 }) | ||||
|             } | ||||
|             T::regs().cr1().modify(|reg| { | ||||
|                 reg.set_ack(false); | ||||
|                 reg.set_stop(true); | ||||
|             }); | ||||
|  | ||||
|             // Receive last byte | ||||
|             *last = unsafe { self.recv_byte(&check_timeout)? }; | ||||
|             *last = self.recv_byte(&check_timeout)?; | ||||
|  | ||||
|             // Wait for the STOP to be sent. | ||||
|             while unsafe { T::regs().cr1().read().stop() } { | ||||
|             while T::regs().cr1().read().stop() { | ||||
|                 check_timeout()?; | ||||
|             } | ||||
|  | ||||
| @@ -326,15 +314,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         write: &[u8], | ||||
|         check_timeout: impl Fn() -> Result<(), Error>, | ||||
|     ) -> Result<(), Error> { | ||||
|         unsafe { | ||||
|             self.write_bytes(addr, write, &check_timeout)?; | ||||
|             // Send a STOP condition | ||||
|             T::regs().cr1().modify(|reg| reg.set_stop(true)); | ||||
|             // Wait for STOP condition to transmit. | ||||
|             while T::regs().cr1().read().stop() { | ||||
|                 check_timeout()?; | ||||
|             } | ||||
|         }; | ||||
|         self.write_bytes(addr, write, &check_timeout)?; | ||||
|         // Send a STOP condition | ||||
|         T::regs().cr1().modify(|reg| reg.set_stop(true)); | ||||
|         // Wait for STOP condition to transmit. | ||||
|         while T::regs().cr1().read().stop() { | ||||
|             check_timeout()?; | ||||
|         } | ||||
|  | ||||
|         // Fallthrough is success | ||||
|         Ok(()) | ||||
| @@ -351,7 +337,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         read: &mut [u8], | ||||
|         check_timeout: impl Fn() -> Result<(), Error>, | ||||
|     ) -> Result<(), Error> { | ||||
|         unsafe { self.write_bytes(addr, write, &check_timeout)? }; | ||||
|         self.write_bytes(addr, write, &check_timeout)?; | ||||
|         self.blocking_read_timeout(addr, read, &check_timeout)?; | ||||
|  | ||||
|         Ok(()) | ||||
| @@ -478,8 +464,6 @@ impl Timings { | ||||
|         assert!(freq >= 2 && freq <= 50); | ||||
|  | ||||
|         // Configure bus frequency into I2C peripheral | ||||
|         //self.i2c.cr2.write(|w| unsafe { w.freq().bits(freq as u8) }); | ||||
|  | ||||
|         let trise = if speed <= 100_000 { | ||||
|             freq + 1 | ||||
|         } else { | ||||
| @@ -539,18 +523,16 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> { | ||||
|     type Config = Hertz; | ||||
|     fn set_config(&mut self, config: &Self::Config) { | ||||
|         let timings = Timings::new(T::frequency(), *config); | ||||
|         unsafe { | ||||
|             T::regs().cr2().modify(|reg| { | ||||
|                 reg.set_freq(timings.freq); | ||||
|             }); | ||||
|             T::regs().ccr().modify(|reg| { | ||||
|                 reg.set_f_s(timings.mode.f_s()); | ||||
|                 reg.set_duty(timings.duty.duty()); | ||||
|                 reg.set_ccr(timings.ccr); | ||||
|             }); | ||||
|             T::regs().trise().modify(|reg| { | ||||
|                 reg.set_trise(timings.trise); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr2().modify(|reg| { | ||||
|             reg.set_freq(timings.freq); | ||||
|         }); | ||||
|         T::regs().ccr().modify(|reg| { | ||||
|             reg.set_f_s(timings.mode.f_s()); | ||||
|             reg.set_duty(timings.duty.duty()); | ||||
|             reg.set_ccr(timings.ccr); | ||||
|         }); | ||||
|         T::regs().trise().modify(|reg| { | ||||
|             reg.set_trise(timings.trise); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -89,49 +89,41 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
|  | ||||
|         unsafe { | ||||
|             scl.set_as_af_pull( | ||||
|                 scl.af_num(), | ||||
|                 AFType::OutputOpenDrain, | ||||
|                 match config.scl_pullup { | ||||
|                     true => Pull::Up, | ||||
|                     false => Pull::None, | ||||
|                 }, | ||||
|             ); | ||||
|             sda.set_as_af_pull( | ||||
|                 sda.af_num(), | ||||
|                 AFType::OutputOpenDrain, | ||||
|                 match config.sda_pullup { | ||||
|                     true => Pull::Up, | ||||
|                     false => Pull::None, | ||||
|                 }, | ||||
|             ); | ||||
|         } | ||||
|         scl.set_as_af_pull( | ||||
|             scl.af_num(), | ||||
|             AFType::OutputOpenDrain, | ||||
|             match config.scl_pullup { | ||||
|                 true => Pull::Up, | ||||
|                 false => Pull::None, | ||||
|             }, | ||||
|         ); | ||||
|         sda.set_as_af_pull( | ||||
|             sda.af_num(), | ||||
|             AFType::OutputOpenDrain, | ||||
|             match config.sda_pullup { | ||||
|                 true => Pull::Up, | ||||
|                 false => Pull::None, | ||||
|             }, | ||||
|         ); | ||||
|  | ||||
|         unsafe { | ||||
|             T::regs().cr1().modify(|reg| { | ||||
|                 reg.set_pe(false); | ||||
|                 reg.set_anfoff(false); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr1().modify(|reg| { | ||||
|             reg.set_pe(false); | ||||
|             reg.set_anfoff(false); | ||||
|         }); | ||||
|  | ||||
|         let timings = Timings::new(T::frequency(), freq.into()); | ||||
|  | ||||
|         unsafe { | ||||
|             T::regs().timingr().write(|reg| { | ||||
|                 reg.set_presc(timings.prescale); | ||||
|                 reg.set_scll(timings.scll); | ||||
|                 reg.set_sclh(timings.sclh); | ||||
|                 reg.set_sdadel(timings.sdadel); | ||||
|                 reg.set_scldel(timings.scldel); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().timingr().write(|reg| { | ||||
|             reg.set_presc(timings.prescale); | ||||
|             reg.set_scll(timings.scll); | ||||
|             reg.set_sclh(timings.sclh); | ||||
|             reg.set_sdadel(timings.sdadel); | ||||
|             reg.set_scldel(timings.scldel); | ||||
|         }); | ||||
|  | ||||
|         unsafe { | ||||
|             T::regs().cr1().modify(|reg| { | ||||
|                 reg.set_pe(true); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr1().modify(|reg| { | ||||
|             reg.set_pe(true); | ||||
|         }); | ||||
|  | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
| @@ -144,12 +136,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|     } | ||||
|  | ||||
|     fn master_stop(&mut self) { | ||||
|         unsafe { | ||||
|             T::regs().cr2().write(|w| w.set_stop(true)); | ||||
|         } | ||||
|         T::regs().cr2().write(|w| w.set_stop(true)); | ||||
|     } | ||||
|  | ||||
|     unsafe fn master_read( | ||||
|     fn master_read( | ||||
|         address: u8, | ||||
|         length: usize, | ||||
|         stop: Stop, | ||||
| @@ -191,7 +181,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     unsafe fn master_write( | ||||
|     fn master_write( | ||||
|         address: u8, | ||||
|         length: usize, | ||||
|         stop: Stop, | ||||
| @@ -229,7 +219,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     unsafe fn master_continue( | ||||
|     fn master_continue( | ||||
|         length: usize, | ||||
|         reload: bool, | ||||
|         check_timeout: impl Fn() -> Result<(), Error>, | ||||
| @@ -259,13 +249,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         //$i2c.txdr.write(|w| w.txdata().bits(0)); | ||||
|         //} | ||||
|  | ||||
|         unsafe { | ||||
|             if T::regs().isr().read().txis() { | ||||
|                 T::regs().txdr().write(|w| w.set_txdata(0)); | ||||
|             } | ||||
|             if !T::regs().isr().read().txe() { | ||||
|                 T::regs().isr().modify(|w| w.set_txe(true)) | ||||
|             } | ||||
|         if T::regs().isr().read().txis() { | ||||
|             T::regs().txdr().write(|w| w.set_txdata(0)); | ||||
|         } | ||||
|         if !T::regs().isr().read().txe() { | ||||
|             T::regs().isr().modify(|w| w.set_txe(true)) | ||||
|         } | ||||
|  | ||||
|         // If TXDR is not flagged as empty, write 1 to flush it | ||||
| @@ -276,21 +264,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|  | ||||
|     fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | ||||
|         loop { | ||||
|             unsafe { | ||||
|                 let isr = T::regs().isr().read(); | ||||
|                 if isr.txe() { | ||||
|                     return Ok(()); | ||||
|                 } else if isr.berr() { | ||||
|                     T::regs().icr().write(|reg| reg.set_berrcf(true)); | ||||
|                     return Err(Error::Bus); | ||||
|                 } else if isr.arlo() { | ||||
|                     T::regs().icr().write(|reg| reg.set_arlocf(true)); | ||||
|                     return Err(Error::Arbitration); | ||||
|                 } else if isr.nackf() { | ||||
|                     T::regs().icr().write(|reg| reg.set_nackcf(true)); | ||||
|                     self.flush_txdr(); | ||||
|                     return Err(Error::Nack); | ||||
|                 } | ||||
|             let isr = T::regs().isr().read(); | ||||
|             if isr.txe() { | ||||
|                 return Ok(()); | ||||
|             } else if isr.berr() { | ||||
|                 T::regs().icr().write(|reg| reg.set_berrcf(true)); | ||||
|                 return Err(Error::Bus); | ||||
|             } else if isr.arlo() { | ||||
|                 T::regs().icr().write(|reg| reg.set_arlocf(true)); | ||||
|                 return Err(Error::Arbitration); | ||||
|             } else if isr.nackf() { | ||||
|                 T::regs().icr().write(|reg| reg.set_nackcf(true)); | ||||
|                 self.flush_txdr(); | ||||
|                 return Err(Error::Nack); | ||||
|             } | ||||
|  | ||||
|             check_timeout()?; | ||||
| @@ -299,21 +285,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|  | ||||
|     fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | ||||
|         loop { | ||||
|             unsafe { | ||||
|                 let isr = T::regs().isr().read(); | ||||
|                 if isr.rxne() { | ||||
|                     return Ok(()); | ||||
|                 } else if isr.berr() { | ||||
|                     T::regs().icr().write(|reg| reg.set_berrcf(true)); | ||||
|                     return Err(Error::Bus); | ||||
|                 } else if isr.arlo() { | ||||
|                     T::regs().icr().write(|reg| reg.set_arlocf(true)); | ||||
|                     return Err(Error::Arbitration); | ||||
|                 } else if isr.nackf() { | ||||
|                     T::regs().icr().write(|reg| reg.set_nackcf(true)); | ||||
|                     self.flush_txdr(); | ||||
|                     return Err(Error::Nack); | ||||
|                 } | ||||
|             let isr = T::regs().isr().read(); | ||||
|             if isr.rxne() { | ||||
|                 return Ok(()); | ||||
|             } else if isr.berr() { | ||||
|                 T::regs().icr().write(|reg| reg.set_berrcf(true)); | ||||
|                 return Err(Error::Bus); | ||||
|             } else if isr.arlo() { | ||||
|                 T::regs().icr().write(|reg| reg.set_arlocf(true)); | ||||
|                 return Err(Error::Arbitration); | ||||
|             } else if isr.nackf() { | ||||
|                 T::regs().icr().write(|reg| reg.set_nackcf(true)); | ||||
|                 self.flush_txdr(); | ||||
|                 return Err(Error::Nack); | ||||
|             } | ||||
|  | ||||
|             check_timeout()?; | ||||
| @@ -322,21 +306,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|  | ||||
|     fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | ||||
|         loop { | ||||
|             unsafe { | ||||
|                 let isr = T::regs().isr().read(); | ||||
|                 if isr.tc() { | ||||
|                     return Ok(()); | ||||
|                 } else if isr.berr() { | ||||
|                     T::regs().icr().write(|reg| reg.set_berrcf(true)); | ||||
|                     return Err(Error::Bus); | ||||
|                 } else if isr.arlo() { | ||||
|                     T::regs().icr().write(|reg| reg.set_arlocf(true)); | ||||
|                     return Err(Error::Arbitration); | ||||
|                 } else if isr.nackf() { | ||||
|                     T::regs().icr().write(|reg| reg.set_nackcf(true)); | ||||
|                     self.flush_txdr(); | ||||
|                     return Err(Error::Nack); | ||||
|                 } | ||||
|             let isr = T::regs().isr().read(); | ||||
|             if isr.tc() { | ||||
|                 return Ok(()); | ||||
|             } else if isr.berr() { | ||||
|                 T::regs().icr().write(|reg| reg.set_berrcf(true)); | ||||
|                 return Err(Error::Bus); | ||||
|             } else if isr.arlo() { | ||||
|                 T::regs().icr().write(|reg| reg.set_arlocf(true)); | ||||
|                 return Err(Error::Arbitration); | ||||
|             } else if isr.nackf() { | ||||
|                 T::regs().icr().write(|reg| reg.set_nackcf(true)); | ||||
|                 self.flush_txdr(); | ||||
|                 return Err(Error::Nack); | ||||
|             } | ||||
|  | ||||
|             check_timeout()?; | ||||
| @@ -358,32 +340,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         }; | ||||
|         let last_chunk_idx = total_chunks.saturating_sub(1); | ||||
|  | ||||
|         unsafe { | ||||
|             Self::master_read( | ||||
|                 address, | ||||
|                 read.len().min(255), | ||||
|                 Stop::Automatic, | ||||
|                 last_chunk_idx != 0, | ||||
|                 restart, | ||||
|                 &check_timeout, | ||||
|             )?; | ||||
|         } | ||||
|         Self::master_read( | ||||
|             address, | ||||
|             read.len().min(255), | ||||
|             Stop::Automatic, | ||||
|             last_chunk_idx != 0, | ||||
|             restart, | ||||
|             &check_timeout, | ||||
|         )?; | ||||
|  | ||||
|         for (number, chunk) in read.chunks_mut(255).enumerate() { | ||||
|             if number != 0 { | ||||
|                 // NOTE(unsafe) We have &mut self | ||||
|                 unsafe { | ||||
|                     Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; | ||||
|                 } | ||||
|                 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; | ||||
|             } | ||||
|  | ||||
|             for byte in chunk { | ||||
|                 // Wait until we have received something | ||||
|                 self.wait_rxne(&check_timeout)?; | ||||
|  | ||||
|                 unsafe { | ||||
|                     *byte = T::regs().rxdr().read().rxdata(); | ||||
|                 } | ||||
|                 *byte = T::regs().rxdr().read().rxdata(); | ||||
|             } | ||||
|         } | ||||
|         Ok(()) | ||||
| @@ -407,23 +382,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         // I2C start | ||||
|         // | ||||
|         // ST SAD+W | ||||
|         // NOTE(unsafe) We have &mut self | ||||
|         unsafe { | ||||
|             Self::master_write( | ||||
|                 address, | ||||
|                 write.len().min(255), | ||||
|                 Stop::Software, | ||||
|                 last_chunk_idx != 0, | ||||
|                 &check_timeout, | ||||
|             )?; | ||||
|         } | ||||
|         Self::master_write( | ||||
|             address, | ||||
|             write.len().min(255), | ||||
|             Stop::Software, | ||||
|             last_chunk_idx != 0, | ||||
|             &check_timeout, | ||||
|         )?; | ||||
|  | ||||
|         for (number, chunk) in write.chunks(255).enumerate() { | ||||
|             if number != 0 { | ||||
|                 // NOTE(unsafe) We have &mut self | ||||
|                 unsafe { | ||||
|                     Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; | ||||
|                 } | ||||
|                 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; | ||||
|             } | ||||
|  | ||||
|             for byte in chunk { | ||||
| @@ -432,9 +401,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|                 // through) | ||||
|                 self.wait_txe(&check_timeout)?; | ||||
|  | ||||
|                 unsafe { | ||||
|                     T::regs().txdr().write(|w| w.set_txdata(*byte)); | ||||
|                 } | ||||
|                 T::regs().txdr().write(|w| w.set_txdata(*byte)); | ||||
|             } | ||||
|         } | ||||
|         // Wait until the write finishes | ||||
| @@ -467,7 +434,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|                     w.set_tcie(true); | ||||
|                 } | ||||
|             }); | ||||
|             let dst = regs.txdr().ptr() as *mut u8; | ||||
|             let dst = regs.txdr().as_ptr() as *mut u8; | ||||
|  | ||||
|             let ch = &mut self.tx_dma; | ||||
|             let request = ch.request(); | ||||
| @@ -479,37 +446,30 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|  | ||||
|         let on_drop = OnDrop::new(|| { | ||||
|             let regs = T::regs(); | ||||
|             unsafe { | ||||
|                 regs.cr1().modify(|w| { | ||||
|                     if last_slice { | ||||
|                         w.set_txdmaen(false); | ||||
|                     } | ||||
|                     w.set_tcie(false); | ||||
|                 }) | ||||
|             } | ||||
|             regs.cr1().modify(|w| { | ||||
|                 if last_slice { | ||||
|                     w.set_txdmaen(false); | ||||
|                 } | ||||
|                 w.set_tcie(false); | ||||
|             }) | ||||
|         }); | ||||
|  | ||||
|         poll_fn(|cx| { | ||||
|             state.waker.register(cx.waker()); | ||||
|  | ||||
|             let isr = unsafe { T::regs().isr().read() }; | ||||
|             let isr = T::regs().isr().read(); | ||||
|             if remaining_len == total_len { | ||||
|                 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers | ||||
|                 if first_slice { | ||||
|                     unsafe { | ||||
|                         Self::master_write( | ||||
|                             address, | ||||
|                             total_len.min(255), | ||||
|                             Stop::Software, | ||||
|                             (total_len > 255) || !last_slice, | ||||
|                             &check_timeout, | ||||
|                         )?; | ||||
|                     } | ||||
|                     Self::master_write( | ||||
|                         address, | ||||
|                         total_len.min(255), | ||||
|                         Stop::Software, | ||||
|                         (total_len > 255) || !last_slice, | ||||
|                         &check_timeout, | ||||
|                     )?; | ||||
|                 } else { | ||||
|                     unsafe { | ||||
|                         Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; | ||||
|                         T::regs().cr1().modify(|w| w.set_tcie(true)); | ||||
|                     } | ||||
|                     Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; | ||||
|                     T::regs().cr1().modify(|w| w.set_tcie(true)); | ||||
|                 } | ||||
|             } else if !(isr.tcr() || isr.tc()) { | ||||
|                 // poll_fn was woken without an interrupt present | ||||
| @@ -519,13 +479,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|             } else { | ||||
|                 let last_piece = (remaining_len <= 255) && last_slice; | ||||
|  | ||||
|                 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers | ||||
|                 unsafe { | ||||
|                     if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { | ||||
|                         return Poll::Ready(Err(e)); | ||||
|                     } | ||||
|                     T::regs().cr1().modify(|w| w.set_tcie(true)); | ||||
|                 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { | ||||
|                     return Poll::Ready(Err(e)); | ||||
|                 } | ||||
|                 T::regs().cr1().modify(|w| w.set_tcie(true)); | ||||
|             } | ||||
|  | ||||
|             remaining_len = remaining_len.saturating_sub(255); | ||||
| @@ -564,7 +521,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|                 w.set_rxdmaen(true); | ||||
|                 w.set_tcie(true); | ||||
|             }); | ||||
|             let src = regs.rxdr().ptr() as *mut u8; | ||||
|             let src = regs.rxdr().as_ptr() as *mut u8; | ||||
|  | ||||
|             let ch = &mut self.rx_dma; | ||||
|             let request = ch.request(); | ||||
| @@ -576,30 +533,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|  | ||||
|         let on_drop = OnDrop::new(|| { | ||||
|             let regs = T::regs(); | ||||
|             unsafe { | ||||
|                 regs.cr1().modify(|w| { | ||||
|                     w.set_rxdmaen(false); | ||||
|                     w.set_tcie(false); | ||||
|                 }) | ||||
|             } | ||||
|             regs.cr1().modify(|w| { | ||||
|                 w.set_rxdmaen(false); | ||||
|                 w.set_tcie(false); | ||||
|             }) | ||||
|         }); | ||||
|  | ||||
|         poll_fn(|cx| { | ||||
|             state.waker.register(cx.waker()); | ||||
|  | ||||
|             let isr = unsafe { T::regs().isr().read() }; | ||||
|             let isr = T::regs().isr().read(); | ||||
|             if remaining_len == total_len { | ||||
|                 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers | ||||
|                 unsafe { | ||||
|                     Self::master_read( | ||||
|                         address, | ||||
|                         total_len.min(255), | ||||
|                         Stop::Software, | ||||
|                         total_len > 255, | ||||
|                         restart, | ||||
|                         &check_timeout, | ||||
|                     )?; | ||||
|                 } | ||||
|                 Self::master_read( | ||||
|                     address, | ||||
|                     total_len.min(255), | ||||
|                     Stop::Software, | ||||
|                     total_len > 255, | ||||
|                     restart, | ||||
|                     &check_timeout, | ||||
|                 )?; | ||||
|             } else if !(isr.tcr() || isr.tc()) { | ||||
|                 // poll_fn was woken without an interrupt present | ||||
|                 return Poll::Pending; | ||||
| @@ -608,13 +560,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|             } else { | ||||
|                 let last_piece = remaining_len <= 255; | ||||
|  | ||||
|                 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers | ||||
|                 unsafe { | ||||
|                     if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { | ||||
|                         return Poll::Ready(Err(e)); | ||||
|                     } | ||||
|                     T::regs().cr1().modify(|w| w.set_tcie(true)); | ||||
|                 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { | ||||
|                     return Poll::Ready(Err(e)); | ||||
|                 } | ||||
|                 T::regs().cr1().modify(|w| w.set_tcie(true)); | ||||
|             } | ||||
|  | ||||
|             remaining_len = remaining_len.saturating_sub(255); | ||||
| @@ -758,16 +707,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|         let first_length = write[0].len(); | ||||
|         let last_slice_index = write.len() - 1; | ||||
|  | ||||
|         // NOTE(unsafe) We have &mut self | ||||
|         unsafe { | ||||
|             Self::master_write( | ||||
|                 address, | ||||
|                 first_length.min(255), | ||||
|                 Stop::Software, | ||||
|                 (first_length > 255) || (last_slice_index != 0), | ||||
|                 &check_timeout, | ||||
|             )?; | ||||
|         } | ||||
|         Self::master_write( | ||||
|             address, | ||||
|             first_length.min(255), | ||||
|             Stop::Software, | ||||
|             (first_length > 255) || (last_slice_index != 0), | ||||
|             &check_timeout, | ||||
|         )?; | ||||
|  | ||||
|         for (idx, slice) in write.iter().enumerate() { | ||||
|             let slice_len = slice.len(); | ||||
| @@ -780,26 +726,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|             let last_chunk_idx = total_chunks.saturating_sub(1); | ||||
|  | ||||
|             if idx != 0 { | ||||
|                 // NOTE(unsafe) We have &mut self | ||||
|                 unsafe { | ||||
|                     Self::master_continue( | ||||
|                         slice_len.min(255), | ||||
|                         (idx != last_slice_index) || (slice_len > 255), | ||||
|                         &check_timeout, | ||||
|                     )?; | ||||
|                 } | ||||
|                 Self::master_continue( | ||||
|                     slice_len.min(255), | ||||
|                     (idx != last_slice_index) || (slice_len > 255), | ||||
|                     &check_timeout, | ||||
|                 )?; | ||||
|             } | ||||
|  | ||||
|             for (number, chunk) in slice.chunks(255).enumerate() { | ||||
|                 if number != 0 { | ||||
|                     // NOTE(unsafe) We have &mut self | ||||
|                     unsafe { | ||||
|                         Self::master_continue( | ||||
|                             chunk.len(), | ||||
|                             (number != last_chunk_idx) || (idx != last_slice_index), | ||||
|                             &check_timeout, | ||||
|                         )?; | ||||
|                     } | ||||
|                     Self::master_continue( | ||||
|                         chunk.len(), | ||||
|                         (number != last_chunk_idx) || (idx != last_slice_index), | ||||
|                         &check_timeout, | ||||
|                     )?; | ||||
|                 } | ||||
|  | ||||
|                 for byte in chunk { | ||||
| @@ -810,9 +750,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||||
|  | ||||
|                     // Put byte on the wire | ||||
|                     //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); | ||||
|                     unsafe { | ||||
|                         T::regs().txdr().write(|w| w.set_txdata(*byte)); | ||||
|                     } | ||||
|                     T::regs().txdr().write(|w| w.set_txdata(*byte)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -1061,14 +999,12 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> { | ||||
|     type Config = Hertz; | ||||
|     fn set_config(&mut self, config: &Self::Config) { | ||||
|         let timings = Timings::new(T::frequency(), *config); | ||||
|         unsafe { | ||||
|             T::regs().timingr().write(|reg| { | ||||
|                 reg.set_presc(timings.prescale); | ||||
|                 reg.set_scll(timings.scll); | ||||
|                 reg.set_sclh(timings.sclh); | ||||
|                 reg.set_sdadel(timings.sdadel); | ||||
|                 reg.set_scldel(timings.scldel); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().timingr().write(|reg| { | ||||
|             reg.set_presc(timings.prescale); | ||||
|             reg.set_scll(timings.scll); | ||||
|             reg.set_sclh(timings.sclh); | ||||
|             reg.set_sdadel(timings.sdadel); | ||||
|             reg.set_scldel(timings.scldel); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -153,19 +153,17 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | ||||
|     ) -> Self { | ||||
|         into_ref!(sd, ws, ck, mck); | ||||
|  | ||||
|         unsafe { | ||||
|             sd.set_as_af(sd.af_num(), AFType::OutputPushPull); | ||||
|             sd.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         sd.set_as_af(sd.af_num(), AFType::OutputPushPull); | ||||
|         sd.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|  | ||||
|             ws.set_as_af(ws.af_num(), AFType::OutputPushPull); | ||||
|             ws.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         ws.set_as_af(ws.af_num(), AFType::OutputPushPull); | ||||
|         ws.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|  | ||||
|             ck.set_as_af(ck.af_num(), AFType::OutputPushPull); | ||||
|             ck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         ck.set_as_af(ck.af_num(), AFType::OutputPushPull); | ||||
|         ck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|  | ||||
|             mck.set_as_af(mck.af_num(), AFType::OutputPushPull); | ||||
|             mck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         } | ||||
|         mck.set_as_af(mck.af_num(), AFType::OutputPushPull); | ||||
|         mck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|  | ||||
|         let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default()); | ||||
|  | ||||
| @@ -178,7 +176,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | ||||
|         let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); | ||||
|  | ||||
|         #[cfg(any(spi_v1, spi_f1))] | ||||
|         unsafe { | ||||
|         { | ||||
|             use stm32_metapac::spi::vals::{I2scfg, Odd}; | ||||
|  | ||||
|             // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud | ||||
| @@ -232,10 +230,6 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | ||||
|                 w.set_i2se(true) | ||||
|             }); | ||||
|         } | ||||
|         #[cfg(spi_v2)] | ||||
|         unsafe {} | ||||
|         #[cfg(any(spi_v3, spi_v4))] | ||||
|         unsafe {} | ||||
|  | ||||
|         Self { | ||||
|             _peri: spi, | ||||
| @@ -264,12 +258,10 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | ||||
|  | ||||
| impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> { | ||||
|     fn drop(&mut self) { | ||||
|         unsafe { | ||||
|             self.sd.as_ref().map(|x| x.set_as_disconnected()); | ||||
|             self.ws.as_ref().map(|x| x.set_as_disconnected()); | ||||
|             self.ck.as_ref().map(|x| x.set_as_disconnected()); | ||||
|             self.mck.as_ref().map(|x| x.set_as_disconnected()); | ||||
|         } | ||||
|         self.sd.as_ref().map(|x| x.set_as_disconnected()); | ||||
|         self.ws.as_ref().map(|x| x.set_as_disconnected()); | ||||
|         self.ck.as_ref().map(|x| x.set_as_disconnected()); | ||||
|         self.mck.as_ref().map(|x| x.set_as_disconnected()); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive | ||||
|         ]; | ||||
|  | ||||
|         // Status register gives channel occupied status. For rx, use cpu1. | ||||
|         let sr = unsafe { regs.cpu(1).sr().read() }; | ||||
|         let sr = regs.cpu(1).sr().read(); | ||||
|         regs.cpu(0).mr().modify(|w| { | ||||
|             for channel in channels { | ||||
|                 if sr.chf(channel as usize) { | ||||
| @@ -57,7 +57,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi | ||||
|         ]; | ||||
|  | ||||
|         // Status register gives channel occupied status. For tx, use cpu0. | ||||
|         let sr = unsafe { regs.cpu(0).sr().read() }; | ||||
|         let sr = regs.cpu(0).sr().read(); | ||||
|         regs.cpu(0).mr().modify(|w| { | ||||
|             for channel in channels { | ||||
|                 if !sr.chf(channel as usize) { | ||||
| @@ -98,16 +98,14 @@ impl Ipcc { | ||||
|         IPCC::reset(); | ||||
|         IPCC::set_cpu2(true); | ||||
|  | ||||
|         unsafe { _configure_pwr() }; | ||||
|         _configure_pwr(); | ||||
|  | ||||
|         let regs = IPCC::regs(); | ||||
|  | ||||
|         unsafe { | ||||
|             regs.cpu(0).cr().modify(|w| { | ||||
|                 w.set_rxoie(true); | ||||
|                 w.set_txfie(true); | ||||
|             }) | ||||
|         } | ||||
|         regs.cpu(0).cr().modify(|w| { | ||||
|             w.set_rxoie(true); | ||||
|             w.set_txfie(true); | ||||
|         }); | ||||
|  | ||||
|         // enable interrupts | ||||
|         crate::interrupt::typelevel::IPCC_C1_RX::unpend(); | ||||
| @@ -129,7 +127,7 @@ impl Ipcc { | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|  | ||||
|         trace!("ipcc: ch {}: send data", channel as u8); | ||||
|         unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) } | ||||
|         regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)); | ||||
|     } | ||||
|  | ||||
|     /// Wait for the tx channel to become clear | ||||
| @@ -137,20 +135,20 @@ impl Ipcc { | ||||
|         let regs = IPCC::regs(); | ||||
|  | ||||
|         // This is a race, but is nice for debugging | ||||
|         if unsafe { regs.cpu(0).sr().read() }.chf(channel as usize) { | ||||
|         if regs.cpu(0).sr().read().chf(channel as usize) { | ||||
|             trace!("ipcc: ch {}:  wait for tx free", channel as u8); | ||||
|         } | ||||
|  | ||||
|         poll_fn(|cx| { | ||||
|             IPCC::state().tx_waker_for(channel).register(cx.waker()); | ||||
|             // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt | ||||
|             unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false)) } | ||||
|             regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false)); | ||||
|  | ||||
|             compiler_fence(Ordering::SeqCst); | ||||
|  | ||||
|             if !unsafe { regs.cpu(0).sr().read() }.chf(channel as usize) { | ||||
|             if !regs.cpu(0).sr().read().chf(channel as usize) { | ||||
|                 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt | ||||
|                 unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)) } | ||||
|                 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)); | ||||
|  | ||||
|                 Poll::Ready(()) | ||||
|             } else { | ||||
| @@ -166,20 +164,20 @@ impl Ipcc { | ||||
|  | ||||
|         loop { | ||||
|             // This is a race, but is nice for debugging | ||||
|             if !unsafe { regs.cpu(1).sr().read() }.chf(channel as usize) { | ||||
|             if !regs.cpu(1).sr().read().chf(channel as usize) { | ||||
|                 trace!("ipcc: ch {}:  wait for rx occupied", channel as u8); | ||||
|             } | ||||
|  | ||||
|             poll_fn(|cx| { | ||||
|                 IPCC::state().rx_waker_for(channel).register(cx.waker()); | ||||
|                 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt | ||||
|                 unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false)) } | ||||
|                 regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false)); | ||||
|  | ||||
|                 compiler_fence(Ordering::SeqCst); | ||||
|  | ||||
|                 if unsafe { regs.cpu(1).sr().read() }.chf(channel as usize) { | ||||
|                 if regs.cpu(1).sr().read().chf(channel as usize) { | ||||
|                     // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt | ||||
|                     unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)) } | ||||
|                     regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)); | ||||
|  | ||||
|                     Poll::Ready(()) | ||||
|                 } else { | ||||
| @@ -199,7 +197,7 @@ impl Ipcc { | ||||
|             trace!("ipcc: ch {}: clear rx", channel as u8); | ||||
|             compiler_fence(Ordering::SeqCst); | ||||
|             // If the channel is clear and the read function returns none, fetch more data | ||||
|             unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) } | ||||
|             regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -210,7 +208,7 @@ impl sealed::Instance for crate::peripherals::IPCC { | ||||
|     } | ||||
|  | ||||
|     fn set_cpu2(enabled: bool) { | ||||
|         unsafe { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)) } | ||||
|         crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)); | ||||
|     } | ||||
|  | ||||
|     fn state() -> &'static self::sealed::State { | ||||
| @@ -269,7 +267,7 @@ pub(crate) mod sealed { | ||||
|     } | ||||
| } | ||||
|  | ||||
| unsafe fn _configure_pwr() { | ||||
| fn _configure_pwr() { | ||||
|     // TODO: move this to RCC | ||||
|  | ||||
|     let pwr = crate::pac::PWR; | ||||
|   | ||||
| @@ -146,35 +146,35 @@ impl Default for Config { | ||||
| pub fn init(config: Config) -> Peripherals { | ||||
|     let p = Peripherals::take(); | ||||
|  | ||||
|     unsafe { | ||||
|         #[cfg(dbgmcu)] | ||||
|         if config.enable_debug_during_sleep { | ||||
|             crate::pac::DBGMCU.cr().modify(|cr| { | ||||
|                 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))] | ||||
|                 { | ||||
|                     cr.set_dbg_stop(true); | ||||
|                     cr.set_dbg_standby(true); | ||||
|                 } | ||||
|                 #[cfg(any( | ||||
|                     dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, | ||||
|                     dbgmcu_l4, dbgmcu_wb, dbgmcu_wl | ||||
|                 ))] | ||||
|                 { | ||||
|                     cr.set_dbg_sleep(true); | ||||
|                     cr.set_dbg_stop(true); | ||||
|                     cr.set_dbg_standby(true); | ||||
|                 } | ||||
|                 #[cfg(dbgmcu_h7)] | ||||
|                 { | ||||
|                     cr.set_d1dbgcken(true); | ||||
|                     cr.set_d3dbgcken(true); | ||||
|                     cr.set_dbgsleep_d1(true); | ||||
|                     cr.set_dbgstby_d1(true); | ||||
|                     cr.set_dbgstop_d1(true); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     #[cfg(dbgmcu)] | ||||
|     if config.enable_debug_during_sleep { | ||||
|         crate::pac::DBGMCU.cr().modify(|cr| { | ||||
|             #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))] | ||||
|             { | ||||
|                 cr.set_dbg_stop(true); | ||||
|                 cr.set_dbg_standby(true); | ||||
|             } | ||||
|             #[cfg(any( | ||||
|                 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, | ||||
|                 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl | ||||
|             ))] | ||||
|             { | ||||
|                 cr.set_dbg_sleep(true); | ||||
|                 cr.set_dbg_stop(true); | ||||
|                 cr.set_dbg_standby(true); | ||||
|             } | ||||
|             #[cfg(dbgmcu_h7)] | ||||
|             { | ||||
|                 cr.set_d1dbgcken(true); | ||||
|                 cr.set_d3dbgcken(true); | ||||
|                 cr.set_dbgsleep_d1(true); | ||||
|                 cr.set_dbgstby_d1(true); | ||||
|                 cr.set_dbgstop_d1(true); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     unsafe { | ||||
|         gpio::init(); | ||||
|         dma::init( | ||||
|             #[cfg(bdma)] | ||||
|   | ||||
| @@ -21,7 +21,7 @@ macro_rules! complementary_channel_impl { | ||||
|         impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { | ||||
|             pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { | ||||
|                 into_ref!(pin); | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     pin.set_low(); | ||||
|                     pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | ||||
|                     #[cfg(gpio_v2)] | ||||
| @@ -72,33 +72,27 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | ||||
|         this.inner.set_frequency(freq); | ||||
|         this.inner.start(); | ||||
|  | ||||
|         unsafe { | ||||
|             this.inner.enable_outputs(true); | ||||
|         this.inner.enable_outputs(true); | ||||
|  | ||||
|             this.inner | ||||
|                 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); | ||||
|             this.inner | ||||
|                 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); | ||||
|             this.inner | ||||
|                 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); | ||||
|             this.inner | ||||
|                 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); | ||||
|         } | ||||
|         this.inner | ||||
|             .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); | ||||
|         this.inner | ||||
|             .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); | ||||
|         this.inner | ||||
|             .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); | ||||
|         this.inner | ||||
|             .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); | ||||
|         this | ||||
|     } | ||||
|  | ||||
|     pub fn enable(&mut self, channel: Channel) { | ||||
|         unsafe { | ||||
|             self.inner.enable_channel(channel, true); | ||||
|             self.inner.enable_complementary_channel(channel, true); | ||||
|         } | ||||
|         self.inner.enable_channel(channel, true); | ||||
|         self.inner.enable_complementary_channel(channel, true); | ||||
|     } | ||||
|  | ||||
|     pub fn disable(&mut self, channel: Channel) { | ||||
|         unsafe { | ||||
|             self.inner.enable_complementary_channel(channel, false); | ||||
|             self.inner.enable_channel(channel, false); | ||||
|         } | ||||
|         self.inner.enable_complementary_channel(channel, false); | ||||
|         self.inner.enable_channel(channel, false); | ||||
|     } | ||||
|  | ||||
|     pub fn set_freq(&mut self, freq: Hertz) { | ||||
| @@ -106,22 +100,20 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | ||||
|     } | ||||
|  | ||||
|     pub fn get_max_duty(&self) -> u16 { | ||||
|         unsafe { self.inner.get_max_compare_value() } | ||||
|         self.inner.get_max_compare_value() | ||||
|     } | ||||
|  | ||||
|     pub fn set_duty(&mut self, channel: Channel, duty: u16) { | ||||
|         assert!(duty < self.get_max_duty()); | ||||
|         unsafe { self.inner.set_compare_value(channel, duty) } | ||||
|         self.inner.set_compare_value(channel, duty) | ||||
|     } | ||||
|  | ||||
|     /// Set the dead time as a proportion of max_duty | ||||
|     pub fn set_dead_time(&mut self, value: u16) { | ||||
|         let (ckd, value) = compute_dead_time_value(value); | ||||
|  | ||||
|         unsafe { | ||||
|             self.inner.set_dead_time_clock_division(ckd); | ||||
|             self.inner.set_dead_time_value(value); | ||||
|         } | ||||
|         self.inner.set_dead_time_clock_division(ckd); | ||||
|         self.inner.set_dead_time_value(value); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -59,33 +59,33 @@ pub(crate) mod sealed { | ||||
|  | ||||
|     pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance { | ||||
|         /// Global output enable. Does not do anything on non-advanced timers. | ||||
|         unsafe fn enable_outputs(&mut self, enable: bool); | ||||
|         fn enable_outputs(&mut self, enable: bool); | ||||
|  | ||||
|         unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | ||||
|         fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | ||||
|  | ||||
|         unsafe fn enable_channel(&mut self, channel: Channel, enable: bool); | ||||
|         fn enable_channel(&mut self, channel: Channel, enable: bool); | ||||
|  | ||||
|         unsafe fn set_compare_value(&mut self, channel: Channel, value: u16); | ||||
|         fn set_compare_value(&mut self, channel: Channel, value: u16); | ||||
|  | ||||
|         unsafe fn get_max_compare_value(&self) -> u16; | ||||
|         fn get_max_compare_value(&self) -> u16; | ||||
|     } | ||||
|  | ||||
|     pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { | ||||
|         unsafe fn set_dead_time_clock_division(&mut self, value: Ckd); | ||||
|         fn set_dead_time_clock_division(&mut self, value: Ckd); | ||||
|  | ||||
|         unsafe fn set_dead_time_value(&mut self, value: u8); | ||||
|         fn set_dead_time_value(&mut self, value: u8); | ||||
|  | ||||
|         unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); | ||||
|         fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); | ||||
|     } | ||||
|  | ||||
|     pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { | ||||
|         unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | ||||
|         fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | ||||
|  | ||||
|         unsafe fn enable_channel(&mut self, channel: Channel, enable: bool); | ||||
|         fn enable_channel(&mut self, channel: Channel, enable: bool); | ||||
|  | ||||
|         unsafe fn set_compare_value(&mut self, channel: Channel, value: u32); | ||||
|         fn set_compare_value(&mut self, channel: Channel, value: u32); | ||||
|  | ||||
|         unsafe fn get_max_compare_value(&self) -> u32; | ||||
|         fn get_max_compare_value(&self) -> u32; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -108,9 +108,9 @@ pub trait CaptureCompare32bitInstance: | ||||
| macro_rules! impl_compare_capable_16bit { | ||||
|     ($inst:ident) => { | ||||
|         impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { | ||||
|             unsafe fn enable_outputs(&mut self, _enable: bool) {} | ||||
|             fn enable_outputs(&mut self, _enable: bool) {} | ||||
|  | ||||
|             unsafe fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) { | ||||
|             fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) { | ||||
|                 use crate::timer::sealed::GeneralPurpose16bitInstance; | ||||
|                 let r = Self::regs_gp16(); | ||||
|                 let raw_channel: usize = channel.raw(); | ||||
| @@ -118,19 +118,19 @@ macro_rules! impl_compare_capable_16bit { | ||||
|                     .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | ||||
|             } | ||||
|  | ||||
|             unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { | ||||
|             fn enable_channel(&mut self, channel: Channel, enable: bool) { | ||||
|                 use crate::timer::sealed::GeneralPurpose16bitInstance; | ||||
|                 Self::regs_gp16() | ||||
|                     .ccer() | ||||
|                     .modify(|w| w.set_cce(channel.raw(), enable)); | ||||
|             } | ||||
|  | ||||
|             unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) { | ||||
|             fn set_compare_value(&mut self, channel: Channel, value: u16) { | ||||
|                 use crate::timer::sealed::GeneralPurpose16bitInstance; | ||||
|                 Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | ||||
|             } | ||||
|  | ||||
|             unsafe fn get_max_compare_value(&self) -> u16 { | ||||
|             fn get_max_compare_value(&self) -> u16 { | ||||
|                 use crate::timer::sealed::GeneralPurpose16bitInstance; | ||||
|                 Self::regs_gp16().arr().read().arr() | ||||
|             } | ||||
| @@ -150,7 +150,7 @@ foreach_interrupt! { | ||||
|     ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { | ||||
|         impl_compare_capable_16bit!($inst); | ||||
|         impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { | ||||
|             unsafe fn set_output_compare_mode( | ||||
|             fn set_output_compare_mode( | ||||
|                 &mut self, | ||||
|                 channel: crate::pwm::Channel, | ||||
|                 mode: OutputCompareMode, | ||||
| @@ -160,17 +160,17 @@ foreach_interrupt! { | ||||
|                 Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | ||||
|             } | ||||
|  | ||||
|             unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { | ||||
|             fn enable_channel(&mut self, channel: Channel, enable: bool) { | ||||
|                 use crate::timer::sealed::GeneralPurpose32bitInstance; | ||||
|                 Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); | ||||
|             } | ||||
|  | ||||
|             unsafe fn set_compare_value(&mut self, channel: Channel, value: u32) { | ||||
|             fn set_compare_value(&mut self, channel: Channel, value: u32) { | ||||
|                 use crate::timer::sealed::GeneralPurpose32bitInstance; | ||||
|                 Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | ||||
|             } | ||||
|  | ||||
|             unsafe fn get_max_compare_value(&self) -> u32 { | ||||
|             fn get_max_compare_value(&self) -> u32 { | ||||
|                 use crate::timer::sealed::GeneralPurpose32bitInstance; | ||||
|                 Self::regs_gp32().arr().read().arr() as u32 | ||||
|             } | ||||
| @@ -185,13 +185,13 @@ foreach_interrupt! { | ||||
|  | ||||
|     ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { | ||||
|         impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { | ||||
|             unsafe fn enable_outputs(&mut self, enable: bool) { | ||||
|             fn enable_outputs(&mut self, enable: bool) { | ||||
|                 use crate::timer::sealed::AdvancedControlInstance; | ||||
|                 let r = Self::regs_advanced(); | ||||
|                 r.bdtr().modify(|w| w.set_moe(enable)); | ||||
|             } | ||||
|  | ||||
|             unsafe fn set_output_compare_mode( | ||||
|             fn set_output_compare_mode( | ||||
|                 &mut self, | ||||
|                 channel: crate::pwm::Channel, | ||||
|                 mode: OutputCompareMode, | ||||
| @@ -203,21 +203,21 @@ foreach_interrupt! { | ||||
|                     .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | ||||
|             } | ||||
|  | ||||
|             unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { | ||||
|             fn enable_channel(&mut self, channel: Channel, enable: bool) { | ||||
|                 use crate::timer::sealed::AdvancedControlInstance; | ||||
|                 Self::regs_advanced() | ||||
|                     .ccer() | ||||
|                     .modify(|w| w.set_cce(channel.raw(), enable)); | ||||
|             } | ||||
|  | ||||
|             unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) { | ||||
|             fn set_compare_value(&mut self, channel: Channel, value: u16) { | ||||
|                 use crate::timer::sealed::AdvancedControlInstance; | ||||
|                 Self::regs_advanced() | ||||
|                     .ccr(channel.raw()) | ||||
|                     .modify(|w| w.set_ccr(value)); | ||||
|             } | ||||
|  | ||||
|             unsafe fn get_max_compare_value(&self) -> u16 { | ||||
|             fn get_max_compare_value(&self) -> u16 { | ||||
|                 use crate::timer::sealed::AdvancedControlInstance; | ||||
|                 Self::regs_advanced().arr().read().arr() | ||||
|             } | ||||
| @@ -228,17 +228,17 @@ foreach_interrupt! { | ||||
|         } | ||||
|  | ||||
|         impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { | ||||
|             unsafe fn set_dead_time_clock_division(&mut self, value: Ckd) { | ||||
|             fn set_dead_time_clock_division(&mut self, value: Ckd) { | ||||
|                 use crate::timer::sealed::AdvancedControlInstance; | ||||
|                 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); | ||||
|             } | ||||
|  | ||||
|             unsafe fn set_dead_time_value(&mut self, value: u8) { | ||||
|             fn set_dead_time_value(&mut self, value: u8) { | ||||
|                 use crate::timer::sealed::AdvancedControlInstance; | ||||
|                 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); | ||||
|             } | ||||
|  | ||||
|             unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { | ||||
|             fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { | ||||
|                 use crate::timer::sealed::AdvancedControlInstance; | ||||
|                 Self::regs_advanced() | ||||
|                     .ccer() | ||||
|   | ||||
| @@ -24,7 +24,7 @@ macro_rules! channel_impl { | ||||
|         impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { | ||||
|             pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { | ||||
|                 into_ref!(pin); | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     pin.set_low(); | ||||
|                     pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | ||||
|                     #[cfg(gpio_v2)] | ||||
| @@ -71,31 +71,25 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | ||||
|         this.inner.set_frequency(freq); | ||||
|         this.inner.start(); | ||||
|  | ||||
|         unsafe { | ||||
|             this.inner.enable_outputs(true); | ||||
|         this.inner.enable_outputs(true); | ||||
|  | ||||
|             this.inner | ||||
|                 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); | ||||
|             this.inner | ||||
|                 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); | ||||
|             this.inner | ||||
|                 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); | ||||
|             this.inner | ||||
|                 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); | ||||
|         } | ||||
|         this.inner | ||||
|             .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); | ||||
|         this.inner | ||||
|             .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); | ||||
|         this.inner | ||||
|             .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); | ||||
|         this.inner | ||||
|             .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); | ||||
|         this | ||||
|     } | ||||
|  | ||||
|     pub fn enable(&mut self, channel: Channel) { | ||||
|         unsafe { | ||||
|             self.inner.enable_channel(channel, true); | ||||
|         } | ||||
|         self.inner.enable_channel(channel, true); | ||||
|     } | ||||
|  | ||||
|     pub fn disable(&mut self, channel: Channel) { | ||||
|         unsafe { | ||||
|             self.inner.enable_channel(channel, false); | ||||
|         } | ||||
|         self.inner.enable_channel(channel, false); | ||||
|     } | ||||
|  | ||||
|     pub fn set_freq(&mut self, freq: Hertz) { | ||||
| @@ -103,11 +97,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | ||||
|     } | ||||
|  | ||||
|     pub fn get_max_duty(&self) -> u16 { | ||||
|         unsafe { self.inner.get_max_compare_value() } | ||||
|         self.inner.get_max_compare_value() | ||||
|     } | ||||
|  | ||||
|     pub fn set_duty(&mut self, channel: Channel, duty: u16) { | ||||
|         assert!(duty < self.get_max_duty()); | ||||
|         unsafe { self.inner.set_compare_value(channel, duty) } | ||||
|         self.inner.set_compare_value(channel, duty) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -96,20 +96,18 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | ||||
|     ) -> Self { | ||||
|         into_ref!(peri, d0, d1, d2, d3, sck, nss); | ||||
|  | ||||
|         unsafe { | ||||
|             sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | ||||
|             sck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|             nss.set_as_af(nss.af_num(), AFType::OutputPushPull); | ||||
|             nss.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|             d0.set_as_af(d0.af_num(), AFType::OutputPushPull); | ||||
|             d0.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|             d1.set_as_af(d1.af_num(), AFType::OutputPushPull); | ||||
|             d1.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|             d2.set_as_af(d2.af_num(), AFType::OutputPushPull); | ||||
|             d2.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|             d3.set_as_af(d3.af_num(), AFType::OutputPushPull); | ||||
|             d3.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         } | ||||
|         sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | ||||
|         sck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         nss.set_as_af(nss.af_num(), AFType::OutputPushPull); | ||||
|         nss.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         d0.set_as_af(d0.af_num(), AFType::OutputPushPull); | ||||
|         d0.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         d1.set_as_af(d1.af_num(), AFType::OutputPushPull); | ||||
|         d1.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         d2.set_as_af(d2.af_num(), AFType::OutputPushPull); | ||||
|         d2.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         d3.set_as_af(d3.af_num(), AFType::OutputPushPull); | ||||
|         d3.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|  | ||||
|         Self::new_inner( | ||||
|             peri, | ||||
| @@ -138,21 +136,19 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | ||||
|         into_ref!(peri, dma); | ||||
|  | ||||
|         T::enable(); | ||||
|         unsafe { | ||||
|             T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into())); | ||||
|         T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into())); | ||||
|  | ||||
|             while T::REGS.sr().read().busy() {} | ||||
|         while T::REGS.sr().read().busy() {} | ||||
|  | ||||
|             T::REGS.cr().write(|w| { | ||||
|                 w.set_prescaler(config.prescaler); | ||||
|                 w.set_en(true); | ||||
|             }); | ||||
|             T::REGS.dcr().write(|w| { | ||||
|                 w.set_fsize(config.memory_size.into()); | ||||
|                 w.set_csht(config.cs_high_time.into()); | ||||
|                 w.set_ckmode(false); | ||||
|             }); | ||||
|         } | ||||
|         T::REGS.cr().write(|w| { | ||||
|             w.set_prescaler(config.prescaler); | ||||
|             w.set_en(true); | ||||
|         }); | ||||
|         T::REGS.dcr().write(|w| { | ||||
|             w.set_fsize(config.memory_size.into()); | ||||
|             w.set_csht(config.cs_high_time.into()); | ||||
|             w.set_ckmode(false); | ||||
|         }); | ||||
|  | ||||
|         Self { | ||||
|             _peri: peri, | ||||
| @@ -168,148 +164,140 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | ||||
|     } | ||||
|  | ||||
|     pub fn command(&mut self, transaction: TransferConfig) { | ||||
|         unsafe { | ||||
|             T::REGS.cr().modify(|v| v.set_dmaen(false)); | ||||
|             self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||||
|         T::REGS.cr().modify(|v| v.set_dmaen(false)); | ||||
|         self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||||
|  | ||||
|             while !T::REGS.sr().read().tcf() {} | ||||
|             T::REGS.fcr().modify(|v| v.set_ctcf(true)); | ||||
|         } | ||||
|         while !T::REGS.sr().read().tcf() {} | ||||
|         T::REGS.fcr().modify(|v| v.set_ctcf(true)); | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { | ||||
|         unsafe { | ||||
|             T::REGS.cr().modify(|v| v.set_dmaen(false)); | ||||
|             self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||||
|         T::REGS.cr().modify(|v| v.set_dmaen(false)); | ||||
|         self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||||
|  | ||||
|             if let Some(len) = transaction.data_len { | ||||
|                 let current_ar = T::REGS.ar().read().address(); | ||||
|                 T::REGS.ccr().modify(|v| { | ||||
|                     v.set_fmode(QspiMode::IndirectRead.into()); | ||||
|                 }); | ||||
|                 T::REGS.ar().write(|v| { | ||||
|                     v.set_address(current_ar); | ||||
|                 }); | ||||
|         if let Some(len) = transaction.data_len { | ||||
|             let current_ar = T::REGS.ar().read().address(); | ||||
|             T::REGS.ccr().modify(|v| { | ||||
|                 v.set_fmode(QspiMode::IndirectRead.into()); | ||||
|             }); | ||||
|             T::REGS.ar().write(|v| { | ||||
|                 v.set_address(current_ar); | ||||
|             }); | ||||
|  | ||||
|                 for idx in 0..len { | ||||
|                     while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} | ||||
|                     buf[idx] = *(T::REGS.dr().ptr() as *mut u8); | ||||
|                 } | ||||
|             for idx in 0..len { | ||||
|                 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} | ||||
|                 buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; | ||||
|             } | ||||
|  | ||||
|             while !T::REGS.sr().read().tcf() {} | ||||
|             T::REGS.fcr().modify(|v| v.set_ctcf(true)); | ||||
|         } | ||||
|  | ||||
|         while !T::REGS.sr().read().tcf() {} | ||||
|         T::REGS.fcr().modify(|v| v.set_ctcf(true)); | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { | ||||
|         unsafe { | ||||
|             T::REGS.cr().modify(|v| v.set_dmaen(false)); | ||||
|             self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||||
|         T::REGS.cr().modify(|v| v.set_dmaen(false)); | ||||
|         self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||||
|  | ||||
|             if let Some(len) = transaction.data_len { | ||||
|                 T::REGS.ccr().modify(|v| { | ||||
|                     v.set_fmode(QspiMode::IndirectWrite.into()); | ||||
|                 }); | ||||
|         if let Some(len) = transaction.data_len { | ||||
|             T::REGS.ccr().modify(|v| { | ||||
|                 v.set_fmode(QspiMode::IndirectWrite.into()); | ||||
|             }); | ||||
|  | ||||
|                 for idx in 0..len { | ||||
|                     while !T::REGS.sr().read().ftf() {} | ||||
|                     *(T::REGS.dr().ptr() as *mut u8) = buf[idx]; | ||||
|                 } | ||||
|             for idx in 0..len { | ||||
|                 while !T::REGS.sr().read().ftf() {} | ||||
|                 unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) }; | ||||
|             } | ||||
|  | ||||
|             while !T::REGS.sr().read().tcf() {} | ||||
|             T::REGS.fcr().modify(|v| v.set_ctcf(true)); | ||||
|         } | ||||
|  | ||||
|         while !T::REGS.sr().read().tcf() {} | ||||
|         T::REGS.fcr().modify(|v| v.set_ctcf(true)); | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) | ||||
|     where | ||||
|         Dma: QuadDma<T>, | ||||
|     { | ||||
|         unsafe { | ||||
|             self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||||
|         self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||||
|  | ||||
|             T::REGS.ccr().modify(|v| { | ||||
|                 v.set_fmode(QspiMode::IndirectRead.into()); | ||||
|             }); | ||||
|             let current_ar = T::REGS.ar().read().address(); | ||||
|             T::REGS.ar().write(|v| { | ||||
|                 v.set_address(current_ar); | ||||
|             }); | ||||
|         T::REGS.ccr().modify(|v| { | ||||
|             v.set_fmode(QspiMode::IndirectRead.into()); | ||||
|         }); | ||||
|         let current_ar = T::REGS.ar().read().address(); | ||||
|         T::REGS.ar().write(|v| { | ||||
|             v.set_address(current_ar); | ||||
|         }); | ||||
|  | ||||
|             let request = self.dma.request(); | ||||
|             let transfer = Transfer::new_read( | ||||
|         let request = self.dma.request(); | ||||
|         let transfer = unsafe { | ||||
|             Transfer::new_read( | ||||
|                 &mut self.dma, | ||||
|                 request, | ||||
|                 T::REGS.dr().ptr() as *mut u8, | ||||
|                 T::REGS.dr().as_ptr() as *mut u8, | ||||
|                 buf, | ||||
|                 Default::default(), | ||||
|             ); | ||||
|             ) | ||||
|         }; | ||||
|  | ||||
|             T::REGS.cr().modify(|v| v.set_dmaen(true)); | ||||
|         T::REGS.cr().modify(|v| v.set_dmaen(true)); | ||||
|  | ||||
|             transfer.blocking_wait(); | ||||
|         } | ||||
|         transfer.blocking_wait(); | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) | ||||
|     where | ||||
|         Dma: QuadDma<T>, | ||||
|     { | ||||
|         unsafe { | ||||
|             self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||||
|         self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||||
|  | ||||
|             T::REGS.ccr().modify(|v| { | ||||
|                 v.set_fmode(QspiMode::IndirectWrite.into()); | ||||
|             }); | ||||
|         T::REGS.ccr().modify(|v| { | ||||
|             v.set_fmode(QspiMode::IndirectWrite.into()); | ||||
|         }); | ||||
|  | ||||
|             let request = self.dma.request(); | ||||
|             let transfer = Transfer::new_write( | ||||
|         let request = self.dma.request(); | ||||
|         let transfer = unsafe { | ||||
|             Transfer::new_write( | ||||
|                 &mut self.dma, | ||||
|                 request, | ||||
|                 buf, | ||||
|                 T::REGS.dr().ptr() as *mut u8, | ||||
|                 T::REGS.dr().as_ptr() as *mut u8, | ||||
|                 Default::default(), | ||||
|             ); | ||||
|             ) | ||||
|         }; | ||||
|  | ||||
|             T::REGS.cr().modify(|v| v.set_dmaen(true)); | ||||
|         T::REGS.cr().modify(|v| v.set_dmaen(true)); | ||||
|  | ||||
|             transfer.blocking_wait(); | ||||
|         } | ||||
|         transfer.blocking_wait(); | ||||
|     } | ||||
|  | ||||
|     fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { | ||||
|         unsafe { | ||||
|             T::REGS.fcr().modify(|v| { | ||||
|                 v.set_csmf(true); | ||||
|                 v.set_ctcf(true); | ||||
|                 v.set_ctef(true); | ||||
|                 v.set_ctof(true); | ||||
|         T::REGS.fcr().modify(|v| { | ||||
|             v.set_csmf(true); | ||||
|             v.set_ctcf(true); | ||||
|             v.set_ctef(true); | ||||
|             v.set_ctof(true); | ||||
|         }); | ||||
|  | ||||
|         while T::REGS.sr().read().busy() {} | ||||
|  | ||||
|         if let Some(len) = transaction.data_len { | ||||
|             T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); | ||||
|         } | ||||
|  | ||||
|         T::REGS.ccr().write(|v| { | ||||
|             v.set_fmode(fmode.into()); | ||||
|             v.set_imode(transaction.iwidth.into()); | ||||
|             v.set_instruction(transaction.instruction); | ||||
|             v.set_admode(transaction.awidth.into()); | ||||
|             v.set_adsize(self.config.address_size.into()); | ||||
|             v.set_dmode(transaction.dwidth.into()); | ||||
|             v.set_abmode(QspiWidth::NONE.into()); | ||||
|             v.set_dcyc(transaction.dummy.into()); | ||||
|         }); | ||||
|  | ||||
|         if let Some(addr) = transaction.address { | ||||
|             T::REGS.ar().write(|v| { | ||||
|                 v.set_address(addr); | ||||
|             }); | ||||
|  | ||||
|             while T::REGS.sr().read().busy() {} | ||||
|  | ||||
|             if let Some(len) = transaction.data_len { | ||||
|                 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); | ||||
|             } | ||||
|  | ||||
|             T::REGS.ccr().write(|v| { | ||||
|                 v.set_fmode(fmode.into()); | ||||
|                 v.set_imode(transaction.iwidth.into()); | ||||
|                 v.set_instruction(transaction.instruction); | ||||
|                 v.set_admode(transaction.awidth.into()); | ||||
|                 v.set_adsize(self.config.address_size.into()); | ||||
|                 v.set_dmode(transaction.dwidth.into()); | ||||
|                 v.set_abmode(QspiWidth::NONE.into()); | ||||
|                 v.set_dcyc(transaction.dummy.into()); | ||||
|             }); | ||||
|  | ||||
|             if let Some(addr) = transaction.address { | ||||
|                 T::REGS.ar().write(|v| { | ||||
|                     v.set_address(addr); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -36,18 +36,18 @@ pub struct Config { | ||||
| } | ||||
|  | ||||
| #[cfg(stm32f410)] | ||||
| unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { | ||||
| fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { | ||||
|     None | ||||
| } | ||||
|  | ||||
| // Not currently implemented, but will be in the future | ||||
| #[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] | ||||
| unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { | ||||
| fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { | ||||
|     None | ||||
| } | ||||
|  | ||||
| #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] | ||||
| unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> { | ||||
| fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> { | ||||
|     let min_div = 2; | ||||
|     let max_div = 7; | ||||
|     let target = match plli2s { | ||||
| @@ -82,13 +82,7 @@ unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> { | ||||
|     Some(output) | ||||
| } | ||||
|  | ||||
| unsafe fn setup_pll( | ||||
|     pllsrcclk: u32, | ||||
|     use_hse: bool, | ||||
|     pllsysclk: Option<u32>, | ||||
|     plli2s: Option<u32>, | ||||
|     pll48clk: bool, | ||||
| ) -> PllResults { | ||||
| fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Option<u32>, pll48clk: bool) -> PllResults { | ||||
|     use crate::pac::rcc::vals::{Pllp, Pllsrc}; | ||||
|  | ||||
|     let sysclk = pllsysclk.unwrap_or(pllsrcclk); | ||||
| @@ -320,7 +314,7 @@ impl<'d, T: McoInstance> Mco<'d, T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| unsafe fn flash_setup(sysclk: u32) { | ||||
| fn flash_setup(sysclk: u32) { | ||||
|     use crate::pac::flash::vals::Latency; | ||||
|  | ||||
|     // Be conservative with voltage ranges | ||||
|   | ||||
| @@ -25,7 +25,7 @@ pub struct Config { | ||||
|     pub pll48: bool, | ||||
| } | ||||
|  | ||||
| unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { | ||||
| fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { | ||||
|     use crate::pac::rcc::vals::{Pllp, Pllsrc}; | ||||
|  | ||||
|     let sysclk = pllsysclk.unwrap_or(pllsrcclk); | ||||
| @@ -97,7 +97,7 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48 | ||||
|     } | ||||
| } | ||||
|  | ||||
| unsafe fn flash_setup(sysclk: u32) { | ||||
| fn flash_setup(sysclk: u32) { | ||||
|     use crate::pac::flash::vals::Latency; | ||||
|  | ||||
|     // Be conservative with voltage ranges | ||||
|   | ||||
| @@ -245,7 +245,7 @@ impl Default for Config { | ||||
| } | ||||
|  | ||||
| impl PllConfig { | ||||
|     pub(crate) unsafe fn init(self) -> u32 { | ||||
|     pub(crate) fn init(self) -> u32 { | ||||
|         assert!(self.n >= 8 && self.n <= 86); | ||||
|         let (src, input_freq) = match self.source { | ||||
|             PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0), | ||||
|   | ||||
| @@ -462,7 +462,7 @@ struct PllOutput { | ||||
|     r: Option<Hertz>, | ||||
| } | ||||
|  | ||||
| unsafe fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { | ||||
| fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { | ||||
|     let Some(config) = config else { | ||||
|         // Stop PLL | ||||
|         RCC.cr().modify(|w| w.set_pllon(num, false)); | ||||
| @@ -595,12 +595,9 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) { | ||||
|  | ||||
|     defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); | ||||
|  | ||||
|     // NOTE(unsafe) Atomic write | ||||
|     unsafe { | ||||
|         FLASH.acr().write(|w| { | ||||
|             w.set_wrhighfreq(wrhighfreq); | ||||
|             w.set_latency(latency); | ||||
|         }); | ||||
|         while FLASH.acr().read().latency() != latency {} | ||||
|     } | ||||
|     FLASH.acr().write(|w| { | ||||
|         w.set_wrhighfreq(wrhighfreq); | ||||
|         w.set_latency(latency); | ||||
|     }); | ||||
|     while FLASH.acr().read().latency() != latency {} | ||||
| } | ||||
|   | ||||
| @@ -253,14 +253,11 @@ fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { | ||||
|         }, | ||||
|     }; | ||||
|  | ||||
|     // NOTE(unsafe) Atomic write | ||||
|     unsafe { | ||||
|         FLASH.acr().write(|w| { | ||||
|             w.set_wrhighfreq(progr_delay); | ||||
|             w.set_latency(wait_states) | ||||
|         }); | ||||
|         while FLASH.acr().read().latency() != wait_states {} | ||||
|     } | ||||
|     FLASH.acr().write(|w| { | ||||
|         w.set_wrhighfreq(progr_delay); | ||||
|         w.set_latency(wait_states) | ||||
|     }); | ||||
|     while FLASH.acr().read().latency() != wait_states {} | ||||
| } | ||||
|  | ||||
| pub enum McoClock { | ||||
| @@ -474,7 +471,6 @@ pub(crate) unsafe fn init(mut config: Config) { | ||||
|     // Configure traceclk from PLL if needed | ||||
|     traceclk_setup(&mut config, sys_use_pll1_p); | ||||
|  | ||||
|     // NOTE(unsafe) We have exclusive access to the RCC | ||||
|     let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0); | ||||
|     let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1); | ||||
|     let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2); | ||||
| @@ -756,7 +752,7 @@ mod pll { | ||||
|     /// # Safety | ||||
|     /// | ||||
|     /// Must have exclusive access to the RCC register block | ||||
|     unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults { | ||||
|     fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults { | ||||
|         use crate::pac::rcc::vals::{Pllrge, Pllvcosel}; | ||||
|  | ||||
|         let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln); | ||||
| @@ -785,11 +781,7 @@ mod pll { | ||||
|     /// # Safety | ||||
|     /// | ||||
|     /// Must have exclusive access to the RCC register block | ||||
|     pub(super) unsafe fn pll_setup( | ||||
|         pll_src: u32, | ||||
|         config: &PllConfig, | ||||
|         plln: usize, | ||||
|     ) -> (Option<u32>, Option<u32>, Option<u32>) { | ||||
|     pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) { | ||||
|         use crate::pac::rcc::vals::Divp; | ||||
|  | ||||
|         match config.p_ck { | ||||
|   | ||||
| @@ -34,40 +34,34 @@ impl<'d, T: Instance> Rng<'d, T> { | ||||
|     pub fn reset(&mut self) { | ||||
|         // rng_v2 locks up on seed error, needs reset | ||||
|         #[cfg(rng_v2)] | ||||
|         if unsafe { T::regs().sr().read().seis() } { | ||||
|         if T::regs().sr().read().seis() { | ||||
|             T::reset(); | ||||
|         } | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 reg.set_rngen(true); | ||||
|                 reg.set_ie(true); | ||||
|             }); | ||||
|             T::regs().sr().modify(|reg| { | ||||
|                 reg.set_seis(false); | ||||
|                 reg.set_ceis(false); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             reg.set_rngen(true); | ||||
|             reg.set_ie(true); | ||||
|         }); | ||||
|         T::regs().sr().modify(|reg| { | ||||
|             reg.set_seis(false); | ||||
|             reg.set_ceis(false); | ||||
|         }); | ||||
|         // Reference manual says to discard the first. | ||||
|         let _ = self.next_u32(); | ||||
|     } | ||||
|  | ||||
|     pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { | ||||
|         unsafe { | ||||
|             T::regs().cr().modify(|reg| { | ||||
|                 reg.set_rngen(true); | ||||
|             }) | ||||
|         } | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             reg.set_rngen(true); | ||||
|         }); | ||||
|  | ||||
|         for chunk in dest.chunks_mut(4) { | ||||
|             poll_fn(|cx| { | ||||
|                 RNG_WAKER.register(cx.waker()); | ||||
|                 unsafe { | ||||
|                     T::regs().cr().modify(|reg| { | ||||
|                         reg.set_ie(true); | ||||
|                     }); | ||||
|                 } | ||||
|                 T::regs().cr().modify(|reg| { | ||||
|                     reg.set_ie(true); | ||||
|                 }); | ||||
|  | ||||
|                 let bits = unsafe { T::regs().sr().read() }; | ||||
|                 let bits = T::regs().sr().read(); | ||||
|  | ||||
|                 if bits.drdy() { | ||||
|                     Poll::Ready(Ok(())) | ||||
| @@ -82,7 +76,7 @@ impl<'d, T: Instance> Rng<'d, T> { | ||||
|                 } | ||||
|             }) | ||||
|             .await?; | ||||
|             let random_bytes = unsafe { T::regs().dr().read() }.to_be_bytes(); | ||||
|             let random_bytes = T::regs().dr().read().to_be_bytes(); | ||||
|             for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) { | ||||
|                 *dest = *src | ||||
|             } | ||||
| @@ -95,11 +89,11 @@ impl<'d, T: Instance> Rng<'d, T> { | ||||
| impl<'d, T: Instance> RngCore for Rng<'d, T> { | ||||
|     fn next_u32(&mut self) -> u32 { | ||||
|         loop { | ||||
|             let sr = unsafe { T::regs().sr().read() }; | ||||
|             let sr = T::regs().sr().read(); | ||||
|             if sr.seis() | sr.ceis() { | ||||
|                 self.reset(); | ||||
|             } else if sr.drdy() { | ||||
|                 return unsafe { T::regs().dr().read() }; | ||||
|                 return T::regs().dr().read(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -154,29 +154,27 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) { | ||||
|     let yr_offset = (yr - 1970_u16) as u8; | ||||
|     let (yt, yu) = byte_to_bcd2(yr_offset); | ||||
|  | ||||
|     unsafe { | ||||
|         use crate::pac::rtc::vals::Ampm; | ||||
|     use crate::pac::rtc::vals::Ampm; | ||||
|  | ||||
|         rtc.tr().write(|w| { | ||||
|             w.set_ht(ht); | ||||
|             w.set_hu(hu); | ||||
|             w.set_mnt(mnt); | ||||
|             w.set_mnu(mnu); | ||||
|             w.set_st(st); | ||||
|             w.set_su(su); | ||||
|             w.set_pm(Ampm::AM); | ||||
|         }); | ||||
|     rtc.tr().write(|w| { | ||||
|         w.set_ht(ht); | ||||
|         w.set_hu(hu); | ||||
|         w.set_mnt(mnt); | ||||
|         w.set_mnu(mnu); | ||||
|         w.set_st(st); | ||||
|         w.set_su(su); | ||||
|         w.set_pm(Ampm::AM); | ||||
|     }); | ||||
|  | ||||
|         rtc.dr().write(|w| { | ||||
|             w.set_dt(dt); | ||||
|             w.set_du(du); | ||||
|             w.set_mt(mt > 0); | ||||
|             w.set_mu(mu); | ||||
|             w.set_yt(yt); | ||||
|             w.set_yu(yu); | ||||
|             w.set_wdu(day_of_week_to_u8(t.day_of_week)); | ||||
|         }); | ||||
|     } | ||||
|     rtc.dr().write(|w| { | ||||
|         w.set_dt(dt); | ||||
|         w.set_du(du); | ||||
|         w.set_mt(mt > 0); | ||||
|         w.set_mu(mu); | ||||
|         w.set_yt(yt); | ||||
|         w.set_yu(yu); | ||||
|         w.set_wdu(day_of_week_to_u8(t.day_of_week)); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| pub(super) fn datetime( | ||||
|   | ||||
| @@ -113,7 +113,7 @@ impl Default for RtcCalibrationCyclePeriod { | ||||
|  | ||||
| impl<'d, T: Instance> Rtc<'d, T> { | ||||
|     pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self { | ||||
|         unsafe { T::enable_peripheral_clk() }; | ||||
|         T::enable_peripheral_clk(); | ||||
|  | ||||
|         let mut rtc_struct = Self { | ||||
|             phantom: PhantomData, | ||||
| @@ -144,34 +144,32 @@ impl<'d, T: Instance> Rtc<'d, T> { | ||||
|     /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. | ||||
|     pub fn now(&self) -> Result<DateTime, RtcError> { | ||||
|         let r = T::regs(); | ||||
|         unsafe { | ||||
|             let tr = r.tr().read(); | ||||
|             let second = bcd2_to_byte((tr.st(), tr.su())); | ||||
|             let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); | ||||
|             let hour = bcd2_to_byte((tr.ht(), tr.hu())); | ||||
|             // Reading either RTC_SSR or RTC_TR locks the values in the higher-order | ||||
|             // calendar shadow registers until RTC_DR is read. | ||||
|             let dr = r.dr().read(); | ||||
|         let tr = r.tr().read(); | ||||
|         let second = bcd2_to_byte((tr.st(), tr.su())); | ||||
|         let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); | ||||
|         let hour = bcd2_to_byte((tr.ht(), tr.hu())); | ||||
|         // Reading either RTC_SSR or RTC_TR locks the values in the higher-order | ||||
|         // calendar shadow registers until RTC_DR is read. | ||||
|         let dr = r.dr().read(); | ||||
|  | ||||
|             let weekday = dr.wdu(); | ||||
|             let day = bcd2_to_byte((dr.dt(), dr.du())); | ||||
|             let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); | ||||
|             let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; | ||||
|         let weekday = dr.wdu(); | ||||
|         let day = bcd2_to_byte((dr.dt(), dr.du())); | ||||
|         let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); | ||||
|         let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; | ||||
|  | ||||
|             self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) | ||||
|         } | ||||
|         self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) | ||||
|     } | ||||
|  | ||||
|     /// Check if daylight savings time is active. | ||||
|     pub fn get_daylight_savings(&self) -> bool { | ||||
|         let cr = unsafe { T::regs().cr().read() }; | ||||
|         let cr = T::regs().cr().read(); | ||||
|         cr.bkp() | ||||
|     } | ||||
|  | ||||
|     /// Enable/disable daylight savings time. | ||||
|     pub fn set_daylight_savings(&mut self, daylight_savings: bool) { | ||||
|         self.write(true, |rtc| { | ||||
|             unsafe { rtc.cr().modify(|w| w.set_bkp(daylight_savings)) }; | ||||
|             rtc.cr().modify(|w| w.set_bkp(daylight_savings)); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| @@ -228,7 +226,7 @@ pub(crate) mod sealed { | ||||
|             crate::pac::RTC | ||||
|         } | ||||
|  | ||||
|         unsafe fn enable_peripheral_clk() {} | ||||
|         fn enable_peripheral_clk() {} | ||||
|  | ||||
|         /// Read content of the backup register. | ||||
|         /// | ||||
|   | ||||
| @@ -8,74 +8,72 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | ||||
|     /// It this changes the RTC clock source the time will be reset | ||||
|     pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { | ||||
|         // Unlock the backup domain | ||||
|         unsafe { | ||||
|             let clock_config = rtc_config.clock_config as u8; | ||||
|         let clock_config = rtc_config.clock_config as u8; | ||||
|  | ||||
|             #[cfg(not(rtc_v2wb))] | ||||
|             use stm32_metapac::rcc::vals::Rtcsel; | ||||
|         #[cfg(not(rtc_v2wb))] | ||||
|         use stm32_metapac::rcc::vals::Rtcsel; | ||||
|  | ||||
|             #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] | ||||
|             let cr = crate::pac::PWR.cr(); | ||||
|             #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] | ||||
|             let cr = crate::pac::PWR.cr1(); | ||||
|         #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] | ||||
|         let cr = crate::pac::PWR.cr(); | ||||
|         #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] | ||||
|         let cr = crate::pac::PWR.cr1(); | ||||
|  | ||||
|             // TODO: Missing from PAC for l0 and f0? | ||||
|             #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] | ||||
|             { | ||||
|                 cr.modify(|w| w.set_dbp(true)); | ||||
|                 while !cr.read().dbp() {} | ||||
|             } | ||||
|  | ||||
|             #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||||
|             let reg = crate::pac::RCC.bdcr().read(); | ||||
|             #[cfg(any(rtc_v2l0, rtc_v2l1))] | ||||
|             let reg = crate::pac::RCC.csr().read(); | ||||
|  | ||||
|             #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] | ||||
|             assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | ||||
|  | ||||
|             #[cfg(rtc_v2wb)] | ||||
|             let rtcsel = reg.rtcsel(); | ||||
|             #[cfg(not(rtc_v2wb))] | ||||
|             let rtcsel = reg.rtcsel().0; | ||||
|  | ||||
|             if !reg.rtcen() || rtcsel != clock_config { | ||||
|                 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||||
|                 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); | ||||
|  | ||||
|                 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||||
|                 let cr = crate::pac::RCC.bdcr(); | ||||
|                 #[cfg(any(rtc_v2l0, rtc_v2l1))] | ||||
|                 let cr = crate::pac::RCC.csr(); | ||||
|  | ||||
|                 cr.modify(|w| { | ||||
|                     // Reset | ||||
|                     #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||||
|                     w.set_bdrst(false); | ||||
|  | ||||
|                     // Select RTC source | ||||
|                     #[cfg(not(rtc_v2wb))] | ||||
|                     w.set_rtcsel(Rtcsel(clock_config)); | ||||
|                     #[cfg(rtc_v2wb)] | ||||
|                     w.set_rtcsel(clock_config); | ||||
|                     w.set_rtcen(true); | ||||
|  | ||||
|                     // Restore bcdr | ||||
|                     #[cfg(any(rtc_v2l4, rtc_v2wb))] | ||||
|                     w.set_lscosel(reg.lscosel()); | ||||
|                     #[cfg(any(rtc_v2l4, rtc_v2wb))] | ||||
|                     w.set_lscoen(reg.lscoen()); | ||||
|  | ||||
|                     w.set_lseon(reg.lseon()); | ||||
|  | ||||
|                     #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] | ||||
|                     w.set_lsedrv(reg.lsedrv()); | ||||
|                     w.set_lsebyp(reg.lsebyp()); | ||||
|                 }); | ||||
|             } | ||||
|         // TODO: Missing from PAC for l0 and f0? | ||||
|         #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] | ||||
|         { | ||||
|             cr.modify(|w| w.set_dbp(true)); | ||||
|             while !cr.read().dbp() {} | ||||
|         } | ||||
|  | ||||
|         self.write(true, |rtc| unsafe { | ||||
|         #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||||
|         let reg = crate::pac::RCC.bdcr().read(); | ||||
|         #[cfg(any(rtc_v2l0, rtc_v2l1))] | ||||
|         let reg = crate::pac::RCC.csr().read(); | ||||
|  | ||||
|         #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] | ||||
|         assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | ||||
|  | ||||
|         #[cfg(rtc_v2wb)] | ||||
|         let rtcsel = reg.rtcsel(); | ||||
|         #[cfg(not(rtc_v2wb))] | ||||
|         let rtcsel = reg.rtcsel().0; | ||||
|  | ||||
|         if !reg.rtcen() || rtcsel != clock_config { | ||||
|             #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||||
|             crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); | ||||
|  | ||||
|             #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||||
|             let cr = crate::pac::RCC.bdcr(); | ||||
|             #[cfg(any(rtc_v2l0, rtc_v2l1))] | ||||
|             let cr = crate::pac::RCC.csr(); | ||||
|  | ||||
|             cr.modify(|w| { | ||||
|                 // Reset | ||||
|                 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||||
|                 w.set_bdrst(false); | ||||
|  | ||||
|                 // Select RTC source | ||||
|                 #[cfg(not(rtc_v2wb))] | ||||
|                 w.set_rtcsel(Rtcsel(clock_config)); | ||||
|                 #[cfg(rtc_v2wb)] | ||||
|                 w.set_rtcsel(clock_config); | ||||
|                 w.set_rtcen(true); | ||||
|  | ||||
|                 // Restore bcdr | ||||
|                 #[cfg(any(rtc_v2l4, rtc_v2wb))] | ||||
|                 w.set_lscosel(reg.lscosel()); | ||||
|                 #[cfg(any(rtc_v2l4, rtc_v2wb))] | ||||
|                 w.set_lscoen(reg.lscoen()); | ||||
|  | ||||
|                 w.set_lseon(reg.lseon()); | ||||
|  | ||||
|                 #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] | ||||
|                 w.set_lsedrv(reg.lsedrv()); | ||||
|                 w.set_lsebyp(reg.lsebyp()); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         self.write(true, |rtc| { | ||||
|             rtc.cr().modify(|w| { | ||||
|                 #[cfg(rtc_v2f2)] | ||||
|                 w.set_fmt(false); | ||||
| @@ -117,47 +115,45 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | ||||
|         clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM; | ||||
|  | ||||
|         self.write(false, |rtc| { | ||||
|             unsafe { | ||||
|                 rtc.calr().write(|w| { | ||||
|                     match period { | ||||
|                         super::RtcCalibrationCyclePeriod::Seconds8 => { | ||||
|                             w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND); | ||||
|                         } | ||||
|                         super::RtcCalibrationCyclePeriod::Seconds16 => { | ||||
|                             w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND); | ||||
|                         } | ||||
|                         super::RtcCalibrationCyclePeriod::Seconds32 => { | ||||
|                             // Set neither `calw8` nor `calw16` to use 32 seconds | ||||
|                         } | ||||
|             rtc.calr().write(|w| { | ||||
|                 match period { | ||||
|                     super::RtcCalibrationCyclePeriod::Seconds8 => { | ||||
|                         w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND); | ||||
|                     } | ||||
|  | ||||
|                     // Extra pulses during calibration cycle period: CALP * 512 - CALM | ||||
|                     // | ||||
|                     // CALP sets whether pulses are added or omitted. | ||||
|                     // | ||||
|                     // CALM contains how many pulses (out of 512) are masked in a | ||||
|                     // given calibration cycle period. | ||||
|                     if clock_drift > 0.0 { | ||||
|                         // Maximum (about 512.2) rounds to 512. | ||||
|                         clock_drift += 0.5; | ||||
|  | ||||
|                         // When the offset is positive (0 to 512), the opposite of | ||||
|                         // the offset (512 - offset) is masked, i.e. for the | ||||
|                         // maximum offset (512), 0 pulses are masked. | ||||
|                         w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ); | ||||
|                         w.set_calm(512 - clock_drift as u16); | ||||
|                     } else { | ||||
|                         // Minimum (about -510.7) rounds to -511. | ||||
|                         clock_drift -= 0.5; | ||||
|  | ||||
|                         // When the offset is negative or zero (-511 to 0), | ||||
|                         // the absolute offset is masked, i.e. for the minimum | ||||
|                         // offset (-511), 511 pulses are masked. | ||||
|                         w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE); | ||||
|                         w.set_calm((clock_drift * -1.0) as u16); | ||||
|                     super::RtcCalibrationCyclePeriod::Seconds16 => { | ||||
|                         w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|                     super::RtcCalibrationCyclePeriod::Seconds32 => { | ||||
|                         // Set neither `calw8` nor `calw16` to use 32 seconds | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // Extra pulses during calibration cycle period: CALP * 512 - CALM | ||||
|                 // | ||||
|                 // CALP sets whether pulses are added or omitted. | ||||
|                 // | ||||
|                 // CALM contains how many pulses (out of 512) are masked in a | ||||
|                 // given calibration cycle period. | ||||
|                 if clock_drift > 0.0 { | ||||
|                     // Maximum (about 512.2) rounds to 512. | ||||
|                     clock_drift += 0.5; | ||||
|  | ||||
|                     // When the offset is positive (0 to 512), the opposite of | ||||
|                     // the offset (512 - offset) is masked, i.e. for the | ||||
|                     // maximum offset (512), 0 pulses are masked. | ||||
|                     w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ); | ||||
|                     w.set_calm(512 - clock_drift as u16); | ||||
|                 } else { | ||||
|                     // Minimum (about -510.7) rounds to -511. | ||||
|                     clock_drift -= 0.5; | ||||
|  | ||||
|                     // When the offset is negative or zero (-511 to 0), | ||||
|                     // the absolute offset is masked, i.e. for the minimum | ||||
|                     // offset (-511), 511 pulses are masked. | ||||
|                     w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE); | ||||
|                     w.set_calm((clock_drift * -1.0) as u16); | ||||
|                 } | ||||
|             }); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| @@ -168,31 +164,27 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | ||||
|         let r = T::regs(); | ||||
|         // Disable write protection. | ||||
|         // This is safe, as we're only writin the correct and expected values. | ||||
|         unsafe { | ||||
|             r.wpr().write(|w| w.set_key(0xca)); | ||||
|             r.wpr().write(|w| w.set_key(0x53)); | ||||
|         r.wpr().write(|w| w.set_key(0xca)); | ||||
|         r.wpr().write(|w| w.set_key(0x53)); | ||||
|  | ||||
|             // true if initf bit indicates RTC peripheral is in init mode | ||||
|             if init_mode && !r.isr().read().initf() { | ||||
|                 // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode | ||||
|                 r.isr().modify(|w| w.set_init(Init::INITMODE)); | ||||
|                 // wait till init state entered | ||||
|                 // ~2 RTCCLK cycles | ||||
|                 while !r.isr().read().initf() {} | ||||
|             } | ||||
|         // true if initf bit indicates RTC peripheral is in init mode | ||||
|         if init_mode && !r.isr().read().initf() { | ||||
|             // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode | ||||
|             r.isr().modify(|w| w.set_init(Init::INITMODE)); | ||||
|             // wait till init state entered | ||||
|             // ~2 RTCCLK cycles | ||||
|             while !r.isr().read().initf() {} | ||||
|         } | ||||
|  | ||||
|         let result = f(&r); | ||||
|  | ||||
|         unsafe { | ||||
|             if init_mode { | ||||
|                 r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode | ||||
|             } | ||||
|  | ||||
|             // Re-enable write protection. | ||||
|             // This is safe, as the field accepts the full range of 8-bit values. | ||||
|             r.wpr().write(|w| w.set_key(0xff)); | ||||
|         if init_mode { | ||||
|             r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode | ||||
|         } | ||||
|  | ||||
|         // Re-enable write protection. | ||||
|         // This is safe, as the field accepts the full range of 8-bit values. | ||||
|         r.wpr().write(|w| w.set_key(0xff)); | ||||
|         result | ||||
|     } | ||||
| } | ||||
| @@ -200,7 +192,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | ||||
| impl sealed::Instance for crate::peripherals::RTC { | ||||
|     const BACKUP_REGISTER_COUNT: usize = 20; | ||||
|  | ||||
|     unsafe fn enable_peripheral_clk() { | ||||
|     fn enable_peripheral_clk() { | ||||
|         #[cfg(any(rtc_v2l4, rtc_v2wb))] | ||||
|         { | ||||
|             // enable peripheral clock for communication | ||||
| @@ -213,7 +205,7 @@ impl sealed::Instance for crate::peripherals::RTC { | ||||
|  | ||||
|     fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> { | ||||
|         if register < Self::BACKUP_REGISTER_COUNT { | ||||
|             Some(unsafe { rtc.bkpr(register).read().bkp() }) | ||||
|             Some(rtc.bkpr(register).read().bkp()) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
| @@ -221,7 +213,7 @@ impl sealed::Instance for crate::peripherals::RTC { | ||||
|  | ||||
|     fn write_backup_register(rtc: &Rtc, register: usize, value: u32) { | ||||
|         if register < Self::BACKUP_REGISTER_COUNT { | ||||
|             unsafe { rtc.bkpr(register).write(|w| w.set_bkp(value)) } | ||||
|             rtc.bkpr(register).write(|w| w.set_bkp(value)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,70 +8,66 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | ||||
|     /// It this changes the RTC clock source the time will be reset | ||||
|     pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { | ||||
|         // Unlock the backup domain | ||||
|         unsafe { | ||||
|             #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] | ||||
|             { | ||||
|                 crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); | ||||
|                 while !crate::pac::PWR.cr1().read().dbp() {} | ||||
|             } | ||||
|             #[cfg(any(rcc_wl5, rcc_wle))] | ||||
|             { | ||||
|                 use crate::pac::pwr::vals::Dbp; | ||||
|         #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] | ||||
|         { | ||||
|             crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); | ||||
|             while !crate::pac::PWR.cr1().read().dbp() {} | ||||
|         } | ||||
|         #[cfg(any(rcc_wl5, rcc_wle))] | ||||
|         { | ||||
|             use crate::pac::pwr::vals::Dbp; | ||||
|  | ||||
|                 crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); | ||||
|                 while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} | ||||
|             } | ||||
|             crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); | ||||
|             while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} | ||||
|         } | ||||
|  | ||||
|             let reg = crate::pac::RCC.bdcr().read(); | ||||
|             assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | ||||
|         let reg = crate::pac::RCC.bdcr().read(); | ||||
|         assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | ||||
|  | ||||
|             let config_rtcsel = rtc_config.clock_config as u8; | ||||
|             #[cfg(not(any(rcc_wl5, rcc_wle)))] | ||||
|             let config_rtcsel = crate::pac::rcc::vals::Rtcsel(config_rtcsel); | ||||
|         let config_rtcsel = rtc_config.clock_config as u8; | ||||
|         #[cfg(not(any(rcc_wl5, rcc_wle)))] | ||||
|         let config_rtcsel = crate::pac::rcc::vals::Rtcsel(config_rtcsel); | ||||
|  | ||||
|             if !reg.rtcen() || reg.rtcsel() != config_rtcsel { | ||||
|                 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); | ||||
|         if !reg.rtcen() || reg.rtcsel() != config_rtcsel { | ||||
|             crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); | ||||
|  | ||||
|                 crate::pac::RCC.bdcr().modify(|w| { | ||||
|                     // Reset | ||||
|                     w.set_bdrst(false); | ||||
|             crate::pac::RCC.bdcr().modify(|w| { | ||||
|                 // Reset | ||||
|                 w.set_bdrst(false); | ||||
|  | ||||
|                     // Select RTC source | ||||
|                     w.set_rtcsel(config_rtcsel); | ||||
|                 // Select RTC source | ||||
|                 w.set_rtcsel(config_rtcsel); | ||||
|  | ||||
|                     w.set_rtcen(true); | ||||
|                 w.set_rtcen(true); | ||||
|  | ||||
|                     // Restore bcdr | ||||
|                     w.set_lscosel(reg.lscosel()); | ||||
|                     w.set_lscoen(reg.lscoen()); | ||||
|                 // Restore bcdr | ||||
|                 w.set_lscosel(reg.lscosel()); | ||||
|                 w.set_lscoen(reg.lscoen()); | ||||
|  | ||||
|                     w.set_lseon(reg.lseon()); | ||||
|                     w.set_lsedrv(reg.lsedrv()); | ||||
|                     w.set_lsebyp(reg.lsebyp()); | ||||
|                 }); | ||||
|             } | ||||
|                 w.set_lseon(reg.lseon()); | ||||
|                 w.set_lsedrv(reg.lsedrv()); | ||||
|                 w.set_lsebyp(reg.lsebyp()); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         self.write(true, |rtc| { | ||||
|             unsafe { | ||||
|                 rtc.cr().modify(|w| { | ||||
|                     w.set_fmt(Fmt::TWENTYFOURHOUR); | ||||
|                     w.set_osel(Osel::DISABLED); | ||||
|                     w.set_pol(Pol::HIGH); | ||||
|                 }); | ||||
|             rtc.cr().modify(|w| { | ||||
|                 w.set_fmt(Fmt::TWENTYFOURHOUR); | ||||
|                 w.set_osel(Osel::DISABLED); | ||||
|                 w.set_pol(Pol::HIGH); | ||||
|             }); | ||||
|  | ||||
|                 rtc.prer().modify(|w| { | ||||
|                     w.set_prediv_s(rtc_config.sync_prescaler); | ||||
|                     w.set_prediv_a(rtc_config.async_prescaler); | ||||
|                 }); | ||||
|             rtc.prer().modify(|w| { | ||||
|                 w.set_prediv_s(rtc_config.sync_prescaler); | ||||
|                 w.set_prediv_a(rtc_config.async_prescaler); | ||||
|             }); | ||||
|  | ||||
|                 // TODO: configuration for output pins | ||||
|                 rtc.cr().modify(|w| { | ||||
|                     w.set_out2en(false); | ||||
|                     w.set_tampalrm_type(TampalrmType::PUSHPULL); | ||||
|                     w.set_tampalrm_pu(TampalrmPu::NOPULLUP); | ||||
|                 }); | ||||
|             } | ||||
|             // TODO: configuration for output pins | ||||
|             rtc.cr().modify(|w| { | ||||
|                 w.set_out2en(false); | ||||
|                 w.set_tampalrm_type(TampalrmType::PUSHPULL); | ||||
|                 w.set_tampalrm_pu(TampalrmPu::NOPULLUP); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         self.rtc_config = rtc_config; | ||||
| @@ -99,47 +95,45 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | ||||
|         clock_drift = clock_drift / Self::RTC_CALR_RESOLUTION_PPM; | ||||
|  | ||||
|         self.write(false, |rtc| { | ||||
|             unsafe { | ||||
|                 rtc.calr().write(|w| { | ||||
|                     match period { | ||||
|                         RtcCalibrationCyclePeriod::Seconds8 => { | ||||
|                             w.set_calw8(Calw8::EIGHTSECONDS); | ||||
|                         } | ||||
|                         RtcCalibrationCyclePeriod::Seconds16 => { | ||||
|                             w.set_calw16(Calw16::SIXTEENSECONDS); | ||||
|                         } | ||||
|                         RtcCalibrationCyclePeriod::Seconds32 => { | ||||
|                             // Set neither `calw8` nor `calw16` to use 32 seconds | ||||
|                         } | ||||
|             rtc.calr().write(|w| { | ||||
|                 match period { | ||||
|                     RtcCalibrationCyclePeriod::Seconds8 => { | ||||
|                         w.set_calw8(Calw8::EIGHTSECONDS); | ||||
|                     } | ||||
|  | ||||
|                     // Extra pulses during calibration cycle period: CALP * 512 - CALM | ||||
|                     // | ||||
|                     // CALP sets whether pulses are added or omitted. | ||||
|                     // | ||||
|                     // CALM contains how many pulses (out of 512) are masked in a | ||||
|                     // given calibration cycle period. | ||||
|                     if clock_drift > 0.0 { | ||||
|                         // Maximum (about 512.2) rounds to 512. | ||||
|                         clock_drift += 0.5; | ||||
|  | ||||
|                         // When the offset is positive (0 to 512), the opposite of | ||||
|                         // the offset (512 - offset) is masked, i.e. for the | ||||
|                         // maximum offset (512), 0 pulses are masked. | ||||
|                         w.set_calp(Calp::INCREASEFREQ); | ||||
|                         w.set_calm(512 - clock_drift as u16); | ||||
|                     } else { | ||||
|                         // Minimum (about -510.7) rounds to -511. | ||||
|                         clock_drift -= 0.5; | ||||
|  | ||||
|                         // When the offset is negative or zero (-511 to 0), | ||||
|                         // the absolute offset is masked, i.e. for the minimum | ||||
|                         // offset (-511), 511 pulses are masked. | ||||
|                         w.set_calp(Calp::NOCHANGE); | ||||
|                         w.set_calm((clock_drift * -1.0) as u16); | ||||
|                     RtcCalibrationCyclePeriod::Seconds16 => { | ||||
|                         w.set_calw16(Calw16::SIXTEENSECONDS); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|                     RtcCalibrationCyclePeriod::Seconds32 => { | ||||
|                         // Set neither `calw8` nor `calw16` to use 32 seconds | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // Extra pulses during calibration cycle period: CALP * 512 - CALM | ||||
|                 // | ||||
|                 // CALP sets whether pulses are added or omitted. | ||||
|                 // | ||||
|                 // CALM contains how many pulses (out of 512) are masked in a | ||||
|                 // given calibration cycle period. | ||||
|                 if clock_drift > 0.0 { | ||||
|                     // Maximum (about 512.2) rounds to 512. | ||||
|                     clock_drift += 0.5; | ||||
|  | ||||
|                     // When the offset is positive (0 to 512), the opposite of | ||||
|                     // the offset (512 - offset) is masked, i.e. for the | ||||
|                     // maximum offset (512), 0 pulses are masked. | ||||
|                     w.set_calp(Calp::INCREASEFREQ); | ||||
|                     w.set_calm(512 - clock_drift as u16); | ||||
|                 } else { | ||||
|                     // Minimum (about -510.7) rounds to -511. | ||||
|                     clock_drift -= 0.5; | ||||
|  | ||||
|                     // When the offset is negative or zero (-511 to 0), | ||||
|                     // the absolute offset is masked, i.e. for the minimum | ||||
|                     // offset (-511), 511 pulses are masked. | ||||
|                     w.set_calp(Calp::NOCHANGE); | ||||
|                     w.set_calm((clock_drift * -1.0) as u16); | ||||
|                 } | ||||
|             }); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| @@ -150,29 +144,26 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | ||||
|         let r = T::regs(); | ||||
|         // Disable write protection. | ||||
|         // This is safe, as we're only writin the correct and expected values. | ||||
|         unsafe { | ||||
|             r.wpr().write(|w| w.set_key(Key::DEACTIVATE1)); | ||||
|             r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); | ||||
|         r.wpr().write(|w| w.set_key(Key::DEACTIVATE1)); | ||||
|         r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); | ||||
|  | ||||
|             if init_mode && !r.icsr().read().initf() { | ||||
|                 r.icsr().modify(|w| w.set_init(Init::INITMODE)); | ||||
|                 // wait till init state entered | ||||
|                 // ~2 RTCCLK cycles | ||||
|                 while !r.icsr().read().initf() {} | ||||
|             } | ||||
|         if init_mode && !r.icsr().read().initf() { | ||||
|             r.icsr().modify(|w| w.set_init(Init::INITMODE)); | ||||
|             // wait till init state entered | ||||
|             // ~2 RTCCLK cycles | ||||
|             while !r.icsr().read().initf() {} | ||||
|         } | ||||
|  | ||||
|         let result = f(&r); | ||||
|  | ||||
|         unsafe { | ||||
|             if init_mode { | ||||
|                 r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode | ||||
|             } | ||||
|  | ||||
|             // Re-enable write protection. | ||||
|             // This is safe, as the field accepts the full range of 8-bit values. | ||||
|             r.wpr().write(|w| w.set_key(Key::ACTIVATE)); | ||||
|         if init_mode { | ||||
|             r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode | ||||
|         } | ||||
|  | ||||
|         // Re-enable write protection. | ||||
|         // This is safe, as the field accepts the full range of 8-bit values. | ||||
|         r.wpr().write(|w| w.set_key(Key::ACTIVATE)); | ||||
|  | ||||
|         result | ||||
|     } | ||||
| } | ||||
| @@ -192,7 +183,7 @@ impl sealed::Instance for crate::peripherals::RTC { | ||||
|     fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) { | ||||
|         if register < Self::BACKUP_REGISTER_COUNT { | ||||
|             // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC | ||||
|             //unsafe { self.rtc.bkpr()[register].write(|w| w.bits(value)) } | ||||
|             //self.rtc.bkpr()[register].write(|w| w.bits(value)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -28,17 +28,14 @@ pub struct InterruptHandler<T: Instance> { | ||||
| impl<T: Instance> InterruptHandler<T> { | ||||
|     fn data_interrupts(enable: bool) { | ||||
|         let regs = T::regs(); | ||||
|         // NOTE(unsafe) Atomic write | ||||
|         unsafe { | ||||
|             regs.maskr().write(|w| { | ||||
|                 w.set_dcrcfailie(enable); | ||||
|                 w.set_dtimeoutie(enable); | ||||
|                 w.set_dataendie(enable); | ||||
|         regs.maskr().write(|w| { | ||||
|             w.set_dcrcfailie(enable); | ||||
|             w.set_dtimeoutie(enable); | ||||
|             w.set_dataendie(enable); | ||||
|  | ||||
|                 #[cfg(sdmmc_v2)] | ||||
|                 w.set_dabortie(enable); | ||||
|             }); | ||||
|         } | ||||
|             #[cfg(sdmmc_v2)] | ||||
|             w.set_dabortie(enable); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -285,7 +282,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | ||||
|     ) -> Self { | ||||
|         into_ref!(clk, cmd, d0); | ||||
|  | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); | ||||
|             cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); | ||||
|             d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); | ||||
| @@ -322,7 +319,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | ||||
|     ) -> Self { | ||||
|         into_ref!(clk, cmd, d0, d1, d2, d3); | ||||
|  | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); | ||||
|             cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); | ||||
|             d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); | ||||
| @@ -364,7 +361,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | ||||
|     ) -> Self { | ||||
|         into_ref!(clk, cmd, d0); | ||||
|  | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); | ||||
|             cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); | ||||
|             d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); | ||||
| @@ -400,7 +397,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | ||||
|     ) -> Self { | ||||
|         into_ref!(clk, cmd, d0, d1, d2, d3); | ||||
|  | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); | ||||
|             cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); | ||||
|             d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); | ||||
| @@ -451,26 +448,24 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
|  | ||||
|         let regs = T::regs(); | ||||
|         unsafe { | ||||
|             regs.clkcr().write(|w| { | ||||
|                 w.set_pwrsav(false); | ||||
|                 w.set_negedge(false); | ||||
|         regs.clkcr().write(|w| { | ||||
|             w.set_pwrsav(false); | ||||
|             w.set_negedge(false); | ||||
|  | ||||
|                 // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors. | ||||
|                 // See chip erratas for more details. | ||||
|                 #[cfg(sdmmc_v1)] | ||||
|                 w.set_hwfc_en(false); | ||||
|                 #[cfg(sdmmc_v2)] | ||||
|                 w.set_hwfc_en(true); | ||||
|             // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors. | ||||
|             // See chip erratas for more details. | ||||
|             #[cfg(sdmmc_v1)] | ||||
|             w.set_hwfc_en(false); | ||||
|             #[cfg(sdmmc_v2)] | ||||
|             w.set_hwfc_en(true); | ||||
|  | ||||
|                 #[cfg(sdmmc_v1)] | ||||
|                 w.set_clken(true); | ||||
|             }); | ||||
|             #[cfg(sdmmc_v1)] | ||||
|             w.set_clken(true); | ||||
|         }); | ||||
|  | ||||
|             // Power off, writen 00: Clock to the card is stopped; | ||||
|             // D[7:0], CMD, and CK are driven high. | ||||
|             regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); | ||||
|         } | ||||
|         // Power off, writen 00: Clock to the card is stopped; | ||||
|         // D[7:0], CMD, and CK are driven high. | ||||
|         regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); | ||||
|  | ||||
|         Self { | ||||
|             _peri: sdmmc, | ||||
| @@ -495,14 +490,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|     fn data_active() -> bool { | ||||
|         let regs = T::regs(); | ||||
|  | ||||
|         // NOTE(unsafe) Atomic read with no side-effects | ||||
|         unsafe { | ||||
|             let status = regs.star().read(); | ||||
|             #[cfg(sdmmc_v1)] | ||||
|             return status.rxact() || status.txact(); | ||||
|             #[cfg(sdmmc_v2)] | ||||
|             return status.dpsmact(); | ||||
|         } | ||||
|         let status = regs.star().read(); | ||||
|         #[cfg(sdmmc_v1)] | ||||
|         return status.rxact() || status.txact(); | ||||
|         #[cfg(sdmmc_v2)] | ||||
|         return status.dpsmact(); | ||||
|     } | ||||
|  | ||||
|     /// Coammand transfer is in progress | ||||
| @@ -510,14 +502,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|     fn cmd_active() -> bool { | ||||
|         let regs = T::regs(); | ||||
|  | ||||
|         // NOTE(unsafe) Atomic read with no side-effects | ||||
|         unsafe { | ||||
|             let status = regs.star().read(); | ||||
|             #[cfg(sdmmc_v1)] | ||||
|             return status.cmdact(); | ||||
|             #[cfg(sdmmc_v2)] | ||||
|             return status.cpsmact(); | ||||
|         } | ||||
|         let status = regs.star().read(); | ||||
|         #[cfg(sdmmc_v1)] | ||||
|         return status.cmdact(); | ||||
|         #[cfg(sdmmc_v2)] | ||||
|         return status.cpsmact(); | ||||
|     } | ||||
|  | ||||
|     /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) | ||||
| @@ -542,44 +531,41 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|         Self::wait_idle(); | ||||
|         Self::clear_interrupt_flags(); | ||||
|  | ||||
|         // NOTE(unsafe) We have exclusive access to the regisers | ||||
|         unsafe { | ||||
|             regs.dtimer() | ||||
|                 .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||||
|             regs.dlenr().write(|w| w.set_datalength(length_bytes)); | ||||
|         regs.dtimer() | ||||
|             .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||||
|         regs.dlenr().write(|w| w.set_datalength(length_bytes)); | ||||
|  | ||||
|         #[cfg(sdmmc_v1)] | ||||
|         let transfer = unsafe { | ||||
|             let request = self.dma.request(); | ||||
|             Transfer::new_read( | ||||
|                 &mut self.dma, | ||||
|                 request, | ||||
|                 regs.fifor().as_ptr() as *mut u32, | ||||
|                 buffer, | ||||
|                 DMA_TRANSFER_OPTIONS, | ||||
|             ) | ||||
|         }; | ||||
|         #[cfg(sdmmc_v2)] | ||||
|         let transfer = { | ||||
|             regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); | ||||
|             regs.idmactrlr().modify(|w| w.set_idmaen(true)); | ||||
|             Transfer { | ||||
|                 _dummy: core::marker::PhantomData, | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         regs.dctrl().modify(|w| { | ||||
|             w.set_dblocksize(block_size); | ||||
|             w.set_dtdir(true); | ||||
|             #[cfg(sdmmc_v1)] | ||||
|             let transfer = { | ||||
|                 let request = self.dma.request(); | ||||
|                 Transfer::new_read( | ||||
|                     &mut self.dma, | ||||
|                     request, | ||||
|                     regs.fifor().ptr() as *mut u32, | ||||
|                     buffer, | ||||
|                     DMA_TRANSFER_OPTIONS, | ||||
|                 ) | ||||
|             }; | ||||
|             #[cfg(sdmmc_v2)] | ||||
|             let transfer = { | ||||
|                 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); | ||||
|                 regs.idmactrlr().modify(|w| w.set_idmaen(true)); | ||||
|                 Transfer { | ||||
|                     _dummy: core::marker::PhantomData, | ||||
|                 } | ||||
|             }; | ||||
|             { | ||||
|                 w.set_dmaen(true); | ||||
|                 w.set_dten(true); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|             regs.dctrl().modify(|w| { | ||||
|                 w.set_dblocksize(block_size); | ||||
|                 w.set_dtdir(true); | ||||
|                 #[cfg(sdmmc_v1)] | ||||
|                 { | ||||
|                     w.set_dmaen(true); | ||||
|                     w.set_dten(true); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             transfer | ||||
|         } | ||||
|         transfer | ||||
|     } | ||||
|  | ||||
|     /// # Safety | ||||
| @@ -598,59 +584,54 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|         Self::wait_idle(); | ||||
|         Self::clear_interrupt_flags(); | ||||
|  | ||||
|         // NOTE(unsafe) We have exclusive access to the regisers | ||||
|         unsafe { | ||||
|             regs.dtimer() | ||||
|                 .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||||
|             regs.dlenr().write(|w| w.set_datalength(length_bytes)); | ||||
|         regs.dtimer() | ||||
|             .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||||
|         regs.dlenr().write(|w| w.set_datalength(length_bytes)); | ||||
|  | ||||
|         #[cfg(sdmmc_v1)] | ||||
|         let transfer = unsafe { | ||||
|             let request = self.dma.request(); | ||||
|             Transfer::new_write( | ||||
|                 &mut self.dma, | ||||
|                 request, | ||||
|                 buffer, | ||||
|                 regs.fifor().as_ptr() as *mut u32, | ||||
|                 DMA_TRANSFER_OPTIONS, | ||||
|             ) | ||||
|         }; | ||||
|         #[cfg(sdmmc_v2)] | ||||
|         let transfer = { | ||||
|             regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32)); | ||||
|             regs.idmactrlr().modify(|w| w.set_idmaen(true)); | ||||
|             Transfer { | ||||
|                 _dummy: core::marker::PhantomData, | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         regs.dctrl().modify(|w| { | ||||
|             w.set_dblocksize(block_size); | ||||
|             w.set_dtdir(false); | ||||
|             #[cfg(sdmmc_v1)] | ||||
|             let transfer = { | ||||
|                 let request = self.dma.request(); | ||||
|                 Transfer::new_write( | ||||
|                     &mut self.dma, | ||||
|                     request, | ||||
|                     buffer, | ||||
|                     regs.fifor().ptr() as *mut u32, | ||||
|                     DMA_TRANSFER_OPTIONS, | ||||
|                 ) | ||||
|             }; | ||||
|             #[cfg(sdmmc_v2)] | ||||
|             let transfer = { | ||||
|                 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32)); | ||||
|                 regs.idmactrlr().modify(|w| w.set_idmaen(true)); | ||||
|                 Transfer { | ||||
|                     _dummy: core::marker::PhantomData, | ||||
|                 } | ||||
|             }; | ||||
|             { | ||||
|                 w.set_dmaen(true); | ||||
|                 w.set_dten(true); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|             regs.dctrl().modify(|w| { | ||||
|                 w.set_dblocksize(block_size); | ||||
|                 w.set_dtdir(false); | ||||
|                 #[cfg(sdmmc_v1)] | ||||
|                 { | ||||
|                     w.set_dmaen(true); | ||||
|                     w.set_dten(true); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             transfer | ||||
|         } | ||||
|         transfer | ||||
|     } | ||||
|  | ||||
|     /// Stops the DMA datapath | ||||
|     fn stop_datapath() { | ||||
|         let regs = T::regs(); | ||||
|  | ||||
|         unsafe { | ||||
|             #[cfg(sdmmc_v1)] | ||||
|             regs.dctrl().modify(|w| { | ||||
|                 w.set_dmaen(false); | ||||
|                 w.set_dten(false); | ||||
|             }); | ||||
|             #[cfg(sdmmc_v2)] | ||||
|             regs.idmactrlr().modify(|w| w.set_idmaen(false)); | ||||
|         } | ||||
|         #[cfg(sdmmc_v1)] | ||||
|         regs.dctrl().modify(|w| { | ||||
|             w.set_dmaen(false); | ||||
|             w.set_dten(false); | ||||
|         }); | ||||
|         #[cfg(sdmmc_v2)] | ||||
|         regs.idmactrlr().modify(|w| w.set_idmaen(false)); | ||||
|     } | ||||
|  | ||||
|     /// Sets the CLKDIV field in CLKCR. Updates clock field in self | ||||
| @@ -673,16 +654,13 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|         assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); | ||||
|         self.clock = new_clock; | ||||
|  | ||||
|         // NOTE(unsafe) We have exclusive access to the regblock | ||||
|         unsafe { | ||||
|             // CPSMACT and DPSMACT must be 0 to set CLKDIV | ||||
|             Self::wait_idle(); | ||||
|             regs.clkcr().modify(|w| { | ||||
|                 w.set_clkdiv(clkdiv); | ||||
|                 #[cfg(sdmmc_v1)] | ||||
|                 w.set_bypass(_bypass); | ||||
|             }); | ||||
|         } | ||||
|         // CPSMACT and DPSMACT must be 0 to set CLKDIV | ||||
|         Self::wait_idle(); | ||||
|         regs.clkcr().modify(|w| { | ||||
|             w.set_clkdiv(clkdiv); | ||||
|             #[cfg(sdmmc_v1)] | ||||
|             w.set_bypass(_bypass); | ||||
|         }); | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
| @@ -710,7 +688,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|  | ||||
|         // Arm `OnDrop` after the buffer, so it will be dropped first | ||||
|         let regs = T::regs(); | ||||
|         let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | ||||
|         let on_drop = OnDrop::new(|| Self::on_drop()); | ||||
|  | ||||
|         let transfer = self.prepare_datapath_read(&mut status, 64, 6); | ||||
|         InterruptHandler::<T>::data_interrupts(true); | ||||
| @@ -718,7 +696,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|  | ||||
|         let res = poll_fn(|cx| { | ||||
|             T::state().register(cx.waker()); | ||||
|             let status = unsafe { regs.star().read() }; | ||||
|             let status = regs.star().read(); | ||||
|  | ||||
|             if status.dcrcfail() { | ||||
|                 return Poll::Ready(Err(Error::Crc)); | ||||
| @@ -769,8 +747,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|  | ||||
|         Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13 | ||||
|  | ||||
|         // NOTE(unsafe) Atomic read with no side-effects | ||||
|         let r1 = unsafe { regs.respr(0).read().cardstatus() }; | ||||
|         let r1 = regs.respr(0).read().cardstatus(); | ||||
|         Ok(r1.into()) | ||||
|     } | ||||
|  | ||||
| @@ -786,7 +763,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|  | ||||
|         // Arm `OnDrop` after the buffer, so it will be dropped first | ||||
|         let regs = T::regs(); | ||||
|         let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | ||||
|         let on_drop = OnDrop::new(|| Self::on_drop()); | ||||
|  | ||||
|         let transfer = self.prepare_datapath_read(&mut status, 64, 6); | ||||
|         InterruptHandler::<T>::data_interrupts(true); | ||||
| @@ -794,7 +771,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|  | ||||
|         let res = poll_fn(|cx| { | ||||
|             T::state().register(cx.waker()); | ||||
|             let status = unsafe { regs.star().read() }; | ||||
|             let status = regs.star().read(); | ||||
|  | ||||
|             if status.dcrcfail() { | ||||
|                 return Poll::Ready(Err(Error::Crc)); | ||||
| @@ -840,35 +817,32 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|     #[inline(always)] | ||||
|     fn clear_interrupt_flags() { | ||||
|         let regs = T::regs(); | ||||
|         // NOTE(unsafe) Atomic write | ||||
|         unsafe { | ||||
|             regs.icr().write(|w| { | ||||
|                 w.set_ccrcfailc(true); | ||||
|                 w.set_dcrcfailc(true); | ||||
|                 w.set_ctimeoutc(true); | ||||
|                 w.set_dtimeoutc(true); | ||||
|                 w.set_txunderrc(true); | ||||
|                 w.set_rxoverrc(true); | ||||
|                 w.set_cmdrendc(true); | ||||
|                 w.set_cmdsentc(true); | ||||
|                 w.set_dataendc(true); | ||||
|                 w.set_dbckendc(true); | ||||
|                 w.set_sdioitc(true); | ||||
|         regs.icr().write(|w| { | ||||
|             w.set_ccrcfailc(true); | ||||
|             w.set_dcrcfailc(true); | ||||
|             w.set_ctimeoutc(true); | ||||
|             w.set_dtimeoutc(true); | ||||
|             w.set_txunderrc(true); | ||||
|             w.set_rxoverrc(true); | ||||
|             w.set_cmdrendc(true); | ||||
|             w.set_cmdsentc(true); | ||||
|             w.set_dataendc(true); | ||||
|             w.set_dbckendc(true); | ||||
|             w.set_sdioitc(true); | ||||
|  | ||||
|                 #[cfg(sdmmc_v2)] | ||||
|                 { | ||||
|                     w.set_dholdc(true); | ||||
|                     w.set_dabortc(true); | ||||
|                     w.set_busyd0endc(true); | ||||
|                     w.set_ackfailc(true); | ||||
|                     w.set_acktimeoutc(true); | ||||
|                     w.set_vswendc(true); | ||||
|                     w.set_ckstopc(true); | ||||
|                     w.set_idmatec(true); | ||||
|                     w.set_idmabtcc(true); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|             #[cfg(sdmmc_v2)] | ||||
|             { | ||||
|                 w.set_dholdc(true); | ||||
|                 w.set_dabortc(true); | ||||
|                 w.set_busyd0endc(true); | ||||
|                 w.set_ackfailc(true); | ||||
|                 w.set_acktimeoutc(true); | ||||
|                 w.set_vswendc(true); | ||||
|                 w.set_ckstopc(true); | ||||
|                 w.set_idmatec(true); | ||||
|                 w.set_idmabtcc(true); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { | ||||
| @@ -880,7 +854,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|  | ||||
|         // Arm `OnDrop` after the buffer, so it will be dropped first | ||||
|         let regs = T::regs(); | ||||
|         let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | ||||
|         let on_drop = OnDrop::new(|| Self::on_drop()); | ||||
|  | ||||
|         let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); | ||||
|         InterruptHandler::<T>::data_interrupts(true); | ||||
| @@ -888,7 +862,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|  | ||||
|         let res = poll_fn(|cx| { | ||||
|             T::state().register(cx.waker()); | ||||
|             let status = unsafe { regs.star().read() }; | ||||
|             let status = regs.star().read(); | ||||
|  | ||||
|             if status.dcrcfail() { | ||||
|                 return Poll::Ready(Err(Error::Crc)); | ||||
| @@ -921,59 +895,53 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|         let regs = T::regs(); | ||||
|  | ||||
|         Self::clear_interrupt_flags(); | ||||
|         // NOTE(safety) Atomic operations | ||||
|         unsafe { | ||||
|             // CP state machine must be idle | ||||
|             while Self::cmd_active() {} | ||||
|         // CP state machine must be idle | ||||
|         while Self::cmd_active() {} | ||||
|  | ||||
|             // Command arg | ||||
|             regs.argr().write(|w| w.set_cmdarg(cmd.arg)); | ||||
|         // Command arg | ||||
|         regs.argr().write(|w| w.set_cmdarg(cmd.arg)); | ||||
|  | ||||
|             // Command index and start CP State Machine | ||||
|             regs.cmdr().write(|w| { | ||||
|                 w.set_waitint(false); | ||||
|                 w.set_waitresp(cmd.resp as u8); | ||||
|                 w.set_cmdindex(cmd.cmd); | ||||
|                 w.set_cpsmen(true); | ||||
|         // Command index and start CP State Machine | ||||
|         regs.cmdr().write(|w| { | ||||
|             w.set_waitint(false); | ||||
|             w.set_waitresp(cmd.resp as u8); | ||||
|             w.set_cmdindex(cmd.cmd); | ||||
|             w.set_cpsmen(true); | ||||
|  | ||||
|                 #[cfg(sdmmc_v2)] | ||||
|                 { | ||||
|                     // Special mode in CP State Machine | ||||
|                     // CMD12: Stop Transmission | ||||
|                     let cpsm_stop_transmission = cmd.cmd == 12; | ||||
|                     w.set_cmdstop(cpsm_stop_transmission); | ||||
|                     w.set_cmdtrans(data); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             let mut status; | ||||
|             if cmd.resp == Response::None { | ||||
|                 // Wait for CMDSENT or a timeout | ||||
|                 while { | ||||
|                     status = regs.star().read(); | ||||
|                     !(status.ctimeout() || status.cmdsent()) | ||||
|                 } {} | ||||
|             } else { | ||||
|                 // Wait for CMDREND or CCRCFAIL or a timeout | ||||
|                 while { | ||||
|                     status = regs.star().read(); | ||||
|                     !(status.ctimeout() || status.cmdrend() || status.ccrcfail()) | ||||
|                 } {} | ||||
|             #[cfg(sdmmc_v2)] | ||||
|             { | ||||
|                 // Special mode in CP State Machine | ||||
|                 // CMD12: Stop Transmission | ||||
|                 let cpsm_stop_transmission = cmd.cmd == 12; | ||||
|                 w.set_cmdstop(cpsm_stop_transmission); | ||||
|                 w.set_cmdtrans(data); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|             if status.ctimeout() { | ||||
|                 return Err(Error::Timeout); | ||||
|             } else if status.ccrcfail() { | ||||
|                 return Err(Error::Crc); | ||||
|             } | ||||
|             Ok(()) | ||||
|         let mut status; | ||||
|         if cmd.resp == Response::None { | ||||
|             // Wait for CMDSENT or a timeout | ||||
|             while { | ||||
|                 status = regs.star().read(); | ||||
|                 !(status.ctimeout() || status.cmdsent()) | ||||
|             } {} | ||||
|         } else { | ||||
|             // Wait for CMDREND or CCRCFAIL or a timeout | ||||
|             while { | ||||
|                 status = regs.star().read(); | ||||
|                 !(status.ctimeout() || status.cmdrend() || status.ccrcfail()) | ||||
|             } {} | ||||
|         } | ||||
|  | ||||
|         if status.ctimeout() { | ||||
|             return Err(Error::Timeout); | ||||
|         } else if status.ccrcfail() { | ||||
|             return Err(Error::Crc); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// # Safety | ||||
|     /// | ||||
|     /// Ensure that `regs` has exclusive access to the regblocks | ||||
|     unsafe fn on_drop() { | ||||
|     fn on_drop() { | ||||
|         let regs = T::regs(); | ||||
|         if Self::data_active() { | ||||
|             Self::clear_interrupt_flags(); | ||||
| @@ -1017,141 +985,138 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|             false => BusWidth::One, | ||||
|         }; | ||||
|  | ||||
|         // NOTE(unsafe) We have exclusive access to the peripheral | ||||
|         unsafe { | ||||
|             // While the SD/SDIO card or eMMC is in identification mode, | ||||
|             // the SDMMC_CK frequency must be no more than 400 kHz. | ||||
|             let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); | ||||
|             self.clock = init_clock; | ||||
|         // While the SD/SDIO card or eMMC is in identification mode, | ||||
|         // the SDMMC_CK frequency must be no more than 400 kHz. | ||||
|         let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); | ||||
|         self.clock = init_clock; | ||||
|  | ||||
|             // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||||
|             Self::wait_idle(); | ||||
|         // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||||
|         Self::wait_idle(); | ||||
|  | ||||
|             regs.clkcr().modify(|w| { | ||||
|                 w.set_widbus(0); | ||||
|                 w.set_clkdiv(clkdiv); | ||||
|                 #[cfg(sdmmc_v1)] | ||||
|                 w.set_bypass(_bypass); | ||||
|             }); | ||||
|         regs.clkcr().modify(|w| { | ||||
|             w.set_widbus(0); | ||||
|             w.set_clkdiv(clkdiv); | ||||
|             #[cfg(sdmmc_v1)] | ||||
|             w.set_bypass(_bypass); | ||||
|         }); | ||||
|  | ||||
|             regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | ||||
|             Self::cmd(Cmd::idle(), false)?; | ||||
|         regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | ||||
|         Self::cmd(Cmd::idle(), false)?; | ||||
|  | ||||
|             // Check if cards supports CMD8 (with pattern) | ||||
|             Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; | ||||
|             let r1 = regs.respr(0).read().cardstatus(); | ||||
|         // Check if cards supports CMD8 (with pattern) | ||||
|         Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; | ||||
|         let r1 = regs.respr(0).read().cardstatus(); | ||||
|  | ||||
|             let mut card = if r1 == 0x1AA { | ||||
|                 // Card echoed back the pattern. Must be at least v2 | ||||
|                 Card::default() | ||||
|             } else { | ||||
|                 return Err(Error::UnsupportedCardVersion); | ||||
|             }; | ||||
|         let mut card = if r1 == 0x1AA { | ||||
|             // Card echoed back the pattern. Must be at least v2 | ||||
|             Card::default() | ||||
|         } else { | ||||
|             return Err(Error::UnsupportedCardVersion); | ||||
|         }; | ||||
|  | ||||
|             let ocr = loop { | ||||
|                 // Signal that next command is a app command | ||||
|                 Self::cmd(Cmd::app_cmd(0), false)?; // CMD55 | ||||
|         let ocr = loop { | ||||
|             // Signal that next command is a app command | ||||
|             Self::cmd(Cmd::app_cmd(0), false)?; // CMD55 | ||||
|  | ||||
|                 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 | ||||
|                     | CmdAppOper::HIGH_CAPACITY as u32 | ||||
|                     | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; | ||||
|             let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 | ||||
|                 | CmdAppOper::HIGH_CAPACITY as u32 | ||||
|                 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; | ||||
|  | ||||
|                 // Initialize card | ||||
|                 match Self::cmd(Cmd::app_op_cmd(arg), false) { | ||||
|                     // ACMD41 | ||||
|                     Ok(_) => (), | ||||
|                     Err(Error::Crc) => (), | ||||
|                     Err(err) => return Err(err), | ||||
|                 } | ||||
|                 let ocr: OCR = regs.respr(0).read().cardstatus().into(); | ||||
|                 if !ocr.is_busy() { | ||||
|                     // Power up done | ||||
|                     break ocr; | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             if ocr.high_capacity() { | ||||
|                 // Card is SDHC or SDXC or SDUC | ||||
|                 card.card_type = CardCapacity::SDHC; | ||||
|             } else { | ||||
|                 card.card_type = CardCapacity::SDSC; | ||||
|             // Initialize card | ||||
|             match Self::cmd(Cmd::app_op_cmd(arg), false) { | ||||
|                 // ACMD41 | ||||
|                 Ok(_) => (), | ||||
|                 Err(Error::Crc) => (), | ||||
|                 Err(err) => return Err(err), | ||||
|             } | ||||
|             card.ocr = ocr; | ||||
|  | ||||
|             Self::cmd(Cmd::all_send_cid(), false)?; // CMD2 | ||||
|             let cid0 = regs.respr(0).read().cardstatus() as u128; | ||||
|             let cid1 = regs.respr(1).read().cardstatus() as u128; | ||||
|             let cid2 = regs.respr(2).read().cardstatus() as u128; | ||||
|             let cid3 = regs.respr(3).read().cardstatus() as u128; | ||||
|             let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | ||||
|             card.cid = cid.into(); | ||||
|  | ||||
|             Self::cmd(Cmd::send_rel_addr(), false)?; | ||||
|             card.rca = regs.respr(0).read().cardstatus() >> 16; | ||||
|  | ||||
|             Self::cmd(Cmd::send_csd(card.rca << 16), false)?; | ||||
|             let csd0 = regs.respr(0).read().cardstatus() as u128; | ||||
|             let csd1 = regs.respr(1).read().cardstatus() as u128; | ||||
|             let csd2 = regs.respr(2).read().cardstatus() as u128; | ||||
|             let csd3 = regs.respr(3).read().cardstatus() as u128; | ||||
|             let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); | ||||
|             card.csd = csd.into(); | ||||
|  | ||||
|             self.select_card(Some(&card))?; | ||||
|  | ||||
|             self.get_scr(&mut card).await?; | ||||
|  | ||||
|             // Set bus width | ||||
|             let (width, acmd_arg) = match bus_width { | ||||
|                 BusWidth::Eight => unimplemented!(), | ||||
|                 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), | ||||
|                 _ => (BusWidth::One, 0), | ||||
|             }; | ||||
|             Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; | ||||
|             Self::cmd(Cmd::cmd6(acmd_arg), false)?; | ||||
|  | ||||
|             // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||||
|             Self::wait_idle(); | ||||
|  | ||||
|             regs.clkcr().modify(|w| { | ||||
|                 w.set_widbus(match width { | ||||
|                     BusWidth::One => 0, | ||||
|                     BusWidth::Four => 1, | ||||
|                     BusWidth::Eight => 2, | ||||
|                     _ => panic!("Invalid Bus Width"), | ||||
|                 }) | ||||
|             }); | ||||
|  | ||||
|             // Set Clock | ||||
|             if freq.0 <= 25_000_000 { | ||||
|                 // Final clock frequency | ||||
|                 self.clkcr_set_clkdiv(freq.0, width)?; | ||||
|             } else { | ||||
|                 // Switch to max clock for SDR12 | ||||
|                 self.clkcr_set_clkdiv(25_000_000, width)?; | ||||
|             let ocr: OCR = regs.respr(0).read().cardstatus().into(); | ||||
|             if !ocr.is_busy() { | ||||
|                 // Power up done | ||||
|                 break ocr; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|             self.card = Some(card); | ||||
|  | ||||
|             // Read status | ||||
|             self.read_sd_status().await?; | ||||
|  | ||||
|             if freq.0 > 25_000_000 { | ||||
|                 // Switch to SDR25 | ||||
|                 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; | ||||
|  | ||||
|                 if self.signalling == Signalling::SDR25 { | ||||
|                     // Set final clock frequency | ||||
|                     self.clkcr_set_clkdiv(freq.0, width)?; | ||||
|  | ||||
|                     if self.read_status(&card)?.state() != CurrentState::Transfer { | ||||
|                         return Err(Error::SignalingSwitchFailed); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             // Read status after signalling change | ||||
|             self.read_sd_status().await?; | ||||
|         if ocr.high_capacity() { | ||||
|             // Card is SDHC or SDXC or SDUC | ||||
|             card.card_type = CardCapacity::SDHC; | ||||
|         } else { | ||||
|             card.card_type = CardCapacity::SDSC; | ||||
|         } | ||||
|         card.ocr = ocr; | ||||
|  | ||||
|         Self::cmd(Cmd::all_send_cid(), false)?; // CMD2 | ||||
|         let cid0 = regs.respr(0).read().cardstatus() as u128; | ||||
|         let cid1 = regs.respr(1).read().cardstatus() as u128; | ||||
|         let cid2 = regs.respr(2).read().cardstatus() as u128; | ||||
|         let cid3 = regs.respr(3).read().cardstatus() as u128; | ||||
|         let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | ||||
|         card.cid = cid.into(); | ||||
|  | ||||
|         Self::cmd(Cmd::send_rel_addr(), false)?; | ||||
|         card.rca = regs.respr(0).read().cardstatus() >> 16; | ||||
|  | ||||
|         Self::cmd(Cmd::send_csd(card.rca << 16), false)?; | ||||
|         let csd0 = regs.respr(0).read().cardstatus() as u128; | ||||
|         let csd1 = regs.respr(1).read().cardstatus() as u128; | ||||
|         let csd2 = regs.respr(2).read().cardstatus() as u128; | ||||
|         let csd3 = regs.respr(3).read().cardstatus() as u128; | ||||
|         let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); | ||||
|         card.csd = csd.into(); | ||||
|  | ||||
|         self.select_card(Some(&card))?; | ||||
|  | ||||
|         self.get_scr(&mut card).await?; | ||||
|  | ||||
|         // Set bus width | ||||
|         let (width, acmd_arg) = match bus_width { | ||||
|             BusWidth::Eight => unimplemented!(), | ||||
|             BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), | ||||
|             _ => (BusWidth::One, 0), | ||||
|         }; | ||||
|         Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; | ||||
|         Self::cmd(Cmd::cmd6(acmd_arg), false)?; | ||||
|  | ||||
|         // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||||
|         Self::wait_idle(); | ||||
|  | ||||
|         regs.clkcr().modify(|w| { | ||||
|             w.set_widbus(match width { | ||||
|                 BusWidth::One => 0, | ||||
|                 BusWidth::Four => 1, | ||||
|                 BusWidth::Eight => 2, | ||||
|                 _ => panic!("Invalid Bus Width"), | ||||
|             }) | ||||
|         }); | ||||
|  | ||||
|         // Set Clock | ||||
|         if freq.0 <= 25_000_000 { | ||||
|             // Final clock frequency | ||||
|             self.clkcr_set_clkdiv(freq.0, width)?; | ||||
|         } else { | ||||
|             // Switch to max clock for SDR12 | ||||
|             self.clkcr_set_clkdiv(25_000_000, width)?; | ||||
|         } | ||||
|  | ||||
|         self.card = Some(card); | ||||
|  | ||||
|         // Read status | ||||
|         self.read_sd_status().await?; | ||||
|  | ||||
|         if freq.0 > 25_000_000 { | ||||
|             // Switch to SDR25 | ||||
|             self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; | ||||
|  | ||||
|             if self.signalling == Signalling::SDR25 { | ||||
|                 // Set final clock frequency | ||||
|                 self.clkcr_set_clkdiv(freq.0, width)?; | ||||
|  | ||||
|                 if self.read_status(&card)?.state() != CurrentState::Transfer { | ||||
|                     return Err(Error::SignalingSwitchFailed); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         // Read status after signalling change | ||||
|         self.read_sd_status().await?; | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
| @@ -1172,7 +1137,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|         Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 | ||||
|  | ||||
|         let regs = T::regs(); | ||||
|         let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | ||||
|         let on_drop = OnDrop::new(|| Self::on_drop()); | ||||
|  | ||||
|         let transfer = self.prepare_datapath_read(buffer, 512, 9); | ||||
|         InterruptHandler::<T>::data_interrupts(true); | ||||
| @@ -1180,7 +1145,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|  | ||||
|         let res = poll_fn(|cx| { | ||||
|             T::state().register(cx.waker()); | ||||
|             let status = unsafe { regs.star().read() }; | ||||
|             let status = regs.star().read(); | ||||
|  | ||||
|             if status.dcrcfail() { | ||||
|                 return Poll::Ready(Err(Error::Crc)); | ||||
| @@ -1217,7 +1182,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|         Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 | ||||
|  | ||||
|         let regs = T::regs(); | ||||
|         let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | ||||
|         let on_drop = OnDrop::new(|| Self::on_drop()); | ||||
|  | ||||
|         // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||||
|         #[cfg(sdmmc_v1)] | ||||
| @@ -1231,7 +1196,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
|  | ||||
|         let res = poll_fn(|cx| { | ||||
|             T::state().register(cx.waker()); | ||||
|             let status = unsafe { regs.star().read() }; | ||||
|             let status = regs.star().read(); | ||||
|  | ||||
|             if status.dcrcfail() { | ||||
|                 return Poll::Ready(Err(Error::Crc)); | ||||
| @@ -1289,9 +1254,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||||
| impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { | ||||
|     fn drop(&mut self) { | ||||
|         T::Interrupt::disable(); | ||||
|         unsafe { Self::on_drop() }; | ||||
|         Self::on_drop(); | ||||
|  | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             self.clk.set_as_disconnected(); | ||||
|             self.cmd.set_as_disconnected(); | ||||
|             self.d0.set_as_disconnected(); | ||||
|   | ||||
| @@ -98,14 +98,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|             Polarity::IdleHigh => Pull::Up, | ||||
|         }; | ||||
|  | ||||
|         unsafe { | ||||
|             sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode); | ||||
|             sck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|             mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); | ||||
|             mosi.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|             miso.set_as_af(miso.af_num(), AFType::Input); | ||||
|             miso.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         } | ||||
|         sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode); | ||||
|         sck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); | ||||
|         mosi.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         miso.set_as_af(miso.af_num(), AFType::Input); | ||||
|         miso.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|  | ||||
|         Self::new_inner( | ||||
|             peri, | ||||
| @@ -129,12 +127,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(sck, miso); | ||||
|         unsafe { | ||||
|             sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | ||||
|             sck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|             miso.set_as_af(miso.af_num(), AFType::Input); | ||||
|             miso.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         } | ||||
|         sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | ||||
|         sck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         miso.set_as_af(miso.af_num(), AFType::Input); | ||||
|         miso.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|  | ||||
|         Self::new_inner( | ||||
|             peri, | ||||
| @@ -158,12 +154,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(sck, mosi); | ||||
|         unsafe { | ||||
|             sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | ||||
|             sck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|             mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); | ||||
|             mosi.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         } | ||||
|         sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | ||||
|         sck.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|         mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); | ||||
|         mosi.set_speed(crate::gpio::Speed::VeryHigh); | ||||
|  | ||||
|         Self::new_inner( | ||||
|             peri, | ||||
| @@ -186,10 +180,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(mosi); | ||||
|         unsafe { | ||||
|             mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down); | ||||
|             mosi.set_speed(crate::gpio::Speed::Medium); | ||||
|         } | ||||
|         mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down); | ||||
|         mosi.set_speed(crate::gpio::Speed::Medium); | ||||
|  | ||||
|         Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config) | ||||
|     } | ||||
| @@ -247,7 +239,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         T::reset(); | ||||
|  | ||||
|         #[cfg(any(spi_v1, spi_f1))] | ||||
|         unsafe { | ||||
|         { | ||||
|             T::REGS.cr2().modify(|w| { | ||||
|                 w.set_ssoe(false); | ||||
|             }); | ||||
| @@ -270,7 +262,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|             }); | ||||
|         } | ||||
|         #[cfg(spi_v2)] | ||||
|         unsafe { | ||||
|         { | ||||
|             T::REGS.cr2().modify(|w| { | ||||
|                 let (ds, frxth) = <u8 as sealed::Word>::CONFIG; | ||||
|                 w.set_frxth(frxth); | ||||
| @@ -292,7 +284,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|             }); | ||||
|         } | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         unsafe { | ||||
|         { | ||||
|             T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); | ||||
|             T::REGS.cfg2().modify(|w| { | ||||
|                 //w.set_ssoe(true); | ||||
| @@ -343,29 +335,25 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         let lsbfirst = config.raw_byte_order(); | ||||
|  | ||||
|         #[cfg(any(spi_v1, spi_f1, spi_v2))] | ||||
|         unsafe { | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_cpha(cpha); | ||||
|                 w.set_cpol(cpol); | ||||
|                 w.set_lsbfirst(lsbfirst); | ||||
|             }); | ||||
|         } | ||||
|         T::REGS.cr1().modify(|w| { | ||||
|             w.set_cpha(cpha); | ||||
|             w.set_cpol(cpol); | ||||
|             w.set_lsbfirst(lsbfirst); | ||||
|         }); | ||||
|  | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         unsafe { | ||||
|             T::REGS.cfg2().modify(|w| { | ||||
|                 w.set_cpha(cpha); | ||||
|                 w.set_cpol(cpol); | ||||
|                 w.set_lsbfirst(lsbfirst); | ||||
|             }); | ||||
|         } | ||||
|         T::REGS.cfg2().modify(|w| { | ||||
|             w.set_cpha(cpha); | ||||
|             w.set_cpol(cpol); | ||||
|             w.set_lsbfirst(lsbfirst); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn get_current_config(&self) -> Config { | ||||
|         #[cfg(any(spi_v1, spi_f1, spi_v2))] | ||||
|         let cfg = unsafe { T::REGS.cr1().read() }; | ||||
|         let cfg = T::REGS.cr1().read(); | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         let cfg = unsafe { T::REGS.cfg2().read() }; | ||||
|         let cfg = T::REGS.cfg2().read(); | ||||
|         let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { | ||||
|             Polarity::IdleLow | ||||
|         } else { | ||||
| @@ -395,7 +383,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         } | ||||
|  | ||||
|         #[cfg(any(spi_v1, spi_f1))] | ||||
|         unsafe { | ||||
|         { | ||||
|             T::REGS.cr1().modify(|reg| { | ||||
|                 reg.set_spe(false); | ||||
|                 reg.set_dff(word_size) | ||||
| @@ -405,7 +393,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|             }); | ||||
|         } | ||||
|         #[cfg(spi_v2)] | ||||
|         unsafe { | ||||
|         { | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_spe(false); | ||||
|             }); | ||||
| @@ -418,7 +406,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|             }); | ||||
|         } | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         unsafe { | ||||
|         { | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_csusp(true); | ||||
|             }); | ||||
| @@ -447,26 +435,22 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         } | ||||
|  | ||||
|         self.set_word_size(W::CONFIG); | ||||
|         unsafe { | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_spe(false); | ||||
|             }); | ||||
|         } | ||||
|         T::REGS.cr1().modify(|w| { | ||||
|             w.set_spe(false); | ||||
|         }); | ||||
|  | ||||
|         let tx_request = self.txdma.request(); | ||||
|         let tx_dst = T::REGS.tx_ptr(); | ||||
|         let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; | ||||
|  | ||||
|         unsafe { | ||||
|             set_txdmaen(T::REGS, true); | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_spe(true); | ||||
|             }); | ||||
|             #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_cstart(true); | ||||
|             }); | ||||
|         } | ||||
|         set_txdmaen(T::REGS, true); | ||||
|         T::REGS.cr1().modify(|w| { | ||||
|             w.set_spe(true); | ||||
|         }); | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         T::REGS.cr1().modify(|w| { | ||||
|             w.set_cstart(true); | ||||
|         }); | ||||
|  | ||||
|         tx_f.await; | ||||
|  | ||||
| @@ -485,11 +469,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         } | ||||
|  | ||||
|         self.set_word_size(W::CONFIG); | ||||
|         unsafe { | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_spe(false); | ||||
|             }); | ||||
|         } | ||||
|         T::REGS.cr1().modify(|w| { | ||||
|             w.set_spe(false); | ||||
|         }); | ||||
|  | ||||
|         // SPIv3 clears rxfifo on SPE=0 | ||||
|         #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
| @@ -517,16 +499,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|             ) | ||||
|         }; | ||||
|  | ||||
|         unsafe { | ||||
|             set_txdmaen(T::REGS, true); | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_spe(true); | ||||
|             }); | ||||
|             #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_cstart(true); | ||||
|             }); | ||||
|         } | ||||
|         set_txdmaen(T::REGS, true); | ||||
|         T::REGS.cr1().modify(|w| { | ||||
|             w.set_spe(true); | ||||
|         }); | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         T::REGS.cr1().modify(|w| { | ||||
|             w.set_cstart(true); | ||||
|         }); | ||||
|  | ||||
|         join(tx_f, rx_f).await; | ||||
|  | ||||
| @@ -548,11 +528,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         } | ||||
|  | ||||
|         self.set_word_size(W::CONFIG); | ||||
|         unsafe { | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_spe(false); | ||||
|             }); | ||||
|         } | ||||
|         T::REGS.cr1().modify(|w| { | ||||
|             w.set_spe(false); | ||||
|         }); | ||||
|  | ||||
|         // SPIv3 clears rxfifo on SPE=0 | ||||
|         #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
| @@ -568,16 +546,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         let tx_dst = T::REGS.tx_ptr(); | ||||
|         let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) }; | ||||
|  | ||||
|         unsafe { | ||||
|             set_txdmaen(T::REGS, true); | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_spe(true); | ||||
|             }); | ||||
|             #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|             T::REGS.cr1().modify(|w| { | ||||
|                 w.set_cstart(true); | ||||
|             }); | ||||
|         } | ||||
|         set_txdmaen(T::REGS, true); | ||||
|         T::REGS.cr1().modify(|w| { | ||||
|             w.set_spe(true); | ||||
|         }); | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         T::REGS.cr1().modify(|w| { | ||||
|             w.set_cstart(true); | ||||
|         }); | ||||
|  | ||||
|         join(tx_f, rx_f).await; | ||||
|  | ||||
| @@ -603,7 +579,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { | ||||
|         unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } | ||||
|         T::REGS.cr1().modify(|w| w.set_spe(true)); | ||||
|         flush_rx_fifo(T::REGS); | ||||
|         self.set_word_size(W::CONFIG); | ||||
|         for word in words.iter() { | ||||
| @@ -613,7 +589,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { | ||||
|         unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } | ||||
|         T::REGS.cr1().modify(|w| w.set_spe(true)); | ||||
|         flush_rx_fifo(T::REGS); | ||||
|         self.set_word_size(W::CONFIG); | ||||
|         for word in words.iter_mut() { | ||||
| @@ -623,7 +599,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { | ||||
|         unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } | ||||
|         T::REGS.cr1().modify(|w| w.set_spe(true)); | ||||
|         flush_rx_fifo(T::REGS); | ||||
|         self.set_word_size(W::CONFIG); | ||||
|         for word in words.iter_mut() { | ||||
| @@ -633,7 +609,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { | ||||
|         unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } | ||||
|         T::REGS.cr1().modify(|w| w.set_spe(true)); | ||||
|         flush_rx_fifo(T::REGS); | ||||
|         self.set_word_size(W::CONFIG); | ||||
|         let len = read.len().max(write.len()); | ||||
| @@ -650,11 +626,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|  | ||||
| impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { | ||||
|     fn drop(&mut self) { | ||||
|         unsafe { | ||||
|             self.sck.as_ref().map(|x| x.set_as_disconnected()); | ||||
|             self.mosi.as_ref().map(|x| x.set_as_disconnected()); | ||||
|             self.miso.as_ref().map(|x| x.set_as_disconnected()); | ||||
|         } | ||||
|         self.sck.as_ref().map(|x| x.set_as_disconnected()); | ||||
|         self.mosi.as_ref().map(|x| x.set_as_disconnected()); | ||||
|         self.miso.as_ref().map(|x| x.set_as_disconnected()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -690,7 +664,7 @@ impl RegsExt for Regs { | ||||
|         let dr = self.dr(); | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         let dr = self.txdr(); | ||||
|         dr.ptr() as *mut W | ||||
|         dr.as_ptr() as *mut W | ||||
|     } | ||||
|  | ||||
|     fn rx_ptr<W>(&self) -> *mut W { | ||||
| @@ -698,7 +672,7 @@ impl RegsExt for Regs { | ||||
|         let dr = self.dr(); | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         let dr = self.rxdr(); | ||||
|         dr.ptr() as *mut W | ||||
|         dr.as_ptr() as *mut W | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -731,7 +705,7 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> { | ||||
|  | ||||
| fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { | ||||
|     loop { | ||||
|         let sr = unsafe { regs.sr().read() }; | ||||
|         let sr = regs.sr().read(); | ||||
|  | ||||
|         check_error_flags(sr)?; | ||||
|  | ||||
| @@ -748,7 +722,7 @@ fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { | ||||
|  | ||||
| fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { | ||||
|     loop { | ||||
|         let sr = unsafe { regs.sr().read() }; | ||||
|         let sr = regs.sr().read(); | ||||
|  | ||||
|         check_error_flags(sr)?; | ||||
|  | ||||
| @@ -764,72 +738,64 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { | ||||
| } | ||||
|  | ||||
| fn flush_rx_fifo(regs: Regs) { | ||||
|     unsafe { | ||||
|         #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
|         while regs.sr().read().rxne() { | ||||
|             let _ = regs.dr().read(); | ||||
|         } | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         while regs.sr().read().rxp() { | ||||
|             let _ = regs.rxdr().read(); | ||||
|         } | ||||
|     #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
|     while regs.sr().read().rxne() { | ||||
|         let _ = regs.dr().read(); | ||||
|     } | ||||
|     #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|     while regs.sr().read().rxp() { | ||||
|         let _ = regs.rxdr().read(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn set_txdmaen(regs: Regs, val: bool) { | ||||
|     unsafe { | ||||
|         #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
|         regs.cr2().modify(|reg| { | ||||
|             reg.set_txdmaen(val); | ||||
|         }); | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         regs.cfg1().modify(|reg| { | ||||
|             reg.set_txdmaen(val); | ||||
|         }); | ||||
|     } | ||||
|     #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
|     regs.cr2().modify(|reg| { | ||||
|         reg.set_txdmaen(val); | ||||
|     }); | ||||
|     #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|     regs.cfg1().modify(|reg| { | ||||
|         reg.set_txdmaen(val); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| fn set_rxdmaen(regs: Regs, val: bool) { | ||||
|     unsafe { | ||||
|         #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
|         regs.cr2().modify(|reg| { | ||||
|             reg.set_rxdmaen(val); | ||||
|         }); | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         regs.cfg1().modify(|reg| { | ||||
|             reg.set_rxdmaen(val); | ||||
|         }); | ||||
|     } | ||||
|     #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
|     regs.cr2().modify(|reg| { | ||||
|         reg.set_rxdmaen(val); | ||||
|     }); | ||||
|     #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|     regs.cfg1().modify(|reg| { | ||||
|         reg.set_rxdmaen(val); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| fn finish_dma(regs: Regs) { | ||||
|     unsafe { | ||||
|         #[cfg(spi_v2)] | ||||
|         while regs.sr().read().ftlvl() > 0 {} | ||||
|     #[cfg(spi_v2)] | ||||
|     while regs.sr().read().ftlvl() > 0 {} | ||||
|  | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         while !regs.sr().read().txc() {} | ||||
|         #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
|         while regs.sr().read().bsy() {} | ||||
|     #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|     while !regs.sr().read().txc() {} | ||||
|     #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
|     while regs.sr().read().bsy() {} | ||||
|  | ||||
|         // Disable the spi peripheral | ||||
|         regs.cr1().modify(|w| { | ||||
|             w.set_spe(false); | ||||
|         }); | ||||
|     // Disable the spi peripheral | ||||
|     regs.cr1().modify(|w| { | ||||
|         w.set_spe(false); | ||||
|     }); | ||||
|  | ||||
|         // The peripheral automatically disables the DMA stream on completion without error, | ||||
|         // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. | ||||
|         #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
|         regs.cr2().modify(|reg| { | ||||
|             reg.set_txdmaen(false); | ||||
|             reg.set_rxdmaen(false); | ||||
|         }); | ||||
|         #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|         regs.cfg1().modify(|reg| { | ||||
|             reg.set_txdmaen(false); | ||||
|             reg.set_rxdmaen(false); | ||||
|         }); | ||||
|     } | ||||
|     // The peripheral automatically disables the DMA stream on completion without error, | ||||
|     // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. | ||||
|     #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | ||||
|     regs.cr2().modify(|reg| { | ||||
|         reg.set_txdmaen(false); | ||||
|         reg.set_rxdmaen(false); | ||||
|     }); | ||||
|     #[cfg(any(spi_v3, spi_v4, spi_v5))] | ||||
|     regs.cfg1().modify(|reg| { | ||||
|         reg.set_txdmaen(false); | ||||
|         reg.set_rxdmaen(false); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> { | ||||
|   | ||||
| @@ -155,8 +155,7 @@ impl RtcDriver { | ||||
|  | ||||
|         let timer_freq = T::frequency(); | ||||
|  | ||||
|         // NOTE(unsafe) Critical section to use the unsafe methods | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             r.cr1().modify(|w| w.set_cen(false)); | ||||
|             r.cnt().write(|w| w.set_cnt(0)); | ||||
|  | ||||
| @@ -184,7 +183,7 @@ impl RtcDriver { | ||||
|             }); | ||||
|  | ||||
|             <T as BasicInstance>::Interrupt::unpend(); | ||||
|             <T as BasicInstance>::Interrupt::enable(); | ||||
|             unsafe { <T as BasicInstance>::Interrupt::enable() }; | ||||
|  | ||||
|             r.cr1().modify(|w| w.set_cen(true)); | ||||
|         }) | ||||
| @@ -193,9 +192,8 @@ impl RtcDriver { | ||||
|     fn on_interrupt(&self) { | ||||
|         let r = T::regs_gp16(); | ||||
|  | ||||
|         // NOTE(unsafe) Use critical section to access the methods | ||||
|         // XXX: reduce the size of this critical section ? | ||||
|         critical_section::with(|cs| unsafe { | ||||
|         critical_section::with(|cs| { | ||||
|             let sr = r.sr().read(); | ||||
|             let dier = r.dier().read(); | ||||
|  | ||||
| @@ -228,7 +226,7 @@ impl RtcDriver { | ||||
|         let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; | ||||
|         let t = (period as u64) << 15; | ||||
|  | ||||
|         critical_section::with(move |cs| unsafe { | ||||
|         critical_section::with(move |cs| { | ||||
|             r.dier().modify(move |w| { | ||||
|                 for n in 0..ALARM_COUNT { | ||||
|                     let alarm = &self.alarms.borrow(cs)[n]; | ||||
| @@ -269,8 +267,7 @@ impl Driver for RtcDriver { | ||||
|  | ||||
|         let period = self.period.load(Ordering::Relaxed); | ||||
|         compiler_fence(Ordering::Acquire); | ||||
|         // NOTE(unsafe) Atomic read with no side-effects | ||||
|         let counter = unsafe { r.cnt().read().cnt() }; | ||||
|         let counter = r.cnt().read().cnt(); | ||||
|         calc_now(period, counter) | ||||
|     } | ||||
|  | ||||
| @@ -310,7 +307,7 @@ impl Driver for RtcDriver { | ||||
|             if timestamp <= t { | ||||
|                 // If alarm timestamp has passed the alarm will not fire. | ||||
|                 // Disarm the alarm and return `false` to indicate that. | ||||
|                 unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) }; | ||||
|                 r.dier().modify(|w| w.set_ccie(n + 1, false)); | ||||
|  | ||||
|                 alarm.timestamp.set(u64::MAX); | ||||
|  | ||||
| @@ -321,12 +318,11 @@ impl Driver for RtcDriver { | ||||
|  | ||||
|             // Write the CCR value regardless of whether we're going to enable it now or not. | ||||
|             // This way, when we enable it later, the right value is already set. | ||||
|             unsafe { r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)) }; | ||||
|             r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)); | ||||
|  | ||||
|             // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. | ||||
|             let diff = timestamp - t; | ||||
|             // NOTE(unsafe) We're in a critical section | ||||
|             unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) }; | ||||
|             r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); | ||||
|  | ||||
|             true | ||||
|         }) | ||||
|   | ||||
| @@ -60,25 +60,19 @@ macro_rules! impl_basic_16bit_timer { | ||||
|             type Interrupt = crate::interrupt::typelevel::$irq; | ||||
|  | ||||
|             fn regs() -> crate::pac::timer::TimBasic { | ||||
|                 crate::pac::timer::TimBasic(crate::pac::$inst.0) | ||||
|                 unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) } | ||||
|             } | ||||
|  | ||||
|             fn start(&mut self) { | ||||
|                 unsafe { | ||||
|                     Self::regs().cr1().modify(|r| r.set_cen(true)); | ||||
|                 } | ||||
|                 Self::regs().cr1().modify(|r| r.set_cen(true)); | ||||
|             } | ||||
|  | ||||
|             fn stop(&mut self) { | ||||
|                 unsafe { | ||||
|                     Self::regs().cr1().modify(|r| r.set_cen(false)); | ||||
|                 } | ||||
|                 Self::regs().cr1().modify(|r| r.set_cen(false)); | ||||
|             } | ||||
|  | ||||
|             fn reset(&mut self) { | ||||
|                 unsafe { | ||||
|                     Self::regs().cnt().write(|r| r.set_cnt(0)); | ||||
|                 } | ||||
|                 Self::regs().cnt().write(|r| r.set_cnt(0)); | ||||
|             } | ||||
|  | ||||
|             fn set_frequency(&mut self, frequency: Hertz) { | ||||
| @@ -90,35 +84,29 @@ macro_rules! impl_basic_16bit_timer { | ||||
|                 let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); | ||||
|  | ||||
|                 let regs = Self::regs(); | ||||
|                 unsafe { | ||||
|                     regs.psc().write(|r| r.set_psc(psc)); | ||||
|                     regs.arr().write(|r| r.set_arr(arr)); | ||||
|                 regs.psc().write(|r| r.set_psc(psc)); | ||||
|                 regs.arr().write(|r| r.set_arr(arr)); | ||||
|  | ||||
|                     regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||||
|                     regs.egr().write(|r| r.set_ug(true)); | ||||
|                     regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||||
|                 } | ||||
|                 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||||
|                 regs.egr().write(|r| r.set_ug(true)); | ||||
|                 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||||
|             } | ||||
|  | ||||
|             fn clear_update_interrupt(&mut self) -> bool { | ||||
|                 let regs = Self::regs(); | ||||
|                 unsafe { | ||||
|                     let sr = regs.sr().read(); | ||||
|                     if sr.uif() { | ||||
|                         regs.sr().modify(|r| { | ||||
|                             r.set_uif(false); | ||||
|                         }); | ||||
|                         true | ||||
|                     } else { | ||||
|                         false | ||||
|                     } | ||||
|                 let sr = regs.sr().read(); | ||||
|                 if sr.uif() { | ||||
|                     regs.sr().modify(|r| { | ||||
|                         r.set_uif(false); | ||||
|                     }); | ||||
|                     true | ||||
|                 } else { | ||||
|                     false | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             fn enable_update_interrupt(&mut self, enable: bool) { | ||||
|                 unsafe { | ||||
|                     Self::regs().dier().write(|r| r.set_uie(enable)); | ||||
|                 } | ||||
|                 Self::regs().dier().write(|r| r.set_uie(enable)); | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| @@ -141,14 +129,12 @@ macro_rules! impl_32bit_timer { | ||||
|                 let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into())); | ||||
|  | ||||
|                 let regs = Self::regs_gp32(); | ||||
|                 unsafe { | ||||
|                     regs.psc().write(|r| r.set_psc(psc)); | ||||
|                     regs.arr().write(|r| r.set_arr(arr)); | ||||
|                 regs.psc().write(|r| r.set_psc(psc)); | ||||
|                 regs.arr().write(|r| r.set_arr(arr)); | ||||
|  | ||||
|                     regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||||
|                     regs.egr().write(|r| r.set_ug(true)); | ||||
|                     regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||||
|                 } | ||||
|                 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | ||||
|                 regs.egr().write(|r| r.set_ug(true)); | ||||
|                 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| @@ -185,7 +171,7 @@ foreach_interrupt! { | ||||
|  | ||||
|         impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { | ||||
|             fn regs_gp16() -> crate::pac::timer::TimGp16 { | ||||
|                 crate::pac::timer::TimGp16(crate::pac::$inst.0) | ||||
|                 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -206,7 +192,7 @@ foreach_interrupt! { | ||||
|  | ||||
|         impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { | ||||
|             fn regs_gp16() -> crate::pac::timer::TimGp16 { | ||||
|                 crate::pac::timer::TimGp16(crate::pac::$inst.0) | ||||
|                 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -19,68 +19,64 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | ||||
|         let state = T::buffered_state(); | ||||
|  | ||||
|         // RX | ||||
|         unsafe { | ||||
|             let sr = sr(r).read(); | ||||
|             // On v1 & v2, reading DR clears the rxne, error and idle interrupt | ||||
|             // flags. Keep this close to the SR read to reduce the chance of a | ||||
|             // flag being set in-between. | ||||
|             let dr = if sr.rxne() || cfg!(any(usart_v1, usart_v2)) && (sr.ore() || sr.idle()) { | ||||
|                 Some(rdr(r).read_volatile()) | ||||
|         let sr_val = sr(r).read(); | ||||
|         // On v1 & v2, reading DR clears the rxne, error and idle interrupt | ||||
|         // flags. Keep this close to the SR read to reduce the chance of a | ||||
|         // flag being set in-between. | ||||
|         let dr = if sr_val.rxne() || cfg!(any(usart_v1, usart_v2)) && (sr_val.ore() || sr_val.idle()) { | ||||
|             Some(rdr(r).read_volatile()) | ||||
|         } else { | ||||
|             None | ||||
|         }; | ||||
|         clear_interrupt_flags(r, sr_val); | ||||
|  | ||||
|         if sr_val.pe() { | ||||
|             warn!("Parity error"); | ||||
|         } | ||||
|         if sr_val.fe() { | ||||
|             warn!("Framing error"); | ||||
|         } | ||||
|         if sr_val.ne() { | ||||
|             warn!("Noise error"); | ||||
|         } | ||||
|         if sr_val.ore() { | ||||
|             warn!("Overrun error"); | ||||
|         } | ||||
|         if sr_val.rxne() { | ||||
|             let mut rx_writer = state.rx_buf.writer(); | ||||
|             let buf = rx_writer.push_slice(); | ||||
|             if !buf.is_empty() { | ||||
|                 buf[0] = dr.unwrap(); | ||||
|                 rx_writer.push_done(1); | ||||
|             } else { | ||||
|                 None | ||||
|             }; | ||||
|             clear_interrupt_flags(r, sr); | ||||
|  | ||||
|             if sr.pe() { | ||||
|                 warn!("Parity error"); | ||||
|             } | ||||
|             if sr.fe() { | ||||
|                 warn!("Framing error"); | ||||
|             } | ||||
|             if sr.ne() { | ||||
|                 warn!("Noise error"); | ||||
|             } | ||||
|             if sr.ore() { | ||||
|                 warn!("Overrun error"); | ||||
|             } | ||||
|             if sr.rxne() { | ||||
|                 let mut rx_writer = state.rx_buf.writer(); | ||||
|                 let buf = rx_writer.push_slice(); | ||||
|                 if !buf.is_empty() { | ||||
|                     buf[0] = dr.unwrap(); | ||||
|                     rx_writer.push_done(1); | ||||
|                 } else { | ||||
|                     // FIXME: Should we disable any further RX interrupts when the buffer becomes full. | ||||
|                 } | ||||
|  | ||||
|                 if state.rx_buf.is_full() { | ||||
|                     state.rx_waker.wake(); | ||||
|                 } | ||||
|                 // FIXME: Should we disable any further RX interrupts when the buffer becomes full. | ||||
|             } | ||||
|  | ||||
|             if sr.idle() { | ||||
|             if state.rx_buf.is_full() { | ||||
|                 state.rx_waker.wake(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if sr_val.idle() { | ||||
|             state.rx_waker.wake(); | ||||
|         } | ||||
|  | ||||
|         // TX | ||||
|         unsafe { | ||||
|             if sr(r).read().txe() { | ||||
|                 let mut tx_reader = state.tx_buf.reader(); | ||||
|                 let buf = tx_reader.pop_slice(); | ||||
|                 if !buf.is_empty() { | ||||
|                     r.cr1().modify(|w| { | ||||
|                         w.set_txeie(true); | ||||
|                     }); | ||||
|                     tdr(r).write_volatile(buf[0].into()); | ||||
|                     tx_reader.pop_done(1); | ||||
|                     state.tx_waker.wake(); | ||||
|                 } else { | ||||
|                     // Disable interrupt until we have something to transmit again | ||||
|                     r.cr1().modify(|w| { | ||||
|                         w.set_txeie(false); | ||||
|                     }); | ||||
|                 } | ||||
|         if sr(r).read().txe() { | ||||
|             let mut tx_reader = state.tx_buf.reader(); | ||||
|             let buf = tx_reader.pop_slice(); | ||||
|             if !buf.is_empty() { | ||||
|                 r.cr1().modify(|w| { | ||||
|                     w.set_txeie(true); | ||||
|                 }); | ||||
|                 tdr(r).write_volatile(buf[0].into()); | ||||
|                 tx_reader.pop_done(1); | ||||
|                 state.tx_waker.wake(); | ||||
|             } else { | ||||
|                 // Disable interrupt until we have something to transmit again | ||||
|                 r.cr1().modify(|w| { | ||||
|                     w.set_txeie(false); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -150,14 +146,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
|  | ||||
|         unsafe { | ||||
|             rts.set_as_af(rts.af_num(), AFType::OutputPushPull); | ||||
|             cts.set_as_af(cts.af_num(), AFType::Input); | ||||
|             T::regs().cr3().write(|w| { | ||||
|                 w.set_rtse(true); | ||||
|                 w.set_ctse(true); | ||||
|             }); | ||||
|         } | ||||
|         rts.set_as_af(rts.af_num(), AFType::OutputPushPull); | ||||
|         cts.set_as_af(cts.af_num(), AFType::Input); | ||||
|         T::regs().cr3().write(|w| { | ||||
|             w.set_rtse(true); | ||||
|             w.set_ctse(true); | ||||
|         }); | ||||
|  | ||||
|         Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) | ||||
|     } | ||||
| @@ -178,12 +172,10 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
|  | ||||
|         unsafe { | ||||
|             de.set_as_af(de.af_num(), AFType::OutputPushPull); | ||||
|             T::regs().cr3().write(|w| { | ||||
|                 w.set_dem(true); | ||||
|             }); | ||||
|         } | ||||
|         de.set_as_af(de.af_num(), AFType::OutputPushPull); | ||||
|         T::regs().cr3().write(|w| { | ||||
|             w.set_dem(true); | ||||
|         }); | ||||
|  | ||||
|         Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) | ||||
|     } | ||||
| @@ -205,22 +197,18 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | ||||
|         unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; | ||||
|  | ||||
|         let r = T::regs(); | ||||
|         unsafe { | ||||
|             rx.set_as_af(rx.af_num(), AFType::Input); | ||||
|             tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||
|         } | ||||
|         rx.set_as_af(rx.af_num(), AFType::Input); | ||||
|         tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||
|  | ||||
|         configure(r, &config, T::frequency(), T::KIND, true, true); | ||||
|  | ||||
|         unsafe { | ||||
|             r.cr1().modify(|w| { | ||||
|                 #[cfg(lpuart_v2)] | ||||
|                 w.set_fifoen(true); | ||||
|         r.cr1().modify(|w| { | ||||
|             #[cfg(lpuart_v2)] | ||||
|             w.set_fifoen(true); | ||||
|  | ||||
|                 w.set_rxneie(true); | ||||
|                 w.set_idleie(true); | ||||
|             }); | ||||
|         } | ||||
|             w.set_rxneie(true); | ||||
|             w.set_idleie(true); | ||||
|         }); | ||||
|  | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
|   | ||||
| @@ -36,35 +36,31 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; | ||||
|         let (sr, cr1, cr3) = (sr(r).read(), r.cr1().read(), r.cr3().read()); | ||||
|  | ||||
|         let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); | ||||
|         if has_errors { | ||||
|             // clear all interrupts and DMA Rx Request | ||||
|             unsafe { | ||||
|                 r.cr1().modify(|w| { | ||||
|                     // disable RXNE interrupt | ||||
|                     w.set_rxneie(false); | ||||
|                     // disable parity interrupt | ||||
|                     w.set_peie(false); | ||||
|                     // disable idle line interrupt | ||||
|                     w.set_idleie(false); | ||||
|                 }); | ||||
|                 r.cr3().modify(|w| { | ||||
|                     // disable Error Interrupt: (Frame error, Noise error, Overrun error) | ||||
|                     w.set_eie(false); | ||||
|                     // disable DMA Rx Request | ||||
|                     w.set_dmar(false); | ||||
|                 }); | ||||
|             } | ||||
|             r.cr1().modify(|w| { | ||||
|                 // disable RXNE interrupt | ||||
|                 w.set_rxneie(false); | ||||
|                 // disable parity interrupt | ||||
|                 w.set_peie(false); | ||||
|                 // disable idle line interrupt | ||||
|                 w.set_idleie(false); | ||||
|             }); | ||||
|             r.cr3().modify(|w| { | ||||
|                 // disable Error Interrupt: (Frame error, Noise error, Overrun error) | ||||
|                 w.set_eie(false); | ||||
|                 // disable DMA Rx Request | ||||
|                 w.set_dmar(false); | ||||
|             }); | ||||
|         } else if cr1.idleie() && sr.idle() { | ||||
|             // IDLE detected: no more data will come | ||||
|             unsafe { | ||||
|                 r.cr1().modify(|w| { | ||||
|                     // disable idle line detection | ||||
|                     w.set_idleie(false); | ||||
|                 }); | ||||
|             } | ||||
|             r.cr1().modify(|w| { | ||||
|                 // disable idle line detection | ||||
|                 w.set_idleie(false); | ||||
|             }); | ||||
|         } else if cr1.rxneie() { | ||||
|             // We cannot check the RXNE flag as it is auto-cleared by the DMA controller | ||||
|  | ||||
| @@ -205,12 +201,10 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
|  | ||||
|         unsafe { | ||||
|             cts.set_as_af(cts.af_num(), AFType::Input); | ||||
|             T::regs().cr3().write(|w| { | ||||
|                 w.set_ctse(true); | ||||
|             }); | ||||
|         } | ||||
|         cts.set_as_af(cts.af_num(), AFType::Input); | ||||
|         T::regs().cr3().write(|w| { | ||||
|             w.set_ctse(true); | ||||
|         }); | ||||
|         Self::new_inner(peri, tx, tx_dma, config) | ||||
|     } | ||||
|  | ||||
| @@ -224,9 +218,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         unsafe { | ||||
|             tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||
|         } | ||||
|         tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||
|  | ||||
|         configure(r, &config, T::frequency(), T::KIND, false, true); | ||||
|  | ||||
| @@ -245,11 +237,9 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | ||||
|     { | ||||
|         let ch = &mut self.tx_dma; | ||||
|         let request = ch.request(); | ||||
|         unsafe { | ||||
|             T::regs().cr3().modify(|reg| { | ||||
|                 reg.set_dmat(true); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().cr3().modify(|reg| { | ||||
|             reg.set_dmat(true); | ||||
|         }); | ||||
|         // If we don't assign future to a variable, the data register pointer | ||||
|         // is held across an await and makes the future non-Send. | ||||
|         let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) }; | ||||
| @@ -258,21 +248,17 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||||
|         unsafe { | ||||
|             let r = T::regs(); | ||||
|             for &b in buffer { | ||||
|                 while !sr(r).read().txe() {} | ||||
|                 tdr(r).write_volatile(b); | ||||
|             } | ||||
|         let r = T::regs(); | ||||
|         for &b in buffer { | ||||
|             while !sr(r).read().txe() {} | ||||
|             unsafe { tdr(r).write_volatile(b) }; | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_flush(&mut self) -> Result<(), Error> { | ||||
|         unsafe { | ||||
|             let r = T::regs(); | ||||
|             while !sr(r).read().tc() {} | ||||
|         } | ||||
|         let r = T::regs(); | ||||
|         while !sr(r).read().tc() {} | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| @@ -305,12 +291,10 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
|  | ||||
|         unsafe { | ||||
|             rts.set_as_af(rts.af_num(), AFType::OutputPushPull); | ||||
|             T::regs().cr3().write(|w| { | ||||
|                 w.set_rtse(true); | ||||
|             }); | ||||
|         } | ||||
|         rts.set_as_af(rts.af_num(), AFType::OutputPushPull); | ||||
|         T::regs().cr3().write(|w| { | ||||
|             w.set_rtse(true); | ||||
|         }); | ||||
|  | ||||
|         Self::new_inner(peri, rx, rx_dma, config) | ||||
|     } | ||||
| @@ -325,9 +309,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         unsafe { | ||||
|             rx.set_as_af(rx.af_num(), AFType::Input); | ||||
|         } | ||||
|         rx.set_as_af(rx.af_num(), AFType::Input); | ||||
|  | ||||
|         configure(r, &config, T::frequency(), T::KIND, true, false); | ||||
|  | ||||
| @@ -347,7 +329,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | ||||
|     } | ||||
|  | ||||
|     #[cfg(any(usart_v1, usart_v2))] | ||||
|     unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> { | ||||
|     fn check_rx_flags(&mut self) -> Result<bool, Error> { | ||||
|         let r = T::regs(); | ||||
|         loop { | ||||
|             // Handle all buffered error flags. | ||||
| @@ -380,7 +362,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | ||||
|     } | ||||
|  | ||||
|     #[cfg(any(usart_v3, usart_v4))] | ||||
|     unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> { | ||||
|     fn check_rx_flags(&mut self) -> Result<bool, Error> { | ||||
|         let r = T::regs(); | ||||
|         let sr = r.isr().read(); | ||||
|         if sr.pe() { | ||||
| @@ -410,22 +392,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | ||||
|  | ||||
|     pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { | ||||
|         let r = T::regs(); | ||||
|         unsafe { | ||||
|             if self.check_rx_flags()? { | ||||
|                 Ok(rdr(r).read_volatile()) | ||||
|             } else { | ||||
|                 Err(nb::Error::WouldBlock) | ||||
|             } | ||||
|         if self.check_rx_flags()? { | ||||
|             Ok(unsafe { rdr(r).read_volatile() }) | ||||
|         } else { | ||||
|             Err(nb::Error::WouldBlock) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||||
|         unsafe { | ||||
|             let r = T::regs(); | ||||
|             for b in buffer { | ||||
|                 while !self.check_rx_flags()? {} | ||||
|                 *b = rdr(r).read_volatile(); | ||||
|             } | ||||
|         let r = T::regs(); | ||||
|         for b in buffer { | ||||
|             while !self.check_rx_flags()? {} | ||||
|             unsafe { *b = rdr(r).read_volatile() } | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| @@ -451,23 +429,20 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | ||||
|         let on_drop = OnDrop::new(move || { | ||||
|             // defmt::trace!("Clear all USART interrupts and DMA Read Request"); | ||||
|             // clear all interrupts and DMA Rx Request | ||||
|             // SAFETY: only clears Rx related flags | ||||
|             unsafe { | ||||
|                 r.cr1().modify(|w| { | ||||
|                     // disable RXNE interrupt | ||||
|                     w.set_rxneie(false); | ||||
|                     // disable parity interrupt | ||||
|                     w.set_peie(false); | ||||
|                     // disable idle line interrupt | ||||
|                     w.set_idleie(false); | ||||
|                 }); | ||||
|                 r.cr3().modify(|w| { | ||||
|                     // disable Error Interrupt: (Frame error, Noise error, Overrun error) | ||||
|                     w.set_eie(false); | ||||
|                     // disable DMA Rx Request | ||||
|                     w.set_dmar(false); | ||||
|                 }); | ||||
|             } | ||||
|             r.cr1().modify(|w| { | ||||
|                 // disable RXNE interrupt | ||||
|                 w.set_rxneie(false); | ||||
|                 // disable parity interrupt | ||||
|                 w.set_peie(false); | ||||
|                 // disable idle line interrupt | ||||
|                 w.set_idleie(false); | ||||
|             }); | ||||
|             r.cr3().modify(|w| { | ||||
|                 // disable Error Interrupt: (Frame error, Noise error, Overrun error) | ||||
|                 w.set_eie(false); | ||||
|                 // disable DMA Rx Request | ||||
|                 w.set_dmar(false); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         let ch = &mut self.rx_dma; | ||||
| @@ -480,78 +455,74 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | ||||
|         // future which will complete when DMA Read request completes | ||||
|         let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) }; | ||||
|  | ||||
|         // SAFETY: The only way we might have a problem is using split rx and tx | ||||
|         // here we only modify or read Rx related flags, interrupts and DMA channel | ||||
|         unsafe { | ||||
|             // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer | ||||
|             if !self.detect_previous_overrun { | ||||
|                 let sr = sr(r).read(); | ||||
|                 // This read also clears the error and idle interrupt flags on v1. | ||||
|                 rdr(r).read_volatile(); | ||||
|                 clear_interrupt_flags(r, sr); | ||||
|         // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer | ||||
|         if !self.detect_previous_overrun { | ||||
|             let sr = sr(r).read(); | ||||
|             // This read also clears the error and idle interrupt flags on v1. | ||||
|             unsafe { rdr(r).read_volatile() }; | ||||
|             clear_interrupt_flags(r, sr); | ||||
|         } | ||||
|  | ||||
|         r.cr1().modify(|w| { | ||||
|             // disable RXNE interrupt | ||||
|             w.set_rxneie(false); | ||||
|             // enable parity interrupt if not ParityNone | ||||
|             w.set_peie(w.pce()); | ||||
|         }); | ||||
|  | ||||
|         r.cr3().modify(|w| { | ||||
|             // enable Error Interrupt: (Frame error, Noise error, Overrun error) | ||||
|             w.set_eie(true); | ||||
|             // enable DMA Rx Request | ||||
|             w.set_dmar(true); | ||||
|         }); | ||||
|  | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|  | ||||
|         // In case of errors already pending when reception started, interrupts may have already been raised | ||||
|         // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts | ||||
|         // have been disabled in interrupt handler and DMA Rx Request has been disabled. | ||||
|  | ||||
|         let cr3 = r.cr3().read(); | ||||
|  | ||||
|         if !cr3.dmar() { | ||||
|             // something went wrong | ||||
|             // because the only way to get this flag cleared is to have an interrupt | ||||
|  | ||||
|             // DMA will be stopped when transfer is dropped | ||||
|  | ||||
|             let sr = sr(r).read(); | ||||
|             // This read also clears the error and idle interrupt flags on v1. | ||||
|             unsafe { rdr(r).read_volatile() }; | ||||
|             clear_interrupt_flags(r, sr); | ||||
|  | ||||
|             if sr.pe() { | ||||
|                 return Err(Error::Parity); | ||||
|             } | ||||
|             if sr.fe() { | ||||
|                 return Err(Error::Framing); | ||||
|             } | ||||
|             if sr.ne() { | ||||
|                 return Err(Error::Noise); | ||||
|             } | ||||
|             if sr.ore() { | ||||
|                 return Err(Error::Overrun); | ||||
|             } | ||||
|  | ||||
|             unreachable!(); | ||||
|         } | ||||
|  | ||||
|         if enable_idle_line_detection { | ||||
|             // clear idle flag | ||||
|             let sr = sr(r).read(); | ||||
|             // This read also clears the error and idle interrupt flags on v1. | ||||
|             unsafe { rdr(r).read_volatile() }; | ||||
|             clear_interrupt_flags(r, sr); | ||||
|  | ||||
|             // enable idle interrupt | ||||
|             r.cr1().modify(|w| { | ||||
|                 // disable RXNE interrupt | ||||
|                 w.set_rxneie(false); | ||||
|                 // enable parity interrupt if not ParityNone | ||||
|                 w.set_peie(w.pce()); | ||||
|                 w.set_idleie(true); | ||||
|             }); | ||||
|  | ||||
|             r.cr3().modify(|w| { | ||||
|                 // enable Error Interrupt: (Frame error, Noise error, Overrun error) | ||||
|                 w.set_eie(true); | ||||
|                 // enable DMA Rx Request | ||||
|                 w.set_dmar(true); | ||||
|             }); | ||||
|  | ||||
|             compiler_fence(Ordering::SeqCst); | ||||
|  | ||||
|             // In case of errors already pending when reception started, interrupts may have already been raised | ||||
|             // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts | ||||
|             // have been disabled in interrupt handler and DMA Rx Request has been disabled. | ||||
|  | ||||
|             let cr3 = r.cr3().read(); | ||||
|  | ||||
|             if !cr3.dmar() { | ||||
|                 // something went wrong | ||||
|                 // because the only way to get this flag cleared is to have an interrupt | ||||
|  | ||||
|                 // DMA will be stopped when transfer is dropped | ||||
|  | ||||
|                 let sr = sr(r).read(); | ||||
|                 // This read also clears the error and idle interrupt flags on v1. | ||||
|                 rdr(r).read_volatile(); | ||||
|                 clear_interrupt_flags(r, sr); | ||||
|  | ||||
|                 if sr.pe() { | ||||
|                     return Err(Error::Parity); | ||||
|                 } | ||||
|                 if sr.fe() { | ||||
|                     return Err(Error::Framing); | ||||
|                 } | ||||
|                 if sr.ne() { | ||||
|                     return Err(Error::Noise); | ||||
|                 } | ||||
|                 if sr.ore() { | ||||
|                     return Err(Error::Overrun); | ||||
|                 } | ||||
|  | ||||
|                 unreachable!(); | ||||
|             } | ||||
|  | ||||
|             if enable_idle_line_detection { | ||||
|                 // clear idle flag | ||||
|                 let sr = sr(r).read(); | ||||
|                 // This read also clears the error and idle interrupt flags on v1. | ||||
|                 rdr(r).read_volatile(); | ||||
|                 clear_interrupt_flags(r, sr); | ||||
|  | ||||
|                 // enable idle interrupt | ||||
|                 r.cr1().modify(|w| { | ||||
|                     w.set_idleie(true); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
| @@ -562,15 +533,11 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | ||||
|  | ||||
|             s.rx_waker.register(cx.waker()); | ||||
|  | ||||
|             // SAFETY: read only and we only use Rx related flags | ||||
|             let sr = unsafe { sr(r).read() }; | ||||
|             let sr = sr(r).read(); | ||||
|  | ||||
|             // SAFETY: only clears Rx related flags | ||||
|             unsafe { | ||||
|                 // This read also clears the error and idle interrupt flags on v1. | ||||
|                 rdr(r).read_volatile(); | ||||
|                 clear_interrupt_flags(r, sr); | ||||
|             } | ||||
|             // This read also clears the error and idle interrupt flags on v1. | ||||
|             unsafe { rdr(r).read_volatile() }; | ||||
|             clear_interrupt_flags(r, sr); | ||||
|  | ||||
|             compiler_fence(Ordering::SeqCst); | ||||
|  | ||||
| @@ -677,14 +644,12 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
|  | ||||
|         unsafe { | ||||
|             rts.set_as_af(rts.af_num(), AFType::OutputPushPull); | ||||
|             cts.set_as_af(cts.af_num(), AFType::Input); | ||||
|             T::regs().cr3().write(|w| { | ||||
|                 w.set_rtse(true); | ||||
|                 w.set_ctse(true); | ||||
|             }); | ||||
|         } | ||||
|         rts.set_as_af(rts.af_num(), AFType::OutputPushPull); | ||||
|         cts.set_as_af(cts.af_num(), AFType::Input); | ||||
|         T::regs().cr3().write(|w| { | ||||
|             w.set_rtse(true); | ||||
|             w.set_ctse(true); | ||||
|         }); | ||||
|         Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) | ||||
|     } | ||||
|  | ||||
| @@ -704,12 +669,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | ||||
|         T::enable(); | ||||
|         T::reset(); | ||||
|  | ||||
|         unsafe { | ||||
|             de.set_as_af(de.af_num(), AFType::OutputPushPull); | ||||
|             T::regs().cr3().write(|w| { | ||||
|                 w.set_dem(true); | ||||
|             }); | ||||
|         } | ||||
|         de.set_as_af(de.af_num(), AFType::OutputPushPull); | ||||
|         T::regs().cr3().write(|w| { | ||||
|             w.set_dem(true); | ||||
|         }); | ||||
|         Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) | ||||
|     } | ||||
|  | ||||
| @@ -725,10 +688,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         unsafe { | ||||
|             rx.set_as_af(rx.af_num(), AFType::Input); | ||||
|             tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||
|         } | ||||
|         rx.set_as_af(rx.af_num(), AFType::Input); | ||||
|         tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||
|  | ||||
|         configure(r, &config, T::frequency(), T::KIND, true, true); | ||||
|  | ||||
| @@ -847,11 +808,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | ||||
|             if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { | ||||
|                 over8 = true; | ||||
|                 let div = div as u32; | ||||
|                 unsafe { | ||||
|                     r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07))); | ||||
|                     #[cfg(usart_v4)] | ||||
|                     r.presc().write(|w| w.set_prescaler(_presc_val)); | ||||
|                 } | ||||
|                 r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07))); | ||||
|                 #[cfg(usart_v4)] | ||||
|                 r.presc().write(|w| w.set_prescaler(_presc_val)); | ||||
|                 found = Some(div); | ||||
|                 break; | ||||
|             } | ||||
| @@ -860,11 +819,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | ||||
|  | ||||
|         if div < brr_max { | ||||
|             let div = div as u32; | ||||
|             unsafe { | ||||
|                 r.brr().write_value(regs::Brr(div)); | ||||
|                 #[cfg(usart_v4)] | ||||
|                 r.presc().write(|w| w.set_prescaler(_presc_val)); | ||||
|             } | ||||
|             r.brr().write_value(regs::Brr(div)); | ||||
|             #[cfg(usart_v4)] | ||||
|             r.presc().write(|w| w.set_prescaler(_presc_val)); | ||||
|             found = Some(div); | ||||
|             break; | ||||
|         } | ||||
| @@ -883,44 +840,42 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | ||||
|         pclk_freq.0 / div | ||||
|     ); | ||||
|  | ||||
|     unsafe { | ||||
|         r.cr2().write(|w| { | ||||
|             w.set_stop(match config.stop_bits { | ||||
|                 StopBits::STOP0P5 => vals::Stop::STOP0P5, | ||||
|                 StopBits::STOP1 => vals::Stop::STOP1, | ||||
|                 StopBits::STOP1P5 => vals::Stop::STOP1P5, | ||||
|                 StopBits::STOP2 => vals::Stop::STOP2, | ||||
|             }); | ||||
|     r.cr2().write(|w| { | ||||
|         w.set_stop(match config.stop_bits { | ||||
|             StopBits::STOP0P5 => vals::Stop::STOP0P5, | ||||
|             StopBits::STOP1 => vals::Stop::STOP1, | ||||
|             StopBits::STOP1P5 => vals::Stop::STOP1P5, | ||||
|             StopBits::STOP2 => vals::Stop::STOP2, | ||||
|         }); | ||||
|         r.cr1().write(|w| { | ||||
|             // enable uart | ||||
|             w.set_ue(true); | ||||
|             // enable transceiver | ||||
|             w.set_te(enable_tx); | ||||
|             // enable receiver | ||||
|             w.set_re(enable_rx); | ||||
|             // configure word size | ||||
|             w.set_m0(if config.parity != Parity::ParityNone { | ||||
|                 vals::M0::BIT9 | ||||
|             } else { | ||||
|                 vals::M0::BIT8 | ||||
|             }); | ||||
|             // configure parity | ||||
|             w.set_pce(config.parity != Parity::ParityNone); | ||||
|             w.set_ps(match config.parity { | ||||
|                 Parity::ParityOdd => vals::Ps::ODD, | ||||
|                 Parity::ParityEven => vals::Ps::EVEN, | ||||
|                 _ => vals::Ps::EVEN, | ||||
|             }); | ||||
|             #[cfg(not(usart_v1))] | ||||
|             w.set_over8(vals::Over8(over8 as _)); | ||||
|     }); | ||||
|     r.cr1().write(|w| { | ||||
|         // enable uart | ||||
|         w.set_ue(true); | ||||
|         // enable transceiver | ||||
|         w.set_te(enable_tx); | ||||
|         // enable receiver | ||||
|         w.set_re(enable_rx); | ||||
|         // configure word size | ||||
|         w.set_m0(if config.parity != Parity::ParityNone { | ||||
|             vals::M0::BIT9 | ||||
|         } else { | ||||
|             vals::M0::BIT8 | ||||
|         }); | ||||
|         // configure parity | ||||
|         w.set_pce(config.parity != Parity::ParityNone); | ||||
|         w.set_ps(match config.parity { | ||||
|             Parity::ParityOdd => vals::Ps::ODD, | ||||
|             Parity::ParityEven => vals::Ps::EVEN, | ||||
|             _ => vals::Ps::EVEN, | ||||
|         }); | ||||
|  | ||||
|         #[cfg(not(usart_v1))] | ||||
|         r.cr3().modify(|w| { | ||||
|             w.set_onebit(config.assume_noise_free); | ||||
|         }); | ||||
|     } | ||||
|         w.set_over8(vals::Over8(over8 as _)); | ||||
|     }); | ||||
|  | ||||
|     #[cfg(not(usart_v1))] | ||||
|     r.cr3().modify(|w| { | ||||
|         w.set_onebit(config.assume_noise_free); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| mod eh02 { | ||||
| @@ -1111,12 +1066,12 @@ use self::sealed::Kind; | ||||
|  | ||||
| #[cfg(any(usart_v1, usart_v2))] | ||||
| fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { | ||||
|     r.dr().ptr() as _ | ||||
|     r.dr().as_ptr() as _ | ||||
| } | ||||
|  | ||||
| #[cfg(any(usart_v1, usart_v2))] | ||||
| fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { | ||||
|     r.dr().ptr() as _ | ||||
|     r.dr().as_ptr() as _ | ||||
| } | ||||
|  | ||||
| #[cfg(any(usart_v1, usart_v2))] | ||||
| @@ -1126,18 +1081,18 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::p | ||||
|  | ||||
| #[cfg(any(usart_v1, usart_v2))] | ||||
| #[allow(unused)] | ||||
| unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) { | ||||
| fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) { | ||||
|     // On v1 the flags are cleared implicitly by reads and writes to DR. | ||||
| } | ||||
|  | ||||
| #[cfg(any(usart_v3, usart_v4))] | ||||
| fn tdr(r: Regs) -> *mut u8 { | ||||
|     r.tdr().ptr() as _ | ||||
|     r.tdr().as_ptr() as _ | ||||
| } | ||||
|  | ||||
| #[cfg(any(usart_v3, usart_v4))] | ||||
| fn rdr(r: Regs) -> *mut u8 { | ||||
|     r.rdr().ptr() as _ | ||||
|     r.rdr().as_ptr() as _ | ||||
| } | ||||
|  | ||||
| #[cfg(any(usart_v3, usart_v4))] | ||||
| @@ -1147,7 +1102,7 @@ fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> { | ||||
|  | ||||
| #[cfg(any(usart_v3, usart_v4))] | ||||
| #[allow(unused)] | ||||
| unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { | ||||
| fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { | ||||
|     r.icr().write(|w| *w = regs::Icr(sr.0)); | ||||
| } | ||||
|  | ||||
| @@ -1214,7 +1169,7 @@ macro_rules! impl_usart { | ||||
|             type Interrupt = crate::interrupt::typelevel::$irq; | ||||
|  | ||||
|             fn regs() -> Regs { | ||||
|                 Regs(crate::pac::$inst.0) | ||||
|                 unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) } | ||||
|             } | ||||
|  | ||||
|             fn state() -> &'static crate::usart::sealed::State { | ||||
|   | ||||
| @@ -59,23 +59,20 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD | ||||
|  | ||||
|         let r = T::regs(); | ||||
|         // clear all interrupts and DMA Rx Request | ||||
|         // SAFETY: only clears Rx related flags | ||||
|         unsafe { | ||||
|             r.cr1().modify(|w| { | ||||
|                 // disable RXNE interrupt | ||||
|                 w.set_rxneie(false); | ||||
|                 // enable parity interrupt if not ParityNone | ||||
|                 w.set_peie(w.pce()); | ||||
|                 // enable idle line interrupt | ||||
|                 w.set_idleie(true); | ||||
|             }); | ||||
|             r.cr3().modify(|w| { | ||||
|                 // enable Error Interrupt: (Frame error, Noise error, Overrun error) | ||||
|                 w.set_eie(true); | ||||
|                 // enable DMA Rx Request | ||||
|                 w.set_dmar(true); | ||||
|             }); | ||||
|         } | ||||
|         r.cr1().modify(|w| { | ||||
|             // disable RXNE interrupt | ||||
|             w.set_rxneie(false); | ||||
|             // enable parity interrupt if not ParityNone | ||||
|             w.set_peie(w.pce()); | ||||
|             // enable idle line interrupt | ||||
|             w.set_idleie(true); | ||||
|         }); | ||||
|         r.cr3().modify(|w| { | ||||
|             // enable Error Interrupt: (Frame error, Noise error, Overrun error) | ||||
|             w.set_eie(true); | ||||
|             // enable DMA Rx Request | ||||
|             w.set_dmar(true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     /// Stop uart background receive | ||||
| @@ -84,23 +81,20 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD | ||||
|  | ||||
|         let r = T::regs(); | ||||
|         // clear all interrupts and DMA Rx Request | ||||
|         // SAFETY: only clears Rx related flags | ||||
|         unsafe { | ||||
|             r.cr1().modify(|w| { | ||||
|                 // disable RXNE interrupt | ||||
|                 w.set_rxneie(false); | ||||
|                 // disable parity interrupt | ||||
|                 w.set_peie(false); | ||||
|                 // disable idle line interrupt | ||||
|                 w.set_idleie(false); | ||||
|             }); | ||||
|             r.cr3().modify(|w| { | ||||
|                 // disable Error Interrupt: (Frame error, Noise error, Overrun error) | ||||
|                 w.set_eie(false); | ||||
|                 // disable DMA Rx Request | ||||
|                 w.set_dmar(false); | ||||
|             }); | ||||
|         } | ||||
|         r.cr1().modify(|w| { | ||||
|             // disable RXNE interrupt | ||||
|             w.set_rxneie(false); | ||||
|             // disable parity interrupt | ||||
|             w.set_peie(false); | ||||
|             // disable idle line interrupt | ||||
|             w.set_idleie(false); | ||||
|         }); | ||||
|         r.cr3().modify(|w| { | ||||
|             // disable Error Interrupt: (Frame error, Noise error, Overrun error) | ||||
|             w.set_eie(false); | ||||
|             // disable DMA Rx Request | ||||
|             w.set_dmar(false); | ||||
|         }); | ||||
|  | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|     } | ||||
| @@ -117,8 +111,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         // Start background receive if it was not already started | ||||
|         // SAFETY: read only | ||||
|         match unsafe { r.cr3().read().dmar() } { | ||||
|         match r.cr3().read().dmar() { | ||||
|             false => self.start()?, | ||||
|             _ => {} | ||||
|         }; | ||||
| @@ -213,19 +206,17 @@ fn check_for_errors(s: Sr) -> Result<(), Error> { | ||||
|  | ||||
| /// Clear IDLE and return the Sr register | ||||
| fn clear_idle_flag(r: Regs) -> Sr { | ||||
|     unsafe { | ||||
|         // SAFETY: read only and we only use Rx related flags | ||||
|     // SAFETY: read only and we only use Rx related flags | ||||
|  | ||||
|         let sr = sr(r).read(); | ||||
|     let sr = sr(r).read(); | ||||
|  | ||||
|         // This read also clears the error and idle interrupt flags on v1. | ||||
|         rdr(r).read_volatile(); | ||||
|         clear_interrupt_flags(r, sr); | ||||
|     // This read also clears the error and idle interrupt flags on v1. | ||||
|     unsafe { rdr(r).read_volatile() }; | ||||
|     clear_interrupt_flags(r, sr); | ||||
|  | ||||
|         r.cr1().modify(|w| w.set_idleie(true)); | ||||
|     r.cr1().modify(|w| w.set_idleie(true)); | ||||
|  | ||||
|         sr | ||||
|     } | ||||
|     sr | ||||
| } | ||||
|  | ||||
| #[cfg(all(feature = "unstable-traits", feature = "nightly"))] | ||||
|   | ||||
| @@ -28,82 +28,80 @@ pub struct InterruptHandler<T: Instance> { | ||||
|  | ||||
| impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         unsafe { | ||||
|             let regs = T::regs(); | ||||
|             //let x = regs.istr().read().0; | ||||
|             //trace!("USB IRQ: {:08x}", x); | ||||
|         let regs = T::regs(); | ||||
|         //let x = regs.istr().read().0; | ||||
|         //trace!("USB IRQ: {:08x}", x); | ||||
|  | ||||
|             let istr = regs.istr().read(); | ||||
|         let istr = regs.istr().read(); | ||||
|  | ||||
|             if istr.susp() { | ||||
|                 //trace!("USB IRQ: susp"); | ||||
|                 IRQ_SUSPEND.store(true, Ordering::Relaxed); | ||||
|                 regs.cntr().modify(|w| { | ||||
|                     w.set_fsusp(true); | ||||
|                     w.set_lpmode(true); | ||||
|                 }); | ||||
|         if istr.susp() { | ||||
|             //trace!("USB IRQ: susp"); | ||||
|             IRQ_SUSPEND.store(true, Ordering::Relaxed); | ||||
|             regs.cntr().modify(|w| { | ||||
|                 w.set_fsusp(true); | ||||
|                 w.set_lpmode(true); | ||||
|             }); | ||||
|  | ||||
|                 // Write 0 to clear. | ||||
|                 let mut clear = regs::Istr(!0); | ||||
|                 clear.set_susp(false); | ||||
|                 regs.istr().write_value(clear); | ||||
|             // Write 0 to clear. | ||||
|             let mut clear = regs::Istr(!0); | ||||
|             clear.set_susp(false); | ||||
|             regs.istr().write_value(clear); | ||||
|  | ||||
|                 // Wake main thread. | ||||
|                 BUS_WAKER.wake(); | ||||
|             } | ||||
|             // Wake main thread. | ||||
|             BUS_WAKER.wake(); | ||||
|         } | ||||
|  | ||||
|             if istr.wkup() { | ||||
|                 //trace!("USB IRQ: wkup"); | ||||
|                 IRQ_RESUME.store(true, Ordering::Relaxed); | ||||
|                 regs.cntr().modify(|w| { | ||||
|                     w.set_fsusp(false); | ||||
|                     w.set_lpmode(false); | ||||
|                 }); | ||||
|         if istr.wkup() { | ||||
|             //trace!("USB IRQ: wkup"); | ||||
|             IRQ_RESUME.store(true, Ordering::Relaxed); | ||||
|             regs.cntr().modify(|w| { | ||||
|                 w.set_fsusp(false); | ||||
|                 w.set_lpmode(false); | ||||
|             }); | ||||
|  | ||||
|                 // Write 0 to clear. | ||||
|                 let mut clear = regs::Istr(!0); | ||||
|                 clear.set_wkup(false); | ||||
|                 regs.istr().write_value(clear); | ||||
|             // Write 0 to clear. | ||||
|             let mut clear = regs::Istr(!0); | ||||
|             clear.set_wkup(false); | ||||
|             regs.istr().write_value(clear); | ||||
|  | ||||
|                 // Wake main thread. | ||||
|                 BUS_WAKER.wake(); | ||||
|             } | ||||
|             // Wake main thread. | ||||
|             BUS_WAKER.wake(); | ||||
|         } | ||||
|  | ||||
|             if istr.reset() { | ||||
|                 //trace!("USB IRQ: reset"); | ||||
|                 IRQ_RESET.store(true, Ordering::Relaxed); | ||||
|         if istr.reset() { | ||||
|             //trace!("USB IRQ: reset"); | ||||
|             IRQ_RESET.store(true, Ordering::Relaxed); | ||||
|  | ||||
|                 // Write 0 to clear. | ||||
|                 let mut clear = regs::Istr(!0); | ||||
|                 clear.set_reset(false); | ||||
|                 regs.istr().write_value(clear); | ||||
|             // Write 0 to clear. | ||||
|             let mut clear = regs::Istr(!0); | ||||
|             clear.set_reset(false); | ||||
|             regs.istr().write_value(clear); | ||||
|  | ||||
|                 // Wake main thread. | ||||
|                 BUS_WAKER.wake(); | ||||
|             } | ||||
|             // Wake main thread. | ||||
|             BUS_WAKER.wake(); | ||||
|         } | ||||
|  | ||||
|             if istr.ctr() { | ||||
|                 let index = istr.ep_id() as usize; | ||||
|                 let mut epr = regs.epr(index).read(); | ||||
|                 if epr.ctr_rx() { | ||||
|                     if index == 0 && epr.setup() { | ||||
|                         EP0_SETUP.store(true, Ordering::Relaxed); | ||||
|                     } | ||||
|                     //trace!("EP {} RX, setup={}", index, epr.setup()); | ||||
|                     EP_OUT_WAKERS[index].wake(); | ||||
|         if istr.ctr() { | ||||
|             let index = istr.ep_id() as usize; | ||||
|             let mut epr = regs.epr(index).read(); | ||||
|             if epr.ctr_rx() { | ||||
|                 if index == 0 && epr.setup() { | ||||
|                     EP0_SETUP.store(true, Ordering::Relaxed); | ||||
|                 } | ||||
|                 if epr.ctr_tx() { | ||||
|                     //trace!("EP {} TX", index); | ||||
|                     EP_IN_WAKERS[index].wake(); | ||||
|                 } | ||||
|                 epr.set_dtog_rx(false); | ||||
|                 epr.set_dtog_tx(false); | ||||
|                 epr.set_stat_rx(Stat(0)); | ||||
|                 epr.set_stat_tx(Stat(0)); | ||||
|                 epr.set_ctr_rx(!epr.ctr_rx()); | ||||
|                 epr.set_ctr_tx(!epr.ctr_tx()); | ||||
|                 regs.epr(index).write_value(epr); | ||||
|                 //trace!("EP {} RX, setup={}", index, epr.setup()); | ||||
|                 EP_OUT_WAKERS[index].wake(); | ||||
|             } | ||||
|             if epr.ctr_tx() { | ||||
|                 //trace!("EP {} TX", index); | ||||
|                 EP_IN_WAKERS[index].wake(); | ||||
|             } | ||||
|             epr.set_dtog_rx(false); | ||||
|             epr.set_dtog_tx(false); | ||||
|             epr.set_stat_rx(Stat(0)); | ||||
|             epr.set_stat_tx(Stat(0)); | ||||
|             epr.set_ctr_rx(!epr.ctr_rx()); | ||||
|             epr.set_ctr_tx(!epr.ctr_tx()); | ||||
|             regs.epr(index).write_value(epr); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -168,20 +166,20 @@ fn calc_out_len(len: u16) -> (u16, u16) { | ||||
| mod btable { | ||||
|     use super::*; | ||||
|  | ||||
|     pub(super) unsafe fn write_in<T: Instance>(index: usize, addr: u16) { | ||||
|     pub(super) fn write_in<T: Instance>(index: usize, addr: u16) { | ||||
|         USBRAM.mem(index * 4 + 0).write_value(addr); | ||||
|     } | ||||
|  | ||||
|     pub(super) unsafe fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { | ||||
|     pub(super) fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { | ||||
|         USBRAM.mem(index * 4 + 1).write_value(len); | ||||
|     } | ||||
|  | ||||
|     pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { | ||||
|     pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { | ||||
|         USBRAM.mem(index * 4 + 2).write_value(addr); | ||||
|         USBRAM.mem(index * 4 + 3).write_value(max_len_bits); | ||||
|     } | ||||
|  | ||||
|     pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { | ||||
|     pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 { | ||||
|         USBRAM.mem(index * 4 + 3).read() | ||||
|     } | ||||
| } | ||||
| @@ -189,19 +187,19 @@ mod btable { | ||||
| mod btable { | ||||
|     use super::*; | ||||
|  | ||||
|     pub(super) unsafe fn write_in<T: Instance>(_index: usize, _addr: u16) {} | ||||
|     pub(super) fn write_in<T: Instance>(_index: usize, _addr: u16) {} | ||||
|  | ||||
|     pub(super) unsafe fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) { | ||||
|     pub(super) fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) { | ||||
|         USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); | ||||
|     } | ||||
|  | ||||
|     pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { | ||||
|     pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { | ||||
|         USBRAM | ||||
|             .mem(index * 2 + 1) | ||||
|             .write_value((addr as u32) | ((max_len_bits as u32) << 16)); | ||||
|     } | ||||
|  | ||||
|     pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { | ||||
|     pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 { | ||||
|         (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 | ||||
|     } | ||||
| } | ||||
| @@ -216,7 +214,7 @@ impl<T: Instance> EndpointBuffer<T> { | ||||
|     fn read(&mut self, buf: &mut [u8]) { | ||||
|         assert!(buf.len() <= self.len as usize); | ||||
|         for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { | ||||
|             let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() }; | ||||
|             let val = USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read(); | ||||
|             let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); | ||||
|             buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]); | ||||
|         } | ||||
| @@ -233,7 +231,7 @@ impl<T: Instance> EndpointBuffer<T> { | ||||
|             let val = u16::from_le_bytes(val); | ||||
|             #[cfg(usbram_32_2048)] | ||||
|             let val = u32::from_le_bytes(val); | ||||
|             unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) }; | ||||
|             USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -266,36 +264,32 @@ impl<'d, T: Instance> Driver<'d, T> { | ||||
|         let regs = T::regs(); | ||||
|  | ||||
|         #[cfg(stm32l5)] | ||||
|         unsafe { | ||||
|         { | ||||
|             crate::peripherals::PWR::enable(); | ||||
|             crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); | ||||
|         } | ||||
|  | ||||
|         #[cfg(pwr_h5)] | ||||
|         unsafe { | ||||
|             crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)) | ||||
|         } | ||||
|         crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)); | ||||
|  | ||||
|         unsafe { | ||||
|             <T as RccPeripheral>::enable(); | ||||
|             <T as RccPeripheral>::reset(); | ||||
|         <T as RccPeripheral>::enable(); | ||||
|         <T as RccPeripheral>::reset(); | ||||
|  | ||||
|             regs.cntr().write(|w| { | ||||
|                 w.set_pdwn(false); | ||||
|                 w.set_fres(true); | ||||
|             }); | ||||
|         regs.cntr().write(|w| { | ||||
|             w.set_pdwn(false); | ||||
|             w.set_fres(true); | ||||
|         }); | ||||
|  | ||||
|             #[cfg(time)] | ||||
|             embassy_time::block_for(embassy_time::Duration::from_millis(100)); | ||||
|             #[cfg(not(time))] | ||||
|             cortex_m::asm::delay(crate::rcc::get_freqs().sys.0 / 10); | ||||
|         #[cfg(time)] | ||||
|         embassy_time::block_for(embassy_time::Duration::from_millis(100)); | ||||
|         #[cfg(not(time))] | ||||
|         cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.0 / 10); | ||||
|  | ||||
|             #[cfg(not(usb_v4))] | ||||
|             regs.btable().write(|w| w.set_btable(0)); | ||||
|         #[cfg(not(usb_v4))] | ||||
|         regs.btable().write(|w| w.set_btable(0)); | ||||
|  | ||||
|             dp.set_as_af(dp.af_num(), AFType::OutputPushPull); | ||||
|             dm.set_as_af(dm.af_num(), AFType::OutputPushPull); | ||||
|         } | ||||
|         dp.set_as_af(dp.af_num(), AFType::OutputPushPull); | ||||
|         dm.set_as_af(dm.af_num(), AFType::OutputPushPull); | ||||
|  | ||||
|         // Initialize the bus so that it signals that power is available | ||||
|         BUS_WAKER.wake(); | ||||
| @@ -363,7 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> { | ||||
|                 let addr = self.alloc_ep_mem(len); | ||||
|  | ||||
|                 trace!("  len_bits = {:04x}", len_bits); | ||||
|                 unsafe { btable::write_out::<T>(index, addr, len_bits) } | ||||
|                 btable::write_out::<T>(index, addr, len_bits); | ||||
|  | ||||
|                 EndpointBuffer { | ||||
|                     addr, | ||||
| @@ -379,7 +373,7 @@ impl<'d, T: Instance> Driver<'d, T> { | ||||
|                 let addr = self.alloc_ep_mem(len); | ||||
|  | ||||
|                 // ep_in_len is written when actually TXing packets. | ||||
|                 unsafe { btable::write_in::<T>(index, addr) } | ||||
|                 btable::write_in::<T>(index, addr); | ||||
|  | ||||
|                 EndpointBuffer { | ||||
|                     addr, | ||||
| @@ -440,19 +434,17 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | ||||
|  | ||||
|         let regs = T::regs(); | ||||
|  | ||||
|         unsafe { | ||||
|             regs.cntr().write(|w| { | ||||
|                 w.set_pdwn(false); | ||||
|                 w.set_fres(false); | ||||
|                 w.set_resetm(true); | ||||
|                 w.set_suspm(true); | ||||
|                 w.set_wkupm(true); | ||||
|                 w.set_ctrm(true); | ||||
|             }); | ||||
|         regs.cntr().write(|w| { | ||||
|             w.set_pdwn(false); | ||||
|             w.set_fres(false); | ||||
|             w.set_resetm(true); | ||||
|             w.set_suspm(true); | ||||
|             w.set_wkupm(true); | ||||
|             w.set_ctrm(true); | ||||
|         }); | ||||
|  | ||||
|             #[cfg(any(usb_v3, usb_v4))] | ||||
|             regs.bcdr().write(|w| w.set_dppu(true)) | ||||
|         } | ||||
|         #[cfg(any(usb_v3, usb_v4))] | ||||
|         regs.bcdr().write(|w| w.set_dppu(true)); | ||||
|  | ||||
|         trace!("enabled"); | ||||
|  | ||||
| @@ -485,7 +477,7 @@ pub struct Bus<'d, T: Instance> { | ||||
|  | ||||
| impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | ||||
|     async fn poll(&mut self) -> Event { | ||||
|         poll_fn(move |cx| unsafe { | ||||
|         poll_fn(move |cx| { | ||||
|             BUS_WAKER.register(cx.waker()); | ||||
|  | ||||
|             if self.inited { | ||||
| @@ -548,7 +540,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | ||||
|         match ep_addr.direction() { | ||||
|             Direction::In => { | ||||
|                 loop { | ||||
|                     let r = unsafe { reg.read() }; | ||||
|                     let r = reg.read(); | ||||
|                     match r.stat_tx() { | ||||
|                         Stat::DISABLED => break, // if disabled, stall does nothing. | ||||
|                         Stat::STALL => break,    // done! | ||||
| @@ -559,7 +551,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | ||||
|                             }; | ||||
|                             let mut w = invariant(r); | ||||
|                             w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); | ||||
|                             unsafe { reg.write_value(w) }; | ||||
|                             reg.write_value(w); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| @@ -567,7 +559,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | ||||
|             } | ||||
|             Direction::Out => { | ||||
|                 loop { | ||||
|                     let r = unsafe { reg.read() }; | ||||
|                     let r = reg.read(); | ||||
|                     match r.stat_rx() { | ||||
|                         Stat::DISABLED => break, // if disabled, stall does nothing. | ||||
|                         Stat::STALL => break,    // done! | ||||
| @@ -578,7 +570,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | ||||
|                             }; | ||||
|                             let mut w = invariant(r); | ||||
|                             w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); | ||||
|                             unsafe { reg.write_value(w) }; | ||||
|                             reg.write_value(w); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| @@ -589,7 +581,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | ||||
|  | ||||
|     fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool { | ||||
|         let regs = T::regs(); | ||||
|         let epr = unsafe { regs.epr(ep_addr.index() as _).read() }; | ||||
|         let epr = regs.epr(ep_addr.index() as _).read(); | ||||
|         match ep_addr.direction() { | ||||
|             Direction::In => epr.stat_tx() == Stat::STALL, | ||||
|             Direction::Out => epr.stat_rx() == Stat::STALL, | ||||
| @@ -600,7 +592,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | ||||
|         trace!("set_enabled {:x} {}", ep_addr, enabled); | ||||
|         // This can race, so do a retry loop. | ||||
|         let reg = T::regs().epr(ep_addr.index() as _); | ||||
|         trace!("EPR before: {:04x}", unsafe { reg.read() }.0); | ||||
|         trace!("EPR before: {:04x}", reg.read().0); | ||||
|         match ep_addr.direction() { | ||||
|             Direction::In => { | ||||
|                 loop { | ||||
| @@ -608,13 +600,13 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | ||||
|                         false => Stat::DISABLED, | ||||
|                         true => Stat::NAK, | ||||
|                     }; | ||||
|                     let r = unsafe { reg.read() }; | ||||
|                     let r = reg.read(); | ||||
|                     if r.stat_tx() == want_stat { | ||||
|                         break; | ||||
|                     } | ||||
|                     let mut w = invariant(r); | ||||
|                     w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); | ||||
|                     unsafe { reg.write_value(w) }; | ||||
|                     reg.write_value(w); | ||||
|                 } | ||||
|                 EP_IN_WAKERS[ep_addr.index()].wake(); | ||||
|             } | ||||
| @@ -624,18 +616,18 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | ||||
|                         false => Stat::DISABLED, | ||||
|                         true => Stat::VALID, | ||||
|                     }; | ||||
|                     let r = unsafe { reg.read() }; | ||||
|                     let r = reg.read(); | ||||
|                     if r.stat_rx() == want_stat { | ||||
|                         break; | ||||
|                     } | ||||
|                     let mut w = invariant(r); | ||||
|                     w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); | ||||
|                     unsafe { reg.write_value(w) }; | ||||
|                     reg.write_value(w); | ||||
|                 } | ||||
|                 EP_OUT_WAKERS[ep_addr.index()].wake(); | ||||
|             } | ||||
|         } | ||||
|         trace!("EPR after: {:04x}", unsafe { reg.read() }.0); | ||||
|         trace!("EPR after: {:04x}", reg.read().0); | ||||
|     } | ||||
|  | ||||
|     async fn enable(&mut self) {} | ||||
| @@ -685,12 +677,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> { | ||||
|     fn write_data(&mut self, buf: &[u8]) { | ||||
|         let index = self.info.addr.index(); | ||||
|         self.buf.write(buf); | ||||
|         unsafe { btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _) } | ||||
|         btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _); | ||||
|     } | ||||
|  | ||||
|     fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { | ||||
|         let index = self.info.addr.index(); | ||||
|         let rx_len = unsafe { btable::read_out_len::<T>(index) as usize } & 0x3FF; | ||||
|         let rx_len = btable::read_out_len::<T>(index) as usize & 0x3FF; | ||||
|         trace!("READ DONE, rx_len = {}", rx_len); | ||||
|         if rx_len > buf.len() { | ||||
|             return Err(EndpointError::BufferOverflow); | ||||
| @@ -711,7 +703,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { | ||||
|         poll_fn(|cx| { | ||||
|             EP_OUT_WAKERS[index].register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
|             if unsafe { regs.epr(index).read() }.stat_tx() == Stat::DISABLED { | ||||
|             if regs.epr(index).read().stat_tx() == Stat::DISABLED { | ||||
|                 Poll::Pending | ||||
|             } else { | ||||
|                 Poll::Ready(()) | ||||
| @@ -733,7 +725,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> { | ||||
|         poll_fn(|cx| { | ||||
|             EP_OUT_WAKERS[index].register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
|             if unsafe { regs.epr(index).read() }.stat_rx() == Stat::DISABLED { | ||||
|             if regs.epr(index).read().stat_rx() == Stat::DISABLED { | ||||
|                 Poll::Pending | ||||
|             } else { | ||||
|                 Poll::Ready(()) | ||||
| @@ -751,7 +743,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | ||||
|         let stat = poll_fn(|cx| { | ||||
|             EP_OUT_WAKERS[index].register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
|             let stat = unsafe { regs.epr(index).read() }.stat_rx(); | ||||
|             let stat = regs.epr(index).read().stat_rx(); | ||||
|             if matches!(stat, Stat::NAK | Stat::DISABLED) { | ||||
|                 Poll::Ready(stat) | ||||
|             } else { | ||||
| @@ -767,16 +759,14 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | ||||
|         let rx_len = self.read_data(buf)?; | ||||
|  | ||||
|         let regs = T::regs(); | ||||
|         unsafe { | ||||
|             regs.epr(index).write(|w| { | ||||
|                 w.set_ep_type(convert_type(self.info.ep_type)); | ||||
|                 w.set_ea(self.info.addr.index() as _); | ||||
|                 w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); | ||||
|                 w.set_stat_tx(Stat(0)); | ||||
|                 w.set_ctr_rx(true); // don't clear | ||||
|                 w.set_ctr_tx(true); // don't clear | ||||
|             }) | ||||
|         }; | ||||
|         regs.epr(index).write(|w| { | ||||
|             w.set_ep_type(convert_type(self.info.ep_type)); | ||||
|             w.set_ea(self.info.addr.index() as _); | ||||
|             w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); | ||||
|             w.set_stat_tx(Stat(0)); | ||||
|             w.set_ctr_rx(true); // don't clear | ||||
|             w.set_ctr_tx(true); // don't clear | ||||
|         }); | ||||
|         trace!("READ OK, rx_len = {}", rx_len); | ||||
|  | ||||
|         Ok(rx_len) | ||||
| @@ -795,7 +785,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | ||||
|         let stat = poll_fn(|cx| { | ||||
|             EP_IN_WAKERS[index].register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
|             let stat = unsafe { regs.epr(index).read() }.stat_tx(); | ||||
|             let stat = regs.epr(index).read().stat_tx(); | ||||
|             if matches!(stat, Stat::NAK | Stat::DISABLED) { | ||||
|                 Poll::Ready(stat) | ||||
|             } else { | ||||
| @@ -811,16 +801,14 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | ||||
|         self.write_data(buf); | ||||
|  | ||||
|         let regs = T::regs(); | ||||
|         unsafe { | ||||
|             regs.epr(index).write(|w| { | ||||
|                 w.set_ep_type(convert_type(self.info.ep_type)); | ||||
|                 w.set_ea(self.info.addr.index() as _); | ||||
|                 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); | ||||
|                 w.set_stat_rx(Stat(0)); | ||||
|                 w.set_ctr_rx(true); // don't clear | ||||
|                 w.set_ctr_tx(true); // don't clear | ||||
|             }) | ||||
|         }; | ||||
|         regs.epr(index).write(|w| { | ||||
|             w.set_ep_type(convert_type(self.info.ep_type)); | ||||
|             w.set_ea(self.info.addr.index() as _); | ||||
|             w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); | ||||
|             w.set_stat_rx(Stat(0)); | ||||
|             w.set_ctr_rx(true); // don't clear | ||||
|             w.set_ctr_tx(true); // don't clear | ||||
|         }); | ||||
|  | ||||
|         trace!("WRITE OK"); | ||||
|  | ||||
| @@ -889,22 +877,20 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|             } | ||||
|             // Note: if this is the first AND last transfer, the above effectively | ||||
|             // changes stat_tx like NAK -> NAK, so noop. | ||||
|             unsafe { | ||||
|                 regs.epr(0).write(|w| { | ||||
|                     w.set_ep_type(EpType::CONTROL); | ||||
|                     w.set_stat_rx(Stat(stat_rx)); | ||||
|                     w.set_stat_tx(Stat(stat_tx)); | ||||
|                     w.set_ctr_rx(true); // don't clear | ||||
|                     w.set_ctr_tx(true); // don't clear | ||||
|                 }) | ||||
|             } | ||||
|             regs.epr(0).write(|w| { | ||||
|                 w.set_ep_type(EpType::CONTROL); | ||||
|                 w.set_stat_rx(Stat(stat_rx)); | ||||
|                 w.set_stat_tx(Stat(stat_tx)); | ||||
|                 w.set_ctr_rx(true); // don't clear | ||||
|                 w.set_ctr_tx(true); // don't clear | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         trace!("data_out WAITING, buf.len() = {}", buf.len()); | ||||
|         poll_fn(|cx| { | ||||
|             EP_OUT_WAKERS[0].register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
|             if unsafe { regs.epr(0).read() }.stat_rx() == Stat::NAK { | ||||
|             if regs.epr(0).read().stat_rx() == Stat::NAK { | ||||
|                 Poll::Ready(()) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
| @@ -919,19 +905,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|  | ||||
|         let rx_len = self.ep_out.read_data(buf)?; | ||||
|  | ||||
|         unsafe { | ||||
|             regs.epr(0).write(|w| { | ||||
|                 w.set_ep_type(EpType::CONTROL); | ||||
|                 w.set_stat_rx(Stat(match last { | ||||
|                     // If last, set STAT_RX=STALL. | ||||
|                     true => Stat::NAK.0 ^ Stat::STALL.0, | ||||
|                     // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet. | ||||
|                     false => Stat::NAK.0 ^ Stat::VALID.0, | ||||
|                 })); | ||||
|                 w.set_ctr_rx(true); // don't clear | ||||
|                 w.set_ctr_tx(true); // don't clear | ||||
|             }) | ||||
|         }; | ||||
|         regs.epr(0).write(|w| { | ||||
|             w.set_ep_type(EpType::CONTROL); | ||||
|             w.set_stat_rx(Stat(match last { | ||||
|                 // If last, set STAT_RX=STALL. | ||||
|                 true => Stat::NAK.0 ^ Stat::STALL.0, | ||||
|                 // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet. | ||||
|                 false => Stat::NAK.0 ^ Stat::VALID.0, | ||||
|             })); | ||||
|             w.set_ctr_rx(true); // don't clear | ||||
|             w.set_ctr_tx(true); // don't clear | ||||
|         }); | ||||
|  | ||||
|         Ok(rx_len) | ||||
|     } | ||||
| @@ -960,15 +944,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|             } | ||||
|             // Note: if this is the first AND last transfer, the above effectively | ||||
|             // does a change of NAK -> VALID. | ||||
|             unsafe { | ||||
|                 regs.epr(0).write(|w| { | ||||
|                     w.set_ep_type(EpType::CONTROL); | ||||
|                     w.set_stat_rx(Stat(stat_rx)); | ||||
|                     w.set_ep_kind(last); // set OUT_STATUS if last. | ||||
|                     w.set_ctr_rx(true); // don't clear | ||||
|                     w.set_ctr_tx(true); // don't clear | ||||
|                 }) | ||||
|             } | ||||
|             regs.epr(0).write(|w| { | ||||
|                 w.set_ep_type(EpType::CONTROL); | ||||
|                 w.set_stat_rx(Stat(stat_rx)); | ||||
|                 w.set_ep_kind(last); // set OUT_STATUS if last. | ||||
|                 w.set_ctr_rx(true); // don't clear | ||||
|                 w.set_ctr_tx(true); // don't clear | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         trace!("WRITE WAITING"); | ||||
| @@ -976,7 +958,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|             EP_IN_WAKERS[0].register(cx.waker()); | ||||
|             EP_OUT_WAKERS[0].register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
|             if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK { | ||||
|             if regs.epr(0).read().stat_tx() == Stat::NAK { | ||||
|                 Poll::Ready(()) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
| @@ -992,15 +974,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|         self.ep_in.write_data(data); | ||||
|  | ||||
|         let regs = T::regs(); | ||||
|         unsafe { | ||||
|             regs.epr(0).write(|w| { | ||||
|                 w.set_ep_type(EpType::CONTROL); | ||||
|                 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); | ||||
|                 w.set_ep_kind(last); // set OUT_STATUS if last. | ||||
|                 w.set_ctr_rx(true); // don't clear | ||||
|                 w.set_ctr_tx(true); // don't clear | ||||
|             }) | ||||
|         }; | ||||
|         regs.epr(0).write(|w| { | ||||
|             w.set_ep_type(EpType::CONTROL); | ||||
|             w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); | ||||
|             w.set_ep_kind(last); // set OUT_STATUS if last. | ||||
|             w.set_ctr_rx(true); // don't clear | ||||
|             w.set_ctr_tx(true); // don't clear | ||||
|         }); | ||||
|  | ||||
|         trace!("WRITE OK"); | ||||
|  | ||||
| @@ -1014,16 +994,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|         self.ep_in.write_data(&[]); | ||||
|  | ||||
|         // Set OUT=stall, IN=accept | ||||
|         unsafe { | ||||
|             let epr = regs.epr(0).read(); | ||||
|             regs.epr(0).write(|w| { | ||||
|                 w.set_ep_type(EpType::CONTROL); | ||||
|                 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); | ||||
|                 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0)); | ||||
|                 w.set_ctr_rx(true); // don't clear | ||||
|                 w.set_ctr_tx(true); // don't clear | ||||
|             }); | ||||
|         } | ||||
|         let epr = regs.epr(0).read(); | ||||
|         regs.epr(0).write(|w| { | ||||
|             w.set_ep_type(EpType::CONTROL); | ||||
|             w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); | ||||
|             w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0)); | ||||
|             w.set_ctr_rx(true); // don't clear | ||||
|             w.set_ctr_tx(true); // don't clear | ||||
|         }); | ||||
|         trace!("control: accept WAITING"); | ||||
|  | ||||
|         // Wait is needed, so that we don't set the address too soon, breaking the status stage. | ||||
| @@ -1031,7 +1009,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|         poll_fn(|cx| { | ||||
|             EP_IN_WAKERS[0].register(cx.waker()); | ||||
|             let regs = T::regs(); | ||||
|             if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK { | ||||
|             if regs.epr(0).read().stat_tx() == Stat::NAK { | ||||
|                 Poll::Ready(()) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
| @@ -1047,16 +1025,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|         trace!("control: reject"); | ||||
|  | ||||
|         // Set IN+OUT to stall | ||||
|         unsafe { | ||||
|             let epr = regs.epr(0).read(); | ||||
|             regs.epr(0).write(|w| { | ||||
|                 w.set_ep_type(EpType::CONTROL); | ||||
|                 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); | ||||
|                 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0)); | ||||
|                 w.set_ctr_rx(true); // don't clear | ||||
|                 w.set_ctr_tx(true); // don't clear | ||||
|             }); | ||||
|         } | ||||
|         let epr = regs.epr(0).read(); | ||||
|         regs.epr(0).write(|w| { | ||||
|             w.set_ep_type(EpType::CONTROL); | ||||
|             w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); | ||||
|             w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0)); | ||||
|             w.set_ctr_rx(true); // don't clear | ||||
|             w.set_ctr_tx(true); // don't clear | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async fn accept_set_address(&mut self, addr: u8) { | ||||
| @@ -1064,11 +1040,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | ||||
|  | ||||
|         let regs = T::regs(); | ||||
|         trace!("setting addr: {}", addr); | ||||
|         unsafe { | ||||
|             regs.daddr().write(|w| { | ||||
|                 w.set_ef(true); | ||||
|                 w.set_add(addr); | ||||
|             }) | ||||
|         } | ||||
|         regs.daddr().write(|w| { | ||||
|             w.set_ef(true); | ||||
|             w.set_add(addr); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -148,7 +148,7 @@ foreach_interrupt!( | ||||
|  | ||||
|             fn regs() -> crate::pac::otg::Otg { | ||||
|                 // OTG HS registers are a superset of FS registers | ||||
|                 crate::pac::otg::Otg(crate::pac::USB_OTG_HS.0) | ||||
|                 unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) } | ||||
|             } | ||||
|  | ||||
|             #[cfg(feature = "nightly")] | ||||
|   | ||||
| @@ -30,19 +30,16 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|         let r = T::regs(); | ||||
|         let state = T::state(); | ||||
|  | ||||
|         // SAFETY: atomic read/write | ||||
|         let ints = unsafe { r.gintsts().read() }; | ||||
|         let ints = r.gintsts().read(); | ||||
|         if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() { | ||||
|             // Mask interrupts and notify `Bus` to process them | ||||
|             unsafe { r.gintmsk().write(|_| {}) }; | ||||
|             r.gintmsk().write(|_| {}); | ||||
|             T::state().bus_waker.wake(); | ||||
|         } | ||||
|  | ||||
|         // Handle RX | ||||
|         // SAFETY: atomic read with no side effects | ||||
|         while unsafe { r.gintsts().read().rxflvl() } { | ||||
|             // SAFETY: atomic "pop" register | ||||
|             let status = unsafe { r.grxstsp().read() }; | ||||
|         while r.gintsts().read().rxflvl() { | ||||
|             let status = r.grxstsp().read(); | ||||
|             let ep_num = status.epnum() as usize; | ||||
|             let len = status.bcnt() as usize; | ||||
|  | ||||
| @@ -57,21 +54,15 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|                     if state.ep0_setup_ready.load(Ordering::Relaxed) == false { | ||||
|                         // SAFETY: exclusive access ensured by atomic bool | ||||
|                         let data = unsafe { &mut *state.ep0_setup_data.get() }; | ||||
|                         // SAFETY: FIFO reads are exclusive to this IRQ | ||||
|                         unsafe { | ||||
|                             data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); | ||||
|                             data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); | ||||
|                         } | ||||
|                         data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); | ||||
|                         data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); | ||||
|                         state.ep0_setup_ready.store(true, Ordering::Release); | ||||
|                         state.ep_out_wakers[0].wake(); | ||||
|                     } else { | ||||
|                         error!("received SETUP before previous finished processing"); | ||||
|                         // discard FIFO | ||||
|                         // SAFETY: FIFO reads are exclusive to IRQ | ||||
|                         unsafe { | ||||
|                             r.fifo(0).read(); | ||||
|                             r.fifo(0).read(); | ||||
|                         } | ||||
|                         r.fifo(0).read(); | ||||
|                         r.fifo(0).read(); | ||||
|                     } | ||||
|                 } | ||||
|                 vals::Pktstsd::OUT_DATA_RX => { | ||||
| @@ -84,8 +75,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|  | ||||
|                         for chunk in buf.chunks_mut(4) { | ||||
|                             // RX FIFO is shared so always read from fifo(0) | ||||
|                             // SAFETY: FIFO reads are exclusive to IRQ | ||||
|                             let data = unsafe { r.fifo(0).read().0 }; | ||||
|                             let data = r.fifo(0).read().0; | ||||
|                             chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]); | ||||
|                         } | ||||
|  | ||||
| @@ -97,8 +87,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|                         // discard FIFO data | ||||
|                         let len_words = (len + 3) / 4; | ||||
|                         for _ in 0..len_words { | ||||
|                             // SAFETY: FIFO reads are exclusive to IRQ | ||||
|                             unsafe { r.fifo(0).read().data() }; | ||||
|                             r.fifo(0).read().data(); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| @@ -114,24 +103,20 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
|  | ||||
|         // IN endpoint interrupt | ||||
|         if ints.iepint() { | ||||
|             // SAFETY: atomic read with no side effects | ||||
|             let mut ep_mask = unsafe { r.daint().read().iepint() }; | ||||
|             let mut ep_mask = r.daint().read().iepint(); | ||||
|             let mut ep_num = 0; | ||||
|  | ||||
|             // Iterate over endpoints while there are non-zero bits in the mask | ||||
|             while ep_mask != 0 { | ||||
|                 if ep_mask & 1 != 0 { | ||||
|                     // SAFETY: atomic read with no side effects | ||||
|                     let ep_ints = unsafe { r.diepint(ep_num).read() }; | ||||
|                     let ep_ints = r.diepint(ep_num).read(); | ||||
|  | ||||
|                     // clear all | ||||
|                     // SAFETY: DIEPINT is exclusive to IRQ | ||||
|                     unsafe { r.diepint(ep_num).write_value(ep_ints) }; | ||||
|                     r.diepint(ep_num).write_value(ep_ints); | ||||
|  | ||||
|                     // TXFE is cleared in DIEPEMPMSK | ||||
|                     if ep_ints.txfe() { | ||||
|                         // SAFETY: DIEPEMPMSK is shared with `Endpoint` so critical section is needed for RMW | ||||
|                         critical_section::with(|_| unsafe { | ||||
|                         critical_section::with(|_| { | ||||
|                             r.diepempmsk().modify(|w| { | ||||
|                                 w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num)); | ||||
|                             }); | ||||
| @@ -172,8 +157,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | ||||
| macro_rules! config_ulpi_pins { | ||||
|     ($($pin:ident),*) => { | ||||
|         into_ref!($($pin),*); | ||||
|         // NOTE(unsafe) Exclusive access to the registers | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             $( | ||||
|                 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); | ||||
|                 #[cfg(gpio_v2)] | ||||
| @@ -298,10 +282,8 @@ impl<'d, T: Instance> Driver<'d, T> { | ||||
|     ) -> Self { | ||||
|         into_ref!(dp, dm); | ||||
|  | ||||
|         unsafe { | ||||
|             dp.set_as_af(dp.af_num(), AFType::OutputPushPull); | ||||
|             dm.set_as_af(dm.af_num(), AFType::OutputPushPull); | ||||
|         } | ||||
|         dp.set_as_af(dp.af_num(), AFType::OutputPushPull); | ||||
|         dm.set_as_af(dm.af_num(), AFType::OutputPushPull); | ||||
|  | ||||
|         Self { | ||||
|             phantom: PhantomData, | ||||
| @@ -508,18 +490,15 @@ pub struct Bus<'d, T: Instance> { | ||||
|  | ||||
| impl<'d, T: Instance> Bus<'d, T> { | ||||
|     fn restore_irqs() { | ||||
|         // SAFETY: atomic write | ||||
|         unsafe { | ||||
|             T::regs().gintmsk().write(|w| { | ||||
|                 w.set_usbrst(true); | ||||
|                 w.set_enumdnem(true); | ||||
|                 w.set_usbsuspm(true); | ||||
|                 w.set_wuim(true); | ||||
|                 w.set_iepint(true); | ||||
|                 w.set_oepint(true); | ||||
|                 w.set_rxflvlm(true); | ||||
|             }); | ||||
|         } | ||||
|         T::regs().gintmsk().write(|w| { | ||||
|             w.set_usbrst(true); | ||||
|             w.set_enumdnem(true); | ||||
|             w.set_usbsuspm(true); | ||||
|             w.set_wuim(true); | ||||
|             w.set_iepint(true); | ||||
|             w.set_oepint(true); | ||||
|             w.set_rxflvlm(true); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -533,8 +512,7 @@ impl<'d, T: Instance> Bus<'d, T> { | ||||
|         let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); | ||||
|         trace!("configuring rx fifo size={}", rx_fifo_size_words); | ||||
|  | ||||
|         // SAFETY: register is exclusive to `Bus` with `&mut self` | ||||
|         unsafe { r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)) }; | ||||
|         r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)); | ||||
|  | ||||
|         // Configure TX (USB in direction) fifo size for each endpoint | ||||
|         let mut fifo_top = rx_fifo_size_words; | ||||
| @@ -549,13 +527,10 @@ impl<'d, T: Instance> Bus<'d, T> { | ||||
|  | ||||
|                 let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; | ||||
|  | ||||
|                 // SAFETY: register is exclusive to `Bus` with `&mut self` | ||||
|                 unsafe { | ||||
|                     dieptxf.write(|w| { | ||||
|                         w.set_fd(ep.fifo_size_words); | ||||
|                         w.set_sa(fifo_top); | ||||
|                     }); | ||||
|                 } | ||||
|                 dieptxf.write(|w| { | ||||
|                     w.set_fd(ep.fifo_size_words); | ||||
|                     w.set_sa(fifo_top); | ||||
|                 }); | ||||
|  | ||||
|                 fifo_top += ep.fifo_size_words; | ||||
|             } | ||||
| @@ -575,8 +550,7 @@ impl<'d, T: Instance> Bus<'d, T> { | ||||
|         // Configure IN endpoints | ||||
|         for (index, ep) in self.ep_in.iter().enumerate() { | ||||
|             if let Some(ep) = ep { | ||||
|                 // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     r.diepctl(index).write(|w| { | ||||
|                         if index == 0 { | ||||
|                             w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); | ||||
| @@ -593,8 +567,7 @@ impl<'d, T: Instance> Bus<'d, T> { | ||||
|         // Configure OUT endpoints | ||||
|         for (index, ep) in self.ep_out.iter().enumerate() { | ||||
|             if let Some(ep) = ep { | ||||
|                 // SAFETY: DOEPCTL/DOEPTSIZ is shared with `Endpoint` so critical section is needed for RMW | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     r.doepctl(index).write(|w| { | ||||
|                         if index == 0 { | ||||
|                             w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); | ||||
| @@ -618,14 +591,11 @@ impl<'d, T: Instance> Bus<'d, T> { | ||||
|         } | ||||
|  | ||||
|         // Enable IRQs for allocated endpoints | ||||
|         // SAFETY: register is exclusive to `Bus` with `&mut self` | ||||
|         unsafe { | ||||
|             r.daintmsk().modify(|w| { | ||||
|                 w.set_iepm(ep_irq_mask(&self.ep_in)); | ||||
|                 // OUT interrupts not used, handled in RXFLVL | ||||
|                 // w.set_oepm(ep_irq_mask(&self.ep_out)); | ||||
|             }); | ||||
|         } | ||||
|         r.daintmsk().modify(|w| { | ||||
|             w.set_iepm(ep_irq_mask(&self.ep_in)); | ||||
|             // OUT interrupts not used, handled in RXFLVL | ||||
|             // w.set_oepm(ep_irq_mask(&self.ep_out)); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     fn disable(&mut self) { | ||||
| @@ -634,10 +604,8 @@ impl<'d, T: Instance> Bus<'d, T> { | ||||
|         <T as RccPeripheral>::disable(); | ||||
|  | ||||
|         #[cfg(stm32l4)] | ||||
|         unsafe { | ||||
|             crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); | ||||
|             // Cannot disable PWR, because other peripherals might be using it | ||||
|         } | ||||
|         crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); | ||||
|         // Cannot disable PWR, because other peripherals might be using it | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -653,7 +621,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | ||||
|  | ||||
|             T::state().bus_waker.register(cx.waker()); | ||||
|  | ||||
|             let ints = unsafe { r.gintsts().read() }; | ||||
|             let ints = r.gintsts().read(); | ||||
|             if ints.usbrst() { | ||||
|                 trace!("reset"); | ||||
|  | ||||
| @@ -661,34 +629,27 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | ||||
|                 self.configure_endpoints(); | ||||
|  | ||||
|                 // Reset address | ||||
|                 // SAFETY: DCFG is shared with `ControlPipe` so critical section is needed for RMW | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     r.dcfg().modify(|w| { | ||||
|                         w.set_dad(0); | ||||
|                     }); | ||||
|                 }); | ||||
|  | ||||
|                 // SAFETY: atomic clear on rc_w1 register | ||||
|                 unsafe { r.gintsts().write(|w| w.set_usbrst(true)) }; // clear | ||||
|                 r.gintsts().write(|w| w.set_usbrst(true)); // clear | ||||
|                 Self::restore_irqs(); | ||||
|             } | ||||
|  | ||||
|             if ints.enumdne() { | ||||
|                 trace!("enumdne"); | ||||
|  | ||||
|                 // SAFETY: atomic read with no side effects | ||||
|                 let speed = unsafe { r.dsts().read().enumspd() }; | ||||
|                 let speed = r.dsts().read().enumspd(); | ||||
|                 trace!("  speed={}", speed.0); | ||||
|  | ||||
|                 // SAFETY: register is only accessed by `Bus` under `&mut self` | ||||
|                 unsafe { | ||||
|                     r.gusbcfg().modify(|w| { | ||||
|                         w.set_trdt(calculate_trdt(speed, T::frequency())); | ||||
|                     }) | ||||
|                 }; | ||||
|                 r.gusbcfg().modify(|w| { | ||||
|                     w.set_trdt(calculate_trdt(speed, T::frequency())); | ||||
|                 }); | ||||
|  | ||||
|                 // SAFETY: atomic clear on rc_w1 register | ||||
|                 unsafe { r.gintsts().write(|w| w.set_enumdne(true)) }; // clear | ||||
|                 r.gintsts().write(|w| w.set_enumdne(true)); // clear | ||||
|                 Self::restore_irqs(); | ||||
|  | ||||
|                 return Poll::Ready(Event::Reset); | ||||
| @@ -696,16 +657,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | ||||
|  | ||||
|             if ints.usbsusp() { | ||||
|                 trace!("suspend"); | ||||
|                 // SAFETY: atomic clear on rc_w1 register | ||||
|                 unsafe { r.gintsts().write(|w| w.set_usbsusp(true)) }; // clear | ||||
|                 r.gintsts().write(|w| w.set_usbsusp(true)); // clear | ||||
|                 Self::restore_irqs(); | ||||
|                 return Poll::Ready(Event::Suspend); | ||||
|             } | ||||
|  | ||||
|             if ints.wkupint() { | ||||
|                 trace!("resume"); | ||||
|                 // SAFETY: atomic clear on rc_w1 register | ||||
|                 unsafe { r.gintsts().write(|w| w.set_wkupint(true)) }; // clear | ||||
|                 r.gintsts().write(|w| w.set_wkupint(true)); // clear | ||||
|                 Self::restore_irqs(); | ||||
|                 return Poll::Ready(Event::Resume); | ||||
|             } | ||||
| @@ -727,8 +686,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | ||||
|         let regs = T::regs(); | ||||
|         match ep_addr.direction() { | ||||
|             Direction::Out => { | ||||
|                 // SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     regs.doepctl(ep_addr.index()).modify(|w| { | ||||
|                         w.set_stall(stalled); | ||||
|                     }); | ||||
| @@ -737,8 +695,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | ||||
|                 T::state().ep_out_wakers[ep_addr.index()].wake(); | ||||
|             } | ||||
|             Direction::In => { | ||||
|                 // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     regs.diepctl(ep_addr.index()).modify(|w| { | ||||
|                         w.set_stall(stalled); | ||||
|                     }); | ||||
| @@ -758,10 +715,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | ||||
|  | ||||
|         let regs = T::regs(); | ||||
|  | ||||
|         // SAFETY: atomic read with no side effects | ||||
|         match ep_addr.direction() { | ||||
|             Direction::Out => unsafe { regs.doepctl(ep_addr.index()).read().stall() }, | ||||
|             Direction::In => unsafe { regs.diepctl(ep_addr.index()).read().stall() }, | ||||
|             Direction::Out => regs.doepctl(ep_addr.index()).read().stall(), | ||||
|             Direction::In => regs.diepctl(ep_addr.index()).read().stall(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -777,8 +733,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | ||||
|         let r = T::regs(); | ||||
|         match ep_addr.direction() { | ||||
|             Direction::Out => { | ||||
|                 // SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     // cancel transfer if active | ||||
|                     if !enabled && r.doepctl(ep_addr.index()).read().epena() { | ||||
|                         r.doepctl(ep_addr.index()).modify(|w| { | ||||
| @@ -796,8 +751,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | ||||
|                 T::state().ep_out_wakers[ep_addr.index()].wake(); | ||||
|             } | ||||
|             Direction::In => { | ||||
|                 // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     // cancel transfer if active | ||||
|                     if !enabled && r.diepctl(ep_addr.index()).read().epena() { | ||||
|                         r.diepctl(ep_addr.index()).modify(|w| { | ||||
| @@ -820,196 +774,193 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | ||||
|     async fn enable(&mut self) { | ||||
|         trace!("enable"); | ||||
|  | ||||
|         // SAFETY: registers are only accessed by `Bus` under `&mut self` | ||||
|         unsafe { | ||||
|             #[cfg(stm32l4)] | ||||
|             { | ||||
|                 crate::peripherals::PWR::enable(); | ||||
|                 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); | ||||
|             } | ||||
|  | ||||
|             #[cfg(stm32f7)] | ||||
|             { | ||||
|                 // Enable ULPI clock if external PHY is used | ||||
|                 let ulpien = !self.phy_type.internal(); | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.ahb1enr().modify(|w| { | ||||
|                         if T::HIGH_SPEED { | ||||
|                             w.set_usb_otg_hsulpien(ulpien); | ||||
|                         } else { | ||||
|                             w.set_usb_otg_hsen(ulpien); | ||||
|                         } | ||||
|                     }); | ||||
|  | ||||
|                     // Low power mode | ||||
|                     crate::pac::RCC.ahb1lpenr().modify(|w| { | ||||
|                         if T::HIGH_SPEED { | ||||
|                             w.set_usb_otg_hsulpilpen(ulpien); | ||||
|                         } else { | ||||
|                             w.set_usb_otg_hslpen(ulpien); | ||||
|                         } | ||||
|                     }); | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             #[cfg(stm32h7)] | ||||
|             { | ||||
|                 // If true, VDD33USB is generated by internal regulator from VDD50USB | ||||
|                 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) | ||||
|                 // TODO: unhardcode | ||||
|                 let internal_regulator = false; | ||||
|  | ||||
|                 // Enable USB power | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::PWR.cr3().modify(|w| { | ||||
|                         w.set_usb33den(true); | ||||
|                         w.set_usbregen(internal_regulator); | ||||
|                     }) | ||||
|                 }); | ||||
|  | ||||
|                 // Wait for USB power to stabilize | ||||
|                 while !crate::pac::PWR.cr3().read().usb33rdy() {} | ||||
|  | ||||
|                 // Use internal 48MHz HSI clock. Should be enabled in RCC by default. | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC | ||||
|                         .d2ccip2r() | ||||
|                         .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) | ||||
|                 }); | ||||
|  | ||||
|                 // Enable ULPI clock if external PHY is used | ||||
|                 let ulpien = !self.phy_type.internal(); | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.ahb1enr().modify(|w| { | ||||
|                         if T::HIGH_SPEED { | ||||
|                             w.set_usb_otg_hs_ulpien(ulpien); | ||||
|                         } else { | ||||
|                             w.set_usb_otg_fs_ulpien(ulpien); | ||||
|                         } | ||||
|                     }); | ||||
|                     crate::pac::RCC.ahb1lpenr().modify(|w| { | ||||
|                         if T::HIGH_SPEED { | ||||
|                             w.set_usb_otg_hs_ulpilpen(ulpien); | ||||
|                         } else { | ||||
|                             w.set_usb_otg_fs_ulpilpen(ulpien); | ||||
|                         } | ||||
|                     }); | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             #[cfg(stm32u5)] | ||||
|             { | ||||
|                 // Enable USB power | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.ahb3enr().modify(|w| { | ||||
|                         w.set_pwren(true); | ||||
|                     }); | ||||
|                     cortex_m::asm::delay(2); | ||||
|  | ||||
|                     crate::pac::PWR.svmcr().modify(|w| { | ||||
|                         w.set_usv(true); | ||||
|                         w.set_uvmen(true); | ||||
|                     }); | ||||
|                 }); | ||||
|  | ||||
|                 // Wait for USB power to stabilize | ||||
|                 while !crate::pac::PWR.svmsr().read().vddusbrdy() {} | ||||
|  | ||||
|                 // Select HSI48 as USB clock source. | ||||
|                 critical_section::with(|_| { | ||||
|                     crate::pac::RCC.ccipr1().modify(|w| { | ||||
|                         w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); | ||||
|                     }) | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             <T as RccPeripheral>::enable(); | ||||
|             <T as RccPeripheral>::reset(); | ||||
|  | ||||
|             T::Interrupt::unpend(); | ||||
|             T::Interrupt::enable(); | ||||
|  | ||||
|             let r = T::regs(); | ||||
|             let core_id = r.cid().read().0; | ||||
|             info!("Core id {:08x}", core_id); | ||||
|  | ||||
|             // Wait for AHB ready. | ||||
|             while !r.grstctl().read().ahbidl() {} | ||||
|  | ||||
|             // Configure as device. | ||||
|             r.gusbcfg().write(|w| { | ||||
|                 // Force device mode | ||||
|                 w.set_fdmod(true); | ||||
|                 // Enable internal full-speed PHY | ||||
|                 w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); | ||||
|             }); | ||||
|  | ||||
|             // Configuring Vbus sense and SOF output | ||||
|             match core_id { | ||||
|                 0x0000_1200 | 0x0000_1100 => { | ||||
|                     assert!(self.phy_type != PhyType::InternalHighSpeed); | ||||
|  | ||||
|                     r.gccfg_v1().modify(|w| { | ||||
|                         // Enable internal full-speed PHY, logic is inverted | ||||
|                         w.set_pwrdwn(self.phy_type.internal()); | ||||
|                     }); | ||||
|  | ||||
|                     // F429-like chips have the GCCFG.NOVBUSSENS bit | ||||
|                     r.gccfg_v1().modify(|w| { | ||||
|                         w.set_novbussens(true); | ||||
|                         w.set_vbusasen(false); | ||||
|                         w.set_vbusbsen(false); | ||||
|                         w.set_sofouten(false); | ||||
|                     }); | ||||
|                 } | ||||
|                 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { | ||||
|                     // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning | ||||
|                     r.gccfg_v2().modify(|w| { | ||||
|                         // Enable internal full-speed PHY, logic is inverted | ||||
|                         w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); | ||||
|                         w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); | ||||
|                     }); | ||||
|  | ||||
|                     r.gccfg_v2().modify(|w| { | ||||
|                         w.set_vbden(false); | ||||
|                     }); | ||||
|  | ||||
|                     // Force B-peripheral session | ||||
|                     r.gotgctl().modify(|w| { | ||||
|                         w.set_bvaloen(true); | ||||
|                         w.set_bvaloval(true); | ||||
|                     }); | ||||
|                 } | ||||
|                 _ => unimplemented!("Unknown USB core id {:X}", core_id), | ||||
|             } | ||||
|  | ||||
|             // Soft disconnect. | ||||
|             r.dctl().write(|w| w.set_sdis(true)); | ||||
|  | ||||
|             // Set speed. | ||||
|             r.dcfg().write(|w| { | ||||
|                 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); | ||||
|                 w.set_dspd(self.phy_type.to_dspd()); | ||||
|             }); | ||||
|  | ||||
|             // Unmask transfer complete EP interrupt | ||||
|             r.diepmsk().write(|w| { | ||||
|                 w.set_xfrcm(true); | ||||
|             }); | ||||
|  | ||||
|             // Unmask and clear core interrupts | ||||
|             Bus::<T>::restore_irqs(); | ||||
|             r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); | ||||
|  | ||||
|             // Unmask global interrupt | ||||
|             r.gahbcfg().write(|w| { | ||||
|                 w.set_gint(true); // unmask global interrupt | ||||
|             }); | ||||
|  | ||||
|             // Connect | ||||
|             r.dctl().write(|w| w.set_sdis(false)); | ||||
|         #[cfg(stm32l4)] | ||||
|         { | ||||
|             crate::peripherals::PWR::enable(); | ||||
|             critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); | ||||
|         } | ||||
|  | ||||
|         #[cfg(stm32f7)] | ||||
|         { | ||||
|             // Enable ULPI clock if external PHY is used | ||||
|             let ulpien = !self.phy_type.internal(); | ||||
|             critical_section::with(|_| { | ||||
|                 crate::pac::RCC.ahb1enr().modify(|w| { | ||||
|                     if T::HIGH_SPEED { | ||||
|                         w.set_usb_otg_hsulpien(ulpien); | ||||
|                     } else { | ||||
|                         w.set_usb_otg_hsen(ulpien); | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|                 // Low power mode | ||||
|                 crate::pac::RCC.ahb1lpenr().modify(|w| { | ||||
|                     if T::HIGH_SPEED { | ||||
|                         w.set_usb_otg_hsulpilpen(ulpien); | ||||
|                     } else { | ||||
|                         w.set_usb_otg_hslpen(ulpien); | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         #[cfg(stm32h7)] | ||||
|         { | ||||
|             // If true, VDD33USB is generated by internal regulator from VDD50USB | ||||
|             // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) | ||||
|             // TODO: unhardcode | ||||
|             let internal_regulator = false; | ||||
|  | ||||
|             // Enable USB power | ||||
|             critical_section::with(|_| { | ||||
|                 crate::pac::PWR.cr3().modify(|w| { | ||||
|                     w.set_usb33den(true); | ||||
|                     w.set_usbregen(internal_regulator); | ||||
|                 }) | ||||
|             }); | ||||
|  | ||||
|             // Wait for USB power to stabilize | ||||
|             while !crate::pac::PWR.cr3().read().usb33rdy() {} | ||||
|  | ||||
|             // Use internal 48MHz HSI clock. Should be enabled in RCC by default. | ||||
|             critical_section::with(|_| { | ||||
|                 crate::pac::RCC | ||||
|                     .d2ccip2r() | ||||
|                     .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) | ||||
|             }); | ||||
|  | ||||
|             // Enable ULPI clock if external PHY is used | ||||
|             let ulpien = !self.phy_type.internal(); | ||||
|             critical_section::with(|_| { | ||||
|                 crate::pac::RCC.ahb1enr().modify(|w| { | ||||
|                     if T::HIGH_SPEED { | ||||
|                         w.set_usb_otg_hs_ulpien(ulpien); | ||||
|                     } else { | ||||
|                         w.set_usb_otg_fs_ulpien(ulpien); | ||||
|                     } | ||||
|                 }); | ||||
|                 crate::pac::RCC.ahb1lpenr().modify(|w| { | ||||
|                     if T::HIGH_SPEED { | ||||
|                         w.set_usb_otg_hs_ulpilpen(ulpien); | ||||
|                     } else { | ||||
|                         w.set_usb_otg_fs_ulpilpen(ulpien); | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         #[cfg(stm32u5)] | ||||
|         { | ||||
|             // Enable USB power | ||||
|             critical_section::with(|_| { | ||||
|                 crate::pac::RCC.ahb3enr().modify(|w| { | ||||
|                     w.set_pwren(true); | ||||
|                 }); | ||||
|                 cortex_m::asm::delay(2); | ||||
|  | ||||
|                 crate::pac::PWR.svmcr().modify(|w| { | ||||
|                     w.set_usv(true); | ||||
|                     w.set_uvmen(true); | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             // Wait for USB power to stabilize | ||||
|             while !crate::pac::PWR.svmsr().read().vddusbrdy() {} | ||||
|  | ||||
|             // Select HSI48 as USB clock source. | ||||
|             critical_section::with(|_| { | ||||
|                 crate::pac::RCC.ccipr1().modify(|w| { | ||||
|                     w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); | ||||
|                 }) | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         <T as RccPeripheral>::enable(); | ||||
|         <T as RccPeripheral>::reset(); | ||||
|  | ||||
|         T::Interrupt::unpend(); | ||||
|         unsafe { T::Interrupt::enable() }; | ||||
|  | ||||
|         let r = T::regs(); | ||||
|         let core_id = r.cid().read().0; | ||||
|         info!("Core id {:08x}", core_id); | ||||
|  | ||||
|         // Wait for AHB ready. | ||||
|         while !r.grstctl().read().ahbidl() {} | ||||
|  | ||||
|         // Configure as device. | ||||
|         r.gusbcfg().write(|w| { | ||||
|             // Force device mode | ||||
|             w.set_fdmod(true); | ||||
|             // Enable internal full-speed PHY | ||||
|             w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); | ||||
|         }); | ||||
|  | ||||
|         // Configuring Vbus sense and SOF output | ||||
|         match core_id { | ||||
|             0x0000_1200 | 0x0000_1100 => { | ||||
|                 assert!(self.phy_type != PhyType::InternalHighSpeed); | ||||
|  | ||||
|                 r.gccfg_v1().modify(|w| { | ||||
|                     // Enable internal full-speed PHY, logic is inverted | ||||
|                     w.set_pwrdwn(self.phy_type.internal()); | ||||
|                 }); | ||||
|  | ||||
|                 // F429-like chips have the GCCFG.NOVBUSSENS bit | ||||
|                 r.gccfg_v1().modify(|w| { | ||||
|                     w.set_novbussens(true); | ||||
|                     w.set_vbusasen(false); | ||||
|                     w.set_vbusbsen(false); | ||||
|                     w.set_sofouten(false); | ||||
|                 }); | ||||
|             } | ||||
|             0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { | ||||
|                 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning | ||||
|                 r.gccfg_v2().modify(|w| { | ||||
|                     // Enable internal full-speed PHY, logic is inverted | ||||
|                     w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); | ||||
|                     w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); | ||||
|                 }); | ||||
|  | ||||
|                 r.gccfg_v2().modify(|w| { | ||||
|                     w.set_vbden(false); | ||||
|                 }); | ||||
|  | ||||
|                 // Force B-peripheral session | ||||
|                 r.gotgctl().modify(|w| { | ||||
|                     w.set_bvaloen(true); | ||||
|                     w.set_bvaloval(true); | ||||
|                 }); | ||||
|             } | ||||
|             _ => unimplemented!("Unknown USB core id {:X}", core_id), | ||||
|         } | ||||
|  | ||||
|         // Soft disconnect. | ||||
|         r.dctl().write(|w| w.set_sdis(true)); | ||||
|  | ||||
|         // Set speed. | ||||
|         r.dcfg().write(|w| { | ||||
|             w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); | ||||
|             w.set_dspd(self.phy_type.to_dspd()); | ||||
|         }); | ||||
|  | ||||
|         // Unmask transfer complete EP interrupt | ||||
|         r.diepmsk().write(|w| { | ||||
|             w.set_xfrcm(true); | ||||
|         }); | ||||
|  | ||||
|         // Unmask and clear core interrupts | ||||
|         Bus::<T>::restore_irqs(); | ||||
|         r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); | ||||
|  | ||||
|         // Unmask global interrupt | ||||
|         r.gahbcfg().write(|w| { | ||||
|             w.set_gint(true); // unmask global interrupt | ||||
|         }); | ||||
|  | ||||
|         // Connect | ||||
|         r.dctl().write(|w| w.set_sdis(false)); | ||||
|  | ||||
|         self.enabled = true; | ||||
|     } | ||||
|  | ||||
| @@ -1066,8 +1017,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, In> { | ||||
|  | ||||
|             T::state().ep_in_wakers[ep_index].register(cx.waker()); | ||||
|  | ||||
|             // SAFETY: atomic read without side effects | ||||
|             if unsafe { T::regs().diepctl(ep_index).read().usbaep() } { | ||||
|             if T::regs().diepctl(ep_index).read().usbaep() { | ||||
|                 Poll::Ready(()) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
| @@ -1088,8 +1038,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, Out> { | ||||
|  | ||||
|             T::state().ep_out_wakers[ep_index].register(cx.waker()); | ||||
|  | ||||
|             // SAFETY: atomic read without side effects | ||||
|             if unsafe { T::regs().doepctl(ep_index).read().usbaep() } { | ||||
|             if T::regs().doepctl(ep_index).read().usbaep() { | ||||
|                 Poll::Ready(()) | ||||
|             } else { | ||||
|                 Poll::Pending | ||||
| @@ -1124,8 +1073,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> { | ||||
|                 // Release buffer | ||||
|                 state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release); | ||||
|  | ||||
|                 // SAFETY: DOEPCTL/DOEPTSIZ is shared with `Bus` so a critical section is needed for RMW | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                 critical_section::with(|_| { | ||||
|                     // Receive 1 packet | ||||
|                     T::regs().doeptsiz(index).modify(|w| { | ||||
|                         w.set_xfrsiz(self.info.max_packet_size as _); | ||||
| @@ -1163,8 +1111,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | ||||
|         poll_fn(|cx| { | ||||
|             state.ep_in_wakers[index].register(cx.waker()); | ||||
|  | ||||
|             // SAFETY: atomic read with no side effects | ||||
|             let diepctl = unsafe { r.diepctl(index).read() }; | ||||
|             let diepctl = r.diepctl(index).read(); | ||||
|             if !diepctl.usbaep() { | ||||
|                 Poll::Ready(Err(EndpointError::Disabled)) | ||||
|             } else if !diepctl.epena() { | ||||
| @@ -1181,12 +1128,10 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | ||||
|  | ||||
|                 let size_words = (buf.len() + 3) / 4; | ||||
|  | ||||
|                 // SAFETY: atomic read with no side effects | ||||
|                 let fifo_space = unsafe { r.dtxfsts(index).read().ineptfsav() as usize }; | ||||
|                 let fifo_space = r.dtxfsts(index).read().ineptfsav() as usize; | ||||
|                 if size_words > fifo_space { | ||||
|                     // Not enough space in fifo, enable tx fifo empty interrupt | ||||
|                     // SAFETY: DIEPEMPMSK is shared with IRQ so critical section is needed for RMW | ||||
|                     critical_section::with(|_| unsafe { | ||||
|                     critical_section::with(|_| { | ||||
|                         r.diepempmsk().modify(|w| { | ||||
|                             w.set_ineptxfem(w.ineptxfem() | (1 << index)); | ||||
|                         }); | ||||
| @@ -1202,18 +1147,14 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | ||||
|             .await | ||||
|         } | ||||
|  | ||||
|         // SAFETY: DIEPTSIZ is exclusive to this endpoint under `&mut self` | ||||
|         unsafe { | ||||
|             // Setup transfer size | ||||
|             r.dieptsiz(index).write(|w| { | ||||
|                 w.set_mcnt(1); | ||||
|                 w.set_pktcnt(1); | ||||
|                 w.set_xfrsiz(buf.len() as _); | ||||
|             }); | ||||
|         } | ||||
|         // Setup transfer size | ||||
|         r.dieptsiz(index).write(|w| { | ||||
|             w.set_mcnt(1); | ||||
|             w.set_pktcnt(1); | ||||
|             w.set_xfrsiz(buf.len() as _); | ||||
|         }); | ||||
|  | ||||
|         // SAFETY: DIEPCTL is shared with `Bus` so a critical section is needed for RMW | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             // Enable endpoint | ||||
|             r.diepctl(index).modify(|w| { | ||||
|                 w.set_cnak(true); | ||||
| @@ -1225,8 +1166,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | ||||
|         for chunk in buf.chunks(4) { | ||||
|             let mut tmp = [0u8; 4]; | ||||
|             tmp[0..chunk.len()].copy_from_slice(chunk); | ||||
|             // SAFETY: FIFO is exclusive to this endpoint under `&mut self` | ||||
|             unsafe { r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))) }; | ||||
|             r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))); | ||||
|         } | ||||
|  | ||||
|         trace!("write done ep={:?}", self.info.addr); | ||||
| @@ -1258,17 +1198,15 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> { | ||||
|                 state.ep0_setup_ready.store(false, Ordering::Release); | ||||
|  | ||||
|                 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section | ||||
|                 unsafe { | ||||
|                     // Receive 1 SETUP packet | ||||
|                     T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| { | ||||
|                         w.set_rxdpid_stupcnt(1); | ||||
|                     }); | ||||
|                 // Receive 1 SETUP packet | ||||
|                 T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| { | ||||
|                     w.set_rxdpid_stupcnt(1); | ||||
|                 }); | ||||
|  | ||||
|                     // Clear NAK to indicate we are ready to receive more data | ||||
|                     T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| { | ||||
|                         w.set_cnak(true); | ||||
|                     }); | ||||
|                 } | ||||
|                 // Clear NAK to indicate we are ready to receive more data | ||||
|                 T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| { | ||||
|                     w.set_cnak(true); | ||||
|                 }); | ||||
|  | ||||
|                 trace!("SETUP received: {:?}", data); | ||||
|                 Poll::Ready(data) | ||||
| @@ -1313,20 +1251,18 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> { | ||||
|         trace!("control: reject"); | ||||
|  | ||||
|         // EP0 should not be controlled by `Bus` so this RMW does not need a critical section | ||||
|         unsafe { | ||||
|             let regs = T::regs(); | ||||
|             regs.diepctl(self.ep_in.info.addr.index()).modify(|w| { | ||||
|                 w.set_stall(true); | ||||
|             }); | ||||
|             regs.doepctl(self.ep_out.info.addr.index()).modify(|w| { | ||||
|                 w.set_stall(true); | ||||
|             }); | ||||
|         } | ||||
|         let regs = T::regs(); | ||||
|         regs.diepctl(self.ep_in.info.addr.index()).modify(|w| { | ||||
|             w.set_stall(true); | ||||
|         }); | ||||
|         regs.doepctl(self.ep_out.info.addr.index()).modify(|w| { | ||||
|             w.set_stall(true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async fn accept_set_address(&mut self, addr: u8) { | ||||
|         trace!("setting addr: {}", addr); | ||||
|         critical_section::with(|_| unsafe { | ||||
|         critical_section::with(|_| { | ||||
|             T::regs().dcfg().modify(|w| { | ||||
|                 w.set_dad(addr); | ||||
|             }); | ||||
|   | ||||
| @@ -48,11 +48,9 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { | ||||
|         let rl = reload_value(psc, timeout_us); | ||||
|  | ||||
|         let wdg = T::regs(); | ||||
|         unsafe { | ||||
|             wdg.kr().write(|w| w.set_key(Key::ENABLE)); | ||||
|             wdg.pr().write(|w| w.set_pr(Pr(pr))); | ||||
|             wdg.rlr().write(|w| w.set_rl(rl)); | ||||
|         } | ||||
|         wdg.kr().write(|w| w.set_key(Key::ENABLE)); | ||||
|         wdg.pr().write(|w| w.set_pr(Pr(pr))); | ||||
|         wdg.rlr().write(|w| w.set_rl(rl)); | ||||
|  | ||||
|         trace!( | ||||
|             "Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})", | ||||
| @@ -67,11 +65,11 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub unsafe fn unleash(&mut self) { | ||||
|     pub fn unleash(&mut self) { | ||||
|         T::regs().kr().write(|w| w.set_key(Key::START)); | ||||
|     } | ||||
|  | ||||
|     pub unsafe fn pet(&mut self) { | ||||
|     pub fn pet(&mut self) { | ||||
|         T::regs().kr().write(|w| w.set_key(Key::RESET)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -16,10 +16,10 @@ async fn main(_spawner: Spawner) { | ||||
|     let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00); | ||||
|  | ||||
|     info!("Watchdog start"); | ||||
|     unsafe { wdg.unleash() }; | ||||
|     wdg.unleash(); | ||||
|  | ||||
|     loop { | ||||
|         Timer::after(Duration::from_secs(1)).await; | ||||
|         unsafe { wdg.pet() }; | ||||
|         wdg.pet(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -17,9 +17,7 @@ async fn main(_spawner: Spawner) { | ||||
|     let mut led = Output::new(p.PB7, Level::High, Speed::Low); | ||||
|  | ||||
|     let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); | ||||
|     unsafe { | ||||
|         wdt.unleash(); | ||||
|     } | ||||
|     wdt.unleash(); | ||||
|  | ||||
|     let mut i = 0; | ||||
|  | ||||
| @@ -36,9 +34,7 @@ async fn main(_spawner: Spawner) { | ||||
|         // MCU should restart in 1 second after the last pet. | ||||
|         if i < 5 { | ||||
|             info!("Petting watchdog"); | ||||
|             unsafe { | ||||
|                 wdt.pet(); | ||||
|             } | ||||
|             wdt.pet(); | ||||
|         } | ||||
|  | ||||
|         i += 1; | ||||
|   | ||||
| @@ -38,9 +38,7 @@ async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_stm32::init(config); | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     unsafe { | ||||
|         pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10)); | ||||
|     } | ||||
|     pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10)); | ||||
|  | ||||
|     let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); | ||||
|  | ||||
|   | ||||
| @@ -45,11 +45,9 @@ async fn main(_spawner: Spawner) { | ||||
|  | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     unsafe { | ||||
|         pac::RCC.ccipr4().write(|w| { | ||||
|             w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); | ||||
|         }); | ||||
|     } | ||||
|     pac::RCC.ccipr4().write(|w| { | ||||
|         w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); | ||||
|     }); | ||||
|  | ||||
|     // Create the driver, from the HAL. | ||||
|     let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); | ||||
|   | ||||
| @@ -62,49 +62,39 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | ||||
|         T::enable(); | ||||
|         <T as embassy_stm32::rcc::low_level::RccPeripheral>::reset(); | ||||
|  | ||||
|         unsafe { | ||||
|             ch1.set_speed(Speed::VeryHigh); | ||||
|             ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); | ||||
|             ch2.set_speed(Speed::VeryHigh); | ||||
|             ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); | ||||
|             ch3.set_speed(Speed::VeryHigh); | ||||
|             ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); | ||||
|             ch4.set_speed(Speed::VeryHigh); | ||||
|             ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); | ||||
|         } | ||||
|         ch1.set_speed(Speed::VeryHigh); | ||||
|         ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); | ||||
|         ch2.set_speed(Speed::VeryHigh); | ||||
|         ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); | ||||
|         ch3.set_speed(Speed::VeryHigh); | ||||
|         ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); | ||||
|         ch4.set_speed(Speed::VeryHigh); | ||||
|         ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); | ||||
|  | ||||
|         let mut this = Self { inner: tim }; | ||||
|  | ||||
|         this.set_freq(freq); | ||||
|         this.inner.start(); | ||||
|  | ||||
|         unsafe { | ||||
|             T::regs_gp32() | ||||
|                 .ccmr_output(0) | ||||
|                 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | ||||
|             T::regs_gp32() | ||||
|                 .ccmr_output(0) | ||||
|                 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); | ||||
|             T::regs_gp32() | ||||
|                 .ccmr_output(1) | ||||
|                 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | ||||
|             T::regs_gp32() | ||||
|                 .ccmr_output(1) | ||||
|                 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); | ||||
|         } | ||||
|         let r = T::regs_gp32(); | ||||
|         r.ccmr_output(0) | ||||
|             .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | ||||
|         r.ccmr_output(0) | ||||
|             .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); | ||||
|         r.ccmr_output(1) | ||||
|             .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | ||||
|         r.ccmr_output(1) | ||||
|             .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); | ||||
|  | ||||
|         this | ||||
|     } | ||||
|  | ||||
|     pub fn enable(&mut self, channel: Channel) { | ||||
|         unsafe { | ||||
|             T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true)); | ||||
|         } | ||||
|         T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true)); | ||||
|     } | ||||
|  | ||||
|     pub fn disable(&mut self, channel: Channel) { | ||||
|         unsafe { | ||||
|             T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false)); | ||||
|         } | ||||
|         T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false)); | ||||
|     } | ||||
|  | ||||
|     pub fn set_freq(&mut self, freq: Hertz) { | ||||
| @@ -112,11 +102,11 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | ||||
|     } | ||||
|  | ||||
|     pub fn get_max_duty(&self) -> u32 { | ||||
|         unsafe { T::regs_gp32().arr().read().arr() } | ||||
|         T::regs_gp32().arr().read().arr() | ||||
|     } | ||||
|  | ||||
|     pub fn set_duty(&mut self, channel: Channel, duty: u32) { | ||||
|         defmt::assert!(duty < self.get_max_duty()); | ||||
|         unsafe { T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) } | ||||
|         T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -15,10 +15,10 @@ async fn main(_spawner: Spawner) { | ||||
|  | ||||
|     let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000); | ||||
|  | ||||
|     unsafe { wdg.unleash() }; | ||||
|     wdg.unleash(); | ||||
|  | ||||
|     loop { | ||||
|         Timer::after(Duration::from_secs(1)).await; | ||||
|         unsafe { wdg.pet() }; | ||||
|         wdg.pet(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -12,12 +12,10 @@ use {defmt_rtt as _, panic_probe as _}; | ||||
| fn main() -> ! { | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     unsafe { | ||||
|         pac::RCC.ccipr().modify(|w| { | ||||
|             w.set_adcsel(0b11); | ||||
|         }); | ||||
|         pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); | ||||
|     } | ||||
|     pac::RCC.ccipr().modify(|w| { | ||||
|         w.set_adcsel(0b11); | ||||
|     }); | ||||
|     pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); | ||||
|  | ||||
|     let p = embassy_stm32::init(Default::default()); | ||||
|  | ||||
|   | ||||
| @@ -11,11 +11,9 @@ use {defmt_rtt as _, panic_probe as _}; | ||||
| fn main() -> ! { | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     unsafe { | ||||
|         pac::RCC.apb1enr1().modify(|w| { | ||||
|             w.set_dac1en(true); | ||||
|         }); | ||||
|     } | ||||
|     pac::RCC.apb1enr1().modify(|w| { | ||||
|         w.set_dac1en(true); | ||||
|     }); | ||||
|  | ||||
|     let p = embassy_stm32::init(Default::default()); | ||||
|  | ||||
|   | ||||
| @@ -35,7 +35,7 @@ async fn main(_spawner: Spawner) { | ||||
|     config.rcc.enable_lsi = true; // enable RNG | ||||
|     let p = embassy_stm32::init(config); | ||||
|  | ||||
|     unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) } | ||||
|     pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)); | ||||
|  | ||||
|     let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); | ||||
|  | ||||
|   | ||||
| @@ -15,11 +15,9 @@ async fn main(_spawner: Spawner) { | ||||
|     config.rcc.enable_lsi = true; //Needed for RNG to work | ||||
|  | ||||
|     let p = embassy_stm32::init(config); | ||||
|     unsafe { | ||||
|         pac::RCC.ccipr().modify(|w| { | ||||
|             w.set_rngsel(0b01); | ||||
|         }); | ||||
|     } | ||||
|     pac::RCC.ccipr().modify(|w| { | ||||
|         w.set_rngsel(0b01); | ||||
|     }); | ||||
|  | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|   | ||||
| @@ -24,10 +24,8 @@ async fn main(_spawner: Spawner) { | ||||
|  | ||||
|     info!("Starting LSI"); | ||||
|  | ||||
|     unsafe { | ||||
|         pac::RCC.csr().modify(|w| w.set_lsion(true)); | ||||
|         while !pac::RCC.csr().read().lsirdy() {} | ||||
|     } | ||||
|     pac::RCC.csr().modify(|w| w.set_lsion(true)); | ||||
|     while !pac::RCC.csr().read().lsirdy() {} | ||||
|  | ||||
|     info!("Started LSI"); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user