diff --git a/Cargo.toml b/Cargo.toml index 73c11909..bec364e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,8 +48,12 @@ default-features = false version = "1.0.2" [dependencies.embedded-hal] +# TODO: Update version when I2S proposal is finalized: +# https://github.com/rust-embedded/embedded-hal/pull/204 features = ["unproven"] -version = "0.2.3" +# version = "0.2.3" +git = "https://github.com/eldruin/embedded-hal/" +branch = "i2s-v0.2.x" [dev-dependencies] panic-semihosting = "0.5.3" diff --git a/examples/delay-blinky.rs b/examples/delay-blinky.rs index b9e94a68..4ebd3a5d 100644 --- a/examples/delay-blinky.rs +++ b/examples/delay-blinky.rs @@ -31,10 +31,10 @@ fn main() -> ! { loop { // On for 1s, off for 1s. - led.set_high().unwrap(); - delay.delay_ms(1000_u32); - led.set_low().unwrap(); - delay.delay_ms(1000_u32); + led.try_set_high().unwrap(); + delay.try_delay_ms(1000_u32).unwrap(); + led.try_set_low().unwrap(); + delay.try_delay_ms(1000_u32).unwrap(); } } diff --git a/examples/pwm.rs b/examples/pwm.rs index 66904fda..3c5096ca 100644 --- a/examples/pwm.rs +++ b/examples/pwm.rs @@ -24,9 +24,9 @@ fn main() -> ! { let pwm = pwm::tim1(dp.TIM1, channels, clocks, 20u32.khz()); let (mut ch1, _ch2) = pwm; - let max_duty = ch1.get_max_duty(); - ch1.set_duty(max_duty / 2); - ch1.enable(); + let max_duty = ch1.try_get_max_duty().unwrap(); + ch1.try_set_duty(max_duty / 2); + ch1.try_enable(); } loop { diff --git a/examples/rng-display.rs b/examples/rng-display.rs index c628c227..29955d19 100644 --- a/examples/rng-display.rs +++ b/examples/rng-display.rs @@ -99,7 +99,7 @@ fn main() -> ! { } disp.flush().unwrap(); //delay a little while between refreshes so the display is readable - delay_source.delay_ms(100u8); + delay_source.try_delay_ms(100u8).unwrap(); } } diff --git a/examples/timer-syst.rs b/examples/timer-syst.rs index 69f91c37..82daeceb 100644 --- a/examples/timer-syst.rs +++ b/examples/timer-syst.rs @@ -1,4 +1,4 @@ -//! Start and stop a periodic system timer. +//! Start and stop a periodic system timer.try_ //! //! This example should run on all stm32f4xx boards but it was tested with //! stm32f4-discovery board (model STM32F407G-DISC1). @@ -36,29 +36,29 @@ fn main() -> ! { hprintln!("hello!").unwrap(); // wait until timer expires - nb::block!(timer.wait()).unwrap(); + nb::block!(timer.try_wait()).unwrap(); hprintln!("timer expired 1").unwrap(); // the function syst() creates a periodic timer, so it is automatically // restarted - nb::block!(timer.wait()).unwrap(); + nb::block!(timer.try_wait()).unwrap(); hprintln!("timer expired 2").unwrap(); // cancel current timer - timer.cancel().unwrap(); + timer.try_cancel().unwrap(); // start it again - timer.start(24.hz()); - nb::block!(timer.wait()).unwrap(); + timer.try_start(24.hz()); + nb::block!(timer.try_wait()).unwrap(); hprintln!("timer expired 3").unwrap(); - timer.cancel().unwrap(); - let cancel_outcome = timer.cancel(); + timer.try_cancel().unwrap(); + let cancel_outcome = timer.try_cancel(); assert_eq!(cancel_outcome, Err(timer::Error::Disabled)); hprintln!("ehy, you cannot cancel a timer two times!").unwrap(); // this time the timer was not restarted, therefore this function should // wait forever - nb::block!(timer.wait()).unwrap(); + nb::block!(timer.try_wait()).unwrap(); // you should never see this print hprintln!("if you see this there is something wrong").unwrap(); panic!(); diff --git a/src/adc.rs b/src/adc.rs index 4b72ae36..0e68a718 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -26,7 +26,7 @@ macro_rules! adc_pins { $( impl Channel for $pin { type ID = u8; - fn channel() -> u8 { $chan } + const CHANNEL: Self::ID = $chan; } )+ }; @@ -665,7 +665,7 @@ macro_rules! adc { } let vref_cal = VrefCal::get().read(); - let vref_samp = self.read(&mut Vref).unwrap(); //This can't actually fail, it's just in a result to satisfy hal trait + let vref_samp = self.try_read(&mut Vref).unwrap(); //This can't actually fail, it's just in a result to satisfy hal trait self.calibrated_vdda = (VDDA_CALIB * u32::from(vref_cal)) / u32::from(vref_samp); if !vref_en { @@ -873,7 +873,7 @@ macro_rules! adc { } }); - let channel = CHANNEL::channel(); + let channel = CHANNEL::CHANNEL; //Set the channel in the right sequence field match sequence { @@ -976,7 +976,7 @@ macro_rules! adc { { type Error = (); - fn read(&mut self, pin: &mut PIN) -> nb::Result { + fn try_read(&mut self, pin: &mut PIN) -> nb::Result { let enabled = self.is_enabled(); if !enabled { self.enable(); diff --git a/src/delay.rs b/src/delay.rs index 56beca43..4092afc8 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -1,6 +1,8 @@ //! Delays use cast::u32; +use core::convert::Infallible; + use cortex_m::peripheral::syst::SystClkSource; use cortex_m::peripheral::SYST; @@ -28,25 +30,33 @@ impl Delay { } impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u32) { - self.delay_us(ms * 1_000); + type Error = Infallible; + + fn try_delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + self.try_delay_us(ms * 1_000) } } impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u16) { - self.delay_ms(u32(ms)); + type Error = Infallible; + + fn try_delay_ms(&mut self, ms: u16) -> Result<(), Self::Error> { + self.try_delay_ms(u32(ms)) } } impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u8) { - self.delay_ms(u32(ms)); + type Error = Infallible; + + fn try_delay_ms(&mut self, ms: u8) -> Result<(), Self::Error> { + self.try_delay_ms(u32(ms)) } } impl DelayUs for Delay { - fn delay_us(&mut self, us: u32) { + type Error = Infallible; + + fn try_delay_us(&mut self, us: u32) -> Result<(), Self::Error> { // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF. const MAX_RVR: u32 = 0x00FF_FFFF; @@ -70,17 +80,23 @@ impl DelayUs for Delay { self.syst.disable_counter(); } + + Ok(()) } } impl DelayUs for Delay { - fn delay_us(&mut self, us: u16) { - self.delay_us(u32(us)) + type Error = Infallible; + + fn try_delay_us(&mut self, us: u16) -> Result<(), Self::Error> { + self.try_delay_us(u32(us)) } } impl DelayUs for Delay { - fn delay_us(&mut self, us: u8) { - self.delay_us(u32(us)) + type Error = Infallible; + + fn try_delay_us(&mut self, us: u8) -> Result<(), Self::Error> { + self.try_delay_us(u32(us)) } } diff --git a/src/dwt.rs b/src/dwt.rs index b650ecac..d83f6754 100644 --- a/src/dwt.rs +++ b/src/dwt.rs @@ -1,8 +1,11 @@ //! Debug and trace and stuff +use core::convert::Infallible; + use crate::rcc::Clocks; use crate::time::Hertz; use cortex_m::peripheral::{DCB, DWT}; + use embedded_hal::blocking::delay::{DelayMs, DelayUs}; pub trait DwtExt { @@ -65,13 +68,13 @@ pub struct Delay { } impl Delay { /// Delay for `ClockDuration::ticks` - pub fn delay(duration: ClockDuration) { + pub fn try_delay(duration: ClockDuration) -> Result<(), Infallible> { let ticks = duration.ticks as u64; - Delay::delay_ticks(DWT::get_cycle_count(), ticks); + Delay::try_delay_ticks(DWT::get_cycle_count(), ticks) } /// Delay ticks /// NOTE DCB and DWT need to be set up for this to work, so it is private - fn delay_ticks(mut start: u32, ticks: u64) { + fn try_delay_ticks(mut start: u32, ticks: u64) -> Result<(), Infallible> { if ticks < (core::u32::MAX / 2) as u64 { // Simple delay let ticks = ticks as u32; @@ -96,24 +99,30 @@ impl Delay { while (DWT::get_cycle_count().wrapping_sub(start)) > ticks {} } } + + Ok(()) } } // Implement DelayUs/DelayMs for various integer types impl> DelayUs for Delay { - fn delay_us(&mut self, us: T) { + type Error = Infallible; + + fn try_delay_us(&mut self, us: T) -> Result<(), Self::Error> { // Convert us to ticks let start = DWT::get_cycle_count(); let ticks = (us.into() * self.clock.0 as u64) / 1_000_000; - Delay::delay_ticks(start, ticks); + Delay::try_delay_ticks(start, ticks) } } impl> DelayMs for Delay { - fn delay_ms(&mut self, ms: T) { + type Error = Infallible; + + fn try_delay_ms(&mut self, ms: T) -> Result<(), Self::Error> { // Convert ms to ticks let start = DWT::get_cycle_count(); let ticks = (ms.into() * self.clock.0 as u64) / 1_000; - Delay::delay_ticks(start, ticks); + Delay::try_delay_ticks(start, ticks) } } diff --git a/src/gpio.rs b/src/gpio.rs index a57c8193..959a2158 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -244,7 +244,7 @@ macro_rules! gpio { use core::marker::PhantomData; use core::convert::Infallible; - use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, toggleable}; + use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin, toggleable}; use crate::stm32::$GPIOX; use crate::stm32::{RCC, EXTI, SYSCFG}; @@ -293,13 +293,13 @@ macro_rules! gpio { impl OutputPin for $PXx> { type Error = Infallible; - fn set_high(&mut self) -> Result<(), Self::Error> { + fn try_set_high(&mut self) -> Result<(), Self::Error> { // NOTE(unsafe) atomic write to a stateless register unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }; Ok(()) } - fn set_low(&mut self) -> Result<(), Self::Error> { + fn try_set_low(&mut self) -> Result<(), Self::Error> { // NOTE(unsafe) atomic write to a stateless register unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (self.i + 16))) }; Ok(()) @@ -307,11 +307,11 @@ macro_rules! gpio { } impl StatefulOutputPin for $PXx> { - fn is_set_high(&self) -> Result { - self.is_set_low().map(|v| !v) + fn try_is_set_high(&self) -> Result { + self.try_is_set_low().map(|v| !v) } - fn is_set_low(&self) -> Result { + fn try_is_set_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects Ok(unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 }) } @@ -322,11 +322,11 @@ macro_rules! gpio { impl InputPin for $PXx> { type Error = Infallible; - fn is_high(&self) -> Result { - self.is_low().map(|v| !v) + fn try_is_high(&self) -> Result { + self.try_is_low().map(|v| !v) } - fn is_low(&self) -> Result { + fn try_is_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }) } @@ -335,11 +335,11 @@ macro_rules! gpio { impl InputPin for $PXx> { type Error = Infallible; - fn is_high(&self) -> Result { - self.is_low().map(|v| !v) + fn try_is_high(&self) -> Result { + self.try_is_low().map(|v| !v) } - fn is_low(&self) -> Result { + fn try_is_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }) } @@ -754,13 +754,13 @@ macro_rules! gpio { impl OutputPin for $PXi> { type Error = Infallible; - fn set_high(&mut self) -> Result<(), Self::Error> { + fn try_set_high(&mut self) -> Result<(), Self::Error> { // NOTE(unsafe) atomic write to a stateless register unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }; Ok(()) } - fn set_low(&mut self) -> Result<(), Self::Error> { + fn try_set_low(&mut self) -> Result<(), Self::Error> { // NOTE(unsafe) atomic write to a stateless register unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << ($i + 16))) }; Ok(()) @@ -768,11 +768,11 @@ macro_rules! gpio { } impl StatefulOutputPin for $PXi> { - fn is_set_high(&self) -> Result { - self.is_set_low().map(|v| !v) + fn try_is_set_high(&self) -> Result { + self.try_is_set_low().map(|v| !v) } - fn is_set_low(&self) -> Result { + fn try_is_set_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects Ok(unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }) } @@ -783,11 +783,11 @@ macro_rules! gpio { impl InputPin for $PXi> { type Error = Infallible; - fn is_high(&self) -> Result { - self.is_low().map(|v| !v) + fn try_is_high(&self) -> Result { + self.try_is_low().map(|v| !v) } - fn is_low(&self) -> Result { + fn try_is_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }) } @@ -796,11 +796,11 @@ macro_rules! gpio { impl InputPin for $PXi> { type Error = Infallible; - fn is_high(&self) -> Result { - self.is_low().map(|v| !v) + fn try_is_high(&self) -> Result { + self.try_is_low().map(|v| !v) } - fn is_low(&self) -> Result { + fn try_is_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }) } diff --git a/src/i2c.rs b/src/i2c.rs index 8d7c3eb3..140f913c 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -905,9 +905,14 @@ where { type Error = Error; - fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { - self.write_bytes(addr, bytes)?; - self.read(addr, buffer)?; + fn try_write_read( + &mut self, + addr: u8, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.try_write(addr, bytes)?; + self.try_read(addr, buffer)?; Ok(()) } @@ -919,7 +924,7 @@ where { type Error = Error; - fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { + fn try_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { self.write_bytes(addr, bytes)?; // Send a STOP condition @@ -939,7 +944,7 @@ where { type Error = Error; - fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + fn try_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { if let Some((last, buffer)) = buffer.split_last_mut() { // Send a START condition and set ACK bit self.i2c diff --git a/src/i2s.rs b/src/i2s.rs new file mode 100644 index 00000000..9ecfe620 --- /dev/null +++ b/src/i2s.rs @@ -0,0 +1,1143 @@ +use core::ops::Deref; +use core::ptr; + +// use embedded_hal::spi; +// pub use embedded_hal::spi::{Mode, Phase, Polarity}; +// use nb; + +#[cfg(any( + feature = "stm32f401", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::stm32::{spi1, RCC, SPI1, SPI2}; + +#[cfg(any( + feature = "stm32f401", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::stm32::SPI3; + +#[cfg(any( + feature = "stm32f401", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::stm32::SPI4; + +#[cfg(any( + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::stm32::SPI5; + +#[cfg(any( + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::stm32::SPI6; + +#[cfg(any( + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpioa::PA9; +#[cfg(any( + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423" +))] +use crate::gpio::gpioa::{PA1, PA11}; +#[cfg(any( + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423" +))] +use crate::gpio::gpioa::{PA10, PA12}; +#[cfg(any( + feature = "stm32f401", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpioa::{PA15, PA4, PA5, PA6, PA7}; +// NOTE: Added PA4 and PA15 here. + +#[cfg(any( + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f446" +))] +use crate::gpio::gpiob::PB0; +#[cfg(any( + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423" +))] +use crate::gpio::gpiob::PB12; +#[cfg(any(feature = "stm32f446"))] +use crate::gpio::gpiob::PB2; +#[cfg(any( + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423" +))] +use crate::gpio::gpiob::PB8; +#[cfg(any( + feature = "stm32f401", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpiob::{PB10, PB13, PB14, PB15, PB3, PB4, PB5}; + +#[cfg(any(feature = "stm32f446", feature = "stm32f469", feature = "stm32f479"))] +use crate::gpio::gpioc::PC1; +#[cfg(any( + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f446" +))] +use crate::gpio::gpioc::PC7; +#[cfg(any( + feature = "stm32f401", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpioc::{PC10, PC11, PC12}; +#[cfg(any( + feature = "stm32f401", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpioc::{PC2, PC3}; + +#[cfg(any(feature = "stm32f446"))] +use crate::gpio::gpiod::PD0; +#[cfg(any( + feature = "stm32f401", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpiod::{PD3, PD6}; + +#[cfg(any( + feature = "stm32f401", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpioe::{PE12, PE13, PE14, PE2, PE5, PE6}; + +#[cfg(any( + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpiof::{PF11, PF7, PF8, PF9}; + +#[cfg(any(feature = "stm32f446"))] +use crate::gpio::gpiog::PG11; +#[cfg(any( + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpiog::PG14; +#[cfg(any( + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpiog::{PG12, PG13}; + +#[cfg(any( + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpioh::{PH6, PH7}; + +#[cfg(any( + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::gpioi::{PI1, PI2, PI3}; + +#[cfg(any( + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f446" +))] +use crate::gpio::AF7; +#[cfg(any( + feature = "stm32f401", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f415", + feature = "stm32f417", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f429", + feature = "stm32f437", + feature = "stm32f439", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479" +))] +use crate::gpio::{Alternate, AF5, AF6, AF7}; + +use crate::rcc::Clocks; +use crate::time::Hertz; + +/// I2S error +#[derive(Debug)] +pub enum Error { + /// Overrun occurred + Overrun, + /// Mode fault occurred + ModeFault, + /// CRC error + Crc, + #[doc(hidden)] + _Extensible, +} + +pub trait Pins {} +pub trait PinCk {} +pub trait PinWs {} +pub trait PinSd {} +pub trait PinSdExt {} + +impl Pins for (CK, WS, SD, SDEXT) +where + CK: PinCk, + WS: PinWs, + SD: PinSd, + SDEXT: PinSdExt, +{ +} + +/// A filler type for when the CK pin is unnecessary +pub struct NoCk; +/// A filler type for when the Ws pin is unnecessary +pub struct NoWs; +/// A filler type for when the Sd pin is unnecessary +pub struct NoSd; +/// A filler type for when the SdExt pin is unnecessary +pub struct NoSdExt; + +// NOTE: Manual pins for I2S3 during development. +// TODO: Should be created with macro. +impl PinCk for NoCk {} +impl PinCk for PB3> {} +impl PinCk for PC10> {} + +impl PinWs for NoWs {} +impl PinWs for PA4> {} +impl PinWs for PA15> {} + +impl PinSd for NoSd {} +impl PinSd for PB5> {} +impl PinSd for PC12> {} + +impl PinSdExt for NoSdExt {} +impl PinSdExt for PB4> {} +impl PinSdExt for PC11> {} + +// macro_rules! pins { +// ($($SPIX:ty: CK: [$($CK:ty),*] WS: [$($WS:ty),*] SD: [$($SD:ty),*] SDEXT: [$($SDEXT:ty),*])+) => { +// $( +// $( +// impl PinCk<$SPIX> for $CK {} +// )* +// $( +// impl PinWs<$SPIX> for $WS {} +// )* +// $( +// impl PinSd<$SPIX> for $SD {} +// )* +// $( +// impl PinSdExt<$SPIX> for $SDEXT {} +// )* +// )+ +// } +// } + +// #[cfg(any( +// feature = "stm32f401", +// feature = "stm32f405", +// feature = "stm32f407", +// feature = "stm32f410", +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f415", +// feature = "stm32f417", +// feature = "stm32f423", +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f446", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// pins! { +// SPI1: +// CK: [ +// NoCk, +// PA5>, +// PB3> +// ] +// WS: [] // TODO: Fill in. +// SD: [ +// NoSd, +// PA7>, +// PB5> +// ] +// SDEXT: [ +// NoSdExt, +// PA6>, +// PB4> +// ] + +// SPI2: +// CK: [ +// NoCk, +// PB10>, +// PB13> +// ] +// WS: [] // TODO: Fill in. +// SD: [ +// NoSd, +// PB15>, +// PC3> +// ] +// SDEXT: [ +// NoSdExt, +// PB14>, +// PC2> +// ] +// } + +// #[cfg(any( +// feature = "stm32f401", +// feature = "stm32f405", +// feature = "stm32f407", +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f415", +// feature = "stm32f417", +// feature = "stm32f423", +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f446", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// pins! { +// SPI3: +// CK: [ +// NoCk, +// PB3>, +// PC10> +// ] +// WS: [] // TODO: Fill in. +// SD: [ +// NoSd, +// PB5>, +// PC12> +// ] +// SDEXT: [ +// NoSdExt, +// PB4>, +// PC11> +// ] +// } + +// #[cfg(any( +// feature = "stm32f401", +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f423", +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f446", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// pins! { +// SPI2: +// CK: [PD3>] +// WS: [] // TODO: Fill in. +// SD: [] +// SDEXT: [] +// SPI3: +// CK: [] +// WS: [] // TODO: Fill in. +// SD: [] +// SDEXT: [PD6>] +// SPI4: +// CK: [ +// NoCk, +// PE2>, +// PE12> +// ] +// WS: [] // TODO: Fill in. +// SD: [ +// NoSd, +// PE6>, +// PE14> +// ] +// SDEXT: [ +// NoSdExt, +// PE5>, +// PE13> +// ] +// } + +// #[cfg(any( +// feature = "stm32f405", +// feature = "stm32f407", +// feature = "stm32f415", +// feature = "stm32f417", +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// pins! { +// SPI2: +// CK: [PI1>] +// WS: [] // TODO: Fill in. +// SD: [PI3>] +// SDEXT: [PI2>] +// } + +// #[cfg(any( +// feature = "stm32f410", +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f423", +// feature = "stm32f446" +// ))] +// pins! { +// SPI2: +// CK: [PC7>] +// WS: [] // TODO: Fill in. +// SD: [] +// SDEXT: [] +// } + +// #[cfg(any( +// feature = "stm32f410", +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f423" +// ))] +// pins! { +// SPI5: +// CK: [ +// NoCk, +// PB0> +// ] +// WS: [] // TODO: Fill in. +// SD: [ +// NoSd, +// PA10>, +// PB8> +// ] +// SDEXT: [ +// NoSdExt, +// PA12> +// ] +// } + +// #[cfg(any( +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f423" +// ))] +// pins! { +// SPI3: +// CK: [PB12>] +// WS: [] // TODO: Fill in. +// SD: [] +// SDEXT: [] +// SPI4: +// CK: [PB13>] +// WS: [] // TODO: Fill in. +// SD: [PA1>] +// SDEXT: [PA11>] +// SPI5: +// CK: [ +// PE2>, +// PE12> +// ] +// WS: [] // TODO: Fill in. +// SD: [ +// PE6>, +// PE14> +// ] +// SDEXT: [ +// PE5>, +// PE13> +// ] +// } + +// #[cfg(any(feature = "stm32f413", feature = "stm32f423"))] +// pins! { +// SPI2: +// CK: [PA9>] +// WS: [] // TODO: Fill in. +// SD: [PA10>] +// SDEXT: [PA12>] +// } + +// #[cfg(any( +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// pins! { +// SPI5: +// CK: [ +// NoCk, +// PF7>, +// PH6> +// ] +// WS: [] // TODO: Fill in. +// SD: [ +// NoSd, +// PF9>, +// PF11> +// ] +// SDEXT: [ +// NoSdExt, +// PF8>, +// PH7> +// ] + +// SPI6: +// CK: [ +// NoCk, +// PG13> +// ] +// WS: [] // TODO: Fill in. +// SD: [ +// NoSd, +// PG14> +// ] +// SDEXT: [ +// NoSdExt, +// PG12> +// ] +// } + +// #[cfg(any(feature = "stm32f446"))] +// pins! { +// SPI2: +// CK: [PA9>] +// WS: [] // TODO: Fill in. +// SD: [PC1>] +// SDEXT: [] + +// SPI3: +// CK: [] +// WS: [] // TODO: Fill in. +// SD: [ +// PB0>, +// PB2>, +// PD0> +// ] +// SDEXT: [] + +// SPI4: +// CK: [PG11>] +// WS: [] // TODO: Fill in. +// SD: [PG13>] +// SDEXT: [ +// PG12>, +// PD0> +// ] +// } + +// #[cfg(any(feature = "stm32f469", feature = "stm32f479"))] +// pins! { +// SPI2: +// CK: [PA9>] +// WS: [] // TODO: Fill in. +// SD: [PC1>] +// SDEXT: [] +// } + +// /// Interrupt events +// pub enum Event { +// /// New data has been received +// Rxne, +// /// Data can be sent +// Txe, +// /// An error occurred +// Error, +// } + +#[derive(Debug)] +pub struct I2s { + spi: SPI, + pins: PINS, +} + +// #[cfg(any( +// feature = "stm32f401", +// feature = "stm32f405", +// feature = "stm32f407", +// feature = "stm32f410", +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f415", +// feature = "stm32f417", +// feature = "stm32f423", +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f446", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// impl Spi { +// pub fn spi1(spi: SPI1, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self +// where +// PINS: Pins, +// { +// // NOTE(unsafe) This executes only during initialisation +// let rcc = unsafe { &(*RCC::ptr()) }; + +// // Enable clock for SPI +// rcc.apb2enr.modify(|_, w| w.spi1en().set_bit()); + +// Spi { spi, pins }.init(mode, freq, clocks.pclk2()) +// } +// } + +// #[cfg(any( +// feature = "stm32f401", +// feature = "stm32f405", +// feature = "stm32f407", +// feature = "stm32f410", +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f415", +// feature = "stm32f417", +// feature = "stm32f423", +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f446", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// impl Spi { +// pub fn spi2(spi: SPI2, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self +// where +// PINS: Pins, +// { +// // NOTE(unsafe) This executes only during initialisation +// let rcc = unsafe { &(*RCC::ptr()) }; + +// // Enable clock for SPI +// rcc.apb1enr.modify(|_, w| w.spi2en().set_bit()); + +// Spi { spi, pins }.init(mode, freq, clocks.pclk1()) +// } +// } + +// #[cfg(any( +// feature = "stm32f401", +// feature = "stm32f405", +// feature = "stm32f407", +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f415", +// feature = "stm32f417", +// feature = "stm32f423", +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f446", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// impl Spi { +// pub fn spi3(spi: SPI3, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self +// where +// PINS: Pins, +// { +// // NOTE(unsafe) This executes only during initialisation +// let rcc = unsafe { &(*RCC::ptr()) }; + +// // Enable clock for SPI +// rcc.apb1enr.modify(|_, w| w.spi3en().set_bit()); + +// Spi { spi, pins }.init(mode, freq, clocks.pclk1()) +// } +// } + +// #[cfg(any( +// feature = "stm32f401", +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f423", +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f446", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// impl Spi { +// pub fn spi4(spi: SPI4, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self +// where +// PINS: Pins, +// { +// // NOTE(unsafe) This executes only during initialisation +// let rcc = unsafe { &(*RCC::ptr()) }; + +// // Enable clock for SPI +// rcc.apb2enr.modify(|_, w| w.spi4en().set_bit()); + +// Spi { spi, pins }.init(mode, freq, clocks.pclk2()) +// } +// } + +// #[cfg(any( +// feature = "stm32f410", +// feature = "stm32f411", +// feature = "stm32f412", +// feature = "stm32f413", +// feature = "stm32f423", +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// impl Spi { +// pub fn spi5(spi: SPI5, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self +// where +// PINS: Pins, +// { +// // NOTE(unsafe) This executes only during initialisation +// let rcc = unsafe { &(*RCC::ptr()) }; + +// // Enable clock for SPI +// rcc.apb2enr.modify(|_, w| w.spi5en().set_bit()); + +// Spi { spi, pins }.init(mode, freq, clocks.pclk2()) +// } +// } + +// #[cfg(any( +// feature = "stm32f427", +// feature = "stm32f429", +// feature = "stm32f437", +// feature = "stm32f439", +// feature = "stm32f469", +// feature = "stm32f479" +// ))] +// impl Spi { +// pub fn spi6(spi: SPI6, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self +// where +// PINS: Pins, +// { +// // NOTE(unsafe) This executes only during initialisation +// let rcc = unsafe { &(*RCC::ptr()) }; + +// // Enable clock for SPI +// rcc.apb2enr.modify(|_, w| w.spi6en().set_bit()); + +// Spi { spi, pins }.init(mode, freq, clocks.pclk2()) +// } +// } + +impl I2s { + pub fn i2s3(spi: SPI3, pins: PINS, freq: Hertz, clocks: Clocks) -> Self + where + PINS: Pins, + { + // NOTE(unsafe) This executes only during initialisation + let rcc = unsafe { &(*RCC::ptr()) }; + + // Enable clock for SPI + rcc.apb1enr.modify(|_, w| w.spi3en().set_bit()); + + // TODO: Use Real clock value from I2S PLL. + I2s { spi, pins }.init(freq, freq) + } +} + +impl I2s +where + SPI: Deref, +{ + pub fn init(self, freq: Hertz, clock: Hertz) -> Self { + // disable SS output + self.spi.cr2.write(|w| w.ssoe().clear_bit()); + + // TODO: Calculate baud rate. + // let br = match clock.0 / freq.0 { + // 0 => unreachable!(), + // 1..=2 => 0b000, + // 3..=5 => 0b001, + // 6..=11 => 0b010, + // 12..=23 => 0b011, + // 24..=47 => 0b100, + // 48..=95 => 0b101, + // 96..=191 => 0b110, + // _ => 0b111, + // }; + let br: u8 = 0; + + // Configure clock polarity. + // self.spi.i2scfgr.write(|w| w.ckpol().idle_high()); + + // Configure the I2S precsaler and enable MCKL output. + // NOTE: Hardcoded for 48KHz audio sampling rate with PLLI2S at 86MHz. + // I2S uses DIV=3, ODD=true to achive a 12.285714 MHz MCKL. + // FS = I2SxCLK / [(16*2)*(((2*I2SDIV)+ODD)*8)] when the channel frame is 16-bit wide. + // FS = 86MHz (from PLLI2S above) / [(16*2)*(((2*3)+1)*8)] = 48KHz + // NOTE: Unsafe because the division can be set incorrectly. + self.spi + .i2spr + .write(|w| unsafe { w.i2sdiv().bits(3).odd().odd().mckoe().enabled() }); + + // Configure I2S. + // TODO: Configurable I2S standard and data length from user input. + self.spi.i2scfgr.write(|w| { + w + // SPI/I2S Mode. + .i2smod() + .i2smode() + // I2S standard. + .i2sstd() + .philips() + // Data and channel length. + .datlen() + .sixteen_bit() + .chlen() + .sixteen_bit() + // Clock steady state polarity. + .ckpol() + .idle_high() + // Master TX mode and enable. + .i2scfg() + .master_tx() + .i2se() + .enabled() + }); + + self + } + + // TODO: Configure interrupts for I2S. + // /// Enable interrupts for the given `event`: + // /// - Received data ready to be read (RXNE) + // /// - Transmit data register empty (TXE) + // /// - Transfer error + // pub fn listen(&mut self, event: Event) { + // match event { + // Event::Rxne => self.spi.cr2.modify(|_, w| w.rxneie().set_bit()), + // Event::Txe => self.spi.cr2.modify(|_, w| w.txeie().set_bit()), + // Event::Error => self.spi.cr2.modify(|_, w| w.errie().set_bit()), + // } + // } + + // /// Disable interrupts for the given `event`: + // /// - Received data ready to be read (RXNE) + // /// - Transmit data register empty (TXE) + // /// - Transfer error + // pub fn unlisten(&mut self, event: Event) { + // match event { + // Event::Rxne => self.spi.cr2.modify(|_, w| w.rxneie().clear_bit()), + // Event::Txe => self.spi.cr2.modify(|_, w| w.txeie().clear_bit()), + // Event::Error => self.spi.cr2.modify(|_, w| w.errie().clear_bit()), + // } + // } + + /// Return `true` if the TXE flag is set, i.e. new data to transmit + /// can be written to the SPI. + pub fn is_txe(&self) -> bool { + self.spi.sr.read().txe().bit_is_set() + } + + /// Return the value of the CHSIDE flag, i.e. which channel to transmit next. + pub fn ch_side(&self) -> bool { + self.spi.sr.read().chside().bit_is_set() + } + + // /// Return `true` if the RXNE flag is set, i.e. new data has been received + // /// and can be read from the SPI. + // pub fn is_rxne(&self) -> bool { + // self.spi.sr.read().rxne().bit_is_set() + // } + + // /// Return `true` if the MODF flag is set, i.e. the SPI has experienced a + // /// Master Mode Fault. (see chapter 28.3.10 of the STM32F4 Reference Manual) + // pub fn is_modf(&self) -> bool { + // self.spi.sr.read().modf().bit_is_set() + // } + + // /// Return `true` if the OVR flag is set, i.e. new data has been received + // /// while the receive data register was already filled. + // pub fn is_ovr(&self) -> bool { + // self.spi.sr.read().ovr().bit_is_set() + // } + + pub fn free(self) -> (SPI, PINS) { + (self.spi, self.pins) + } + + pub fn send(&mut self, data: u16) -> Result<(), Error> { + unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u16, data) } + while self.spi.sr.read().txe().bit_is_clear() {} + Ok(()) + } +} + +// impl spi::FullDuplex for Spi +// where +// SPI: Deref, +// { +// type Error = Error; + +// fn read(&mut self) -> nb::Result { +// let sr = self.spi.sr.read(); + +// Err(if sr.ovr().bit_is_set() { +// nb::Error::Other(Error::Overrun) +// } else if sr.modf().bit_is_set() { +// nb::Error::Other(Error::ModeFault) +// } else if sr.crcerr().bit_is_set() { +// nb::Error::Other(Error::Crc) +// } else if sr.rxne().bit_is_set() { +// // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows +// // reading a half-word) +// return Ok(unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) }); +// } else { +// nb::Error::WouldBlock +// }) +// } + +// fn send(&mut self, byte: u8) -> nb::Result<(), Error> { +// let sr = self.spi.sr.read(); + +// Err(if sr.ovr().bit_is_set() { +// nb::Error::Other(Error::Overrun) +// } else if sr.modf().bit_is_set() { +// nb::Error::Other(Error::ModeFault) +// } else if sr.crcerr().bit_is_set() { +// nb::Error::Other(Error::Crc) +// } else if sr.txe().bit_is_set() { +// // NOTE(write_volatile) see note above +// unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) } +// return Ok(()); +// } else { +// nb::Error::WouldBlock +// }) +// } +// } + +// impl embedded_hal::blocking::spi::transfer::Default for Spi where +// SPI: Deref +// { +// } + +// impl embedded_hal::blocking::spi::write::Default for Spi where +// SPI: Deref +// { +// } diff --git a/src/lib.rs b/src/lib.rs index be09750d..b0cc385e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,6 +98,8 @@ pub mod delay; pub mod gpio; #[cfg(feature = "device-selected")] pub mod i2c; +#[cfg(feature = "device-selected")] +pub mod i2s; #[cfg(all( feature = "usb_fs", any( diff --git a/src/prelude.rs b/src/prelude.rs index f4dd80fc..52b26883 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,7 +1,7 @@ -pub use embedded_hal::digital::v2::InputPin as _embedded_hal_digital_v2_InputPin; -pub use embedded_hal::digital::v2::OutputPin as _embedded_hal_digital_v2_OutputPin; -pub use embedded_hal::digital::v2::StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin; -pub use embedded_hal::digital::v2::ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin; +pub use embedded_hal::digital::InputPin as _embedded_hal_digital_v2_InputPin; +pub use embedded_hal::digital::OutputPin as _embedded_hal_digital_v2_OutputPin; +pub use embedded_hal::digital::StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin; +pub use embedded_hal::digital::ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin; pub use embedded_hal::prelude::*; #[cfg(all( diff --git a/src/pwm.rs b/src/pwm.rs index c3740403..194d4cc0 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -1,4 +1,5 @@ use cast::{u16, u32}; +use core::convert::Infallible; use core::{marker::PhantomData, mem::MaybeUninit}; #[cfg(any( @@ -220,119 +221,135 @@ macro_rules! pwm_all_channels { unsafe { MaybeUninit::uninit().assume_init() } } - impl hal::PwmPin for PwmChannels<$TIMX, C1> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C1> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty.into())) }; + Ok(()) } } - impl hal::PwmPin for PwmChannels<$TIMX, C2> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C2> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty.into())) }; + Ok(()) } } - impl hal::PwmPin for PwmChannels<$TIMX, C3> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C3> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty.into())) }; + Ok(()) } } - impl hal::PwmPin for PwmChannels<$TIMX, C4> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C4> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty.into())) }; + Ok(()) } } )+ @@ -397,61 +414,69 @@ macro_rules! pwm_2_channels { unsafe { MaybeUninit::uninit().assume_init() } } - impl hal::PwmPin for PwmChannels<$TIMX, C1> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C1> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty.into())) }; + Ok(()) } } - impl hal::PwmPin for PwmChannels<$TIMX, C2> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C2> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty.into())) }; + Ok(()) } } )+ @@ -509,32 +534,36 @@ macro_rules! pwm_1_channel { unsafe { MaybeUninit::uninit().assume_init() } } - impl hal::PwmPin for PwmChannels<$TIMX, C1> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C1> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty.into())) }; + Ok(()) } } )+ @@ -608,119 +637,135 @@ macro_rules! pwm_tim5_f410 { unsafe { MaybeUninit::uninit().assume_init() } } - impl hal::PwmPin for PwmChannels<$TIMX, C1> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C1> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr1.read().ccr1_l().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr1.read().ccr1_l().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr_l().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr_l().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr1_l().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr1_l().bits(duty.into())) }; + Ok(()) } } - impl hal::PwmPin for PwmChannels<$TIMX, C2> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C2> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr2.read().ccr1_l().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr2.read().ccr1_l().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr_l().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr_l().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr1_l().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr1_l().bits(duty.into())) }; + Ok(()) } } - impl hal::PwmPin for PwmChannels<$TIMX, C3> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C3> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr3.read().ccr1_l().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr3.read().ccr1_l().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr_l().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr_l().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr1_l().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr1_l().bits(duty.into())) }; + Ok(()) } } - impl hal::PwmPin for PwmChannels<$TIMX, C4> { + impl hal::pwm::PwmPin for PwmChannels<$TIMX, C4> { + type Error = Infallible; type Duty = u16; //NOTE(unsafe) atomic write with no side effects - fn disable(&mut self) { - unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) } + fn try_disable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) }; + Ok(()) } //NOTE(unsafe) atomic write with no side effects - fn enable(&mut self) { - unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) } + fn try_enable(&mut self) -> Result<(), Self::Error> { + unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) }; + Ok(()) } //NOTE(unsafe) atomic read with no side effects - fn get_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).ccr4.read().ccr1_l().bits() as u16 } + fn try_get_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).ccr4.read().ccr1_l().bits() as u16 }) } //NOTE(unsafe) atomic read with no side effects - fn get_max_duty(&self) -> u16 { - unsafe { (*$TIMX::ptr()).arr.read().arr_l().bits() as u16 } + fn try_get_max_duty(&self) -> Result { + Ok(unsafe { (*$TIMX::ptr()).arr.read().arr_l().bits() as u16 }) } //NOTE(unsafe) atomic write with no side effects - fn set_duty(&mut self, duty: u16) { - unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr1_l().bits(duty.into())) } + fn try_set_duty(&mut self, duty: u16) -> Result<(), Self::Error> { + unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr1_l().bits(duty.into())) }; + Ok(()) } } )+ diff --git a/src/qei.rs b/src/qei.rs index 3a90c831..79f9ca76 100644 --- a/src/qei.rs +++ b/src/qei.rs @@ -1,6 +1,7 @@ //! # Quadrature Encoder Interface -use crate::hal::{self, Direction}; +use crate::hal::{self, qei::Direction}; use crate::stm32::RCC; +use core::convert::Infallible; #[cfg(any( feature = "stm32f401", @@ -126,18 +127,19 @@ macro_rules! hal { } } - impl hal::Qei for Qei<$TIM, PINS> { + impl hal::qei::Qei for Qei<$TIM, PINS> { + type Error = Infallible; type Count = $bits; - fn count(&self) -> $bits { - self.tim.cnt.read().bits() as $bits + fn try_count(&self) -> Result { + Ok(self.tim.cnt.read().bits() as $bits) } - fn direction(&self) -> Direction { + fn try_direction(&self) -> Result { if self.tim.cr1.read().dir().bit_is_clear() { - hal::Direction::Upcounting + Ok(Direction::Upcounting) } else { - hal::Direction::Downcounting + Ok(Direction::Downcounting) } } } diff --git a/src/rcc.rs b/src/rcc.rs index 88f7ef06..4d34d3e0 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -19,6 +19,7 @@ impl RccExt for RCC { pclk2: None, sysclk: None, pll48clk: false, + plli2sclk: None, }, } } @@ -124,6 +125,7 @@ pub struct CFGR { pclk2: Option, sysclk: Option, pll48clk: bool, + plli2sclk: Option, } impl CFGR { @@ -174,13 +176,21 @@ impl CFGR { self } + pub fn plli2sclk(mut self, freq: F) -> Self + where + F: Into, + { + self.plli2sclk = Some(freq.into().0); + self + } + #[inline(always)] - fn pll_setup(&self) -> (bool, bool, u32, Option) { + fn pll_setup(&self) -> (bool, bool, u32, Option, Option) { let pllsrcclk = self.hse.unwrap_or(HSI); let sysclk = self.sysclk.unwrap_or(pllsrcclk); let sysclk_on_pll = sysclk != pllsrcclk; - if !sysclk_on_pll && !self.pll48clk { - return (false, false, sysclk, None); + if !sysclk_on_pll && !self.pll48clk && !self.plli2sclk.is_some() { + return (false, false, sysclk, None, None); } // Sysclk output divisor must be one of 2, 4, 6 or 8 @@ -240,12 +250,34 @@ impl CFGR { w.pllsrc().bit(self.hse.is_some()) }); + // NOTE: Hardcoded for 48KHz audio sampling rate with VCO at 2MHz. + // plli2sclk = 2MHz * 258 / 6 = 86MHz + // I2S uses DIV=3, ODD=true to achive a 12.285714 MHz MCKL. + // TODO: Calculate PLLI2S N an R values from desired frequency. + let plli2sn = 258; + let plli2sr = 6; + let plli2sclk = vco_in * plli2sn / plli2sr; + if self.plli2sclk.is_some() { + unsafe { &*RCC::ptr() }.plli2scfgr.write(|w| unsafe { + w.plli2sn() + .bits(plli2sn as u16) + .plli2sr() + .bits(plli2sr as u8) + }); + } + let real_sysclk = if sysclk_on_pll { vco_in * plln / sysclk_div } else { sysclk }; - (true, sysclk_on_pll, real_sysclk, Some(Hertz(pll48clk))) + ( + true, + sysclk_on_pll, + real_sysclk, + Some(Hertz(pll48clk)), + Some(Hertz(plli2sclk)), + ) } fn flash_setup(sysclk: u32) { @@ -288,7 +320,7 @@ impl CFGR { pub fn freeze(self) -> Clocks { let rcc = unsafe { &*RCC::ptr() }; - let (use_pll, sysclk_on_pll, sysclk, pll48clk) = self.pll_setup(); + let (use_pll, sysclk_on_pll, sysclk, pll48clk, plli2sclk) = self.pll_setup(); assert!(!sysclk_on_pll || sysclk <= SYSCLK_MAX && sysclk >= SYSCLK_MIN); @@ -346,13 +378,13 @@ impl CFGR { Self::flash_setup(sysclk); if self.hse.is_some() { - // enable HSE and wait for it to be ready + // Enable HSE and wait for it to be ready. rcc.cr.modify(|_, w| w.hseon().set_bit()); while rcc.cr.read().hserdy().bit_is_clear() {} } if use_pll { - // Enable PLL + // Enable PLL and wait for it to be ready. rcc.cr.modify(|_, w| w.pllon().set_bit()); // Enable voltage regulator overdrive if HCLK is above the limit @@ -380,6 +412,12 @@ impl CFGR { while rcc.cr.read().pllrdy().bit_is_clear() {} } + if self.plli2sclk.is_some() { + // Enable PLLI2S and wait for it to be ready. + rcc.cr.modify(|_, w| w.plli2son().set_bit()); + while rcc.cr.read().plli2srdy().bit_is_clear() {} + } + // Set scaling factors rcc.cfgr.modify(|_, w| unsafe { w.ppre2() @@ -413,6 +451,7 @@ impl CFGR { ppre2, sysclk: Hertz(sysclk), pll48clk, + plli2sclk, }; if self.pll48clk { @@ -435,6 +474,7 @@ pub struct Clocks { ppre2: u8, sysclk: Hertz, pll48clk: Option, + plli2sclk: Option, } impl Clocks { @@ -473,6 +513,11 @@ impl Clocks { self.pll48clk } + /// Returns the frequency of the PLLI2S clock + pub fn plli2sclk(&self) -> Option { + self.plli2sclk + } + /// Returns true if the PLL48 clock is within USB /// specifications. It is required to use the USB functionality. pub fn is_pll48clk_valid(&self) -> bool { diff --git a/src/rng.rs b/src/rng.rs index 5a6ec2e9..64868b5a 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -93,7 +93,7 @@ impl Rng { impl rng::Read for Rng { type Error = rand_core::Error; - fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> { + fn try_read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> { self.try_fill_bytes(buffer) } } diff --git a/src/serial.rs b/src/serial.rs index cf33dc82..6d8b5f44 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -1544,18 +1544,18 @@ macro_rules! halUsartImpl { impl serial::Read for Serial<$USARTX, PINS> { type Error = Error; - fn read(&mut self) -> nb::Result { + fn try_read(&mut self) -> nb::Result { let mut rx: Rx<$USARTX> = Rx { _usart: PhantomData, }; - rx.read() + rx.try_read() } } impl serial::Read for Rx<$USARTX> { type Error = Error; - fn read(&mut self) -> nb::Result { + fn try_read(&mut self) -> nb::Result { // NOTE(unsafe) atomic read with no side effects let sr = unsafe { (*$USARTX::ptr()).sr.read() }; @@ -1597,18 +1597,18 @@ macro_rules! halUsartImpl { impl serial::Write for Serial<$USARTX, PINS> { type Error = Error; - fn flush(&mut self) -> nb::Result<(), Self::Error> { + fn try_flush(&mut self) -> nb::Result<(), Self::Error> { let mut tx: Tx<$USARTX> = Tx { _usart: PhantomData, }; - tx.flush() + tx.try_flush() } - fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { + fn try_write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { let mut tx: Tx<$USARTX> = Tx { _usart: PhantomData, }; - tx.write(byte) + tx.try_write(byte) } } @@ -1624,7 +1624,7 @@ macro_rules! halUsartImpl { impl serial::Write for Tx<$USARTX> { type Error = Error; - fn flush(&mut self) -> nb::Result<(), Self::Error> { + fn try_flush(&mut self) -> nb::Result<(), Self::Error> { // NOTE(unsafe) atomic read with no side effects let sr = unsafe { (*$USARTX::ptr()).sr.read() }; @@ -1635,7 +1635,7 @@ macro_rules! halUsartImpl { } } - fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { + fn try_write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { // NOTE(unsafe) atomic read with no side effects let sr = unsafe { (*$USARTX::ptr()).sr.read() }; @@ -1653,10 +1653,10 @@ macro_rules! halUsartImpl { impl blocking::serial::Write for Tx<$USARTX> { type Error = Error; - fn bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { + fn try_bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { for &b in bytes { loop { - match self.write(b) { + match self.try_write(b) { Err(nb::Error::WouldBlock) => continue, Err(nb::Error::Other(err)) => return Err(err), Ok(()) => break, @@ -1666,9 +1666,9 @@ macro_rules! halUsartImpl { Ok(()) } - fn bflush(&mut self) -> Result<(), Self::Error> { + fn try_bflush(&mut self) -> Result<(), Self::Error> { loop { - match self.flush() { + match self.try_flush() { Ok(()) => return Ok(()), Err(nb::Error::WouldBlock) => continue, Err(nb::Error::Other(err)) => return Err(err), @@ -1680,18 +1680,18 @@ macro_rules! halUsartImpl { impl blocking::serial::Write for Serial<$USARTX, PINS> { type Error = Error; - fn bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { + fn try_bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { let mut tx: Tx<$USARTX> = Tx { _usart: PhantomData, }; - tx.bwrite_all(bytes) + tx.try_bwrite_all(bytes) } - fn bflush(&mut self) -> Result<(), Self::Error> { + fn try_bflush(&mut self) -> Result<(), Self::Error> { let mut tx: Tx<$USARTX> = Tx { _usart: PhantomData, }; - tx.bflush() + tx.try_bflush() } } )+ @@ -1864,7 +1864,11 @@ where Tx: serial::Write, { fn write_str(&mut self, s: &str) -> fmt::Result { - let _ = s.as_bytes().iter().map(|c| block!(self.write(*c))).last(); + let _ = s + .as_bytes() + .iter() + .map(|c| block!(self.try_write(*c))) + .last(); Ok(()) } } diff --git a/src/spi.rs b/src/spi.rs index d16aedd4..49c60cfc 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -1013,7 +1013,7 @@ where { type Error = Error; - fn read(&mut self) -> nb::Result { + fn try_read(&mut self) -> nb::Result { let sr = self.spi.sr.read(); Err(if sr.ovr().bit_is_set() { @@ -1031,7 +1031,7 @@ where }) } - fn send(&mut self, byte: u8) -> nb::Result<(), Error> { + fn try_send(&mut self, byte: u8) -> nb::Result<(), Error> { let sr = self.spi.sr.read(); Err(if sr.ovr().bit_is_set() { diff --git a/src/timer.rs b/src/timer.rs index cc9c6445..b29a5dee 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,10 +1,11 @@ //! Timers use cast::{u16, u32}; + use cortex_m::peripheral::syst::SystClkSource; use cortex_m::peripheral::SYST; use embedded_hal::timer::{Cancel, CountDown, Periodic}; -use void::Void; +use nb; use crate::stm32::RCC; #[cfg(any( @@ -111,7 +112,7 @@ impl Timer { { syst.set_clock_source(SystClkSource::Core); let mut timer = Timer { tim: syst, clocks }; - timer.start(timeout); + let _ = timer.try_start(timeout); timer } @@ -131,9 +132,10 @@ impl Timer { } impl CountDown for Timer { + type Error = Error; type Time = Hertz; - fn start(&mut self, timeout: T) + fn try_start(&mut self, timeout: T) -> Result<(), Self::Error> where T: Into, { @@ -144,9 +146,11 @@ impl CountDown for Timer { self.tim.set_reload(rvr); self.tim.clear_current(); self.tim.enable_counter(); + + Ok(()) } - fn wait(&mut self) -> nb::Result<(), Void> { + fn try_wait(&mut self) -> nb::Result<(), Self::Error> { if self.tim.has_wrapped() { Ok(()) } else { @@ -156,9 +160,7 @@ impl CountDown for Timer { } impl Cancel for Timer { - type Error = Error; - - fn cancel(&mut self) -> Result<(), Self::Error> { + fn try_cancel(&mut self) -> Result<(), Self::Error> { if !self.tim.is_counter_enabled() { return Err(Self::Error::Disabled); } @@ -189,7 +191,7 @@ macro_rules! hal { clocks, tim, }; - timer.start(timeout); + let _ = timer.try_start(timeout); timer } @@ -239,9 +241,10 @@ macro_rules! hal { } impl CountDown for Timer<$TIM> { + type Error = Error; type Time = Hertz; - fn start(&mut self, timeout: T) + fn try_start(&mut self, timeout: T) -> Result<(), Self::Error> where T: Into, { @@ -262,13 +265,16 @@ macro_rules! hal { // start counter self.tim.cr1.modify(|_, w| w.cen().set_bit()); + + Ok(()) } - fn wait(&mut self) -> nb::Result<(), Void> { + fn try_wait(&mut self) -> nb::Result<(), Self::Error> { if self.tim.sr.read().uif().bit_is_clear() { Err(nb::Error::WouldBlock) } else { self.tim.sr.modify(|_, w| w.uif().clear_bit()); + Ok(()) } } @@ -276,9 +282,7 @@ macro_rules! hal { impl Cancel for Timer<$TIM> { - type Error = Error; - - fn cancel(&mut self) -> Result<(), Self::Error> { + fn try_cancel(&mut self) -> Result<(), Self::Error> { let is_counter_enabled = self.tim.cr1.read().cen().is_enabled(); if !is_counter_enabled { return Err(Self::Error::Disabled); diff --git a/src/watchdog.rs b/src/watchdog.rs index 440afb57..31f87a2b 100644 --- a/src/watchdog.rs +++ b/src/watchdog.rs @@ -5,6 +5,7 @@ use crate::{ stm32::{DBGMCU, IWDG}, time::MilliSeconds, }; +use core::convert::Infallible; /// Wraps the Independent Watchdog (IWDG) peripheral pub struct IndependentWatchdog { @@ -88,17 +89,24 @@ impl IndependentWatchdog { } impl WatchdogEnable for IndependentWatchdog { + type Error = Infallible; type Time = MilliSeconds; - fn start>(&mut self, period: T) { + fn try_start>(&mut self, period: T) -> Result<(), Self::Error> { self.setup(period.into().0); self.iwdg.kr.write(|w| unsafe { w.key().bits(KR_START) }); + + Ok(()) } } impl Watchdog for IndependentWatchdog { - fn feed(&mut self) { + type Error = Infallible; + + fn try_feed(&mut self) -> Result<(), Self::Error> { self.iwdg.kr.write(|w| unsafe { w.key().bits(KR_RELOAD) }); + + Ok(()) } }