diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db7b1060..333c9aa5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,6 @@ on: pull_request: - + name: Continuous integration # Make sure CI fails on all warnings, including Clippy lints @@ -22,13 +22,14 @@ jobs: - stm32g474 - stm32g483 - stm32g484 - #- stm32g491 # Does not seem ready yet - #- stm32g4a1 # Does not seem ready yet + - stm32g491 # Does not seem ready yet + - stm32g4a1 # Does not seem ready yet features: - log-rtt,defmt # TODO: -log-rtt # log-rtt without defmt, more combos? - log-itm - log-semihost + - cordic,log-rtt,defmt steps: - uses: actions/checkout@v2 diff --git a/.vscode/settings.json b/.vscode/settings.json index 648fb929..535b9ec0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,6 @@ "rust-analyzer.cargo.target": "thumbv7em-none-eabihf", "rust-analyzer.cargo.features": [ "stm32g473", - "defmt-logging", + "defmt", ] } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 14b7b966..369b447b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,8 @@ version = "0.0.2" [dependencies] nb = "1" -stm32g4 = "0.15.1" +#stm32g4 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies" } #"0.15.1" +stm32g4 = { version = "0.19.0", package = "stm32g4-staging" } paste = "1.0" bitflags = "1.2" vcell = "0.1" @@ -65,6 +66,7 @@ optional = true [dev-dependencies] cortex-m-rt = "0.7.2" defmt-rtt = "0.4.0" +defmt-test = "0.3.2" cortex-m-rtic = "1.1.4" cortex-m-semihosting = "0.3.5" panic-probe = { version = "0.3.0", features = ["print-defmt"] } @@ -113,6 +115,13 @@ codegen-units = 1 incremental = false lto = true +[profile.test] +opt-level = "s" +debug = true +codegen-units = 1 +incremental = false +lto = true + [[example]] name = "flash_with_rtic" required-features = ["stm32g474"] @@ -124,3 +133,10 @@ required-features = ["usb"] [[example]] name = "cordic" required-features = ["cordic"] + +[[test]] +name = "pwm" +harness = false + +[lib] +test = false \ No newline at end of file diff --git a/examples/adc-continious-dma.rs b/examples/adc-continious-dma.rs index 9788af0e..c3ffbac5 100644 --- a/examples/adc-continious-dma.rs +++ b/examples/adc-continious-dma.rs @@ -11,7 +11,7 @@ use crate::hal::{ AdcClaim, ClockSource, Temperature, Vref, }, delay::SYSTDelayExt, - dma::{config::DmaConfig, stream::DMAExt, TransferExt}, + dma::{channel::DMAExt, config::DmaConfig, TransferExt}, gpio::GpioExt, pwr::PwrExt, rcc::{Config, RccExt}, @@ -36,7 +36,7 @@ fn main() -> ! { let pwr = dp.PWR.constrain().freeze(); let mut rcc = rcc.freeze(Config::hsi(), pwr); - let streams = dp.DMA1.split(&rcc); + let channels = dp.DMA1.split(&rcc); let config = DmaConfig::default() .transfer_complete_interrupt(false) .circular_buffer(true) @@ -63,7 +63,7 @@ fn main() -> ! { info!("Setup DMA"); let first_buffer = cortex_m::singleton!(: [u16; 15] = [0; 15]).unwrap(); - let mut transfer = streams.0.into_circ_peripheral_to_memory_transfer( + let mut transfer = channels.ch1.into_circ_peripheral_to_memory_transfer( adc.enable_dma(AdcDma::Continuous), &mut first_buffer[..], config, diff --git a/examples/adc-one-shot-dma.rs b/examples/adc-one-shot-dma.rs index 7226f6a2..8a0eab7e 100644 --- a/examples/adc-one-shot-dma.rs +++ b/examples/adc-one-shot-dma.rs @@ -9,7 +9,7 @@ use crate::hal::{ AdcClaim, ClockSource, Temperature, }, delay::SYSTDelayExt, - dma::{config::DmaConfig, stream::DMAExt, TransferExt}, + dma::{channel::DMAExt, config::DmaConfig, TransferExt}, gpio::GpioExt, pwr::PwrExt, rcc::{Config, RccExt}, @@ -36,7 +36,7 @@ fn main() -> ! { let pwr = dp.PWR.constrain().freeze(); let mut rcc = rcc.freeze(Config::hsi(), pwr); - let mut streams = dp.DMA1.split(&rcc); + let mut channels = dp.DMA1.split(&rcc); let config = DmaConfig::default() .transfer_complete_interrupt(false) .circular_buffer(false) @@ -61,7 +61,7 @@ fn main() -> ! { info!("Setup DMA"); let first_buffer = cortex_m::singleton!(: [u16; 2] = [0; 2]).unwrap(); - let mut transfer = streams.0.into_peripheral_to_memory_transfer( + let mut transfer = channels.ch1.into_peripheral_to_memory_transfer( adc.enable_dma(AdcDma::Single), &mut first_buffer[..], config, @@ -74,10 +74,10 @@ fn main() -> ! { info!("Conversion Done"); transfer.pause(|adc| adc.cancel_conversion()); - let (s0, adc, first_buffer) = transfer.free(); + let (ch1, adc, first_buffer) = transfer.free(); let adc = adc.disable(); - streams.0 = s0; + channels.ch1 = ch1; let millivolts = adc.sample_to_millivolts(first_buffer[0]); info!("pa3: {}mV", millivolts); diff --git a/examples/cordic.rs b/examples/cordic.rs index 170f018d..a3efa083 100644 --- a/examples/cordic.rs +++ b/examples/cordic.rs @@ -7,11 +7,11 @@ extern crate cortex_m; extern crate cortex_m_rt as rt; extern crate stm32g4xx_hal as hal; -use fixed::types::I1F15; use hal::cordic::{ - func::{dynamic::Mode as _, scale::N0, Magnitude, SinCos, Sqrt}, + op::{dynamic::Mode as _, Magnitude, SinCos, Sqrt}, prec::P60, - types::{Q15, Q31}, + scale::N0, + types::{I1F15, Q15, Q31}, Ext as _, }; use hal::prelude::*; @@ -34,7 +34,7 @@ fn main() -> ! { let mut cordic = dp .CORDIC .constrain(&mut rcc) - .freeze::(); // 16 bit arguments, 32 bit results, compute sine and cosine, 60 iterations + .freeze::(); // 16 bit arguments, 32 bit results, compute sine and cosine, 60 iterations // static operation (zero overhead) @@ -53,5 +53,6 @@ fn main() -> ! { let magnitude = cordic.run::((I1F15::from_num(0.25), I1F15::from_num(0.5))); println!("magnitude: {}", magnitude.to_num::()); + #[allow(clippy::empty_loop)] loop {} } diff --git a/examples/flash_with_rtic.rs b/examples/flash_with_rtic.rs index c48f45b1..8277d08c 100644 --- a/examples/flash_with_rtic.rs +++ b/examples/flash_with_rtic.rs @@ -73,7 +73,7 @@ mod app { unsafe { let mut flash = &(*stm32g4xx_hal::stm32::FLASH::ptr()); - flash.acr.modify(|_, w| { + flash.acr().modify(|_, w| { w.latency().bits(0b1000) // 8 wait states }); } diff --git a/examples/spi-dma.rs b/examples/spi-dma.rs index dcfff763..3404f2c0 100644 --- a/examples/spi-dma.rs +++ b/examples/spi-dma.rs @@ -22,8 +22,8 @@ use crate::hal::{ use cortex_m_rt::entry; use stm32g4xx_hal as hal; +use stm32g4xx_hal::dma::channel::DMAExt; use stm32g4xx_hal::dma::config::DmaConfig; -use stm32g4xx_hal::dma::stream::DMAExt; use stm32g4xx_hal::dma::TransferExt; #[macro_use] @@ -51,7 +51,7 @@ fn main() -> ! { let spi = dp .SPI1 .spi((sclk, miso, mosi), spi::MODE_0, 400.kHz(), &mut rcc); - let streams = dp.DMA1.split(&rcc); + let channels = dp.DMA1.split(&rcc); let config = DmaConfig::default() .transfer_complete_interrupt(false) .circular_buffer(true) @@ -63,10 +63,11 @@ fn main() -> ! { *item = index as u8; } let dma_buf = cortex_m::singleton!(: [u8; BUFFER_SIZE] = buf).unwrap(); - let mut transfer_dma = - streams - .0 - .into_memory_to_peripheral_transfer(spi.enable_tx_dma(), &mut dma_buf[..], config); + let mut transfer_dma = channels.ch1.into_memory_to_peripheral_transfer( + spi.enable_tx_dma(), + &mut dma_buf[..], + config, + ); transfer_dma.start(|_spi| {}); loop { delay_tim2.delay_ms(1000); diff --git a/examples/uart-dma-rx.rs b/examples/uart-dma-rx.rs index 5a1742fb..4b26d3fc 100644 --- a/examples/uart-dma-rx.rs +++ b/examples/uart-dma-rx.rs @@ -5,7 +5,7 @@ extern crate cortex_m_rt as rt; -use hal::dma::{config::DmaConfig, stream::DMAExt, TransferExt}; +use hal::dma::{channel::DMAExt, config::DmaConfig, TransferExt}; use hal::prelude::*; use hal::pwr::PwrExt; use hal::serial::*; @@ -30,7 +30,7 @@ fn main() -> ! { let pwr = dp.PWR.constrain().freeze(); let mut rcc = rcc.freeze(rcc::Config::hsi(), pwr); - let streams = dp.DMA1.split(&rcc); + let channels = dp.DMA1.split(&rcc); let config = DmaConfig::default() .transfer_complete_interrupt(false) .circular_buffer(true) @@ -65,7 +65,7 @@ fn main() -> ! { let (_tx, rx) = usart.split(); - let mut transfer = streams.0.into_circ_peripheral_to_memory_transfer( + let mut transfer = channels.ch1.into_circ_peripheral_to_memory_transfer( rx.enable_dma(), &mut rx_buffer[..], config, diff --git a/examples/uart-dma-tx.rs b/examples/uart-dma-tx.rs index bc92922a..544e84ec 100644 --- a/examples/uart-dma-tx.rs +++ b/examples/uart-dma-tx.rs @@ -7,7 +7,7 @@ extern crate cortex_m_rt as rt; use core::fmt::Write; -use hal::dma::{config::DmaConfig, stream::DMAExt, TransferExt}; +use hal::dma::{channel::DMAExt, config::DmaConfig, TransferExt}; use hal::prelude::*; use hal::pwr::PwrExt; use hal::serial::*; @@ -32,7 +32,7 @@ fn main() -> ! { let pwr = dp.PWR.constrain().freeze(); let mut rcc = rcc.freeze(rcc::Config::hsi(), pwr); - let streams = dp.DMA1.split(&rcc); + let channels = dp.DMA1.split(&rcc); let config = DmaConfig::default() .transfer_complete_interrupt(false) .circular_buffer(false) @@ -64,10 +64,11 @@ fn main() -> ! { let (tx, _rx) = usart.split(); // Setup DMA for USART2 TX with dma channel 1. - let mut transfer = - streams - .0 - .into_memory_to_peripheral_transfer(tx.enable_dma(), &mut tx_buffer[..], config); + let mut transfer = channels.ch1.into_memory_to_peripheral_transfer( + tx.enable_dma(), + &mut tx_buffer[..], + config, + ); transfer.start(|_tx| {}); loop { diff --git a/examples/utils/logger.rs b/examples/utils/logger.rs index 07c64191..a5e38d06 100644 --- a/examples/utils/logger.rs +++ b/examples/utils/logger.rs @@ -1,6 +1,6 @@ #![allow(unsafe_code)] cfg_if::cfg_if! { - if #[cfg(all(feature = "log-rtt", feature = "defmt"))] { + if #[cfg(feature = "defmt")] { #[allow(unused_imports)] pub use defmt::{info, trace, warn, debug, error}; @@ -55,7 +55,7 @@ cfg_if::cfg_if! { } } - else if #[cfg(all(feature = "log-rtt"/*, feature = "defmt"*/))] { + else if #[cfg(feature = "defmt")] { use defmt_rtt as _; // global logger use panic_probe as _; #[allow(unused_imports)] @@ -66,9 +66,6 @@ cfg_if::cfg_if! { #[allow(dead_code)] pub fn init() {} } - else if #[cfg(all(feature = "log-rtt", not(feature = "defmt")))] { - // TODO - } else if #[cfg(feature = "log-semihost")] { use panic_semihosting as _; diff --git a/src/adc.rs b/src/adc.rs index e2ed773d..65a646f1 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -1300,7 +1300,7 @@ impl Conversion { /// /// //Channel 1 /// //Disable the channel before configuring it -/// tim.ccer.modify(|_, w| w.cc1e().clear_bit()); +/// tim.ccer().modify(|_, w| w.cc1e().clear_bit()); /// /// tim.ccmr1_output().modify(|_, w| w /// //Preload enable for channel @@ -1312,14 +1312,14 @@ impl Conversion { /// /// //Set the duty cycle, 0 won't work in pwm mode but might be ok in /// //toggle mode or match mode -/// let max_duty = tim.arr.read().arr().bits() as u16; -/// tim.ccr1.modify(|_, w| w.ccr().bits(max_duty / 2)); +/// let max_duty = tim.arr().read().arr().bits() as u16; +/// tim.ccr1().modify(|_, w| w.ccr().bits(max_duty / 2)); /// /// //Enable the channel -/// tim.ccer.modify(|_, w| w.cc1e().set_bit()); +/// tim.ccer().modify(|_, w| w.cc1e().set_bit()); /// /// //Enable the TIM main Output -/// tim.bdtr.modify(|_, w| w.moe().set_bit()); +/// tim.bdtr().modify(|_, w| w.moe().set_bit()); /// } /// ``` #[derive(Clone, Copy)] @@ -1412,7 +1412,7 @@ pub trait TriggerType { #[inline(always)] fn configure_clock_source12(cs: ClockSource, rcc: &Rcc) { // Select system clock as ADC clock source - rcc.rb.ccipr.modify(|_, w| { + rcc.rb.ccipr().modify(|_, w| { // This is sound, as `0b10` is a valid value for this field. unsafe { w.adc12sel().bits(cs.into()); @@ -1426,7 +1426,7 @@ fn configure_clock_source12(cs: ClockSource, rcc: &Rcc) { #[allow(dead_code)] fn configure_clock_source345(cs: ClockSource, rcc: &Rcc) { // Select system clock as ADC clock source - rcc.rb.ccipr.modify(|_, w| { + rcc.rb.ccipr().modify(|_, w| { // This is sound, as `0b10` is a valid value for this field. unsafe { w.adc345sel().bits(cs.into()); @@ -1607,21 +1607,21 @@ macro_rules! adc { /// Enables the Deep Power Down Modus #[inline(always)] pub fn enable_deeppwd_down(&mut self) { - self.adc_reg.cr.modify(|_, w| w.deeppwd().set_bit()); + self.adc_reg.cr().modify(|_, w| w.deeppwd().set_bit()); } /// Disables the Deep Power Down Modus #[inline(always)] pub fn disable_deeppwd_down(&mut self) { - self.adc_reg.cr.modify(|_, w| w.deeppwd().clear_bit()); + self.adc_reg.cr().modify(|_, w| w.deeppwd().clear_bit()); } /// Enables the Voltage Regulator #[inline(always)] pub fn enable_vreg(&mut self, delay: &mut impl DelayNs) { - self.adc_reg.cr.modify(|_, w| w.advregen().set_bit()); - while !self.adc_reg.cr.read().advregen().bit_is_set() {} + self.adc_reg.cr().modify(|_, w| w.advregen().set_bit()); + while !self.adc_reg.cr().read().advregen().bit_is_set() {} // According to the STM32G4xx Reference Manual, section 21.4.6, we need // to wait for T_ADCVREG_STUP after enabling the internal voltage @@ -1633,13 +1633,13 @@ macro_rules! adc { /// Disables the Voltage Regulator #[inline(always)] pub fn disable_vreg(&mut self) { - self.adc_reg.cr.modify(|_, w| w.advregen().clear_bit()); + self.adc_reg.cr().modify(|_, w| w.advregen().clear_bit()); } /// Returns if the ADC is enabled (ADEN) #[inline(always)] pub fn is_enabled(&self) -> bool { - self.adc_reg.cr.read().aden().bit_is_set() + self.adc_reg.cr().read().aden().bit_is_set() } /// Disables the adc, since we don't know in what state we get it. @@ -1649,11 +1649,11 @@ macro_rules! adc { self.cancel_conversion(); // Turn off ADC - self.adc_reg.cr.modify(|_, w| w.addis().set_bit()); - while self.adc_reg.cr.read().addis().bit_is_set() {} + self.adc_reg.cr().modify(|_, w| w.addis().set_bit()); + while self.adc_reg.cr().read().addis().bit_is_set() {} // Wait until the ADC has turned off - while self.adc_reg.cr.read().aden().bit_is_set() {} + while self.adc_reg.cr().read().aden().bit_is_set() {} } /// Enables the adc @@ -1662,14 +1662,14 @@ macro_rules! adc { self.calibrate_all(); self.apply_config(self.config); - self.adc_reg.isr.modify(|_, w| w.adrdy().set_bit()); - self.adc_reg.cr.modify(|_, w| w.aden().set_bit()); + self.adc_reg.isr().modify(|_, w| w.adrdy().set_bit()); + self.adc_reg.cr().modify(|_, w| w.aden().set_bit()); // Wait for adc to get ready - while !self.adc_reg.isr.read().adrdy().bit_is_set() {} + while !self.adc_reg.isr().read().adrdy().bit_is_set() {} // Clear ready flag - self.adc_reg.isr.modify(|_, w| w.adrdy().set_bit()); + self.adc_reg.isr().modify(|_, w| w.adrdy().set_bit()); self.clear_end_of_conversion_flag(); } @@ -1708,7 +1708,7 @@ macro_rules! adc { self.config.clock_mode = clock_mode; unsafe { let common = &(*stm32::$common_type::ptr()); - common.ccr.modify(|_, w| w.ckmode().bits(clock_mode.into())); + common.ccr().modify(|_, w| w.ckmode().bits(clock_mode.into())); } } @@ -1718,7 +1718,7 @@ macro_rules! adc { self.config.clock = clock; unsafe { let common = &(*stm32::$common_type::ptr()); - common.ccr.modify(|_, w| w.presc().bits(clock.into())); + common.ccr().modify(|_, w| w.presc().bits(clock.into())); } } @@ -1726,30 +1726,34 @@ macro_rules! adc { #[inline(always)] pub fn set_resolution(&mut self, resolution: config::Resolution) { self.config.resolution = resolution; - self.adc_reg.cfgr.modify(|_, w| w.res().bits(resolution.into())); + unsafe { + self.adc_reg.cfgr().modify(|_, w| w.res().bits(resolution.into())); + } } /// Enable oversampling #[inline(always)] pub fn set_oversampling(&mut self, oversampling: config::OverSampling, shift: config::OverSamplingShift) { - self.adc_reg.cfgr2.modify(|_, w| unsafe { w.ovsr().bits(oversampling.into()) - .ovss().bits(shift.into()) - .rovse().set_bit()}); + self.adc_reg.cfgr2().modify(|_, w| unsafe { + w.ovsr().bits(oversampling.into()) + .ovss().bits(shift.into()) + .rovse().set_bit() + }); } /// Sets the DR register alignment to left or right #[inline(always)] pub fn set_align(&mut self, align: config::Align) { self.config.align = align; - self.adc_reg.cfgr.modify(|_, w| w.align().bit(align.into())); + self.adc_reg.cfgr().modify(|_, w| w.align().bit(align.into())); } /// Sets which external trigger to use and if it is disabled, rising, falling or both #[inline(always)] pub fn set_external_trigger(&mut self, (edge, extsel): (config::TriggerMode, $trigger_type)) { self.config.external_trigger = (edge, extsel); - self.adc_reg.cfgr.modify(|_, w| unsafe { w + self.adc_reg.cfgr().modify(|_, w| unsafe { w .extsel().bits(extsel.into()) .exten().bits(edge.into()) }); @@ -1759,14 +1763,14 @@ macro_rules! adc { #[inline(always)] pub fn set_auto_delay(&mut self, delay: bool) { self.config.auto_delay = delay; - self.adc_reg.cfgr.modify(|_, w| w.autdly().bit(delay) ); + self.adc_reg.cfgr().modify(|_, w| w.autdly().bit(delay) ); } /// Enables and disables dis-/continuous mode #[inline(always)] pub fn set_continuous(&mut self, continuous: config::Continuous) { self.config.continuous = continuous; - self.adc_reg.cfgr.modify(|_, w| w + self.adc_reg.cfgr().modify(|_, w| w .cont().bit(continuous == config::Continuous::Continuous) .discen().bit(continuous == config::Continuous::Discontinuous) ); @@ -1776,7 +1780,9 @@ macro_rules! adc { // NOTE: The software is allowed to write these bits only when ADSTART = 0 fn set_subgroup_len(&mut self, subgroup_len: config::SubGroupLength) { self.config.subgroup_len = subgroup_len; - self.adc_reg.cfgr.modify(|_, w| w.discnum().bits(subgroup_len as u8)) + unsafe { + self.adc_reg.cfgr().modify(|_, w| w.discnum().bits(subgroup_len as u8)); + } } /// Sets DMA to disabled, single or continuous @@ -1788,7 +1794,7 @@ macro_rules! adc { config::Dma::Single => (false, true), config::Dma::Continuous => (true, true), }; - self.adc_reg.cfgr.modify(|_, w| w + self.adc_reg.cfgr().modify(|_, w| w //DDS stands for "DMA disable selection" //0 means do one DMA then stop //1 means keep sending DMA requests as long as DMA=1 @@ -1807,7 +1813,7 @@ macro_rules! adc { config::Eoc::Conversion => (true, true), config::Eoc::Sequence => (true, false), }; - self.adc_reg.ier.modify(|_, w|w + self.adc_reg.ier().modify(|_, w|w .eosie().bit(eocs) .eocie().bit(en) ); @@ -1817,7 +1823,7 @@ macro_rules! adc { /// /// This is triggered when the AD finishes a conversion before the last value was read by CPU/DMA pub fn set_overrun_interrupt(&mut self, enable: bool) { - self.adc_reg.ier.modify(|_, w| w.ovrie().bit(enable)); + self.adc_reg.ier().modify(|_, w| w.ovrie().bit(enable)); } /// Sets the default sample time that is used for one-shot conversions. @@ -1833,7 +1839,7 @@ macro_rules! adc { pub fn set_channel_input_type(&mut self, df: config::DifferentialSelection) { self.config.difsel = df; - self.adc_reg.difsel.modify(|_, w| {w + self.adc_reg.difsel().modify(|_, w| {w .difsel_0().bit(df.get_channel(0).into() ) .difsel_1().bit(df.get_channel(1).into() ) .difsel_2().bit(df.get_channel(2).into() ) @@ -1860,19 +1866,19 @@ macro_rules! adc { #[inline(always)] pub fn reset_sequence(&mut self) { //The reset state is One conversion selected - self.adc_reg.sqr1.modify(|_, w| w.l().bits(config::Sequence::One.into())); + self.adc_reg.sqr1().modify(|_, w| unsafe { w.l().bits(config::Sequence::One.into()) }); } /// Returns the current sequence length. Primarily useful for configuring DMA. #[inline(always)] pub fn sequence_length(&mut self) -> u8 { - self.adc_reg.sqr1.read().l().bits() + 1 + self.adc_reg.sqr1().read().l().bits() + 1 } /// Returns the address of the ADC data register. Primarily useful for configuring DMA. #[inline(always)] pub fn data_register_address(&self) -> u32 { - &self.adc_reg.dr as *const _ as u32 + &self.adc_reg.dr() as *const _ as u32 } /// Calibrate the adc for @@ -1880,15 +1886,15 @@ macro_rules! adc { pub fn calibrate(&mut self, it: config::InputType) { match it { config::InputType::SingleEnded => { - self.adc_reg.cr.modify(|_, w| w.adcaldif().clear_bit() ); + self.adc_reg.cr().modify(|_, w| w.adcaldif().clear_bit() ); }, config::InputType::Differential => { - self.adc_reg.cr.modify(|_, w| w.adcaldif().set_bit() ); + self.adc_reg.cr().modify(|_, w| w.adcaldif().set_bit() ); }, } - self.adc_reg.cr.modify(|_, w| w.adcal().set_bit() ); - while self.adc_reg.cr.read().adcal().bit_is_set() {} + self.adc_reg.cr().modify(|_, w| w.adcal().set_bit() ); + while self.adc_reg.cr().read().adcal().bit_is_set() {} } /// Calibrate the Adc for all Input Types @@ -1911,7 +1917,7 @@ macro_rules! adc { { //Check the sequence is long enough - self.adc_reg.sqr1.modify(|r, w| { + self.adc_reg.sqr1().modify(|r, w| unsafe { let prev: config::Sequence = r.l().bits().into(); if prev < sequence { w.l().bits(sequence.into()) @@ -1924,47 +1930,49 @@ macro_rules! adc { //Set the channel in the right sequence field match sequence { - config::Sequence::One => self.adc_reg.sqr1.modify(|_, w| unsafe {w.sq1().bits(channel) }), - config::Sequence::Two => self.adc_reg.sqr1.modify(|_, w| unsafe {w.sq2().bits(channel) }), - config::Sequence::Three => self.adc_reg.sqr1.modify(|_, w| unsafe {w.sq3().bits(channel) }), - config::Sequence::Four => self.adc_reg.sqr1.modify(|_, w| unsafe {w.sq4().bits(channel) }), - config::Sequence::Five => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq5().bits(channel) }), - config::Sequence::Six => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq6().bits(channel) }), - config::Sequence::Seven => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq7().bits(channel) }), - config::Sequence::Eight => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq8().bits(channel) }), - config::Sequence::Nine => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq9().bits(channel) }), - config::Sequence::Ten => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq10().bits(channel) }), - config::Sequence::Eleven => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq11().bits(channel) }), - config::Sequence::Twelve => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq12().bits(channel) }), - config::Sequence::Thirteen => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq13().bits(channel) }), - config::Sequence::Fourteen => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq14().bits(channel) }), - config::Sequence::Fifteen => self.adc_reg.sqr4.modify(|_, w| unsafe {w.sq15().bits(channel) }), - config::Sequence::Sixteen => self.adc_reg.sqr4.modify(|_, w| unsafe {w.sq16().bits(channel) }), - } + config::Sequence::One => self.adc_reg.sqr1().modify(|_, w| unsafe {w.sq1().bits(channel) }), + config::Sequence::Two => self.adc_reg.sqr1().modify(|_, w| unsafe {w.sq2().bits(channel) }), + config::Sequence::Three => self.adc_reg.sqr1().modify(|_, w| unsafe {w.sq3().bits(channel) }), + config::Sequence::Four => self.adc_reg.sqr1().modify(|_, w| unsafe {w.sq4().bits(channel) }), + config::Sequence::Five => self.adc_reg.sqr2().modify(|_, w| unsafe {w.sq5().bits(channel) }), + config::Sequence::Six => self.adc_reg.sqr2().modify(|_, w| unsafe {w.sq6().bits(channel) }), + config::Sequence::Seven => self.adc_reg.sqr2().modify(|_, w| unsafe {w.sq7().bits(channel) }), + config::Sequence::Eight => self.adc_reg.sqr2().modify(|_, w| unsafe {w.sq8().bits(channel) }), + config::Sequence::Nine => self.adc_reg.sqr2().modify(|_, w| unsafe {w.sq9().bits(channel) }), + config::Sequence::Ten => self.adc_reg.sqr3().modify(|_, w| unsafe {w.sq10().bits(channel) }), + config::Sequence::Eleven => self.adc_reg.sqr3().modify(|_, w| unsafe {w.sq11().bits(channel) }), + config::Sequence::Twelve => self.adc_reg.sqr3().modify(|_, w| unsafe {w.sq12().bits(channel) }), + config::Sequence::Thirteen => self.adc_reg.sqr3().modify(|_, w| unsafe {w.sq13().bits(channel) }), + config::Sequence::Fourteen => self.adc_reg.sqr3().modify(|_, w| unsafe {w.sq14().bits(channel) }), + config::Sequence::Fifteen => self.adc_reg.sqr4().modify(|_, w| unsafe {w.sq15().bits(channel) }), + config::Sequence::Sixteen => self.adc_reg.sqr4().modify(|_, w| unsafe {w.sq16().bits(channel) }), + }; //Set the sample time for the channel let st = u8::from(sample_time); - match channel { - 0 => self.adc_reg.smpr1.modify(|_, w| w.smp0().bits(st) ), - 1 => self.adc_reg.smpr1.modify(|_, w| w.smp1().bits(st) ), - 2 => self.adc_reg.smpr1.modify(|_, w| w.smp2().bits(st) ), - 3 => self.adc_reg.smpr1.modify(|_, w| w.smp3().bits(st) ), - 4 => self.adc_reg.smpr1.modify(|_, w| w.smp4().bits(st) ), - 5 => self.adc_reg.smpr1.modify(|_, w| w.smp5().bits(st) ), - 6 => self.adc_reg.smpr1.modify(|_, w| w.smp6().bits(st) ), - 7 => self.adc_reg.smpr1.modify(|_, w| w.smp7().bits(st) ), - 8 => self.adc_reg.smpr1.modify(|_, w| w.smp8().bits(st) ), - 9 => self.adc_reg.smpr1.modify(|_, w| w.smp9().bits(st) ), - 10 => self.adc_reg.smpr2.modify(|_, w| w.smp10().bits(st) ), - 11 => self.adc_reg.smpr2.modify(|_, w| w.smp11().bits(st) ), - 12 => self.adc_reg.smpr2.modify(|_, w| w.smp12().bits(st) ), - 13 => self.adc_reg.smpr2.modify(|_, w| w.smp13().bits(st) ), - 14 => self.adc_reg.smpr2.modify(|_, w| w.smp14().bits(st) ), - 15 => self.adc_reg.smpr2.modify(|_, w| w.smp15().bits(st) ), - 16 => self.adc_reg.smpr2.modify(|_, w| w.smp16().bits(st) ), - 17 => self.adc_reg.smpr2.modify(|_, w| w.smp17().bits(st) ), - 18 => self.adc_reg.smpr2.modify(|_, w| w.smp18().bits(st) ), - _ => unimplemented!(), + unsafe { + match channel { + 0 => self.adc_reg.smpr1().modify(|_, w| w.smp0().bits(st) ), + 1 => self.adc_reg.smpr1().modify(|_, w| w.smp1().bits(st) ), + 2 => self.adc_reg.smpr1().modify(|_, w| w.smp2().bits(st) ), + 3 => self.adc_reg.smpr1().modify(|_, w| w.smp3().bits(st) ), + 4 => self.adc_reg.smpr1().modify(|_, w| w.smp4().bits(st) ), + 5 => self.adc_reg.smpr1().modify(|_, w| w.smp5().bits(st) ), + 6 => self.adc_reg.smpr1().modify(|_, w| w.smp6().bits(st) ), + 7 => self.adc_reg.smpr1().modify(|_, w| w.smp7().bits(st) ), + 8 => self.adc_reg.smpr1().modify(|_, w| w.smp8().bits(st) ), + 9 => self.adc_reg.smpr1().modify(|_, w| w.smp9().bits(st) ), + 10 => self.adc_reg.smpr2().modify(|_, w| w.smp10().bits(st) ), + 11 => self.adc_reg.smpr2().modify(|_, w| w.smp11().bits(st) ), + 12 => self.adc_reg.smpr2().modify(|_, w| w.smp12().bits(st) ), + 13 => self.adc_reg.smpr2().modify(|_, w| w.smp13().bits(st) ), + 14 => self.adc_reg.smpr2().modify(|_, w| w.smp14().bits(st) ), + 15 => self.adc_reg.smpr2().modify(|_, w| w.smp15().bits(st) ), + 16 => self.adc_reg.smpr2().modify(|_, w| w.smp16().bits(st) ), + 17 => self.adc_reg.smpr2().modify(|_, w| w.smp17().bits(st) ), + 18 => self.adc_reg.smpr2().modify(|_, w| w.smp18().bits(st) ), + _ => unimplemented!(), + }; } } /// Synchronously convert a single sample @@ -1974,12 +1982,14 @@ macro_rules! adc { PIN: Channel { let saved_config = self.config; - self.adc_reg.cfgr.modify(|_, w| w - .dmaen().clear_bit() //Disable dma - .cont().clear_bit() //Disable continuous mode - .exten().bits(config::TriggerMode::Disabled.into()) //Disable trigger - ); - self.adc_reg.ier.modify(|_, w| w + unsafe { + self.adc_reg.cfgr().modify(|_, w| w + .dmaen().clear_bit() //Disable dma + .cont().clear_bit() //Disable continuous mode + .exten().bits(config::TriggerMode::Disabled.into()) //Disable trigger + ); + } + self.adc_reg.ier().modify(|_, w| w .eocie().clear_bit() //Disable end of conversion interrupt ); @@ -2004,116 +2014,116 @@ macro_rules! adc { /// Resets the end-of-conversion flag #[inline(always)] pub fn clear_end_of_conversion_flag(&mut self) { - self.adc_reg.isr.modify(|_, w| w.eoc().set_bit()); + self.adc_reg.isr().modify(|_, w| w.eoc().set_bit()); } /// Block until the conversion is completed and return to configured pub fn wait_for_conversion_sequence(&mut self) { - while !self.adc_reg.isr.read().eoc().bit_is_set() {} + while !self.adc_reg.isr().read().eoc().bit_is_set() {} } /// get current sample #[inline(always)] pub fn current_sample(&self) -> u16 { - self.adc_reg.dr.read().rdata().bits() + self.adc_reg.dr().read().rdata().bits() } /// Starts conversion sequence. Waits for the hardware to indicate it's actually started. #[inline(always)] pub fn start_conversion(&mut self) { //Start conversion - self.adc_reg.cr.modify(|_, w| w.adstart().set_bit()); + self.adc_reg.cr().modify(|_, w| w.adstart().set_bit()); } /// Cancels an ongoing conversion #[inline(always)] pub fn cancel_conversion(&mut self) { - self.adc_reg.cr.modify(|_, w| w.adstp().set_bit()); - while self.adc_reg.cr.read().adstart().bit_is_set() {} + self.adc_reg.cr().modify(|_, w| w.adstp().set_bit()); + while self.adc_reg.cr().read().adstart().bit_is_set() {} } /// Returns if the Voltage Regulator is enabled #[inline(always)] pub fn is_vreg_enabled(&self) -> bool { - self.adc_reg.cr.read().advregen().bit_is_set() + self.adc_reg.cr().read().advregen().bit_is_set() } /// Returns if Deep Power Down is enabled #[inline(always)] pub fn is_deeppwd_enabled(&self) -> bool { - self.adc_reg.cr.read().deeppwd().bit_is_set() + self.adc_reg.cr().read().deeppwd().bit_is_set() } /// Returns if a conversion is active #[inline(always)] pub fn is_conversion_active(&self) -> bool { - self.adc_reg.cr.read().adstart().bit_is_set() + self.adc_reg.cr().read().adstart().bit_is_set() } /// Enables the vbat internal channel #[inline(always)] pub fn enable_vbat(&self, common: &stm32::$common_type) { - common.ccr.modify(|_, w| w.vbatsel().set_bit()); + common.ccr().modify(|_, w| w.vbatsel().set_bit()); } /// Enables the vbat internal channel #[inline(always)] pub fn disable_vbat(&self, common: &stm32::$common_type) { - common.ccr.modify(|_, w| w.vbatsel().clear_bit()); + common.ccr().modify(|_, w| w.vbatsel().clear_bit()); } /// Returns if the vbat internal channel is enabled #[inline(always)] pub fn is_vbat_enabled(&mut self, common: &stm32::$common_type) -> bool { - common.ccr.read().vbatsel().bit_is_set() + common.ccr().read().vbatsel().bit_is_set() } /// Enables the temp internal channel. #[inline(always)] pub fn enable_temperature(&mut self, common: &stm32::$common_type) { - common.ccr.modify(|_, w| w.vsensesel().set_bit()); + common.ccr().modify(|_, w| w.vsensesel().set_bit()); } /// Disables the temp internal channel #[inline(always)] pub fn disable_temperature(&mut self, common: &stm32::$common_type) { - common.ccr.modify(|_, w| w.vsensesel().clear_bit()); + common.ccr().modify(|_, w| w.vsensesel().clear_bit()); } /// Returns if the temp internal channel is enabled #[inline(always)] pub fn is_temperature_enabled(&mut self, common: &stm32::$common_type) -> bool { - common.ccr.read().vsensesel().bit_is_set() + common.ccr().read().vsensesel().bit_is_set() } /// Enables the vref internal channel. #[inline(always)] pub fn enable_vref(&mut self, common: &stm32::$common_type) { - common.ccr.modify(|_, w| w.vrefen().set_bit()); + common.ccr().modify(|_, w| w.vrefen().set_bit()); } /// Disables the vref internal channel #[inline(always)] pub fn disable_vref(&mut self, common: &stm32::$common_type) { - common.ccr.modify(|_, w| w.vrefen().clear_bit()); + common.ccr().modify(|_, w| w.vrefen().clear_bit()); } /// Returns if the vref internal channel is enabled #[inline(always)] pub fn is_vref_enabled(&mut self, common: &stm32::$common_type) -> bool { - common.ccr.read().vrefen().bit_is_set() + common.ccr().read().vrefen().bit_is_set() } /// Read overrun flag #[inline(always)] pub fn get_overrun_flag(&self) -> bool { - self.adc_reg.isr.read().ovr().bit() + self.adc_reg.isr().read().ovr().bit() } /// Resets the overrun flag #[inline(always)] pub fn clear_overrun_flag(&mut self) { - self.adc_reg.isr.modify(|_, w| w.ovr().set_bit()); + self.adc_reg.isr().modify(|_, w| w.ovr().set_bit()); } } @@ -2833,6 +2843,15 @@ adc_opamp!( ))] adc_opamp!( opamp::Opamp3 => (ADC3, 13), +); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g474", + feature = "stm32g483", + feature = "stm32g484", +))] +adc_opamp!( opamp::Opamp4 => (ADC5, 5), opamp::Opamp5 => (ADC5, 3), opamp::Opamp6 => (ADC4, 17), diff --git a/src/comparator.rs b/src/comparator.rs index d0597ea7..b5e80fc4 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -55,26 +55,26 @@ impl EnabledState for Enabled {} impl EnabledState for Locked {} macro_rules! impl_comp { - ($($t:ident: $reg_t:ident, $reg:ident,)+) => {$( + ($($t:ident: $reg:ident,)+) => {$( pub struct $t { _rb: PhantomData<()>, } impl $t { - pub fn csr(&self) -> &$crate::stm32::comp::$reg_t { + pub fn csr(&self) -> &$crate::stm32::comp::CCSR { // SAFETY: The COMP1 type is only constructed with logical ownership of // these registers. - &unsafe { &*COMP::ptr() }.$reg + &unsafe { &*COMP::ptr() }.$reg() } } )+}; } impl_comp! { - COMP1: C1CSR, c1csr, - COMP2: C2CSR, c2csr, - COMP3: C3CSR, c3csr, - COMP4: C4CSR, c4csr, + COMP1: c1csr, + COMP2: c2csr, + COMP3: c3csr, + COMP4: c4csr, } #[cfg(any( feature = "stm32g473", @@ -83,9 +83,9 @@ impl_comp! { feature = "stm32g484" ))] impl_comp! { - COMP5: C5CSR, c5csr, - COMP6: C6CSR, c6csr, - COMP7: C7CSR, c7csr, + COMP5: c5csr, + COMP6: c6csr, + COMP7: c7csr, } // TODO: Split COMP in PAC @@ -162,13 +162,13 @@ macro_rules! positive_input_pin { ($COMP:ident, $pin_0:ident, $pin_1:ident) => { impl PositiveInput<$COMP> for &$pin_0 { fn setup(&self, comp: &$COMP) { - comp.csr().modify(|_, w| w.inpsel().bit(false)) + comp.csr().modify(|_, w| w.inpsel().bit(false)); } } impl PositiveInput<$COMP> for &$pin_1 { fn setup(&self, comp: &$COMP) { - comp.csr().modify(|_, w| w.inpsel().bit(true)) + comp.csr().modify(|_, w| w.inpsel().bit(true)); } } }; @@ -213,7 +213,7 @@ macro_rules! negative_input_pin_helper { } fn setup(&self, comp: &$COMP) { - comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) }) + comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) }); } } }; @@ -268,7 +268,7 @@ macro_rules! refint_input { fn setup(&self, comp: &$COMP) { comp.csr() - .modify(|_, w| unsafe { w.inmsel().bits(*self as u8) }) + .modify(|_, w| unsafe { w.inmsel().bits(*self as u8) }); } } )+}; @@ -294,7 +294,7 @@ macro_rules! dac_input_helper { } fn setup(&self, comp: &$COMP) { - comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) }) + comp.csr().modify(|_, w| unsafe { w.inmsel().bits($bits) }); } } }; @@ -541,11 +541,11 @@ type Comparators = (COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7); /// Enables the comparator peripheral, and splits the [`COMP`] into independent [`COMP1`] and [`COMP2`] pub fn split(_comp: COMP, rcc: &mut Rcc) -> Comparators { // Enable COMP, SYSCFG, VREFBUF clocks - rcc.rb.apb2enr.modify(|_, w| w.syscfgen().set_bit()); + rcc.rb.apb2enr().modify(|_, w| w.syscfgen().set_bit()); // Reset COMP, SYSCFG, VREFBUF - rcc.rb.apb2rstr.modify(|_, w| w.syscfgrst().set_bit()); - rcc.rb.apb2rstr.modify(|_, w| w.syscfgrst().clear_bit()); + rcc.rb.apb2rstr().modify(|_, w| w.syscfgrst().set_bit()); + rcc.rb.apb2rstr().modify(|_, w| w.syscfgrst().clear_bit()); ( COMP1 { _rb: PhantomData }, diff --git a/src/cordic.rs b/src/cordic.rs index 05f7c0e2..104420ee 100644 --- a/src/cordic.rs +++ b/src/cordic.rs @@ -15,7 +15,7 @@ //! let mut cordic = dp //! .CORDIC //! .constrain(&mut rcc) -//! .freeze::(); // 16 bit arguments, 32 bit results, compute sine and cosine, 60 iterations +//! .freeze::(); // 16 bit arguments, 32 bit results, 60 iterations, compute sine and cosine //! //! // static operation (zero overhead) //! @@ -38,41 +38,65 @@ //! } //! ``` -use crate::{rcc::Rcc, stm32::CORDIC}; +use crate::{ + rcc::Rcc, + {stm32::cordic::csr, stm32::CORDIC}, +}; use core::marker::PhantomData; -/// Extension trait for constraining the CORDIC peripheral. +/// Extension trait for constraining the Cordic peripheral. pub trait Ext { - /// Constrain the CORDIC peripheral. + /// Constrain the Cordic peripheral. fn constrain(self, rcc: &mut Rcc) -> CordicReset; } impl Ext for CORDIC { #[inline] fn constrain(self, rcc: &mut Rcc) -> CordicReset { - rcc.rb.ahb1enr.modify(|_, w| w.cordicen().set_bit()); + rcc.rb.ahb1enr().modify(|_, w| w.cordicen().set_bit()); - // SAFETY: the resource is assumed to be - // in the "reset" configuration. - unsafe { Cordic::wrap(self) } + // SAFETY: we assume the resource is already + // in a reset state + // BONUS: this line enforces that the + // abstraction is of zero-size + unsafe { core::mem::transmute(()) } } } /// Traits and structures related to data types. pub mod types { + use super::csr; use fixed::traits::Fixed; pub use fixed::types::{I1F15, I1F31}; + pub(crate) mod sealed { + use super::Ext; + + /// Trait for tags to represent Cordic argument or result data. + pub trait Tag { + /// Internal fixed point representation. + type Repr: Ext; + } + } + /// q1.15 fixed point number. pub struct Q15; /// q1.31 fixed point number. pub struct Q31; + impl sealed::Tag for Q15 { + type Repr = I1F15; + } + + impl sealed::Tag for Q31 { + type Repr = I1F31; + } + /// Extension trait for fixed point types. pub trait Ext: Fixed { - /// Type-state representing this type. - type Repr: DataType; + /// Tag representing this type. + type Tag: sealed::Tag; /// Convert to bits of the register width, fn to_register(self) -> u32; @@ -81,58 +105,48 @@ pub mod types { } impl Ext for I1F15 { - type Repr = Q15; + type Tag = Q15; + #[inline] fn to_register(self) -> u32 { self.to_bits() as u16 as u32 } + + #[inline] fn from_register(bits: u32) -> Self { Self::from_bits(bits as u16 as i16) } } impl Ext for I1F31 { - type Repr = Q31; + type Tag = Q31; + #[inline] fn to_register(self) -> u32 { self.to_bits() as u32 } + #[inline] fn from_register(bits: u32) -> Self { Self::from_bits(bits as i32) } } - /// Trait for newtypes to represent CORDIC argument or result data. - pub trait DataType { - /// Internal fixed point representation. - type Inner: Ext; - } - - impl DataType for Q15 { - type Inner = I1F15; - } - - impl DataType for Q31 { - type Inner = I1F31; - } - /// Traits and structures related to argument type-states. - pub mod arg { - pub(crate) type Raw = crate::stm32::cordic::csr::ARGSIZE_A; + pub(crate) mod arg { + use super::{csr, sealed::Tag}; + + pub type Raw = csr::ARGSIZE; /// Trait for argument type-states. - pub(crate) trait State: super::DataType { + pub trait State: Tag { /// Raw representation of the configuration /// in the form of a bitfield variant. const RAW: Raw; /// Configure the resource to be represented /// by this type-state. - #[inline] - fn set(w: crate::stm32::cordic::csr::ARGSIZE_W) { - w.variant(Self::RAW); - } + fn set(w: csr::ARGSIZE_W) -> Self; } macro_rules! impls { @@ -140,6 +154,13 @@ pub mod types { $( impl State for $NAME { const RAW: Raw = Raw::$RAW; + + #[inline] + fn set(w: csr::ARGSIZE_W) -> Self { + w.variant(Self::RAW); + + Self + } } )+ }; @@ -152,21 +173,20 @@ pub mod types { } /// Traits and structures related to result type-states. - pub mod res { - pub(crate) type Raw = crate::stm32::cordic::csr::RESSIZE_A; + pub(crate) mod res { + use super::{csr, sealed::Tag}; + + pub type Raw = csr::RESSIZE; /// Trait for argument type-states. - pub(crate) trait State: super::DataType { + pub trait State: Tag { /// Raw representation of the configuration /// in the form of a bitfield variant. const RAW: Raw; /// Configure the resource to be represented /// by this type-state. - #[inline] - fn set(w: crate::stm32::cordic::csr::RESSIZE_W) { - w.variant(Self::RAW); - } + fn set(w: csr::RESSIZE_W) -> Self; } macro_rules! impls { @@ -174,6 +194,13 @@ pub mod types { $( impl State for $NAME { const RAW: Raw = Raw::$RAW; + + #[inline] + fn set(w: csr::RESSIZE_W) -> Self { + w.variant(Self::RAW); + + Self + } } )+ }; @@ -186,221 +213,344 @@ pub mod types { } } -/// Traits and structures related to function type-states. -pub mod func { - use super::*; - - /// For internal use. A means of indirectly specifying a signature property - /// based solely on the number of elements. - mod data_count { - use super::types; +/// Traits and structures related to data counts (argument or result). +pub(crate) mod reg_count { + use super::{csr, op::data_count, types, PhantomData}; - pub enum Count { - One, - Two, - } + pub struct NReg + where + T: types::sealed::Tag, + Count: data_count::Property, + { + _t: PhantomData, + _count: PhantomData, + } - /// One (primary) function argument/result. - pub struct One; - /// Two (primary and secondary) function arguments/results. - pub struct Two; + pub mod arg { + use super::{csr, data_count, types, NReg, PhantomData}; - pub trait Property - where - T: types::DataType, - { - type Signature: super::signature::Property; + type Raw = csr::NARGS; - const COUNT: Count; + pub(crate) trait State { + fn set(w: csr::NARGS_W) -> Self; } - impl Property for One + impl State for NReg where - T: types::DataType, + Arg: types::arg::State, + Count: data_count::Property, { - type Signature = T::Inner; + #[inline] + fn set(w: csr::NARGS_W) -> Self { + w.variant( + const { + match (Arg::RAW, Count::COUNT) { + (types::arg::Raw::Bits32, data_count::Count::Two) => Raw::Num2, + (_, _) => Raw::Num1, + } + }, + ); + + Self { + _t: PhantomData, + _count: PhantomData, + } + } + } + } - const COUNT: Count = Count::One; + pub mod res { + use super::{csr, data_count, types, NReg, PhantomData}; + + type Raw = csr::NRES; + + pub(crate) trait State { + fn set(w: csr::NRES_W) -> Self; } - impl Property for Two + impl State for NReg where - T: types::DataType, + Res: types::res::State, + Count: data_count::Property, { - type Signature = (T::Inner, T::Inner); - - const COUNT: Count = Count::Two; + #[inline] + fn set(w: csr::NRES_W) -> Self { + w.variant( + const { + match (Res::RAW, Count::COUNT) { + (types::res::Raw::Bits32, data_count::Count::Two) => Raw::Num2, + (_, _) => Raw::Num1, + } + }, + ); + + Self { + _t: PhantomData, + _count: PhantomData, + } + } } } +} - /// Traits and structures related to data counts (argument or result). - pub(crate) mod reg_count { - use super::{super::types, data_count, PhantomData}; +/// Traits and structures related to function scale type-states. +pub mod scale { + use super::csr; - pub struct NReg - where - T: types::DataType, - Count: data_count::Property, - { - _t: PhantomData, - _count: PhantomData, - } + pub(crate) type Raw = u8; - pub mod arg { - use super::{data_count, types, NReg}; + /// Trait for function scale type-states. + pub(crate) trait State { + /// Raw representation of the configuration + /// in the form of a bitfield variant. + const RAW: Raw; - type Raw = crate::stm32::cordic::csr::NARGS_A; + /// Configure the resource to be represented + /// by this type-state. + fn set(w: csr::SCALE_W) -> Self; + } - pub(crate) trait State { - fn set(w: crate::stm32::cordic::csr::NARGS_W); - } + /// Scale of 0. + pub struct N0; + /// Scale of 1. + pub struct N1; + /// Scale of 2. + pub struct N2; + /// Scale of 3. + pub struct N3; + /// Scale of 4. + pub struct N4; + /// Scale of 5. + pub struct N5; + /// Scale of 6. + pub struct N6; + /// Scale of 7. + pub struct N7; - impl State for NReg - where - Arg: types::arg::State, - Count: data_count::Property, - { - fn set(w: crate::stm32::cordic::csr::NARGS_W) { - w.variant( - const { - match (Arg::RAW, Count::COUNT) { - (types::arg::Raw::Bits32, data_count::Count::Two) => Raw::Num2, - (_, _) => Raw::Num1, - } - }, - ); + macro_rules! impls { + ( $( ($NAME:ident, $BITS:expr) $(,)? )+ ) => { + $( + impl State for $NAME { + const RAW: u8 = $BITS; + + #[inline] + fn set(w: csr::SCALE_W) -> Self { + // SAFETY: all bits are valid + unsafe { w.bits(::RAW) }; + + Self + } } - } - } + )+ + }; + } - pub mod res { - use super::{data_count, types, NReg}; + impls! { + (N0, 0), + (N1, 1), + (N2, 2), + (N3, 3), + (N4, 4), + (N5, 5), + (N6, 6), + (N7, 7), + } +} - type Raw = crate::stm32::cordic::csr::NRES_A; +/// Traits and structures related to precision type-states. +pub mod prec { + use super::csr; - pub(crate) trait State { - fn set(w: crate::stm32::cordic::csr::NRES_W); - } + /// Trait for precision type-states. + pub(crate) trait State { + /// Bit representation of the precision. + const BITS: u8; - impl State for NReg - where - Res: types::res::State, - Count: data_count::Property, - { - fn set(w: crate::stm32::cordic::csr::NRES_W) { - w.variant( - const { - match (Res::RAW, Count::COUNT) { - (types::res::Raw::Bits32, data_count::Count::Two) => Raw::Num2, - (_, _) => Raw::Num1, - } - }, - ); + /// Configure the resource to be represented + /// by this type-state. + fn set(w: csr::PRECISION_W) -> Self; + } + + /// 4 iterations. + pub struct P4; + /// 8 iterations. + pub struct P8; + /// 12 iterations. + pub struct P12; + /// 16 iterations. + pub struct P16; + /// 20 iterations. + pub struct P20; + /// 24 iterations. + pub struct P24; + /// 28 iterations. + pub struct P28; + /// 32 iterations. + pub struct P32; + /// 36 iterations. + pub struct P36; + /// 40 iterations. + pub struct P40; + /// 44 iterations. + pub struct P44; + /// 48 iterations. + pub struct P48; + /// 52 iterations. + pub struct P52; + /// 56 iterations. + pub struct P56; + /// 60 iterations. + pub struct P60; + + macro_rules! impls { + ( $( ($NAME:ident, $BITS:expr) $(,)? )+ ) => { + $( + impl State for $NAME { + const BITS: u8 = $BITS; + + #[inline] + fn set(w: csr::PRECISION_W) -> Self { + // SAFETY: reliant on valid type-state + // implementations. + unsafe { w.bits(::BITS) }; + + Self + } } - } - } + )+ + }; } - /// Traits and structures related to function scale type-states. - pub mod scale { - pub(crate) type Raw = u8; + impls! { + (P4, 1), + (P8, 2), + (P12, 3), + (P16, 4), + (P20, 5), + (P24, 6), + (P28, 7), + (P32, 8), + (P36, 9), + (P40, 10), + (P44, 11), + (P48, 12), + (P52, 13), + (P56, 14), + (P60, 15), + } +} - /// Trait for function scale type-states. - pub(crate) trait State { - /// Raw representation of the configuration - /// in the form of a bitfield variant. - const RAW: Raw; +/// Traits and structures related to function type-states. +pub(crate) mod func { + use super::csr; - /// Configure the resource to be represented - /// by this type-state. - #[inline] - fn set(w: crate::stm32::cordic::csr::SCALE_W) { - w.bits(::RAW); - } - } + pub type Raw = csr::FUNC; - /// Scale of 0. - pub struct N0; - /// Scale of 1. - pub struct N1; - /// Scale of 2. - pub struct N2; - /// Scale of 3. - pub struct N3; - /// Scale of 4. - pub struct N4; - /// Scale of 5. - pub struct N5; - /// Scale of 6. - pub struct N6; - /// Scale of 7. - pub struct N7; + /// Trait for function type-states. + pub trait State { + /// Raw representation of the function. + const RAW: Raw; - macro_rules! impls { - ( $( ($NAME:ident, $BITS:expr) $(,)? )+ ) => { - $( - impl State for $NAME { - const RAW: u8 = $BITS; + /// Configure the resource to be represented + /// by this type-state. + fn set(w: csr::FUNC_W) -> Self; + } + + pub struct Cos; + pub struct Sin; + pub struct ATan2; + pub struct Magnitude; + pub struct ATan; + pub struct CosH; + pub struct SinH; + pub struct ATanH; + pub struct Ln; + pub struct Sqrt; + + macro_rules! impls { + ( $( ($NAME:ident, $RAW:ident) $(,)? )+ ) => { + $( + impl State for $NAME { + const RAW: Raw = Raw::$RAW; + + #[inline] + fn set(w: csr::FUNC_W) -> Self { + w.variant(Self::RAW); + + Self } - )+ - }; - } + } + )+ + }; + } - impls! { - (N0, 0), - (N1, 1), - (N2, 2), - (N3, 3), - (N4, 4), - (N5, 5), - (N6, 6), - (N7, 7), - } + impls! { + (Cos, Cosine), + (Sin, Sine), + (ATan2, Phase), + (Magnitude, Modulus), + (ATan, Arctangent), + (CosH, HyperbolicCosine), + (SinH, HyperbolicSine), + (ATanH, Arctanh), + (Ln, NaturalLogarithm), + (Sqrt, SquareRoot), } +} + +/// Traits and structures related to operating the Cordic. +pub mod op { + use core::marker::PhantomData; - /// Traits and structures related to the function signature. - pub mod signature { - use super::{data_count, reg_count, types}; + use super::{func, prec, reg_count, scale, types, Cordic}; + + /// Traits and structures related to the operation signature. + pub(crate) mod signature { + use super::types; use types::arg::State as _; use types::res::State as _; - type WData = crate::stm32g4::Reg; - type RData = crate::stm32g4::Reg; + type WData = crate::stm32::cordic::WDATA; + type RData = crate::stm32::cordic::RDATA; - /// The signature is a property of the function type-state. + /// The signature is a property of the operation type-state. pub trait Property where T: types::Ext, { - /// Number of register operations required. - type NReg; - /// Write arguments to the argument register. - fn write(self, reg: &WData) + /// + /// # Safety: + /// Cordic must be configured to expect the + /// correct number of register writes. + unsafe fn write(self, reg: &WData) where - T::Repr: types::arg::State; + T::Tag: types::arg::State; /// Read results from the result register. - fn read(reg: &RData) -> Self + /// + /// # Safety: + /// Cordic must be configured to expect the + /// correct number of register reades. + unsafe fn read(reg: &RData) -> Self where - T::Repr: types::res::State; + T::Tag: types::res::State; } impl Property for T where T: types::Ext, { - type NReg = reg_count::NReg; - - fn write(self, reg: &WData) + #[inline] + unsafe fn write(self, reg: &WData) where - T::Repr: types::arg::State, + T::Tag: types::arg::State, { - let data = match const { T::Repr::RAW } { + let data = match const { T::Tag::RAW } { types::arg::Raw::Bits16 => { // $RM0440 17.4.2 // since we are only using the lower half of the register, - // the CORDIC **will** read the upper half if the function + // the Cordic **will** read the upper half if the function // accepts two arguments, so we fill it with +1 as per the // stated default. self.to_register() | (0x7fff << 16) @@ -408,12 +558,14 @@ pub mod func { types::arg::Raw::Bits32 => self.to_register(), }; - reg.write(|w| w.arg().bits(data)); + // SAFETY: all bits are valid + reg.write(|w| unsafe { w.arg().bits(data) }); } - fn read(reg: &RData) -> Self + #[inline] + unsafe fn read(reg: &RData) -> Self where - T::Repr: types::res::State, + T::Tag: types::res::State, { T::from_register(reg.read().res().bits()) } @@ -423,34 +575,37 @@ pub mod func { where T: types::Ext, { - type NReg = reg_count::NReg; - - fn write(self, reg: &WData) + #[inline] + unsafe fn write(self, reg: &WData) where - T::Repr: types::arg::State, + T::Tag: types::arg::State, { let (primary, secondary) = self; - match const { T::Repr::RAW } { + match const { T::Tag::RAW } { types::arg::Raw::Bits16 => { // $RM0440 17.4.2 - reg.write(|w| { + // SAFETY: all bits are valid + reg.write(|w| unsafe { w.arg() .bits(primary.to_register() | (secondary.to_register() << 16)) }); } types::arg::Raw::Bits32 => { - reg.write(|w| w.arg().bits(primary.to_register())); - reg.write(|w| w.arg().bits(secondary.to_register())); + // SAFETY: all bits are valid + reg.write(|w| unsafe { w.arg().bits(primary.to_register()) }); + // SAFETY: all bits are valid + reg.write(|w| unsafe { w.arg().bits(secondary.to_register()) }); } }; } - fn read(reg: &RData) -> Self + #[inline] + unsafe fn read(reg: &RData) -> Self where - T::Repr: types::res::State, + T::Tag: types::res::State, { - match const { T::Repr::RAW } { + match const { T::Tag::RAW } { types::res::Raw::Bits16 => { let data = reg.read().res().bits(); @@ -469,69 +624,131 @@ pub mod func { } } - pub(crate) type Raw = crate::stm32::cordic::csr::FUNC_A; + /// For internal use. A means of indirectly specifying a signature property + /// based solely on the number of elements. + pub(crate) mod data_count { + use super::types; - /// Trait for function type-states. - pub trait State { - /// Raw representation of the function. - const RAW: Raw; + pub enum Count { + One, + Two, + } - /// Configure the resource to be represented - /// by this type-state. - #[inline] - fn set(w: crate::stm32::cordic::csr::FUNC_W) { - w.variant(Self::RAW); + pub struct One; + pub struct Two; + + pub trait Property + where + T: types::sealed::Tag, + { + type Signature: super::signature::Property; + + const COUNT: Count; + } + + impl Property for One + where + T: types::sealed::Tag, + { + type Signature = T::Repr; + + const COUNT: Count = Count::One; + } + + impl Property for Two + where + T: types::sealed::Tag, + { + type Signature = (T::Repr, T::Repr); + + const COUNT: Count = Count::Two; + } + } + + pub(crate) mod sealed { + use super::types; + + /// An operation is a feature of the Cordic. + /// + /// Operations are permutations of: + /// - nargs + /// - nres + /// - scale + /// - func + pub trait Feature { + /// The required argument register writes. + type NArgs + where + Arg: types::arg::State + types::sealed::Tag; + /// The required result register reads. + type NRes + where + Res: types::res::State + types::sealed::Tag; + /// The scale to be applied. + type Scale; + /// The function to evaluate. + type Func; + + /// The number of arguments required. + type ArgCount; + /// The number of results produced. + type ResCount; } } - /// Define specific combinations - /// of states and properties for each function. - pub trait Feature: State + /// An operation of the Cordic. + /// + /// Enables writing and reading values + /// to and from the Cordic. + #[allow(unused)] + struct Operation<'a, Arg, Res, Op> where Arg: types::arg::State, Res: types::res::State, + Op: sealed::Feature, { - /// The number of arguments required. - type Arguments: signature::Property; - /// The number of arguments produced. - type Results: signature::Property; - - /// The operation to perform. - type Op: State; - /// The scale to be applied. - type Scale: scale::State; - /// The required argument register writes. - type NArgs: reg_count::arg::State; - /// The required result register reads. - type NRes: reg_count::res::State; - } - - impl Cordic + nargs: &'a Op::NArgs, + nres: &'a Op::NRes, + scale: &'a Op::Scale, + func: &'a Op::Func, + } + + impl Operation<'_, Arg, Res, Op> where Arg: types::arg::State, Res: types::res::State, - Func: Feature, - Prec: prec::State, - Func::Arguments: signature::Property, - Func::Results: signature::Property, + Op: sealed::Feature, { - /// Start the configured operation. - pub fn start(&mut self, args: Func::Arguments) { - use signature::Property as _; - - args.write(&self.rb.wdata); + /// Write arguments to the argument register. + #[inline] + fn write(&mut self, args: Args, reg: &crate::stm32::cordic::WDATA) + where + Arg: types::sealed::Tag, + Args: signature::Property, + Op::ArgCount: data_count::Property, + { + // SAFETY: Cordic is necessarily configured properly if + // an instance of `Operation` exists. + unsafe { + signature::Property::::write(args, reg); + } } - /// Get the result of an operation. - pub fn result(&mut self) -> Func::Results { - use signature::Property as _; - - Func::Results::read(&self.rb.rdata) + /// Read results from the result register. + #[inline] + fn read( + &mut self, + reg: &crate::stm32::cordic::RDATA, + ) -> >::Signature + where + Op::ResCount: data_count::Property, + { + // SAFETY: Cordic is necessarily configured properly if + // an instance of `Operation` exists. + unsafe { signature::Property::::read(reg) } } } - // function types with argument count encoded - /// Cosine of an angle theta divided by pi. pub struct Cos; /// Sine of an angle theta divided by pi. @@ -578,50 +795,42 @@ pub mod func { } macro_rules! impls { - ( $( ($NAME:ident < $SCALE:ident >, $RAW:ident, $NARGS:ident, $NRES:ident, start( $($START_PARAM:ident),+ )) $(,)?)+ ) => { + ( $( ($TAG:ident<$SCALE:ident>, $NARGS:ident, $NRES:ident, $FUNC:ident) $(,)?)+ ) => { $( - impl State for $NAME { - const RAW: Raw = Raw::$RAW; - } - - impl Feature for $NAME - where - Arg: types::arg::State, - Res: types::res::State, + impl sealed::Feature for $TAG { - type Arguments = >::Signature; - type Results = >::Signature; - - type Op = Self; + type NArgs = reg_count::NReg + where + Arg: types::arg::State + types::sealed::Tag; + type NRes = reg_count::NReg + where + Res: types::res::State + types::sealed::Tag; type Scale = scale::$SCALE; - type NArgs = >::NReg; - type NRes = >::NReg; + type Func = func::$FUNC; + + type ArgCount = data_count::$NARGS; + type ResCount = data_count::$NRES; } )+ }; } macro_rules! impls_multi_scale { - // root / config (almost identical to single scale) - ( $( ($NAME:ident < $( $SCALE:ident $(,)? )+ >, $RAW:ident, $NARGS:ident, $NRES:ident, start $START_PARAM:tt ) $(,)?)+ ) => { + ( $( ($TAG:ident<$($SCALE:ident $(,)?)+>, $NARGS:ident, $NRES:ident, $FUNC:ident) $(,)?)+ ) => { $( $( - impl State for $NAME { - const RAW: Raw = Raw::$RAW; - } - - impl Feature for $NAME - where - Arg: types::arg::State, - Res: types::res::State, - { - type Arguments = >::Signature; - type Results = >::Signature; - - type Op = Self; + impl sealed::Feature for $TAG { + type NArgs = reg_count::NReg + where + Arg: types::arg::State + types::sealed::Tag; + type NRes = reg_count::NReg + where + Res: types::res::State + types::sealed::Tag; type Scale = scale::$SCALE; - type NArgs = >::NReg; - type NRes = >::NReg; + type Func = func::$FUNC; + + type ArgCount = data_count::$NARGS; + type ResCount = data_count::$NRES; } )+ )+ @@ -629,194 +838,200 @@ pub mod func { } impls! { - (Cos, Cosine, One, One, start(angle)), - (Sin, Sine, One, One, start(angle)), - (SinCos, Sine, One, Two, start(angle)), - (CosM, Cosine, Two, One, start(angle, modulus)), - (SinM, Sine, Two, One, start(angle, modulus)), - (SinCosM, Sine, Two, Two, start(angle, modulus)), - (ATan2, Phase, Two, One, start(x, y)), - (Magnitude, Modulus, Two, One, start(x, y)), - (ATan2Magnitude, Phase, Two, Two, start(x, y)), - (CosH, HyperbolicCosine, One, One, start(x)), - (SinH, HyperbolicSine, One, One, start(x)), - (SinHCosH, HyperbolicSine, One, Two, start(x)), - (ATanH, Arctanh, One, One, start(x)), + (Cos, One, One, Cos), + (Sin, One, One, Sin), + (SinCos, One, Two, Sin), + (CosM, Two, One, Cos), + (SinM, Two, One, Sin), + (SinCosM, Two, Two, Sin), + (ATan2, Two, One, ATan2), + (Magnitude, Two, One, Magnitude), + (ATan2Magnitude, Two, Two, ATan2), + (CosH, One, One, CosH), + (SinH, One, One, SinH), + (SinHCosH, One, Two, SinH), + (ATanH, One, One, ATan), } impls_multi_scale! { - (ATan, Arctangent, One, One, start(x)), - (Ln, NaturalLogarithm, One, One, start(x)), - (Sqrt, SquareRoot, One, One, start(x)), + (ATan, One, One, ATan), + (Ln, One, One, Ln), + (Sqrt, One, One, Sqrt), + } + + impl Cordic + where + Arg: types::arg::State, + Res: types::res::State, + Prec: prec::State, + Op: sealed::Feature, + { + /// Start the configured operation. + #[inline] + pub fn start(&mut self, args: >::Signature) + where + Op::ArgCount: data_count::Property, + { + let config = &self.config; + let mut op = Operation:: { + nargs: &config.nargs, + nres: &config.nres, + scale: &config.scale, + func: &config.func, + }; + + op.write(args, self.rb.wdata()); + } + + /// Get the result of an operation. + #[inline] + pub fn result(&mut self) -> >::Signature + where + Op::ResCount: data_count::Property, + { + let config = &self.config; + let mut op = Operation:: { + nargs: &config.nargs, + nres: &config.nres, + scale: &config.scale, + func: &config.func, + }; + + op.read(self.rb.rdata()) + } } /// Traits and structures for dynamic function operation. pub mod dynamic { - use super::{prec, signature, types, Cordic, Feature}; + use super::{ + super::{prec, reg_count, Cordic}, + data_count, func, scale, + sealed::Feature, + types, Operation, + }; - /// Any function can be invoked with this type-state. + /// Any operation can be invoked with this type-state. pub struct Any; + impl Feature for Any { + type NArgs + = () + where + Arg: types::arg::State + types::sealed::Tag; + type NRes + = () + where + Res: types::res::State + types::sealed::Tag; + type Scale = (); + type Func = (); + + type ArgCount = (); + type ResCount = (); + } + /// A Cordic in dynamic mode. pub trait Mode where Arg: types::arg::State, Res: types::res::State, { - /// Run a function with provided arguments and get the result. + /// Run an operation with provided arguments and get the result. /// /// *Note: This employs the polling strategy. /// For less overhead, use static operations.* - fn run(&mut self, args: Func::Arguments) -> Func::Results + fn run( + &mut self, + args: >::Signature, + ) -> >::Signature where - Func: Feature; + Op: Feature, + Op::NArgs: reg_count::arg::State, + Op::NRes: reg_count::res::State, + Op::Scale: scale::State, + Op::Func: func::State, + Op::ArgCount: data_count::Property, + Op::ResCount: data_count::Property; } - impl Mode for Cordic + impl Mode for Cordic where Arg: types::arg::State, Res: types::res::State, Prec: prec::State, { - fn run(&mut self, args: Func::Arguments) -> Func::Results + #[inline] + fn run( + &mut self, + args: >::Signature, + ) -> >::Signature where - Func: Feature, + Op: Feature, + Op::NArgs: reg_count::arg::State, + Op::NRes: reg_count::res::State, + Op::Scale: scale::State, + Op::Func: func::State, + Op::ArgCount: data_count::Property, + Op::ResCount: data_count::Property, { - use signature::Property as _; - - self.apply_config::(); + use func::State as _; + use reg_count::{arg::State as _, res::State as _}; + use scale::State as _; + + let (nargs, nres, scale, func) = self.rb.csr().from_modify(|_, w| { + ( + Op::NArgs::set(w.nargs()), + Op::NRes::set(w.nres()), + Op::Scale::set(w.scale()), + Op::Func::set(w.func()), + ) + }); + + let mut op = Operation:: { + nargs: &nargs, + nres: &nres, + scale: &scale, + func: &func, + }; - args.write(&self.rb.wdata); - self.when_ready(|cordic| Func::Results::read(&cordic.rb.rdata)) + op.write(args, self.rb.wdata()); + self.when_ready(|cordic| op.read(cordic.rb.rdata())) } } } } -/// Traits and structures related to precision type-states. -pub mod prec { - /// Trait for precision type-states. - pub(crate) trait State { - /// Bit representation of the precision. - const BITS: u8; - - /// Configure the resource to be represented - /// by this type-state. - fn set(w: crate::stm32::cordic::csr::PRECISION_W); - } - - /// 4 iterations. - pub struct P4; - /// 8 iterations. - pub struct P8; - /// 12 iterations. - pub struct P12; - /// 16 iterations. - pub struct P16; - /// 20 iterations. - pub struct P20; - /// 24 iterations. - pub struct P24; - /// 28 iterations. - pub struct P28; - /// 32 iterations. - pub struct P32; - /// 36 iterations. - pub struct P36; - /// 40 iterations. - pub struct P40; - /// 44 iterations. - pub struct P44; - /// 48 iterations. - pub struct P48; - /// 52 iterations. - pub struct P52; - /// 56 iterations. - pub struct P56; - /// 60 iterations. - pub struct P60; - - macro_rules! impls { - ( $( ($NAME:ident, $BITS:expr) $(,)? )+ ) => { - $( - impl State for $NAME { - const BITS: u8 = $BITS; - - #[inline] - fn set(w: crate::stm32::cordic::csr::PRECISION_W) { - // SAFETY: reliant on valid type-state - // implementations. - unsafe { w.bits(::BITS) }; - } - } - )+ - }; - } - - impls! { - (P4, 1), - (P8, 2), - (P12, 3), - (P16, 4), - (P20, 5), - (P24, 6), - (P28, 7), - (P32, 8), - (P36, 9), - (P40, 10), - (P44, 11), - (P48, 12), - (P52, 13), - (P56, 14), - (P60, 15), - } +/// Configuration for the Cordic. +struct Config { + arg: Arg, + res: Res, + nargs: NArgs, + nres: NRes, + scale: Scale, + prec: Prec, + func: Func, } /// Cordic co-processor interface. -pub struct Cordic +pub struct Cordic where Arg: types::arg::State, Res: types::res::State, Prec: prec::State, + Op: op::sealed::Feature, { rb: CORDIC, - _arg_size: PhantomData, - _res_size: PhantomData, - _func: PhantomData, - _prec: PhantomData, + #[allow(clippy::type_complexity)] + config: Config, Op::NRes, Op::Scale, Prec, Op::Func>, } // root impl -impl Cordic +impl Cordic where Arg: types::arg::State, Res: types::res::State, Prec: prec::State, + Op: op::sealed::Feature, { - fn apply_config(&mut self) - where - NewArg: types::arg::State, - NewRes: types::res::State, - NewFunc: func::Feature, - NewPrec: prec::State, - { - self.rb.csr.write(|w| { - use func::reg_count::arg::State as _; - use func::reg_count::res::State as _; - use func::scale::State as _; - - NewArg::set(w.argsize()); - NewRes::set(w.ressize()); - NewPrec::set(w.precision()); - NewFunc::set(w.func()); - NewFunc::NArgs::set(w.nargs()); - NewFunc::NRes::set(w.nres()); - NewFunc::Scale::set(w.scale()); - - w - }); - } - /// Configure the resource as dictated by the resulting /// type-states. The produced binding represents /// a frozen configuration, since it is represented @@ -826,26 +1041,43 @@ where /// /// *Note: The configuration is inferred from context because /// it is represented by generic type-states.* - pub fn freeze( - mut self, - ) -> Cordic + #[inline] + pub fn freeze(self) -> Cordic where NewArg: types::arg::State, NewRes: types::res::State, - NewFunc: func::Feature, NewPrec: prec::State, + NewOp: op::sealed::Feature, + NewOp::NArgs: reg_count::arg::State, + NewOp::NRes: reg_count::res::State, + NewOp::Scale: scale::State, + NewOp::Func: func::State, { - self.apply_config::(); + use func::State as _; + use reg_count::arg::State as _; + use reg_count::res::State as _; + use scale::State as _; + + let config = self.rb.csr().from_modify(|_, w| Config { + arg: NewArg::set(w.argsize()), + res: NewRes::set(w.ressize()), + nargs: NewOp::NArgs::set(w.nargs()), + nres: NewOp::NRes::set(w.nres()), + scale: NewOp::Scale::set(w.scale()), + prec: NewPrec::set(w.precision()), + func: NewOp::Func::set(w.func()), + }); - // SAFETY: the resource has been configured - // to represent the new type-states. - unsafe { Cordic::wrap(self.rb) } + Cordic { + rb: self.rb, + config, + } } /// Determine whether a result is pending or not. #[inline] pub fn is_ready(&self) -> bool { - self.rb.csr.read().rrdy().bit_is_set() + self.rb.csr().read().rrdy().bit_is_set() } /// Dispatch an operation once a result is @@ -868,93 +1100,83 @@ where /// Convert into a Cordic interface that supports /// runtime function selection. #[inline] - pub fn into_dynamic(self) -> Cordic { - unsafe { Cordic::wrap(self.rb) } - } - - /// Wrap the resource as a noop. - /// - /// # Safety - /// - /// If the resource configuration and - /// type-states are incongruent, the invariance - /// is broken and actions may exhibit - /// undefined behavior. - pub const unsafe fn wrap(rb: CORDIC) -> Self { - Self { - rb, - _arg_size: PhantomData, - _res_size: PhantomData, - _func: PhantomData, - _prec: PhantomData, + pub fn into_dynamic(self) -> Cordic { + Cordic { + rb: self.rb, + config: Config { + arg: self.config.arg, + res: self.config.res, + nargs: (), + nres: (), + scale: (), + prec: self.config.prec, + func: (), + }, } } } /// $RM0440 17.4.1 -pub type CordicReset = Cordic; +pub type CordicReset = Cordic; -// reset -impl Cordic +impl Cordic where Arg: types::arg::State, Res: types::res::State, - Func: func::Feature, Prec: prec::State, + Op: op::sealed::Feature, { - /// Configure the resource back to the "reset" - /// state. #[inline] - fn reset(self) -> CordicReset { + fn into_reset(self) -> CordicReset { self.freeze() } } // listen -impl Cordic +impl Cordic where Arg: types::arg::State, Res: types::res::State, - Func: func::Feature, Prec: prec::State, + Op: op::sealed::Feature, { /// Enable the result ready interrupt. #[inline] pub fn listen(&mut self) { - self.rb.csr.modify(|_, w| w.ien().set_bit()); + self.rb.csr().modify(|_, w| w.ien().set_bit()); } /// Disable the result ready interrupt. #[inline] pub fn unlisten(&mut self) { - self.rb.csr.modify(|_, w| w.ien().clear_bit()); + self.rb.csr().modify(|_, w| w.ien().clear_bit()); } } // release -impl Cordic +impl Cordic where Arg: types::arg::State, Res: types::res::State, - Func: func::Feature, Prec: prec::State, + Op: op::sealed::Feature, { - /// Release the CORDIC resource binding as a noop. + /// Release the Cordic resource binding as a noop. /// /// # Safety /// - /// The CORDIC peripheral is not reset. + /// The Cordic peripheral is not reset. #[inline] pub unsafe fn release(self) -> CORDIC { self.rb } - /// Release the CORDIC resource binding after reset. + /// Release the Cordic resource binding after reset. #[inline] pub fn release_and_reset(self, rcc: &mut Rcc) -> CORDIC { - let reset = self.reset(); + let reset = self.into_reset(); - rcc.rb.ahb1enr.modify(|_, w| w.cordicen().clear_bit()); + rcc.rb.ahb1enr().modify(|_, w| w.cordicen().clear_bit()); // SAFETY: the resource has been reset unsafe { reset.release() } diff --git a/src/dac.rs b/src/dac.rs index 5289da29..e2bafb4b 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -179,7 +179,7 @@ macro_rules! dac_helper { $trim:ident, $mode:ident, $dhrx:ident, - $dac_dor:ident, + $dor:ident, $daccxdhr:ident, $wave:ident, $mamp:ident, @@ -193,8 +193,8 @@ macro_rules! dac_helper { pub fn enable(self) -> $CX { let dac = unsafe { &(*<$DAC>::ptr()) }; - dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(MODE_BITS) }); - dac.dac_cr.modify(|_, w| w.$en().set_bit()); + dac.mcr().modify(|_, w| unsafe { w.$mode().bits(MODE_BITS) }); + dac.cr().modify(|_, w| w.$en().set_bit()); $CX { _enabled: PhantomData, @@ -204,8 +204,8 @@ macro_rules! dac_helper { pub fn enable_generator(self, config: GeneratorConfig) -> $CX { let dac = unsafe { &(*<$DAC>::ptr()) }; - dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(MODE_BITS) }); - dac.dac_cr.modify(|_, w| unsafe { + dac.mcr().modify(|_, w| unsafe { w.$mode().bits(MODE_BITS) }); + dac.cr().modify(|_, w| unsafe { w.$wave().bits(config.mode); w.$ten().set_bit(); w.$mamp().bits(config.amp); @@ -235,19 +235,19 @@ macro_rules! dac_helper { D: DelayNs { let dac = unsafe { &(*<$DAC>::ptr()) }; - dac.dac_cr.modify(|_, w| w.$en().clear_bit()); - dac.dac_mcr.modify(|_, w| unsafe { w.$mode().bits(0) }); - dac.dac_cr.modify(|_, w| w.$cen().set_bit()); + dac.cr().modify(|_, w| w.$en().clear_bit()); + dac.mcr().modify(|_, w| unsafe { w.$mode().bits(0) }); + dac.cr().modify(|_, w| w.$cen().set_bit()); let mut trim = 0; while true { - dac.dac_ccr.modify(|_, w| unsafe { w.$trim().bits(trim) }); + dac.ccr().modify(|_, w| unsafe { w.$trim().bits(trim) }); delay.delay_us(64_u32); - if dac.dac_sr.read().$cal_flag().bit() { + if dac.sr().read().$cal_flag().bit() { break; } trim += 1; } - dac.dac_cr.modify(|_, w| w.$cen().clear_bit()); + dac.cr().modify(|_, w| w.$cen().clear_bit()); $CX { _enabled: PhantomData, @@ -257,7 +257,7 @@ macro_rules! dac_helper { /// Disable the DAC channel pub fn disable(self) -> $CX { let dac = unsafe { &(*<$DAC>::ptr()) }; - dac.dac_cr.modify(|_, w| unsafe { + dac.cr().modify(|_, w| unsafe { w.$en().clear_bit().$wave().bits(0).$ten().clear_bit() }); @@ -272,12 +272,12 @@ macro_rules! dac_helper { impl DacOut for $CX { fn set_value(&mut self, val: u16) { let dac = unsafe { &(*<$DAC>::ptr()) }; - dac.$dhrx.write(|w| unsafe { w.bits(val as u32) }); + dac.$dhrx().write(|w| unsafe { w.bits(val as u32) }); } fn get_value(&mut self) -> u16 { let dac = unsafe { &(*<$DAC>::ptr()) }; - dac.$dac_dor.read().bits() as u16 + dac.$dor().read().bits() as u16 } } @@ -285,7 +285,7 @@ macro_rules! dac_helper { impl $CX { pub fn trigger(&mut self) { let dac = unsafe { &(*<$DAC>::ptr()) }; - dac.dac_swtrgr.write(|w| { w.$swtrig().set_bit() }); + dac.swtrgr().write(|w| { w.$swtrig().set_bit() }); } } )+ @@ -300,8 +300,8 @@ macro_rules! dac { cal_flag1, otrim1, mode1, - dac_dhr12r1, - dac_dor1, + dhr12r1, + dor1, dacc1dhr, wave1, mamp1, @@ -314,8 +314,8 @@ macro_rules! dac { cal_flag2, otrim2, mode2, - dac_dhr12r2, - dac_dor2, + dhr12r2, + dor2, dacc2dhr, wave2, mamp2, diff --git a/src/dma.rs b/src/dma.rs index d1033762..41e5e059 100644 --- a/src/dma.rs +++ b/src/dma.rs @@ -1,7 +1,7 @@ //! Direct Memory Access. //! //! [Transfer::init](struct.Transfer.html#method.init) is only implemented for -//! valid combinations of peripheral-stream-channel-direction, providing compile +//! valid combinations of peripheral-channel-direction, providing compile //! time checking. //! //! This module implements Memory To Memory, Peripheral To Memory and Memory to @@ -17,13 +17,13 @@ use core::fmt::Debug; +pub mod channel; // DMA MUX // DMA1 and DMA2 pub mod config; pub(crate) mod mux; -pub mod stream; // DMA MUX // DMA1 and DMA2 pub mod traits; pub mod transfer; -use traits::{sealed::Bits, Direction, Stream, TargetAddress}; +use traits::{sealed::Bits, Channel, Direction, TargetAddress}; pub use transfer::{Transfer, TransferExt}; /// Errors. diff --git a/src/dma/channel.rs b/src/dma/channel.rs new file mode 100644 index 00000000..d50f67db --- /dev/null +++ b/src/dma/channel.rs @@ -0,0 +1,469 @@ +//! DMA + +use super::{ + config, + traits::sealed::{Bits, Sealed}, + traits::*, + DmaDirection, +}; +use core::marker::PhantomData; + +use crate::rcc::Rcc; +use crate::stm32; + +use stm32::{DMA1, DMA2, DMAMUX}; + +use crate::dma::config::DmaConfig; +use core::ops::Deref; + +impl Sealed for DMA1 {} +impl Sealed for DMA2 {} + +/// Type aliases for register blocks +pub type DMARegisterBlock = stm32::dma1::RegisterBlock; +pub type DMAMUXRegisterBlock = stm32::dmamux::RegisterBlock; + +/// Trait that represents an instance of a DMA peripheral +pub trait Instance: Deref + Sealed { + const IS_DMA1: bool; + + /// Gives a pointer to the RegisterBlock. + fn ptr() -> *const DMARegisterBlock; + + /// Gives a pointer to the DMAMUX used for this DMA. + fn mux_ptr() -> *const DMAMUXRegisterBlock; +} + +impl Instance for DMA1 { + const IS_DMA1: bool = true; + + #[inline(always)] + fn ptr() -> *const DMARegisterBlock { + DMA1::ptr() + } + + #[inline(always)] + fn mux_ptr() -> *const DMAMUXRegisterBlock { + DMAMUX::ptr() + } +} + +impl Instance for DMA2 { + const IS_DMA1: bool = false; + + #[inline(always)] + fn ptr() -> *const DMARegisterBlock { + DMA2::ptr() + } + + #[inline(always)] + fn mux_ptr() -> *const DMAMUXRegisterBlock { + DMAMUX::ptr() + } +} + +/// DMA interrupts +#[derive(Debug, Clone, Copy)] +pub struct DmaInterrupts { + transfer_complete: bool, + transfer_error: bool, + half_transfer: bool, +} + +/// Alias for a tuple with all DMA channels. +pub struct Channels { + pub ch1: C, + pub ch2: C, + pub ch3: C, + pub ch4: C, + pub ch5: C, + pub ch6: C, + #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))] + pub ch7: C, + #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))] + pub ch8: C, +} + +pub trait DMAExt { + fn split(self, rcc: &Rcc) -> Channels; +} + +impl DMAExt for DMA1 { + fn split(self, rcc: &Rcc) -> Channels { + // Enable DMAMux is not yet enabled + if !rcc.rb.ahb1enr().read().dmamuxen().bit_is_set() { + // Enable peripheral + rcc.rb.ahb1enr().modify(|_, w| w.dmamuxen().set_bit()); + } + + // Enable peripheral + rcc.rb.ahb1enr().modify(|_, w| w.dma1en().set_bit()); + + Channels::new(self) + } +} + +impl DMAExt for DMA2 { + fn split(self, rcc: &Rcc) -> Channels { + // Enable DMAMux is not yet enabled + if !rcc.rb.ahb1enr().read().dmamuxen().bit_is_set() { + // Enable peripheral + rcc.rb.ahb1enr().modify(|_, w| w.dmamuxen().set_bit()); + } + + // Enable peripheral + rcc.rb.ahb1enr().modify(|_, w| w.dma2en().set_bit()); + + Channels::new(self) + } +} + +impl Channels { + /// Splits the DMA peripheral into channels. + pub(crate) fn new(_regs: I) -> Self { + Self { + ch1: C { _dma: PhantomData }, + ch2: C { _dma: PhantomData }, + ch3: C { _dma: PhantomData }, + ch4: C { _dma: PhantomData }, + ch5: C { _dma: PhantomData }, + ch6: C { _dma: PhantomData }, + #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))] + ch7: C { _dma: PhantomData }, + #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))] + ch8: C { _dma: PhantomData }, + } + } +} + +/// Channel on DMA +/// +/// Note that `C` here maps to Channel1 +pub struct C { + _dma: PhantomData, +} + +impl Sealed for C {} + +impl C { + fn ch(&self) -> &stm32::dma1::CH { + // NOTE(unsafe) grants access only to this channels registers + unsafe { &*I::ptr() }.ch(N as usize) + } +} + +impl Channel for C { + type Interrupts = DmaInterrupts; + + fn apply_config(&mut self, config: DmaConfig) { + self.set_priority(config.priority); + self.set_memory_increment(config.memory_increment); + self.set_peripheral_increment(config.peripheral_increment); + self.set_circular_buffer(config.circular_buffer); + self.set_transfer_complete_interrupt_enable(config.transfer_complete_interrupt); + self.set_half_transfer_interrupt_enable(config.half_transfer_interrupt); + self.set_transfer_error_interrupt_enable(config.transfer_error_interrupt); + } + + #[inline(always)] + fn clear_interrupts(&mut self) { + //NOTE(unsafe) Atomic write with no side-effects and we only access the bits + // that belongs to the ChannelX + let dma = unsafe { &*I::ptr() }; + dma.ifcr().write( + |w| { + w.ctcif(N) + .set_bit() //Clear transfer complete interrupt flag + .chtif(N) + .set_bit() //Clear half transfer interrupt flag + .cteif(N) + .set_bit() //Clear transfer error interrupt flag + .cgif(N) + .set_bit() + }, //Clear global interrupt flag + ); + let _ = dma.isr().read(); + let _ = dma.isr().read(); // Delay 2 peripheral clocks + } + + #[inline(always)] + fn clear_transfer_complete_flag(&mut self) { + //NOTE(unsafe) Atomic write with no side-effects and we only access the bits + // that belongs to the ChannelX + let dma = unsafe { &*I::ptr() }; + dma.ifcr().write(|w| w.ctcif(N).set_bit()); + } + + #[inline(always)] + fn clear_transfer_complete_interrupt(&mut self) { + self.clear_transfer_complete_flag(); + //NOTE(unsafe) Atomic read with no side-effects. + let dma = unsafe { &*I::ptr() }; + let _ = dma.isr().read(); + let _ = dma.isr().read(); // Delay 2 peripheral clocks + } + + #[inline(always)] + fn clear_transfer_error_interrupt(&mut self) { + //NOTE(unsafe) Atomic write with no side-effects and we only access the bits + // that belongs to the ChannelX + let dma = unsafe { &*I::ptr() }; + dma.ifcr().write(|w| w.ctcif(N).set_bit()); + let _ = dma.isr().read(); + let _ = dma.isr().read(); // Delay 2 peripheral clocks + } + + #[inline(always)] + fn get_transfer_complete_flag(&self) -> bool { + //NOTE(unsafe) Atomic read with no side effects + let dma = unsafe { &*I::ptr() }; + dma.isr().read().tcif(N).bit_is_set() + } + + #[inline(always)] + fn get_transfer_error_flag(&self) -> bool { + //NOTE(unsafe) Atomic read with no side effects + let dma = unsafe { &*I::ptr() }; + dma.isr().read().tcif(N).bit_is_set() + } + + #[inline(always)] + unsafe fn enable(&mut self) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = &unsafe { &*I::ptr() }.ch(N as usize); + dma_ch.cr().modify(|_, w| w.en().set_bit()); + } + + #[inline(always)] + fn is_enabled(&self) -> bool { + //NOTE(unsafe) Atomic read with no side effects + let dma_ch = &unsafe { &*I::ptr() }.ch(N as usize); + dma_ch.cr().read().en().bit_is_set() + } + + fn disable(&mut self) { + if self.is_enabled() { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = &unsafe { &*I::ptr() }.ch(N as usize); + + // Aborting an on-going transfer might cause interrupts to fire, disable + // them + let interrupts = self.get_interrupts_enable(); + self.disable_interrupts(); + + dma_ch.cr().modify(|_, w| w.en().clear_bit()); + while self.is_enabled() {} + + self.clear_interrupts(); + self.enable_interrupts(interrupts); + } + } + + #[inline(always)] + fn set_request_line(&mut self, request_line: u8) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dmamux = unsafe { &*I::mux_ptr() }; + unsafe { + dmamux + .ccr(N as usize) + .modify(|_, w| w.dmareq_id().bits(request_line)); + } + } + + #[inline(always)] + fn set_priority(&mut self, priority: config::Priority) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = &self.ch(); + dma_ch + .cr() + .modify(|_, w| unsafe { w.pl().bits(priority.bits()) }); + } + + #[inline(always)] + fn disable_interrupts(&mut self) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dmacr = &self.ch().cr(); + dmacr.modify(|_, w| w.tcie().clear_bit().teie().clear_bit().htie().clear_bit()); + let _ = dmacr.read(); + let _ = dmacr.read(); // Delay 2 peripheral clocks + } + + #[inline(always)] + fn enable_interrupts(&mut self, interrupt: Self::Interrupts) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = &self.ch(); + dma_ch.cr().modify(|_, w| { + w.tcie() + .bit(interrupt.transfer_complete) + .teie() + .bit(interrupt.transfer_error) + .htie() + .bit(interrupt.half_transfer) + }); + } + + #[inline(always)] + fn get_interrupts_enable(&self) -> Self::Interrupts { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + let cr = dma_ch.cr().read(); + + DmaInterrupts { + transfer_complete: cr.tcie().bit_is_set(), + half_transfer: cr.htie().bit_is_set(), + transfer_error: cr.teie().bit_is_set(), + } + } + + #[inline(always)] + fn set_transfer_complete_interrupt_enable(&mut self, transfer_complete_interrupt: bool) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dmacr = &self.ch().cr(); + dmacr.modify(|_, w| w.tcie().bit(transfer_complete_interrupt)); + let _ = dmacr.read(); + let _ = dmacr.read(); // Delay 2 peripheral clocks + } + + #[inline(always)] + fn set_transfer_error_interrupt_enable(&mut self, transfer_error_interrupt: bool) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dmacr = &self.ch().cr(); + dmacr.modify(|_, w| w.teie().bit(transfer_error_interrupt)); + let _ = dmacr.read(); + let _ = dmacr.read(); // Delay 2 peripheral clocks + } + + #[inline(always)] + fn set_half_transfer_interrupt_enable(&mut self, half_transfer_interrupt: bool) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dmacr = &self.ch().cr(); + dmacr.modify(|_, w| w.htie().bit(half_transfer_interrupt)); + let _ = dmacr.read(); + let _ = dmacr.read(); // Delay 2 peripheral clocks + } + + #[inline(always)] + fn get_half_transfer_flag(&self) -> bool { + //NOTE(unsafe) Atomic read with no side effects + let dma = unsafe { &*I::ptr() }; + dma.isr().read().htif(N).bit_is_set() + } + + #[inline(always)] + fn clear_half_transfer_interrupt(&mut self) { + //NOTE(unsafe) Atomic write with no side-effects and we only access the bits + // that belongs to the ChannelX + let dma = unsafe { &*I::ptr() }; + dma.ifcr().write(|w| w.chtif(N).set_bit()); + let _ = dma.isr().read(); + let _ = dma.isr().read(); // Delay 2 peripheral clocks + } + + #[inline(always)] + unsafe fn set_peripheral_address(&mut self, value: u32) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.par().write(|w| w.pa().bits(value)); + } + + #[inline(always)] + unsafe fn set_memory_address(&mut self, value: u32) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.mar().write(|w| w.ma().bits(value)); + } + + #[inline(always)] + fn get_memory_address(&self) -> u32 { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.mar().read().ma().bits() + } + + #[inline(always)] + fn set_number_of_transfers(&mut self, value: u16) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.ndtr().write(|w| unsafe { w.ndt().bits(value) }); + } + + #[inline(always)] + fn get_number_of_transfers(&self) -> u16 { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.ndtr().read().ndt().bits() + } + #[inline(always)] + unsafe fn set_memory_size(&mut self, size: u8) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.cr().modify(|_, w| w.msize().bits(size)); + } + + #[inline(always)] + unsafe fn set_peripheral_size(&mut self, size: u8) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.cr().modify(|_, w| w.psize().bits(size)); + } + + #[inline(always)] + fn set_memory_increment(&mut self, increment: bool) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.cr().modify(|_, w| w.minc().bit(increment)); + } + + #[inline(always)] + fn set_peripheral_increment(&mut self, increment: bool) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.cr().modify(|_, w| w.pinc().bit(increment)); + } + + #[inline(always)] + fn set_direction(&mut self, direction: DmaDirection) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.cr().modify(|_, w| match direction { + DmaDirection::PeripheralToMemory => w.dir().clear_bit().mem2mem().clear_bit(), + DmaDirection::MemoryToPeripheral => w.dir().set_bit().mem2mem().clear_bit(), + DmaDirection::MemoryToMemory => w.mem2mem().set_bit().dir().clear_bit(), + }); + } + + #[inline(always)] + fn set_circular_buffer(&mut self, circular_buffer: bool) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dma_ch = self.ch(); + dma_ch.cr().modify(|_, w| w.circ().bit(circular_buffer)); + } +} + +impl C { + #[inline(always)] + pub fn clear_half_transfer_interrupt(&mut self) { + //NOTE(unsafe) Atomic write with no side-effects and we only access the bits + // that belongs to the ChannelX + let dma = unsafe { &*I::ptr() }; + dma.ifcr().write(|w| w.chtif(N).set_bit()); + let _ = dma.isr().read(); + let _ = dma.isr().read(); // Delay 2 peripheral clocks + } + + #[inline(always)] + pub fn get_half_transfer_flag() -> bool { + //NOTE(unsafe) Atomic read with no side effects + let dma = unsafe { &*I::ptr() }; + dma.isr().read().htif(N).bit_is_set() + } + + #[inline(always)] + pub fn set_half_transfer_interrupt_enable(&mut self, half_transfer_interrupt: bool) { + //NOTE(unsafe) We only access the registers that belongs to the ChannelX + let dmacr = &self.ch().cr(); + dmacr.modify(|_, w| w.htie().bit(half_transfer_interrupt)); + let _ = dmacr.read(); + let _ = dmacr.read(); // Delay 2 peripheral clocks + } +} diff --git a/src/dma/config.rs b/src/dma/config.rs index 21b3bd02..ebf790ff 100644 --- a/src/dma/config.rs +++ b/src/dma/config.rs @@ -1,9 +1,9 @@ use super::Bits; -/// Priority of the DMA stream, defaults to `Medium`. If two requests have -/// the same software priority level, the stream with the lower number takes -/// priority over the stream with the higher number. For example, Stream 2 -/// takes priority over Stream 4. +/// Priority of the DMA channel, defaults to `Medium`. If two requests have +/// the same software priority level, the channel with the lower number takes +/// priority over the channel with the higher number. For example, channel 2 +/// takes priority over channel 4. #[derive(Debug, Clone, Copy, Default)] pub enum Priority { /// Low priority. @@ -28,7 +28,7 @@ impl Bits for Priority { } } -/// Contains the complete set of configuration for a DMA stream. +/// Contains the complete set of configuration for a DMA channel. #[derive(Debug, Default, Clone, Copy)] pub struct DmaConfig { pub(crate) priority: Priority, diff --git a/src/dma/stream.rs b/src/dma/stream.rs deleted file mode 100644 index 18dc4085..00000000 --- a/src/dma/stream.rs +++ /dev/null @@ -1,622 +0,0 @@ -//! DMA - -use super::{ - config, - traits::sealed::{Bits, Sealed}, - traits::*, - DmaDirection, -}; -use core::marker::PhantomData; - -use crate::rcc::Rcc; -use crate::stm32; - -use stm32::{DMA1, DMA2, DMAMUX}; - -use crate::dma::config::DmaConfig; -use core::ops::Deref; - -impl Sealed for DMA1 {} -impl Sealed for DMA2 {} - -/// Type aliases for register blocks -pub type DMARegisterBlock = stm32::dma1::RegisterBlock; -pub type DMAMUXRegisterBlock = stm32::dmamux::RegisterBlock; - -/// Trait that represents an instance of a DMA peripheral -pub trait Instance: Deref + Sealed { - const IS_DMA1: bool; - - /// Gives a pointer to the RegisterBlock. - fn ptr() -> *const DMARegisterBlock; - - /// Gives a pointer to the DMAMUX used for this DMA. - fn mux_ptr() -> *const DMAMUXRegisterBlock; -} - -impl Instance for DMA1 { - const IS_DMA1: bool = true; - - #[inline(always)] - fn ptr() -> *const DMARegisterBlock { - DMA1::ptr() - } - - #[inline(always)] - fn mux_ptr() -> *const DMAMUXRegisterBlock { - DMAMUX::ptr() - } -} - -impl Instance for DMA2 { - const IS_DMA1: bool = false; - - #[inline(always)] - fn ptr() -> *const DMARegisterBlock { - DMA2::ptr() - } - - #[inline(always)] - fn mux_ptr() -> *const DMAMUXRegisterBlock { - DMAMUX::ptr() - } -} - -/// DMA interrupts -#[derive(Debug, Clone, Copy)] -pub struct DmaInterrupts { - transfer_complete: bool, - transfer_error: bool, - half_transfer: bool, -} - -/// Stream 0 on DMA -pub struct Stream0 { - _dma: PhantomData, -} -/// Stream 1 on DMA -pub struct Stream1 { - _dma: PhantomData, -} -/// Stream 2 on DMA -pub struct Stream2 { - _dma: PhantomData, -} -/// Stream 3 on DMA -pub struct Stream3 { - _dma: PhantomData, -} -/// Stream 4 on DMA -pub struct Stream4 { - _dma: PhantomData, -} -/// Stream 5 on DMA -pub struct Stream5 { - _dma: PhantomData, -} -/// Stream 6 on DMA -pub struct Stream6 { - _dma: PhantomData, -} -/// Stream 7 on DMA -pub struct Stream7 { - _dma: PhantomData, -} - -impl Sealed for Stream0 {} -impl Sealed for Stream1 {} -impl Sealed for Stream2 {} -impl Sealed for Stream3 {} -impl Sealed for Stream4 {} -impl Sealed for Stream5 {} -impl Sealed for Stream6 {} -impl Sealed for Stream7 {} - -/// Alias for a tuple with all DMA streams. -pub struct StreamsTuple( - pub Stream0, - pub Stream1, - pub Stream2, - pub Stream3, - pub Stream4, - pub Stream5, - #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))] pub Stream6, - #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))] pub Stream7, -); - -pub trait DMAExt { - fn split(self, rcc: &Rcc) -> StreamsTuple; -} - -impl DMAExt for DMA1 { - fn split(self, rcc: &Rcc) -> StreamsTuple { - // Enable DMAMux is not yet enabled - if !rcc.rb.ahb1enr.read().dmamuxen().bit_is_set() { - // Enable peripheral - rcc.rb.ahb1enr.modify(|_, w| w.dmamuxen().set_bit()); - } - - // Enable peripheral - rcc.rb.ahb1enr.modify(|_, w| w.dma1en().set_bit()); - - StreamsTuple::new(self) - } -} - -impl DMAExt for DMA2 { - fn split(self, rcc: &Rcc) -> StreamsTuple { - // Enable DMAMux is not yet enabled - if !rcc.rb.ahb1enr.read().dmamuxen().bit_is_set() { - // Enable peripheral - rcc.rb.ahb1enr.modify(|_, w| w.dmamuxen().set_bit()); - } - - // Enable peripheral - rcc.rb.ahb1enr.modify(|_, w| w.dma2en().set_bit()); - - StreamsTuple::new(self) - } -} - -impl StreamsTuple { - /// Splits the DMA peripheral into streams. - pub(crate) fn new(_regs: I) -> Self { - Self( - Stream0 { _dma: PhantomData }, - Stream1 { _dma: PhantomData }, - Stream2 { _dma: PhantomData }, - Stream3 { _dma: PhantomData }, - Stream4 { _dma: PhantomData }, - Stream5 { _dma: PhantomData }, - #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))] - Stream6 { _dma: PhantomData }, - #[cfg(not(any(feature = "stm32g431", feature = "stm32g441",)))] - Stream7 { _dma: PhantomData }, - ) - } -} - -// Macro that creates a struct representing a stream on either DMA controller -// -// The implementation does the heavy lifting of mapping to the right fields on -// the stream -macro_rules! dma_stream { - ($(($name:ident, $number:expr, - regs => $ccr:ident, $cparX:ident, $cmarX:ident, $cndtrX:ident, - fields => $tcif:ident, $htif:ident, $teif:ident, $gif:ident, $tcisr:ident, $htisr:ident, $teisr:ident, $gisr:ident, - dmamux => $dma1_cXcr:ident, $dma2_cXcr:ident, ) - ),+$(,)*) => { - $( - impl Stream for $name { - - const NUMBER: usize = $number; - type Config = DmaConfig; - type Interrupts = DmaInterrupts; - - fn apply_config(&mut self, config: DmaConfig) { - self.set_priority(config.priority); - self.set_memory_increment(config.memory_increment); - self.set_peripheral_increment(config.peripheral_increment); - self.set_circular_buffer(config.circular_buffer); - self.set_transfer_complete_interrupt_enable( - config.transfer_complete_interrupt - ); - self.set_half_transfer_interrupt_enable(config.half_transfer_interrupt); - self.set_transfer_error_interrupt_enable( - config.transfer_error_interrupt - ); - } - - #[inline(always)] - fn clear_interrupts(&mut self) { - //NOTE(unsafe) Atomic write with no side-effects and we only access the bits - // that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.ifcr.write(|w| w - .$tcif().set_bit() //Clear transfer complete interrupt flag - .$htif().set_bit() //Clear half transfer interrupt flag - .$teif().set_bit() //Clear transfer error interrupt flag - .$gif().set_bit() //Clear global interrupt flag - ); - let _ = dma.isr.read(); - let _ = dma.isr.read(); // Delay 2 peripheral clocks - } - - #[inline(always)] - fn clear_transfer_complete_flag(&mut self) { - //NOTE(unsafe) Atomic write with no side-effects and we only access the bits - // that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.ifcr.write(|w| w.$tcif().set_bit()); - } - - #[inline(always)] - fn clear_transfer_complete_interrupt(&mut self) { - self.clear_transfer_complete_flag(); - //NOTE(unsafe) Atomic read with no side-effects. - let dma = unsafe { &*I::ptr() }; - let _ = dma.isr.read(); - let _ = dma.isr.read(); // Delay 2 peripheral clocks - } - - #[inline(always)] - fn clear_transfer_error_interrupt(&mut self) { - //NOTE(unsafe) Atomic write with no side-effects and we only access the bits - // that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.ifcr.write(|w| w.$teif().set_bit()); - let _ = dma.isr.read(); - let _ = dma.isr.read(); // Delay 2 peripheral clocks - } - - #[inline(always)] - fn get_transfer_complete_flag() -> bool { - //NOTE(unsafe) Atomic read with no side effects - let dma = unsafe { &*I::ptr() }; - dma.isr.read().$tcisr().bit_is_set() - } - - #[inline(always)] - fn get_transfer_error_flag() -> bool { - //NOTE(unsafe) Atomic read with no side effects - let dma = unsafe { &*I::ptr() }; - dma.isr.read().$teisr().bit_is_set() - } - - #[inline(always)] - unsafe fn enable(&mut self) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = &*I::ptr(); - dma.$ccr.modify(|_, w| w.en().set_bit()); - } - - #[inline(always)] - fn is_enabled() -> bool { - //NOTE(unsafe) Atomic read with no side effects - let dma = unsafe { &*I::ptr() }; - dma.$ccr.read().en().bit_is_set() - } - - fn disable(&mut self) { - if Self::is_enabled() { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - - // Aborting an on-going transfer might cause interrupts to fire, disable - // them - let interrupts = Self::get_interrupts_enable(); - self.disable_interrupts(); - - dma.$ccr.modify(|_, w| w.en().clear_bit()); - while Self::is_enabled() {} - - self.clear_interrupts(); - self.enable_interrupts(interrupts); - } - } - - #[inline(always)] - fn set_request_line(&mut self, request_line: u8) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dmamux = unsafe { &*I::mux_ptr() }; - unsafe { - if I::IS_DMA1 { - dmamux.$dma1_cXcr - .modify(|_, w| w.dmareq_id().bits(request_line)); - } else { - dmamux.$dma2_cXcr - .modify(|_, w| w.dmareq_id().bits(request_line)); - }; - } - } - - #[inline(always)] - fn set_priority(&mut self, priority: config::Priority) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.$ccr.modify(|_, w| unsafe { w.pl().bits(priority.bits()) }); - } - - #[inline(always)] - fn disable_interrupts(&mut self) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dmacr = &unsafe { &*I::ptr() }.$ccr; - dmacr.modify(|_, w| w - .tcie().clear_bit() - .teie().clear_bit() - .htie().clear_bit()); - let _ = dmacr.read(); - let _ = dmacr.read(); // Delay 2 peripheral clocks - } - - #[inline(always)] - fn enable_interrupts(&mut self, interrupt: Self::Interrupts) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.$ccr.modify(|_, w| w - .tcie().bit(interrupt.transfer_complete) - .teie().bit(interrupt.transfer_error) - .htie().bit(interrupt.half_transfer) - ); - } - - #[inline(always)] - fn get_interrupts_enable() -> Self::Interrupts { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - let cr = dma.$ccr.read(); - - DmaInterrupts { - transfer_complete: cr.tcie().bit_is_set(), - half_transfer: cr.htie().bit_is_set(), - transfer_error: cr.teie().bit_is_set() - } - } - - - #[inline(always)] - fn set_transfer_complete_interrupt_enable(&mut self, transfer_complete_interrupt: bool) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dmacr = &unsafe { &*I::ptr() }.$ccr; - dmacr.modify(|_, w| w.tcie().bit(transfer_complete_interrupt)); - let _ = dmacr.read(); - let _ = dmacr.read(); // Delay 2 peripheral clocks - } - - #[inline(always)] - fn set_transfer_error_interrupt_enable(&mut self, transfer_error_interrupt: bool) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dmacr = &unsafe { &*I::ptr() }.$ccr; - dmacr.modify(|_, w| w.teie().bit(transfer_error_interrupt)); - let _ = dmacr.read(); - let _ = dmacr.read(); // Delay 2 peripheral clocks - } - - #[inline(always)] - fn set_half_transfer_interrupt_enable(&mut self, half_transfer_interrupt: bool) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dmacr = &unsafe { &*I::ptr() }.$ccr; - dmacr.modify(|_, w| w.htie().bit(half_transfer_interrupt)); - let _ = dmacr.read(); - let _ = dmacr.read(); // Delay 2 peripheral clocks - } - - #[inline(always)] - fn get_half_transfer_flag() -> bool { - //NOTE(unsafe) Atomic read with no side effects - let dma = unsafe { &*I::ptr() }; - dma.isr.read().$htisr().bit_is_set() - } - - #[inline(always)] - fn clear_half_transfer_interrupt(&mut self) { - //NOTE(unsafe) Atomic write with no side-effects and we only access the bits - // that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.ifcr.write(|w| w.$htif().set_bit()); - let _ = dma.isr.read(); - let _ = dma.isr.read(); // Delay 2 peripheral clocks - } - - #[inline(always)] - unsafe fn set_peripheral_address(&mut self, value: u32) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = &*I::ptr(); - dma.$cparX.write(|w| w.pa().bits(value)); - } - - #[inline(always)] - unsafe fn set_memory_address(&mut self, value: u32) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = &*I::ptr(); - dma.$cmarX.write(|w| w.ma().bits(value) ); - } - - #[inline(always)] - fn get_memory_address(&self) -> u32 { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.$cmarX.read().ma().bits() - } - - #[inline(always)] - fn set_number_of_transfers(&mut self, value: u16) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.$cndtrX.write(|w| unsafe {w.ndt().bits(value) }); - } - - #[inline(always)] - fn get_number_of_transfers() -> u16 { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.$cndtrX.read().ndt().bits() - } - #[inline(always)] - unsafe fn set_memory_size(&mut self, size: u8) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = &*I::ptr(); - dma.$ccr.modify(|_, w| w.msize().bits(size)); - } - - #[inline(always)] - unsafe fn set_peripheral_size(&mut self, size: u8) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = &*I::ptr(); - dma.$ccr.modify(|_, w| w.psize().bits(size)); - } - - #[inline(always)] - fn set_memory_increment(&mut self, increment: bool) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.$ccr.modify(|_, w| w.minc().bit(increment)); - } - - #[inline(always)] - fn set_peripheral_increment(&mut self, increment: bool) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.$ccr.modify(|_, w| w.pinc().bit(increment)); - } - - #[inline(always)] - fn set_direction(&mut self, direction: DmaDirection) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.$ccr.modify(|_, w| { - match direction { - DmaDirection::PeripheralToMemory => - w.dir().clear_bit().mem2mem().clear_bit(), - DmaDirection::MemoryToPeripheral => - w.dir().set_bit().mem2mem().clear_bit(), - DmaDirection::MemoryToMemory => - w.mem2mem().set_bit().dir().clear_bit(), - } - }); - } - - #[inline(always)] - fn set_circular_buffer(&mut self, circular_buffer: bool) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.$ccr.modify(|_, w| w.circ().bit(circular_buffer)); - } - } - - impl $name { - #[inline(always)] - pub fn clear_half_transfer_interrupt(&mut self) { - //NOTE(unsafe) Atomic write with no side-effects and we only access the bits - // that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - dma.ifcr.write(|w| w.$htif().set_bit()); - let _ = dma.isr.read(); - let _ = dma.isr.read(); // Delay 2 peripheral clocks - } - - #[inline(always)] - pub fn get_half_transfer_flag() -> bool { - //NOTE(unsafe) Atomic read with no side effects - let dma = unsafe { &*I::ptr() }; - dma.isr.read().$htisr().bit_is_set() - } - - #[inline(always)] - pub fn set_half_transfer_interrupt_enable(&mut self, half_transfer_interrupt: bool) { - //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dmacr = &unsafe { &*I::ptr() }.$ccr; - dmacr.modify(|_, w| w.htie().bit(half_transfer_interrupt)); - let _ = dmacr.read(); - let _ = dmacr.read(); // Delay 2 peripheral clocks - } - } - )+ - }; -} - -// Cat 3 and 4 devices -#[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484", - feature = "stm32g491", - feature = "stm32g4a1", -))] -dma_stream!( - // Note: the field names start from one, unlike the RM where they start from - // zero. May need updating if it gets fixed upstream. - ( - Stream0, 0, - regs => ccr1, cpar1, cmar1, cndtr1, - fields => tcif1, htif1, teif1, gif1, tcif1, htif1, teif1, gif1, - dmamux => c0cr, c8cr, - ), - ( - Stream1, 1, - regs => ccr2, cpar2, cmar2, cndtr2, - fields => tcif2, htif2, teif2, gif2, tcif2, htif2, teif2, gif2, - dmamux => c1cr, c9cr, - ), - ( - Stream2, 2, - regs => ccr3, cpar3, cmar3, cndtr3, - fields => tcif3, htif3, teif3, gif3, tcif3, htif3, teif3, gif3, - dmamux => c2cr, c10cr, - ), - ( - Stream3, 3, - regs => ccr4, cpar4, cmar4, cndtr4, - fields => tcif4, htif4, teif4, gif4, tcif4, htif4, teif4, gif4, - dmamux => c3cr, c11cr, - ), - ( - Stream4, 4, - regs => ccr5, cpar5, cmar5, cndtr5, - fields => tcif5, htif5, teif5, gif5, tcif5, htif5, teif5, gif5, - dmamux => c4cr, c12cr, - ), - ( - Stream5, 5, - regs => ccr6, cpar6, cmar6, cndtr6, - fields => tcif6, htif6, teif6, gif6, tcif6, htif6, teif6, gif6, - dmamux => c5cr, c13cr, - ), - ( - Stream6, 6, - regs => ccr7, cpar7, cmar7, cndtr7, - fields => tcif7, htif7, teif7, gif7, tcif7, htif7, teif7, gif7, - dmamux => c6cr, c14cr, - ), - ( - Stream7, 7, - regs => ccr8, cpar8, cmar8, cndtr8, - fields => tcif8, htif8, teif8, gif8, tcif8, htif8, teif8, gif8, - dmamux => c7cr, c15cr, - ), -); - -// Cat 2 devices -#[cfg(any(feature = "stm32g431", feature = "stm32g441",))] -dma_stream!( - // Note: the field names start from one, unlike the RM where they start from - // zero. May need updating if it gets fixed upstream. - ( - Stream0, 0, - regs => ccr1, cpar1, cmar1, cndtr1, - fields => tcif1, htif1, teif1, gif1, tcif1, htif1, teif1, gif1, - dmamux => c0cr, c6cr, - ), - ( - Stream1, 1, - regs => ccr2, cpar2, cmar2, cndtr2, - fields => tcif2, htif2, teif2, gif2, tcif2, htif2, teif2, gif2, - dmamux => c1cr, c7cr, - ), - ( - Stream2, 2, - regs => ccr3, cpar3, cmar3, cndtr3, - fields => tcif3, htif3, teif3, gif3, tcif3, htif3, teif3, gif3, - dmamux => c2cr, c8cr, - ), - ( - Stream3, 3, - regs => ccr4, cpar4, cmar4, cndtr4, - fields => tcif4, htif4, teif4, gif4, tcif4, htif4, teif4, gif4, - dmamux => c3cr, c9cr, - ), - ( - Stream4, 4, - regs => ccr5, cpar5, cmar5, cndtr5, - fields => tcif5, htif5, teif5, gif5, tcif5, htif5, teif5, gif5, - dmamux => c4cr, c10cr, - ), - ( - Stream5, 5, - regs => ccr6, cpar6, cmar6, cndtr6, - fields => tcif6, htif6, teif6, gif6, tcif6, htif6, teif6, gif6, - dmamux => c5cr, c11cr, - ), -); diff --git a/src/dma/traits.rs b/src/dma/traits.rs index 214cc17a..c72d6287 100644 --- a/src/dma/traits.rs +++ b/src/dma/traits.rs @@ -13,121 +13,116 @@ pub(crate) mod sealed { } pub trait Sealed {} } +use config::DmaConfig; use sealed::Sealed; -/// Minimal trait for DMA streams -pub trait Stream: Sealed { - /// Number of the stream register - const NUMBER: usize; - - /// Configuration structure for this stream. - type Config; - +/// Minimal trait for DMA channels +pub trait Channel: Sealed { /// Structure representing interrupts type Interrupts: Copy + Debug; - /// Apply the configation structure to this stream. - fn apply_config(&mut self, config: Self::Config); + /// Apply the configation structure to this channel. + fn apply_config(&mut self, config: DmaConfig); - /// Clear all interrupts for the DMA stream. + /// Clear all interrupts for the DMA channel. fn clear_interrupts(&mut self); - /// Clear transfer complete interrupt flag (tcif) for the DMA stream + /// Clear transfer complete interrupt flag (tcif) for the DMA channel /// but do not insert artificial delays. fn clear_transfer_complete_flag(&mut self); - /// Clear transfer complete interrupt (tcif) for the DMA stream and delay + /// Clear transfer complete interrupt (tcif) for the DMA channel and delay /// to ensure the change has settled through the bridge, peripheral, and /// synchronizers. fn clear_transfer_complete_interrupt(&mut self); - /// Clear transfer error interrupt (teif) for the DMA stream. + /// Clear transfer error interrupt (teif) for the DMA channel. fn clear_transfer_error_interrupt(&mut self); /// Get transfer complete flag. - fn get_transfer_complete_flag() -> bool; + fn get_transfer_complete_flag(&self) -> bool; /// Get transfer error flag. - fn get_transfer_error_flag() -> bool; + fn get_transfer_error_flag(&self) -> bool; - /// Enable the DMA stream. + /// Enable the DMA channel. /// /// # Safety /// /// The user must ensure that all registers are properly configured. unsafe fn enable(&mut self); - /// Returns the state of the DMA stream. - fn is_enabled() -> bool; + /// Returns the state of the DMA channel. + fn is_enabled(&self) -> bool; - /// Disable the DMA stream. + /// Disable the DMA channel. /// - /// Disabling the stream during an on-going transfer needs to be performed - /// in a certain way to prevent problems if the stream is to be re-enabled + /// Disabling the channel during an on-going transfer needs to be performed + /// in a certain way to prevent problems if the channel is to be re-enabled /// shortly after, because of that, this method will also clear all the - /// stream's interrupt flags if the stream is active. + /// channel's interrupt flags if the channel is active. fn disable(&mut self); - /// Sets the request or trigger line for this stream + /// Sets the request or trigger line for this channel fn set_request_line(&mut self, request_line: u8); - /// Set the priority the DMA stream. + /// Set the priority the DMA channel. fn set_priority(&mut self, priority: config::Priority); - /// Disable all interrupts for the DMA stream. + /// Disable all interrupts for the DMA channel. fn disable_interrupts(&mut self); - /// Configure interrupts for the DMA stream + /// Configure interrupts for the DMA channel fn enable_interrupts(&mut self, interrupts: Self::Interrupts); - /// Get the value of all the interrupts for this DMA stream - fn get_interrupts_enable() -> Self::Interrupts; + /// Get the value of all the interrupts for this DMA channel + fn get_interrupts_enable(&self) -> Self::Interrupts; - /// Enable/disable the transfer complete interrupt (tcie) of the DMA stream. + /// Enable/disable the transfer complete interrupt (tcie) of the DMA channel. fn set_transfer_complete_interrupt_enable(&mut self, transfer_complete_interrupt: bool); - /// Enable/disable the transfer error interrupt (teie) of the DMA stream. + /// Enable/disable the transfer error interrupt (teie) of the DMA channel. fn set_transfer_error_interrupt_enable(&mut self, transfer_error_interrupt: bool); - /// Set the peripheral address (par) for the DMA stream. + /// Set the peripheral address (par) for the DMA channel. /// /// # Safety /// /// Value should be a word aligned valid peripheral address unsafe fn set_peripheral_address(&mut self, value: u32); - /// Set the memory address (m0ar or m1ar) for the DMA stream. + /// Set the memory address (m0ar or m1ar) for the DMA channel. /// /// # Safety /// /// Value should be a word aligned valid memory address unsafe fn set_memory_address(&mut self, value: u32); - /// Enable/disable the half transfer interrupt (htie) of the DMA stream. + /// Enable/disable the half transfer interrupt (htie) of the DMA channel. fn set_half_transfer_interrupt_enable(&mut self, transfer_complete_interrupt: bool); - /// Clear half transfer interrupt (htif) for the DMA stream. + /// Clear half transfer interrupt (htif) for the DMA channel. fn clear_half_transfer_interrupt(&mut self); /// Get half transfer flag. - fn get_half_transfer_flag() -> bool; + fn get_half_transfer_flag(&self) -> bool; - /// Get the memory address for the DMA stream. + /// Get the memory address for the DMA channel. fn get_memory_address(&self) -> u32; - /// Enable/disable memory increment (minc) for the DMA stream. + /// Enable/disable memory increment (minc) for the DMA channel. fn set_memory_increment(&mut self, increment: bool); - /// Enable/disable peripheral increment (pinc) for the DMA stream. + /// Enable/disable peripheral increment (pinc) for the DMA channel. fn set_peripheral_increment(&mut self, increment: bool); - /// Set the number of transfers (ndt) for the DMA stream. + /// Set the number of transfers (ndt) for the DMA channel. fn set_number_of_transfers(&mut self, value: u16); - /// Get the number of transfers (ndt) for the DMA stream. - fn get_number_of_transfers() -> u16; + /// Get the number of transfers (ndt) for the DMA channel. + fn get_number_of_transfers(&self) -> u16; - /// Set the memory size (msize) for the DMA stream. + /// Set the memory size (msize) for the DMA channel. /// /// # Safety /// @@ -140,7 +135,7 @@ pub trait Stream: Sealed { /// * 3 -> double word unsafe fn set_memory_size(&mut self, size: u8); - /// Set the peripheral memory size (psize) for the DMA stream. + /// Set the peripheral memory size (psize) for the DMA channel. /// /// # Safety /// @@ -153,19 +148,13 @@ pub trait Stream: Sealed { /// * 2 -> word unsafe fn set_peripheral_size(&mut self, size: u8); - /// Set the direction (dir) of the DMA stream. + /// Set the direction (dir) of the DMA channel. fn set_direction(&mut self, direction: DmaDirection); - /// Enable/disable circular buffering for the DMA stream. + /// Enable/disable circular buffering for the DMA channel. fn set_circular_buffer(&mut self, circular_buffer: bool); } -/// Trait for Master DMA streams -/// -/// TODO -#[allow(unused)] -pub trait MasterStream: Stream + Sealed {} - /// DMA direction. pub trait Direction { /// Returns the `DmaDirection` of the type. @@ -189,7 +178,7 @@ pub unsafe trait TargetAddress { /// Memory size of the target address type MemSize; - /// The address to be used by the DMA stream + /// The address to be used by the DMA channel fn address(&self) -> u32; /// An optional associated request line diff --git a/src/dma/transfer.rs b/src/dma/transfer.rs index 2c0d2f3d..e5c6e708 100644 --- a/src/dma/transfer.rs +++ b/src/dma/transfer.rs @@ -1,6 +1,6 @@ use crate::dma::{ - traits, Direction, DmaDirection, MemoryToMemory, MemoryToPeripheral, PeripheralToMemory, - Stream, TargetAddress, + traits, Channel, Direction, DmaDirection, MemoryToMemory, MemoryToPeripheral, + PeripheralToMemory, TargetAddress, }; use core::{ marker::PhantomData, @@ -11,19 +11,21 @@ use core::{ }; use embedded_dma::{StaticReadBuffer, StaticWriteBuffer}; +use super::config::DmaConfig; + /// Marker type for a transfer with a mutable source and backed by a pub struct MutTransfer; /// Marker type for a transfer with a constant source and backed by a pub struct ConstTransfer; /// DMA Transfer. -pub struct Transfer +pub struct Transfer where - STREAM: Stream, + CHANNEL: Channel, PERIPHERAL: TargetAddress, DIR: Direction, { - stream: STREAM, + channel: CHANNEL, peripheral: PERIPHERAL, _direction: PhantomData, _transfer_type: PhantomData, @@ -33,10 +35,10 @@ where macro_rules! transfer_def { ($Marker:ty, $init:ident, $Buffer:tt, $rw_buffer:ident $(, $mut:tt)*; $($constraint:stmt)*) => { - impl - Transfer + impl + Transfer where - STREAM: Stream, + CHANNEL: Channel, DIR: Direction, PERIPHERAL: TargetAddress, BUF: $Buffer>::MemSize>, @@ -49,12 +51,12 @@ macro_rules! transfer_def { /// /// * When the transfer length is greater than (2^16 - 1) pub(crate) fn $init( - mut stream: STREAM, + mut channel: CHANNEL, peripheral: PERIPHERAL, $($mut)* memory: BUF, - config: CONFIG, + config: DmaConfig, ) -> Self { - stream.disable(); + channel.disable(); fence(Ordering::SeqCst); @@ -62,7 +64,7 @@ macro_rules! transfer_def { $($constraint)* // Set peripheral to memory mode - stream.set_direction(DIR::direction()); + channel.set_direction(DIR::direction()); // NOTE(unsafe) We now own this buffer and we won't call any &mut // methods on it until the end of the DMA transfer @@ -74,7 +76,7 @@ macro_rules! transfer_def { // // Must be a valid memory address unsafe { - stream.set_memory_address( + channel.set_memory_address( buf_ptr as u32, ); } @@ -85,7 +87,7 @@ macro_rules! transfer_def { // // Must be a valid peripheral address or source address unsafe { - stream.set_peripheral_address(peripheral.address()); + channel.set_peripheral_address(peripheral.address()); } assert!( @@ -93,15 +95,15 @@ macro_rules! transfer_def { "Hardware does not support more than 65535 transfers" ); let buf_len = buf_len as u16; - stream.set_number_of_transfers(buf_len); + channel.set_number_of_transfers(buf_len); // Set the DMAMUX request line if needed if let Some(request_line) = PERIPHERAL::REQUEST_LINE { - stream.set_request_line(request_line); + channel.set_request_line(request_line); } let mut transfer = Self { - stream, + channel, peripheral, _direction: PhantomData, _transfer_type: PhantomData, @@ -113,24 +115,24 @@ macro_rules! transfer_def { } /// Starts the transfer, the closure will be executed right after enabling - /// the stream. + /// the channel. #[inline(always)] pub fn restart(&mut self, f: F) where F: FnOnce(&mut PERIPHERAL), { - self.stream.disable(); + self.channel.disable(); fence(Ordering::SeqCst); let (_, buf_len) = unsafe { self.buf.$rw_buffer() }; - self.stream.set_number_of_transfers(buf_len as u16); + self.channel.set_number_of_transfers(buf_len as u16); f(&mut self.peripheral); // Preserve the instruction and bus ordering of preceding buffer access // to the subsequent access by the DMA peripheral due to enabling it. fence(Ordering::SeqCst); unsafe { - self.stream.enable(); + self.channel.enable(); } } } @@ -141,26 +143,26 @@ transfer_def!(MutTransfer, init, StaticWriteBuffer, write_buffer, mut;); transfer_def!(ConstTransfer, init_const, StaticReadBuffer, read_buffer; assert!(DIR::direction() != DmaDirection::PeripheralToMemory)); -impl Transfer +impl Transfer where - STREAM: Stream, + CHANNEL: Channel, DIR: Direction, PERIPHERAL: TargetAddress, { /// Applies all fields in DmaConfig. - fn apply_config(&mut self, config: CONFIG) { + fn apply_config(&mut self, config: DmaConfig) { let msize = mem::size_of::<>::MemSize>() / 2; - self.stream.clear_interrupts(); + self.channel.clear_interrupts(); // NOTE(unsafe) These values are correct because of the // invariants of TargetAddress unsafe { - self.stream.set_memory_size(msize as u8); - self.stream.set_peripheral_size(msize as u8); + self.channel.set_memory_size(msize as u8); + self.channel.set_peripheral_size(msize as u8); } - self.stream.apply_config(config); + self.channel.apply_config(config); } pub fn peek_buffer(&mut self, func: F) -> T @@ -168,7 +170,7 @@ where F: FnOnce(&BUF, usize) -> T, { // Single buffer mode - self.stream.disable(); + self.channel.disable(); // Protect the instruction sequence of preceding DMA disable/inactivity // verification/poisoning and subsequent (old completed) buffer content @@ -178,7 +180,7 @@ where fence(Ordering::SeqCst); // Check how many data in the transfer are remaining. - let remaining_data = STREAM::get_number_of_transfers(); + let remaining_data = self.channel.get_number_of_transfers(); let result = func(&self.buf, remaining_data as usize); @@ -190,13 +192,13 @@ where fence(Ordering::SeqCst); unsafe { - self.stream.enable(); + self.channel.enable(); } result } /// Starts the transfer, the closure will be executed right after enabling - /// the stream. + /// the channel. pub fn start(&mut self, f: F) where F: FnOnce(&mut PERIPHERAL), @@ -206,90 +208,90 @@ where fence(Ordering::SeqCst); unsafe { - self.stream.enable(); + self.channel.enable(); } f(&mut self.peripheral); } - /// Pauses the dma stream, the closure will be executed right before - /// disabling the stream. + /// Pauses the dma channel, the closure will be executed right before + /// disabling the channel. pub fn pause(&mut self, f: F) where F: FnOnce(&mut PERIPHERAL), { f(&mut self.peripheral); fence(Ordering::SeqCst); - self.stream.disable(); + self.channel.disable(); fence(Ordering::SeqCst); } - /// Stops the stream and returns the underlying resources. - pub fn free(mut self) -> (STREAM, PERIPHERAL, BUF) { - self.stream.disable(); + /// Stops the channel and returns the underlying resources. + pub fn free(mut self) -> (CHANNEL, PERIPHERAL, BUF) { + self.channel.disable(); // Protect the instruction and bus sequence of the preceding disable and // the subsequent buffer access. fence(Ordering::SeqCst); - self.stream.clear_interrupts(); + self.channel.clear_interrupts(); unsafe { - let stream = ptr::read(&self.stream); + let channel = ptr::read(&self.channel); let peripheral = ptr::read(&self.peripheral); let buf = ptr::read(&self.buf); mem::forget(self); - (stream, peripheral, buf) + (channel, peripheral, buf) } } - /// Clear all interrupts for the DMA stream. + /// Clear all interrupts for the DMA channel. #[inline(always)] pub fn clear_interrupts(&mut self) { - self.stream.clear_interrupts(); + self.channel.clear_interrupts(); } - /// Clear transfer complete interrupt (tcif) for the DMA stream. + /// Clear transfer complete interrupt (tcif) for the DMA channel. #[inline(always)] pub fn clear_transfer_complete_interrupt(&mut self) { - self.stream.clear_transfer_complete_interrupt(); + self.channel.clear_transfer_complete_interrupt(); } - /// Clear transfer error interrupt (teif) for the DMA stream. + /// Clear transfer error interrupt (teif) for the DMA channel. #[inline(always)] pub fn clear_transfer_error_interrupt(&mut self) { - self.stream.clear_transfer_error_interrupt(); + self.channel.clear_transfer_error_interrupt(); } #[inline(always)] pub fn get_transfer_complete_flag(&self) -> bool { - STREAM::get_transfer_complete_flag() + self.channel.get_transfer_complete_flag() } #[inline(always)] pub fn get_transfer_error_flag(&self) -> bool { - STREAM::get_transfer_error_flag() + self.channel.get_transfer_error_flag() } - /// Clear half transfer interrupt (htif) for the DMA stream. + /// Clear half transfer interrupt (htif) for the DMA channel. #[inline(always)] pub fn clear_half_transfer_interrupt(&mut self) { - self.stream.clear_half_transfer_interrupt(); + self.channel.clear_half_transfer_interrupt(); } #[inline(always)] pub fn get_half_transfer_flag(&self) -> bool { - STREAM::get_half_transfer_flag() + self.channel.get_half_transfer_flag() } } -impl Drop for Transfer +impl Drop for Transfer where - STREAM: Stream, + CHANNEL: Channel, PERIPHERAL: TargetAddress, DIR: Direction, { fn drop(&mut self) { - self.stream.disable(); + self.channel.disable(); // Protect the instruction and bus sequence of the preceding disable and // the subsequent buffer access. @@ -298,18 +300,18 @@ where } /// Circular DMA Transfer. -pub struct CircTransfer +pub struct CircTransfer where - STREAM: Stream, + CHANNEL: Channel, PERIPHERAL: TargetAddress, { - transfer: Transfer, + transfer: Transfer, r_pos: usize, } -impl CircTransfer +impl CircTransfer where - STREAM: Stream, + CHANNEL: Channel, BUF: StaticWriteBuffer + Deref, ::Target: Index, Output = [>::MemSize]>, @@ -319,7 +321,7 @@ where /// Return the number of elements available to read pub fn elements_available(&mut self) -> usize { let blen = unsafe { self.transfer.buf.static_write_buffer().1 }; - let ndtr = STREAM::get_number_of_transfers() as usize; + let ndtr = self.transfer.channel.get_number_of_transfers() as usize; let pos_at = self.r_pos; // the position the DMA would write to next @@ -397,7 +399,7 @@ where } /// Starts the transfer, the closure will be executed right after enabling - /// the stream. + /// the channel. pub fn start(&mut self, f: F) where F: FnOnce(&mut PERIPHERAL), @@ -405,8 +407,8 @@ where self.transfer.start(f) } - /// Pauses the dma stream, the closure will be executed right before - /// disabling the stream. + /// Pauses the dma channel, the closure will be executed right before + /// disabling the channel. pub fn pause(&mut self, f: F) where F: FnOnce(&mut PERIPHERAL), @@ -414,24 +416,24 @@ where self.transfer.pause(f) } - /// Stops the stream and returns the underlying resources. - pub fn free(self) -> (STREAM, PERIPHERAL, BUF) { + /// Stops the channel and returns the underlying resources. + pub fn free(self) -> (CHANNEL, PERIPHERAL, BUF) { self.transfer.free() } - /// Clear all interrupts for the DMA stream. + /// Clear all interrupts for the DMA channel. #[inline(always)] pub fn clear_interrupts(&mut self) { self.transfer.clear_interrupts(); } - /// Clear transfer complete interrupt (tcif) for the DMA stream. + /// Clear transfer complete interrupt (tcif) for the DMA channel. #[inline(always)] pub fn clear_transfer_complete_interrupt(&mut self) { self.transfer.clear_transfer_complete_interrupt(); } - /// Clear transfer error interrupt (teif) for the DMA stream. + /// Clear transfer error interrupt (teif) for the DMA channel. #[inline(always)] pub fn clear_transfer_error_interrupt(&mut self) { self.transfer.clear_transfer_error_interrupt(); @@ -447,7 +449,7 @@ where self.transfer.get_transfer_error_flag() } - /// Clear half transfer interrupt (htif) for the DMA stream. + /// Clear half transfer interrupt (htif) for the DMA channel. #[inline(always)] pub fn clear_half_transfer_interrupt(&mut self) { self.transfer.clear_half_transfer_interrupt(); @@ -461,9 +463,9 @@ where macro_rules! impl_adc_overrun { ($($adc:ident, )*) => {$( - impl CircTransfer, BUF> + impl CircTransfer, BUF> where - STREAM: Stream, + CHANNEL: Channel, BUF: StaticWriteBuffer + Deref, ::Target: Index, Output = [u16]> { /// This is set when the AD finishes a conversion before the DMA has hade time to transfer the previous value @@ -512,9 +514,9 @@ impl_adc_overrun!(ADC4, ADC5,); macro_rules! impl_serial_timeout { ($($uart:ident, )*) => {$( - impl CircTransfer, BUF> + impl CircTransfer, BUF> where - STREAM: Stream, + CHANNEL: Channel, /*BUF: StaticWriteBuffer + Deref*/ { pub fn timeout_lapsed(&self) -> bool { self.transfer.peripheral.timeout_lapsed() @@ -531,16 +533,16 @@ impl_serial_timeout!(USART1, USART2, USART3, UART4,); #[cfg(not(any(feature = "stm32g431", feature = "stm32g441")))] impl_serial_timeout!(UART5,); -pub trait TransferExt +pub trait TransferExt where - STREAM: traits::Stream, + CHANNEL: traits::Channel, { fn into_memory_to_memory_transfer( self, per: PERIPHERAL, buf: BUF, - config: ::Config, - ) -> Transfer, BUF, MutTransfer> + config: DmaConfig, + ) -> Transfer, BUF, MutTransfer> where T: Into, PERIPHERAL: TargetAddress>, @@ -549,8 +551,8 @@ where self, per: PERIPHERAL, buf: BUF, - config: ::Config, - ) -> Transfer + config: DmaConfig, + ) -> Transfer where PERIPHERAL: TargetAddress, BUF: StaticWriteBuffer>::MemSize>; @@ -558,8 +560,8 @@ where self, per: PERIPHERAL, buf: BUF, - config: ::Config, - ) -> Transfer + config: DmaConfig, + ) -> Transfer where PERIPHERAL: TargetAddress, BUF: StaticReadBuffer>::MemSize>; @@ -567,8 +569,8 @@ where self, src: PSRC, dst: PDST, - config: ::Config, - ) -> Transfer + config: DmaConfig, + ) -> Transfer where PSRC: TargetAddress, PDST: TargetAddress, @@ -579,8 +581,8 @@ where self, per: PERIPHERAL, buf: BUF, - config: ::Config, - ) -> CircTransfer + config: DmaConfig, + ) -> CircTransfer where PERIPHERAL: TargetAddress, >::MemSize: Copy, @@ -592,126 +594,87 @@ where >; } -macro_rules! transfer_constructor { - ($(($DMA:ident, $STREAM:ident),)+) => { - $( - impl TransferExt for crate::dma::stream::$STREAM - where - crate::stm32::$DMA: crate::dma::stream::Instance, - Self: traits::Stream, - { - fn into_memory_to_memory_transfer( - self, - per: PERIPHERAL, - buf: BUF, - mut config: ::Config, - ) -> Transfer, BUF, MutTransfer> - where - T: Into, - PERIPHERAL: TargetAddress>, - BUF: StaticWriteBuffer< - Word = >>::MemSize, - >, - { - config.circular_buffer = false; - Transfer::init(self, per, buf, config) - } - fn into_peripheral_to_memory_transfer( - self, - per: PERIPHERAL, - buf: BUF, - config: ::Config, - ) -> Transfer - where - PERIPHERAL: TargetAddress, - BUF: StaticWriteBuffer< - Word = >::MemSize, - >, - { - Transfer::init(self, per, buf, config) - } - fn into_memory_to_peripheral_transfer( - self, - per: PERIPHERAL, - buf: BUF, - config: ::Config, - ) -> Transfer - where - PERIPHERAL: TargetAddress, - BUF: StaticReadBuffer< - Word = >::MemSize, - >, - { - Transfer::init_const(self, per, buf, config) - } - fn into_peripheral_to_peripheral_transfer( - self, - src: PSRC, - dst: PDST, - config: ::Config, - ) -> Transfer - where - PSRC: TargetAddress, - PDST: TargetAddress, - [>::MemSize; 1]: embedded_dma::WriteTarget, - &'static mut [>::MemSize; 1]: - StaticWriteBuffer>::MemSize> { - let data_addr: u32 = dst.address(); - let ptr: &mut PDST::MemSize = unsafe { &mut *(data_addr as *mut _) }; - //TODO: check that this is correct; nightly has core::array::from_mut... - let dst: &mut [PDST::MemSize; 1] = core::array::from_mut(ptr); - Transfer::init(self, src, dst, config) - } - fn into_circ_peripheral_to_memory_transfer( - self, - per: PERIPHERAL, - buf: BUF, - config: ::Config, - ) -> CircTransfer - where PERIPHERAL: TargetAddress, - >::MemSize: Copy, - BUF: StaticWriteBuffer>::MemSize>, - BUF: Deref, - ::Target: Index< Range, - Output = [>::MemSize], > { - CircTransfer { - transfer: Transfer::init(self, per, buf, config), - r_pos: 0, - } - } +impl TransferExt for crate::dma::channel::C +where + DMA: crate::dma::channel::Instance, + Self: traits::Channel, +{ + fn into_memory_to_memory_transfer( + self, + per: PERIPHERAL, + buf: BUF, + mut config: DmaConfig, + ) -> Transfer, BUF, MutTransfer> + where + T: Into, + PERIPHERAL: TargetAddress>, + BUF: StaticWriteBuffer>>::MemSize>, + { + config.circular_buffer = false; + Transfer::init(self, per, buf, config) + } + fn into_peripheral_to_memory_transfer( + self, + per: PERIPHERAL, + buf: BUF, + config: DmaConfig, + ) -> Transfer + where + PERIPHERAL: TargetAddress, + BUF: StaticWriteBuffer>::MemSize>, + { + Transfer::init(self, per, buf, config) + } + fn into_memory_to_peripheral_transfer( + self, + per: PERIPHERAL, + buf: BUF, + config: DmaConfig, + ) -> Transfer + where + PERIPHERAL: TargetAddress, + BUF: StaticReadBuffer>::MemSize>, + { + Transfer::init_const(self, per, buf, config) + } + fn into_peripheral_to_peripheral_transfer( + self, + src: PSRC, + dst: PDST, + config: DmaConfig, + ) -> Transfer + where + PSRC: TargetAddress, + PDST: TargetAddress, + [>::MemSize; 1]: embedded_dma::WriteTarget, + &'static mut [>::MemSize; 1]: + StaticWriteBuffer>::MemSize>, + { + let data_addr: u32 = dst.address(); + let ptr: &mut PDST::MemSize = unsafe { &mut *(data_addr as *mut _) }; + //TODO: check that this is correct; nightly has core::array::from_mut... + let dst: &mut [PDST::MemSize; 1] = core::array::from_mut(ptr); + Transfer::init(self, src, dst, config) + } + fn into_circ_peripheral_to_memory_transfer( + self, + per: PERIPHERAL, + buf: BUF, + config: DmaConfig, + ) -> CircTransfer + where + PERIPHERAL: TargetAddress, + >::MemSize: Copy, + BUF: StaticWriteBuffer>::MemSize>, + BUF: Deref, + ::Target: Index< + Range, + Output = [>::MemSize], + >, + { + CircTransfer { + transfer: Transfer::init(self, per, buf, config), + r_pos: 0, } - )+ - }; + } } - -transfer_constructor!( - (DMA1, Stream0), - (DMA1, Stream1), - (DMA1, Stream2), - (DMA1, Stream3), - (DMA1, Stream4), - (DMA1, Stream5), - (DMA2, Stream0), - (DMA2, Stream1), - (DMA2, Stream2), - (DMA2, Stream3), - (DMA2, Stream4), - (DMA2, Stream5), -); - -// Cat 3 and 4 devices -#[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484", - feature = "stm32g491", - feature = "stm32g4a1", -))] -transfer_constructor!( - (DMA1, Stream6), - (DMA1, Stream7), - (DMA2, Stream6), - (DMA2, Stream7), -); diff --git a/src/exti.rs b/src/exti.rs index bbdaffb7..83abc5af 100644 --- a/src/exti.rs +++ b/src/exti.rs @@ -88,14 +88,18 @@ impl ExtiExt for EXTI { let mask = 1 << line; match edge { SignalEdge::Rising => { - self.rtsr1.modify(|r, w| unsafe { w.bits(r.bits() | mask) }); + self.rtsr1() + .modify(|r, w| unsafe { w.bits(r.bits() | mask) }); } SignalEdge::Falling => { - self.ftsr1.modify(|r, w| unsafe { w.bits(r.bits() | mask) }); + self.ftsr1() + .modify(|r, w| unsafe { w.bits(r.bits() | mask) }); } SignalEdge::RisingFalling => { - self.rtsr1.modify(|r, w| unsafe { w.bits(r.bits() | mask) }); - self.ftsr1.modify(|r, w| unsafe { w.bits(r.bits() | mask) }); + self.rtsr1() + .modify(|r, w| unsafe { w.bits(r.bits() | mask) }); + self.ftsr1() + .modify(|r, w| unsafe { w.bits(r.bits() | mask) }); } } self.wakeup(ev); @@ -104,12 +108,12 @@ impl ExtiExt for EXTI { fn wakeup(&self, ev: Event) { match ev as u8 { line if line < 32 => self - .imr1 + .imr1() .modify(|r, w| unsafe { w.bits(r.bits() | 1 << line) }), line => self - .imr2 + .imr2() .modify(|r, w| unsafe { w.bits(r.bits() | 1 << (line - 32)) }), - } + }; } fn unlisten(&self, ev: Event) { @@ -117,15 +121,19 @@ impl ExtiExt for EXTI { match ev as u8 { line if line < 32 => { let mask = !(1 << line); - self.imr1.modify(|r, w| unsafe { w.bits(r.bits() & mask) }); + self.imr1() + .modify(|r, w| unsafe { w.bits(r.bits() & mask) }); if line <= 18 { - self.rtsr1.modify(|r, w| unsafe { w.bits(r.bits() & mask) }); - self.ftsr1.modify(|r, w| unsafe { w.bits(r.bits() & mask) }); + self.rtsr1() + .modify(|r, w| unsafe { w.bits(r.bits() & mask) }); + self.ftsr1() + .modify(|r, w| unsafe { w.bits(r.bits() & mask) }); } } line => { let mask = !(1 << (line - 32)); - self.imr2.modify(|r, w| unsafe { w.bits(r.bits() & mask) }) + self.imr2() + .modify(|r, w| unsafe { w.bits(r.bits() & mask) }); } } } @@ -136,13 +144,13 @@ impl ExtiExt for EXTI { return false; } let mask = 1 << line; - self.pr1.read().bits() & mask != 0 + self.pr1().read().bits() & mask != 0 } fn unpend(&self, ev: Event) { let line = ev as u8; if line <= 18 { - self.pr1.modify(|_, w| unsafe { w.bits(1 << line) }); + self.pr1().modify(|_, w| unsafe { w.bits(1 << line) }); } } } diff --git a/src/fdcan.rs b/src/fdcan.rs new file mode 100644 index 00000000..997e11b9 --- /dev/null +++ b/src/fdcan.rs @@ -0,0 +1,1784 @@ +#![deny(missing_docs)] + +//! FdCAN Operations + +/// Configuration of an FdCAN instance +pub mod config; +/// Filtering of CAN Messages +pub mod filter; +/// Header and info of transmitted and receiving frames +pub mod frame; +/// Standard and Extended Id +pub mod id; +/// Interrupt Line Information +pub mod interrupt; +mod message_ram; + +use id::{Id, IdReg}; + +use crate::rcc::Rcc; +use crate::stm32::fdcan::RegisterBlock; +use config::{ + ClockDivider, DataBitTiming, FdCanConfig, FrameTransmissionConfig, GlobalFilter, + NominalBitTiming, TimestampSource, +}; +use filter::{ + ActivateFilter as _, ExtendedFilter, ExtendedFilterSlot, StandardFilter, StandardFilterSlot, + EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX, +}; +use frame::MergeTxFrameHeader; +use frame::{RxFrameInfo, TxFrameHeader}; +use interrupt::{Interrupt, InterruptLine, Interrupts}; + +use message_ram::MsgRamExt; +use message_ram::RxFifoElement; + +use core::cmp::Ord; +use core::convert::Infallible; +use core::convert::TryFrom; +use core::marker::PhantomData; +use core::ptr::NonNull; + +mod sealed { + /// A TX pin configured for CAN communication + pub trait Tx {} + /// An RX pin configured for CAN communication + pub trait Rx {} +} + +/// An FdCAN peripheral instance. +/// +/// This trait is meant to be implemented for a HAL-specific type that represent ownership of +/// the CAN peripheral (and any pins required by it, although that is entirely up to the HAL). +/// +/// # Safety +/// +/// It is only safe to implement this trait, when: +/// +/// * The implementing type has ownership of the peripheral, preventing any other accesses to the +/// register block. +/// * `REGISTERS` is a pointer to that peripheral's register block and can be safely accessed for as +/// long as ownership or a borrow of the implementing type is present. +pub unsafe trait Instance: MsgRamExt + crate::rcc::Instance { + /// Pointer to the instance's register block. + const REGISTERS: *mut RegisterBlock; +} + +/// Indicates if an Receive Overflow has occurred +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub enum ReceiveErrorOverflow { + /// No overflow has occurred + Normal(u8), + /// An overflow has occurred + Overflow(u8), +} + +///Error Counters +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +#[allow(dead_code)] +pub struct ErrorCounters { + /// General CAN error counter + can_errors: u8, + /// Receive CAN error counter + receive_err: ReceiveErrorOverflow, + /// Transmit CAN error counter + transmit_err: u8, +} + +/// Loopback Mode +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +enum LoopbackMode { + None, + Internal, + External, +} + +/// Bus Activity +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub enum Activity { + /// Node is Synchronizing + Synchronizing = 0b00, + /// Node is Idle + Idle = 0b01, + /// Node is receiver only + Receiver = 0b10, + /// Node is transmitter only + Transmitter = 0b11, +} +impl TryFrom for Activity { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 0b000 => Ok(Self::Synchronizing), + 0b001 => Ok(Self::Idle), + 0b010 => Ok(Self::Receiver), + 0b011 => Ok(Self::Transmitter), + _ => Err(()), + } + } +} + +/// Indicates the type of the last error which occurred on the CAN bus +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub enum LastErrorCode { + /// There has been no error since last read + NoError = 0b000, + /// More than 5 equal bits in sequence are not allowed + StuffError = 0b001, + /// a fixed format part of ta received frame had the wrong format + FormError = 0b010, + /// message tramsitted by this node was not acknowledged by another + AckError = 0b011, + /// During transmit, the node wanted to send a 1 but monitored a 0 + Bit1Error = 0b100, + /// During transmit, the node wanted to send a 0 but monitored a 1 + Bit0Error = 0b101, + /// CRC checksum of a received message was incorrect + CRCError = 0b110, + /// No CAN bus event detected since last read + NoChange = 0b111, +} +impl TryFrom for LastErrorCode { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 0b000 => Ok(Self::NoError), + 0b001 => Ok(Self::StuffError), + 0b010 => Ok(Self::FormError), + 0b011 => Ok(Self::AckError), + 0b100 => Ok(Self::Bit1Error), + 0b101 => Ok(Self::Bit0Error), + 0b110 => Ok(Self::CRCError), + 0b111 => Ok(Self::NoChange), + _ => Err(()), + } + } +} + +/// Some status indications regarding the FDCAN protocl +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub struct ProtocolStatus { + /// Type of current activity + activity: Activity, + /// Transmitter delay companstation + transmitter_delay_comp: u8, + /// But Off Status + bus_off_status: bool, + /// Shows if Error counters are aat their limit of 96 + error_warning: bool, + /// Shows if the node send and active error flag (false) or stays silent (true). + error_passive_state: bool, + /// Indicates te last type of error which occurred on the CAN bus. + last_error: LastErrorCode, +} + +/// Allows for Transmit Operations +pub trait Transmit {} +/// Allows for Receive Operations +pub trait Receive {} + +/// Allows for the FdCan Instance to be released or to enter ConfigMode +pub struct PoweredDownMode; +/// Allows for the configuration for the Instance +pub struct ConfigMode; +/// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without +/// affecting a running CAN system connected to the FDCAN_TX and FDCAN_RX pins. In this +/// mode, FDCAN_RX pin is disconnected from the FDCAN and FDCAN_TX pin is held +/// recessive. +pub struct InternalLoopbackMode; +impl Transmit for InternalLoopbackMode {} +impl Receive for InternalLoopbackMode {} +/// This mode is provided for hardware self-test. To be independent from external stimulation, +/// the FDCAN ignores acknowledge errors (recessive bit sampled in the acknowledge slot of a +/// data / remote frame) in Loop Back mode. In this mode the FDCAN performs an internal +/// feedback from its transmit output to its receive input. The actual value of the FDCAN_RX +/// input pin is disregarded by the FDCAN. The transmitted messages can be monitored at the +/// FDCAN_TX transmit pin. +pub struct ExternalLoopbackMode; +impl Transmit for ExternalLoopbackMode {} +impl Receive for ExternalLoopbackMode {} +/// The normal use of the FdCan instance after configurations +pub struct NormalOperationMode; +impl Transmit for NormalOperationMode {} +impl Receive for NormalOperationMode {} +/// In Restricted operation mode the node is able to receive data and remote frames and to give +/// acknowledge to valid frames, but it does not send data frames, remote frames, active error +/// frames, or overload frames. In case of an error condition or overload condition, it does not +/// send dominant bits, instead it waits for the occurrence of bus idle condition to resynchronize +/// itself to the CAN communication. The error counters for transmit and receive are frozen while +/// error logging (can_errors) is active. TODO: automatically enter in this mode? +pub struct RestrictedOperationMode; +impl Receive for RestrictedOperationMode {} +/// In Bus monitoring mode (for more details refer to ISO11898-1, 10.12 Bus monitoring), +/// the FDCAN is able to receive valid data frames and valid remote frames, but cannot start a +/// transmission. In this mode, it sends only recessive bits on the CAN bus. If the FDCAN is +/// required to send a dominant bit (ACK bit, overload flag, active error flag), the bit is +/// rerouted internally so that the FDCAN can monitor it, even if the CAN bus remains in recessive +/// state. In Bus monitoring mode the TXBRP register is held in reset state. The Bus monitoring +/// mode can be used to analyze the traffic on a CAN bus without affecting it by the transmission +/// of dominant bits. +pub struct BusMonitoringMode; +impl Receive for BusMonitoringMode {} +/// Test mode must be used for production tests or self test only. The software control for +/// FDCAN_TX pin interferes with all CAN protocol functions. It is not recommended to use test +/// modes for application. +pub struct TestMode; + +/// Interface to a FdCAN peripheral. +pub struct FdCan { + control: FdCanControl, +} + +impl FdCan +where + I: Instance, +{ + fn create_can(config: FdCanConfig, instance: I) -> FdCan { + FdCan { + control: FdCanControl { + config, + instance, + _mode: core::marker::PhantomData, + }, + } + } + + fn into_can_mode(self) -> FdCan { + FdCan { + control: FdCanControl { + config: self.control.config, + instance: self.control.instance, + _mode: core::marker::PhantomData, + }, + } + } + + /// Returns a reference to the peripheral instance. + /// + /// This allows accessing HAL-specific data stored in the instance type. + #[inline] + pub fn instance(&mut self) -> &mut I { + &mut self.control.instance + } + + #[inline] + fn registers(&self) -> &RegisterBlock { + unsafe { &*I::REGISTERS } + } + + #[inline] + fn msg_ram_mut(&mut self) -> &mut message_ram::RegisterBlock { + self.instance().msg_ram_mut() + } + + #[inline] + fn reset_msg_ram(&mut self) { + self.msg_ram_mut().reset(); + } + + #[inline] + fn enter_init_mode(&mut self) { + let can = self.registers(); + + can.cccr().modify(|_, w| w.init().set_bit()); + while can.cccr().read().init().bit_is_clear() {} + can.cccr().modify(|_, w| w.cce().set_bit()); + } + + /// Returns the current FDCAN config settings + #[inline] + pub fn get_config(&self) -> FdCanConfig { + self.control.config + } + + /// Enables or disables loopback mode: Internally connects the TX and RX + /// signals together. + #[inline] + fn set_loopback_mode(&mut self, mode: LoopbackMode) { + let (test, mon, lbck) = match mode { + LoopbackMode::None => (false, false, false), + LoopbackMode::Internal => (true, true, true), + LoopbackMode::External => (true, false, true), + }; + + self.set_test_mode(test); + self.set_bus_monitoring_mode(mon); + + let can = self.registers(); + can.test().modify(|_, w| w.lbck().bit(lbck)); + } + + /// Enables or disables silent mode: Disconnects the TX signal from the pin. + #[inline] + fn set_bus_monitoring_mode(&mut self, enabled: bool) { + let can = self.registers(); + can.cccr().modify(|_, w| w.mon().bit(enabled)); + } + + #[inline] + fn set_restricted_operations(&mut self, enabled: bool) { + let can = self.registers(); + can.cccr().modify(|_, w| w.asm().bit(enabled)); + } + + #[inline] + fn set_normal_operations(&mut self, _enabled: bool) { + self.set_loopback_mode(LoopbackMode::None); + } + + #[inline] + fn set_test_mode(&mut self, enabled: bool) { + let can = self.registers(); + can.cccr().modify(|_, w| w.test().bit(enabled)); + } + + #[inline] + fn set_power_down_mode(&mut self, enabled: bool) { + let can = self.registers(); + can.cccr().modify(|_, w| w.csr().bit(enabled)); + while can.cccr().read().csa().bit() != enabled {} + } + + /// Enable/Disable the specific Interrupt Line + #[inline] + pub fn enable_interrupt_line(&mut self, line: InterruptLine, enabled: bool) { + let can = self.registers(); + match line { + InterruptLine::_0 => can.ile().modify(|_, w| w.eint1().bit(enabled)), + InterruptLine::_1 => can.ile().modify(|_, w| w.eint0().bit(enabled)), + } + } + + /// Starts listening for a CAN interrupt. + #[inline] + pub fn enable_interrupt(&mut self, interrupt: Interrupt) { + self.enable_interrupts(Interrupts::from_bits_truncate(interrupt as u32)) + } + + /// Starts listening for a set of CAN interrupts. + #[inline] + pub fn enable_interrupts(&mut self, interrupts: Interrupts) { + self.registers() + .ie + .modify(|r, w| unsafe { w.bits(r.bits() | interrupts.bits()) }) + } + + /// Stops listening for a CAN interrupt. + pub fn disable_interrupt(&mut self, interrupt: Interrupt) { + self.disable_interrupts(Interrupts::from_bits_truncate(interrupt as u32)) + } + + /// Stops listening for a set of CAN interrupts. + #[inline] + pub fn disable_interrupts(&mut self, interrupts: Interrupts) { + self.registers() + .ie + .modify(|r, w| unsafe { w.bits(r.bits() & !interrupts.bits()) }) + } + + /// Retrieve the CAN error counters + #[inline] + pub fn error_counters(&self) -> ErrorCounters { + self.control.error_counters() + } + + /// Set an Standard Address CAN filter into slot 'id' + #[inline] + pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) { + self.msg_ram_mut().filters.flssa[slot as usize].activate(filter); + } + + /// Set an array of Standard Address CAN filters and overwrite the current set + pub fn set_standard_filters( + &mut self, + filters: &[StandardFilter; STANDARD_FILTER_MAX as usize], + ) { + for (i, f) in filters.iter().enumerate() { + self.msg_ram_mut().filters.flssa[i].activate(*f); + } + } + + /// Set an Extended Address CAN filter into slot 'id' + #[inline] + pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) { + self.msg_ram_mut().filters.flesa[slot as usize].activate(filter); + } + + /// Set an array of Extended Address CAN filters and overwrite the current set + pub fn set_extended_filters( + &mut self, + filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize], + ) { + for (i, f) in filters.iter().enumerate() { + self.msg_ram_mut().filters.flesa[i].activate(*f); + } + } + + /// Retrieve the current protocol status + pub fn get_protocol_status(&self) -> ProtocolStatus { + let psr = self.registers().psr().read(); + ProtocolStatus { + activity: Activity::try_from(0 /*psr.act().bits()*/).unwrap(), //TODO: stm32g4 does not allow reading from this register + transmitter_delay_comp: psr.tdcv().bits(), + bus_off_status: psr.bo().bit_is_set(), + error_warning: psr.ew().bit_is_set(), + error_passive_state: psr.ep().bit_is_set(), + last_error: LastErrorCode::try_from(psr.lec().bits()).unwrap(), + } + } + + /// Check if the interrupt is triggered + #[inline] + pub fn has_interrupt(&mut self, interrupt: Interrupt) -> bool { + self.control.has_interrupt(interrupt) + } + + /// Clear specified interrupt + #[inline] + pub fn clear_interrupt(&mut self, interrupt: Interrupt) { + self.control.clear_interrupt(interrupt) + } + + /// Clear specified interrupts + #[inline] + pub fn clear_interrupts(&mut self, interrupts: Interrupts) { + self.control.clear_interrupts(interrupts) + } + + /// Splits this `FdCan` instance into transmitting and receiving halves, by reference. + #[inline] + #[allow(clippy::type_complexity)] + fn split_by_ref_generic( + &mut self, + ) -> ( + &mut FdCanControl, + &mut Tx, + &mut Rx, + &mut Rx, + ) { + // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. + let tx = unsafe { Tx::conjure_by_ref() }; + let rx0 = unsafe { Rx::conjure_by_ref() }; + let rx1 = unsafe { Rx::conjure_by_ref() }; + (&mut self.control, tx, rx0, rx1) + } + + /// Consumes this `FdCan` instance and splits it into transmitting and receiving halves. + #[inline] + #[allow(clippy::type_complexity)] + fn split_generic( + self, + ) -> ( + FdCanControl, + Tx, + Rx, + Rx, + ) { + // Safety: We must be carefull to not let them use each others registers + unsafe { (self.control, Tx::conjure(), Rx::conjure(), Rx::conjure()) } + } + + /// Combines an FdCanControl, Tx and the two Rx instances back into an FdCan instance + #[inline] + #[allow(clippy::type_complexity)] + pub fn combine( + t: ( + FdCanControl, + Tx, + Rx, + Rx, + ), + ) -> Self { + Self::create_can(t.0.config, t.0.instance) + } +} + +/// Select an FDCAN Clock Source +pub enum FdCanClockSource { + /// Select HSE as the FDCAN clock source + HSE = 0b00, + /// Select PLL "Q" clock as the FDCAN clock source + PLLQ = 0b01, + /// Select "P" clock as the FDCAN clock source + PCLK = 0b10, + //Reserved = 0b10, +} + +impl FdCan +where + I: Instance, +{ + /// Creates a CAN interface. + /// + /// Sets the FDCAN clock to the P clock if no FDCAN clock has been configured + /// If one has been configured, it will leave it as is. + #[inline] + pub fn new(can_instance: I, _tx: TX, _rx: RX, rcc: &Rcc) -> Self + where + TX: sealed::Tx, + RX: sealed::Rx, + { + I::enable(&rcc.rb); + + if rcc.rb.ccipr().read().fdcansel().is_hse() { + // Select P clock as FDCAN clock source + rcc.rb.ccipr().modify(|_, w| { + // This is sound, as `FdCanClockSource` only contains valid values for this field. + unsafe { + w.fdcansel().bits(FdCanClockSource::PCLK as u8); + } + + w + }); + } + //TODO: Set Speed to VeryHigh? + + let can = Self::create_can(FdCanConfig::default(), can_instance); + let reg = can.registers(); + assert!(reg.endn().read().bits() == 0x87654321_u32); + can + } + + /// Creates a CAN interface. + /// + /// Sets the FDCAN clock to the selected clock source + /// Note that this is shared across all instances. + /// Do not call this if there is allready an active FDCAN instance. + #[inline] + pub fn new_with_clock_source( + can_instance: I, + _tx: TX, + _rx: RX, + rcc: &Rcc, + clock_source: FdCanClockSource, + ) -> Self + where + TX: sealed::Tx, + RX: sealed::Rx, + { + rcc.rb.ccipr().modify(|_, w| { + // This is sound, as `FdCanClockSource` only contains valid values for this field. + unsafe { + w.fdcansel().bits(clock_source as u8); + } + + w + }); + + Self::new(can_instance, _tx, _rx, rcc) + } + + /// Moves out of PoweredDownMode and into ConfigMode + #[inline] + pub fn into_config_mode(mut self) -> FdCan { + self.set_power_down_mode(false); + self.enter_init_mode(); + + self.reset_msg_ram(); + + let can = self.registers(); + + // Framework specific settings are set here. // + + // set TxBuffer to Queue Mode; + // TODO: don't require this. + // can.txbc().write(|w| w.tfqm().set_bit()); + //FIXME: stm32g4 has the wrong layout here! + //We should be able to use the above, + //But right now, we just set the 24th bit. + can.txbc().write(|w| unsafe { w.bits(1_u32 << 24) }); + + // set standard filters list size to 28 + // set extended filters list size to 8 + // REQUIRED: we use the memory map as if these settings are set + // instead of re-calculating them. + can.rxgfc().modify(|_, w| unsafe { + w.lse() + .bits(EXTENDED_FILTER_MAX) + .lss() + .bits(STANDARD_FILTER_MAX) + }); + for fid in 0..STANDARD_FILTER_MAX { + self.set_standard_filter((fid as u8).into(), StandardFilter::disable()); + } + for fid in 0..EXTENDED_FILTER_MAX { + self.set_extended_filter(fid.into(), ExtendedFilter::disable()); + } + + self.into_can_mode() + } + + /// Disables the CAN interface and returns back the raw peripheral it was created from. + #[inline] + pub fn free(mut self) -> I { + self.disable_interrupts(Interrupts::all()); + + //TODO check this! + self.enter_init_mode(); + self.set_power_down_mode(true); + self.control.instance + } +} + +impl FdCan +where + I: Instance, +{ + #[inline] + fn leave_init_mode(&mut self) { + self.apply_config(self.control.config); + + let can = self.registers(); + can.cccr().modify(|_, w| w.cce().clear_bit()); + can.cccr().modify(|_, w| w.init().clear_bit()); + while can.cccr().read().init().bit_is_set() {} + } + + /// Moves out of ConfigMode and into InternalLoopbackMode + #[inline] + pub fn into_internal_loopback(mut self) -> FdCan { + self.set_loopback_mode(LoopbackMode::Internal); + self.leave_init_mode(); + + self.into_can_mode() + } + + /// Moves out of ConfigMode and into ExternalLoopbackMode + #[inline] + pub fn into_external_loopback(mut self) -> FdCan { + self.set_loopback_mode(LoopbackMode::External); + self.leave_init_mode(); + + self.into_can_mode() + } + + /// Moves out of ConfigMode and into RestrictedOperationMode + #[inline] + pub fn into_restricted(mut self) -> FdCan { + self.set_restricted_operations(true); + self.leave_init_mode(); + + self.into_can_mode() + } + + /// Moves out of ConfigMode and into NormalOperationMode + #[inline] + pub fn into_normal(mut self) -> FdCan { + self.set_normal_operations(true); + self.leave_init_mode(); + + self.into_can_mode() + } + + /// Moves out of ConfigMode and into BusMonitoringMode + #[inline] + pub fn into_bus_monitoring(mut self) -> FdCan { + self.set_bus_monitoring_mode(true); + self.leave_init_mode(); + + self.into_can_mode() + } + + /// Moves out of ConfigMode and into Testmode + #[inline] + pub fn into_test_mode(mut self) -> FdCan { + self.set_test_mode(true); + self.leave_init_mode(); + + self.into_can_mode() + } + + /// Moves out of ConfigMode and into PoweredDownmode + #[inline] + pub fn into_powered_down(mut self) -> FdCan { + self.set_power_down_mode(true); + self.leave_init_mode(); + + self.into_can_mode() + } + + /// Applies the settings of a new FdCanConfig + /// See `[FdCanConfig]` for more information + #[inline] + pub fn apply_config(&mut self, config: FdCanConfig) { + self.set_data_bit_timing(config.dbtr); + self.set_nominal_bit_timing(config.nbtr); + self.set_automatic_retransmit(config.automatic_retransmit); + self.set_transmit_pause(config.transmit_pause); + self.set_frame_transmit(config.frame_transmit); + self.set_interrupt_line_config(config.interrupt_line_config); + self.set_non_iso_mode(config.non_iso_mode); + self.set_edge_filtering(config.edge_filtering); + self.set_protocol_exception_handling(config.protocol_exception_handling); + self.set_global_filter(config.global_filter); + } + + /// Configures the bit timings. + /// + /// You can use to calculate the `btr` parameter. Enter + /// parameters as follows: + /// + /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). + /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). + /// - *Sample Point*: Should normally be left at the default value of 87.5%. + /// - *SJW*: Should normally be left at the default value of 1. + /// + /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` + /// parameter to this method. + #[inline] + pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) { + self.control.config.nbtr = btr; + + let can = self.registers(); + can.nbtp().write(|w| unsafe { + w.nbrp() + .bits(btr.nbrp() - 1) + .ntseg1() + .bits(btr.ntseg1() - 1) + .ntseg2() + .bits(btr.ntseg2() - 1) + .nsjw() + .bits(btr.nsjw() - 1) + }); + } + + /// Configures the data bit timings for the FdCan Variable Bitrates. + /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS. + #[inline] + pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) { + self.control.config.dbtr = btr; + + let can = self.registers(); + can.dbtp().write(|w| unsafe { + w.dbrp() + .bits(btr.dbrp() - 1) + .dtseg1() + .bits(btr.dtseg1() - 1) + .dtseg2() + .bits(btr.dtseg2() - 1) + .dsjw() + .bits(btr.dsjw() - 1) + }); + } + + /// Enables or disables automatic retransmission of messages + /// + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// util it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + #[inline] + pub fn set_automatic_retransmit(&mut self, enabled: bool) { + let can = self.registers(); + can.cccr().modify(|_, w| w.dar().bit(!enabled)); + self.control.config.automatic_retransmit = enabled; + } + + /// Configures the transmit pause feature + /// See `[FdCanConfig]` for more information + #[inline] + pub fn set_transmit_pause(&mut self, enabled: bool) { + let can = self.registers(); + can.cccr().modify(|_, w| w.dar().bit(!enabled)); + self.control.config.transmit_pause = enabled; + } + + /// Configures non-iso mode + /// See `[FdCanConfig]` for more information + #[inline] + pub fn set_non_iso_mode(&mut self, enabled: bool) { + let can = self.registers(); + can.cccr().modify(|_, w| w.niso().bit(enabled)); + self.control.config.non_iso_mode = enabled; + } + + /// Configures edge filtering + /// See `[FdCanConfig]` for more information + #[inline] + pub fn set_edge_filtering(&mut self, enabled: bool) { + let can = self.registers(); + can.cccr().modify(|_, w| w.efbi().bit(enabled)); + self.control.config.edge_filtering = enabled; + } + + /// Configures frame transmission mode + /// See `[FdCanConfig]` for more information + #[inline] + pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) { + let (fdoe, brse) = match fts { + FrameTransmissionConfig::ClassicCanOnly => (false, false), + FrameTransmissionConfig::AllowFdCan => (true, false), + FrameTransmissionConfig::AllowFdCanAndBRS => (true, true), + }; + + let can = self.registers(); + can.cccr().modify(|_, w| w.fdoe().bit(fdoe).brse().bit(brse)); + + self.control.config.frame_transmit = fts; + } + + /// Configures the interrupt lines + /// See `[FdCanConfig]` for more information + #[inline] + pub fn set_interrupt_line_config(&mut self, l0int: Interrupts) { + let can = self.registers(); + + can.ils().modify(|_, w| unsafe { w.bits(l0int.bits()) }); + + self.control.config.interrupt_line_config = l0int; + } + + /// Sets the protocol exception handling on/off + #[inline] + pub fn set_protocol_exception_handling(&mut self, enabled: bool) { + let can = self.registers(); + + can.cccr().modify(|_, w| w.pxhd().bit(!enabled)); + + self.control.config.protocol_exception_handling = enabled; + } + + /// Sets the General FdCAN clock divider for this instance + //TODO: ?clock divider is a shared register? + #[inline] + pub fn set_clock_divider(&mut self, div: ClockDivider) { + let can = self.registers(); + + can.ckdiv().write(|w| unsafe { w.pdiv().bits(div as u8) }); + + self.control.config.clock_divider = div; + } + + /// Configures and resets the timestamp counter + #[inline] + pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { + let (tcp, tss) = match select { + TimestampSource::None => (0, 0b00), + TimestampSource::Prescaler(p) => (p as u8, 0b01), + TimestampSource::FromTIM3 => (0, 0b10), + }; + self.registers() + .tscc + .write(|w| unsafe { w.tcp().bits(tcp).tss().bits(tss) }); + + self.control.config.timestamp_source = select; + } + + /// Configures the global filter settings + #[inline] + pub fn set_global_filter(&mut self, filter: GlobalFilter) { + self.registers().rxgfc().modify(|_, w| { + unsafe { + w.anfs() + .bits(filter.handle_standard_frames as u8) + .anfe() + .bits(filter.handle_extended_frames as u8) + } + .rrfs() + .bit(filter.reject_remote_standard_frames) + .rrfe() + .bit(filter.reject_remote_extended_frames) + }); + } + + /// Returns the current FdCan timestamp counter + #[inline] + pub fn timestamp(&self) -> u16 { + self.control.timestamp() + } +} + +impl FdCan +where + I: Instance, +{ + /// Returns out of InternalLoopbackMode and back into ConfigMode + #[inline] + pub fn into_config_mode(mut self) -> FdCan { + self.set_loopback_mode(LoopbackMode::None); + self.enter_init_mode(); + + self.into_can_mode() + } +} + +impl FdCan +where + I: Instance, +{ + /// Returns out of ExternalLoopbackMode and back into ConfigMode + #[inline] + pub fn into_config_mode(mut self) -> FdCan { + self.set_loopback_mode(LoopbackMode::None); + self.enter_init_mode(); + + self.into_can_mode() + } +} + +impl FdCan +where + I: Instance, +{ + /// Returns out of NormalOperationMode and back into ConfigMode + #[inline] + pub fn into_config_mode(mut self) -> FdCan { + self.set_normal_operations(false); + self.enter_init_mode(); + + self.into_can_mode() + } +} + +impl FdCan +where + I: Instance, +{ + /// Returns out of RestrictedOperationMode and back into ConfigMode + #[inline] + pub fn into_config_mode(mut self) -> FdCan { + self.set_restricted_operations(false); + self.enter_init_mode(); + + self.into_can_mode() + } +} + +impl FdCan +where + I: Instance, +{ + /// Returns out of BusMonitoringMode and back into ConfigMode + #[inline] + pub fn into_config_mode(mut self) -> FdCan { + self.set_bus_monitoring_mode(false); + self.enter_init_mode(); + + self.into_can_mode() + } +} + +/// states of the test.tx register +pub enum TestTransmitPinState { + /// CAN core has control (default) + CoreHasControl = 0b00, + /// Sample point can be monitored + ShowSamplePoint = 0b01, + /// Set to Dominant (0) Level + SetDominant = 0b10, + /// Set to Recessive (1) Level + SetRecessive = 0b11, +} + +impl FdCan +where + I: Instance, +{ + /// Returns out of TestMode and back into ConfigMode + #[inline] + pub fn into_config_mode(mut self) -> FdCan { + self.set_test_mode(false); + self.enter_init_mode(); + + self.into_can_mode() + } + + /// Gets the state of the receive pin to either Dominant (false), or Recessive (true) + pub fn get_receive_pin(&mut self) -> bool { + let can = self.registers(); + + can.test().read().rx().bit_is_set() + } + + /// Sets the state of the transmit pin according to TestTransmitPinState + pub fn set_transmit_pin(&mut self, state: TestTransmitPinState) { + let can = self.registers(); + + //SAFE: state has all possible values, and this can only occur in TestMode + can.test().modify(|_, w| unsafe { w.tx().bits(state as u8) }); + } +} + +impl FdCan +where + I: Instance, + M: Transmit + Receive, +{ + /// Splits this `FdCan` instance into transmitting and receiving halves, by reference. + #[inline] + #[allow(clippy::type_complexity)] + pub fn split_by_ref( + &mut self, + ) -> ( + &mut FdCanControl, + &mut Tx, + &mut Rx, + &mut Rx, + ) { + self.split_by_ref_generic() + } + + /// Consumes this `FdCan` instance and splits it into transmitting and receiving halves. + #[allow(clippy::type_complexity)] + pub fn split( + self, + ) -> ( + FdCanControl, + Tx, + Rx, + Rx, + ) { + self.split_generic() + } +} + +impl FdCan +where + I: Instance, + M: Transmit, +{ + /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. + /// + /// Frames are transmitted to the bus based on their priority (identifier). + /// Transmit order is preserved for frames with identical identifiers. + /// If all transmit mailboxes are full, this overwrites the mailbox with + /// the lowest priority. + #[inline] + pub fn transmit( + &mut self, + frame: TxFrameHeader, + write: &mut WTX, + ) -> nb::Result, Infallible> + where + WTX: FnMut(&mut [u32]), + { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Tx::::conjure().transmit(frame, write) } + } + + /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. + /// + /// Frames are transmitted to the bus based on their priority (identifier). + /// Transmit order is preserved for frames with identical identifiers. + /// If all transmit mailboxes are full, `pending` is called with the mailbox, + /// header and data of the to-be-replaced frame. + pub fn transmit_preserve( + &mut self, + frame: TxFrameHeader, + write: &mut WTX, + pending: &mut PTX, + ) -> nb::Result, Infallible> + where + PTX: FnMut(Mailbox, TxFrameHeader, &[u32]) -> P, + WTX: FnMut(&mut [u32]), + { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Tx::::conjure().transmit_preserve(frame, write, pending) } + } + + /// Returns `true` if no frame is pending for transmission. + #[inline] + pub fn is_transmitter_idle(&self) -> bool { + // Safety: Read-only operation. + unsafe { Tx::::conjure().is_idle() } + } + + /// Attempts to abort the sending of a frame that is pending in a mailbox. + /// + /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be + /// aborted, this function has no effect and returns `false`. + /// + /// If there is a frame in the provided mailbox, and it is canceled successfully, this function + /// returns `true`. + #[inline] + pub fn abort(&mut self, mailbox: Mailbox) -> bool { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Tx::::conjure().abort(mailbox) } + } +} + +impl FdCan +where + I: Instance, + M: Receive, +{ + /// Returns a received frame from FIFO_0 if available. + #[inline] + pub fn receive0( + &mut self, + receive: &mut RECV, + ) -> nb::Result, Infallible> + where + RECV: FnMut(RxFrameInfo, &[u32]) -> R, + { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Rx::::conjure().receive(receive) } + } + + /// Returns a received frame from FIFO_1 if available. + #[inline] + pub fn receive1( + &mut self, + receive: &mut RECV, + ) -> nb::Result, Infallible> + where + RECV: FnMut(RxFrameInfo, &[u32]) -> R, + { + // Safety: We have a `&mut self` and have unique access to the peripheral. + unsafe { Rx::::conjure().receive(receive) } + } +} + +/// FdCanControl Struct +/// Used to house some information during an FdCan split. +/// and can be used for some generic information retrieval during operation. +pub struct FdCanControl +where + I: Instance, +{ + config: FdCanConfig, + instance: I, + _mode: PhantomData, +} +impl FdCanControl +where + I: Instance, +{ + #[inline] + fn registers(&self) -> &RegisterBlock { + unsafe { &*I::REGISTERS } + } + + /// Returns the current error counters + #[inline] + pub fn error_counters(&self) -> ErrorCounters { + let can = self.registers(); + let ecr = can.ecr().read(); + let cel: u8 = ecr.cel().bits(); + let rp: bool = ecr.rp().bit(); + let rec: u8 = ecr.rec().bits(); + let tec: u8 = ecr.tec().bits(); + + ErrorCounters { + can_errors: cel, + transmit_err: tec, + receive_err: match rp { + false => ReceiveErrorOverflow::Normal(rec), + true => ReceiveErrorOverflow::Overflow(rec), + }, + } + } + + /// Returns the current FdCan Timestamp counter + #[inline] + pub fn timestamp(&self) -> u16 { + self.registers().tscv().read().tsc().bits() + } + + /// Check if the interrupt is triggered + #[inline] + pub fn has_interrupt(&mut self, interrupt: Interrupt) -> bool { + let can = self.registers(); + can.ir().read().bits() & (interrupt as u32) > 0 + } + + /// Clear specified interrupt + #[inline] + pub fn clear_interrupt(&mut self, interrupt: Interrupt) { + let can = self.registers(); + can.ir().write(|w| unsafe { w.bits(interrupt as u32) }); + } + + /// Clear specified interrupts + #[inline] + pub fn clear_interrupts(&mut self, interrupts: Interrupts) { + let can = self.registers(); + can.ir().write(|w| unsafe { w.bits(interrupts.bits()) }); + } +} + +/// Interface to the CAN transmitter part. +pub struct Tx { + _can: PhantomData, + _mode: PhantomData, +} + +impl Tx +where + I: Instance, +{ + #[inline] + unsafe fn conjure() -> Self { + Self { + _can: PhantomData, + _mode: PhantomData, + } + } + + /// Creates a `&mut Self` out of thin air. + /// + /// This is only safe if it is the only way to access a `Tx`. + #[inline] + unsafe fn conjure_by_ref<'a>() -> &'a mut Self { + // Cause out of bounds access when `Self` is not zero-sized. + #[allow(clippy::unnecessary_operation)] + [()][core::mem::size_of::()]; + + // Any aligned pointer is valid for ZSTs. + &mut *NonNull::dangling().as_ptr() + } + + #[inline] + fn registers(&self) -> &RegisterBlock { + unsafe { &*I::REGISTERS } + } + + #[inline] + fn tx_msg_ram(&self) -> &message_ram::Transmit { + unsafe { &(*I::MSG_RAM).transmit } + } + + #[inline] + fn tx_msg_ram_mut(&mut self) -> &mut message_ram::Transmit { + unsafe { &mut (*I::MSG_RAM).transmit } + } + + /// Puts a CAN frame in a transmit mailbox for transmission on the bus. + /// + /// Frames are transmitted to the bus based on their priority (identifier). Transmit order is + /// preserved for frames with identical identifiers. + /// + /// If all transmit mailboxes are full, a higher priority frame can replace a lower-priority + /// frame, which is returned via the closure 'pending'. If 'pending' is called; it's return value + /// is returned via Option

, if it is not, None is returned. + /// If there are only higher priority frames in the queue, this returns Err::WouldBlock + pub fn transmit( + &mut self, + frame: TxFrameHeader, + write: &mut WTX, + ) -> nb::Result, Infallible> + where + WTX: FnMut(&mut [u32]), + { + self.transmit_preserve(frame, write, &mut |_, _, _| ()) + } + + /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can + /// be preserved. + pub fn transmit_preserve( + &mut self, + frame: TxFrameHeader, + write: &mut WTX, + pending: &mut PTX, + ) -> nb::Result, Infallible> + where + PTX: FnMut(Mailbox, TxFrameHeader, &[u32]) -> P, + WTX: FnMut(&mut [u32]), + { + let can = self.registers(); + let queue_is_full = self.tx_queue_is_full(); + + let id = frame.into(); + + // If the queue is full, + // Discard the first slot with a lower priority message + let (idx, pending_frame) = if queue_is_full { + if self.is_available(Mailbox::_0, id) { + ( + Mailbox::_0, + self.abort_pending_mailbox(Mailbox::_0, pending), + ) + } else if self.is_available(Mailbox::_1, id) { + ( + Mailbox::_1, + self.abort_pending_mailbox(Mailbox::_1, pending), + ) + } else if self.is_available(Mailbox::_2, id) { + ( + Mailbox::_2, + self.abort_pending_mailbox(Mailbox::_2, pending), + ) + } else { + // For now we bail when there is no lower priority slot available + // Can this lead to priority inversion? + return Err(nb::Error::WouldBlock); + } + } else { + // Read the Write Pointer + let idx = can.txfqs().read().tfqpi().bits(); + + (Mailbox::new(idx), None) + }; + + self.write_mailbox(idx, frame, write); + + Ok(pending_frame) + } + + /// Returns if the tx queue is able to accept new messages without having to cancel an existing one + #[inline] + pub fn tx_queue_is_full(&self) -> bool { + self.registers().txfqs().read().tfqf().bit() + } + + /// Returns `Ok` when the mailbox is free or if it contains pending frame with a + /// lower priority (higher ID) than the identifier `id`. + #[inline] + fn is_available(&self, idx: Mailbox, id: IdReg) -> bool { + if self.has_pending_frame(idx) { + //read back header section + let header: TxFrameHeader = (&self.tx_msg_ram().tbsa[idx as usize].header).into(); + let old_id: IdReg = header.into(); + + id > old_id + } else { + true + } + } + + #[inline] + fn write_mailbox(&mut self, idx: Mailbox, tx_header: TxFrameHeader, transmit: TX) -> R + where + TX: FnOnce(&mut [u32]) -> R, + { + let tx_ram = self.tx_msg_ram_mut(); + + // Clear mail slot; mainly for debugging purposes. + tx_ram.tbsa[idx as usize].reset(); + + // Calculate length of data in words + let data_len = ((tx_header.len as usize) + 3) / 4; + + //set header section + tx_ram.tbsa[idx as usize].header.merge(tx_header); + + //set data + let result = transmit(&mut tx_ram.tbsa[idx as usize].data[0..data_len]); + + // Set as ready to transmit + self.registers() + .txbar + .modify(|r, w| unsafe { w.ar().bits(r.ar().bits() | 1 << (idx as u32)) }); + + result + } + + #[inline] + fn abort_pending_mailbox(&mut self, idx: Mailbox, pending: PTX) -> Option + where + PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R, + { + if self.abort(idx) { + let tx_ram = self.tx_msg_ram(); + + //read back header section + let header = (&tx_ram.tbsa[idx as usize].header).into(); + Some(pending(idx, header, &tx_ram.tbsa[idx as usize].data)) + } else { + // Abort request failed because the frame was already sent (or being sent) on + // the bus. All mailboxes are now free. This can happen for small prescaler + // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR + // has preempted the execution. + None + } + } + + /// Attempts to abort the sending of a frame that is pending in a mailbox. + /// + /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be + /// aborted, this function has no effect and returns `false`. + /// + /// If there is a frame in the provided mailbox, and it is canceled successfully, this function + /// returns `true`. + #[inline] + fn abort(&mut self, idx: Mailbox) -> bool { + let can = self.registers(); + + // Check if there is a request pending to abort + if self.has_pending_frame(idx) { + let idx: u8 = idx.into(); + let idx = 1u8 << idx; + + // Abort Request + can.txbcr().write(|w| unsafe { w.cr().bits(idx) }); + + // Wait for the abort request to be finished. + loop { + if can.txbcf().read().cf().bits() & idx != 0 { + // Return false when a transmission has occured + break can.txbto().read().to().bits() & idx == 0; + } + } + } else { + false + } + } + + #[inline] + fn has_pending_frame(&self, idx: Mailbox) -> bool { + let can = self.registers(); + let idx: u8 = idx.into(); + let idx = 1u8 << idx; + + can.txbrp().read().trp().bits() & idx != 0 + } + + /// Returns `true` if no frame is pending for transmission. + #[inline] + pub fn is_idle(&self) -> bool { + let can = self.registers(); + can.txbrp().read().trp().bits() == 0x0 + } + + /// Clears the transmission complete flag. + #[inline] + pub fn clear_transmission_completed_flag(&mut self) { + let can = self.registers(); + can.ir().write(|w| w.tc().set_bit()); + } + + /// Clears the transmission cancelled flag. + #[inline] + pub fn clear_transmission_cancelled_flag(&mut self) { + let can = self.registers(); + can.ir().write(|w| w.tcf().set_bit()); + } +} + +#[doc(hidden)] +pub trait FifoNr: crate::sealed::Sealed { + const NR: usize; +} +#[doc(hidden)] +pub struct Fifo0; +impl crate::sealed::Sealed for Fifo0 {} +impl FifoNr for Fifo0 { + const NR: usize = 0; +} +#[doc(hidden)] +pub struct Fifo1; +impl crate::sealed::Sealed for Fifo1 {} +impl FifoNr for Fifo1 { + const NR: usize = 1; +} + +/// Notes whether an overrun has occurred. +/// Since both arms contain T, this can be 'unwrap'ed without causing a panic. +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub enum ReceiveOverrun { + /// No overrun has occured + NoOverrun(T), + /// an overrun has occurered + Overrun(T), +} +impl ReceiveOverrun { + /// unwraps itself and returns T + /// in contradiction to Option::unwrap, this does not panic + /// since both elements contain T. + #[inline] + pub fn unwrap(self) -> T { + match self { + ReceiveOverrun::NoOverrun(t) | ReceiveOverrun::Overrun(t) => t, + } + } +} + +/// Interface to the CAN receiver part. +pub struct Rx +where + FIFONR: FifoNr, +{ + _can: PhantomData, + _mode: PhantomData, + _nr: PhantomData, +} + +impl Rx +where + FIFONR: FifoNr, + I: Instance, +{ + #[inline] + unsafe fn conjure() -> Self { + Self { + _can: PhantomData, + _mode: PhantomData, + _nr: PhantomData, + } + } + + /// Creates a `&mut Self` out of thin air. + /// + /// This is only safe if it is the only way to access an `Rx`. + #[inline] + unsafe fn conjure_by_ref<'a>() -> &'a mut Self { + // Cause out of bounds access when `Self` is not zero-sized. + #[allow(clippy::unnecessary_operation)] + [()][core::mem::size_of::()]; + + // Any aligned pointer is valid for ZSTs. + &mut *NonNull::dangling().as_ptr() + } + + /// Returns a received frame if available. + /// + /// Returns `Err` when a frame was lost due to buffer overrun. + pub fn receive( + &mut self, + receive: &mut RECV, + ) -> nb::Result, Infallible> + where + RECV: FnMut(RxFrameInfo, &[u32]) -> R, + { + if !self.rx_fifo_is_empty() { + let mbox = self.get_rx_mailbox(); + let idx: usize = mbox.into(); + let mailbox: &RxFifoElement = &self.rx_msg_ram().fxsa[idx]; + + let header: RxFrameInfo = (&mailbox.header).into(); + let word_len = (header.len + 3) / 4; + let result = Ok(receive(header, &mailbox.data[0..word_len as usize])); + self.release_mailbox(mbox); + + if self.has_overrun() { + result.map(ReceiveOverrun::Overrun) + } else { + result.map(ReceiveOverrun::NoOverrun) + } + } else { + Err(nb::Error::WouldBlock) + } + } + + #[inline] + fn registers(&self) -> &RegisterBlock { + unsafe { &*I::REGISTERS } + } + + #[inline] + fn rx_msg_ram(&self) -> &message_ram::Receive { + unsafe { &(&(*I::MSG_RAM).receive)[FIFONR::NR] } + } + + #[inline] + fn has_overrun(&self) -> bool { + let can = self.registers(); + match FIFONR::NR { + 0 => can.rxf0s().read().rf0l().bit(), + 1 => can.rxf1s().read().rf1l().bit(), + _ => unreachable!(), + } + } + + /// Returns if the fifo contains any new messages. + #[inline] + pub fn rx_fifo_is_empty(&self) -> bool { + let can = self.registers(); + match FIFONR::NR { + 0 => can.rxf0s().read().f0fl().bits() == 0, + 1 => can.rxf1s().read().f1fl().bits() == 0, + _ => unreachable!(), + } + } + + #[inline] + fn release_mailbox(&mut self, idx: Mailbox) { + unsafe { + (*I::MSG_RAM).receive[FIFONR::NR].fxsa[idx as u8 as usize].reset(); + } + + let can = self.registers(); + match FIFONR::NR { + 0 => can.rxf0a().write(|w| unsafe { w.f0ai().bits(idx.into()) }), + 1 => can.rxf1a().write(|w| unsafe { w.f1ai().bits(idx.into()) }), + _ => unreachable!(), + } + } + + #[inline] + fn get_rx_mailbox(&self) -> Mailbox { + let can = self.registers(); + let idx = match FIFONR::NR { + 0 => can.rxf0s().read().f0gi().bits(), + 1 => can.rxf1s().read().f1gi().bits(), + _ => unreachable!(), + }; + Mailbox::new(idx) + } +} + +/// The three mailboxes. +/// These are used for the transmit queue +/// and the two Receive FIFOs +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub enum Mailbox { + /// Transmit mailbox 0 + _0 = 0, + /// Transmit mailbox 1 + _1 = 1, + /// Transmit mailbox 2 + _2 = 2, +} +impl Mailbox { + #[inline] + fn new(idx: u8) -> Self { + match idx & 0b11 { + 0 => Mailbox::_0, + 1 => Mailbox::_1, + 2 => Mailbox::_2, + _ => unreachable!(), + } + } +} +impl From for u8 { + #[inline] + fn from(m: Mailbox) -> Self { + m as u8 + } +} +impl From for usize { + #[inline] + fn from(m: Mailbox) -> Self { + m as u8 as usize + } +} + +mod impls { + use super::sealed; + + /// Implements sealed::{Tx,Rx} for pins associated with a CAN peripheral + macro_rules! pins { + ($PER:ident => + (tx: [ $($( #[ $pmetatx:meta ] )* $tx:ident<$txaf:ident>),+ $(,)? ], + rx: [ $($( #[ $pmetarx:meta ] )* $rx:ident<$rxaf:ident>),+ $(,)? ])) => { + $( + $( #[ $pmetatx ] )* + impl super::sealed::Tx<$PER> for $tx> {} + )+ + $( + $( #[ $pmetarx ] )* + impl super::sealed::Rx<$PER> for $rx> {} + )+ + }; + } + + mod fdcan1 { + use crate::fdcan; + use crate::fdcan::message_ram; + use crate::gpio::{ + gpioa::{PA11, PA12}, + gpiob::{PB8, PB9}, + gpiod::{PD0, PD1}, + AF9, + }; + use crate::stm32; + use crate::stm32::FDCAN1; + + // All STM32G4 models with CAN support these pins + pins! { + FDCAN1 => ( + tx: [ + PA12, + PB9, + PD1, + ], + rx: [ + PA11, + PB8, + PD0, + ] + ) + } + + unsafe impl message_ram::MsgRamExt for FDCAN1 { + const MSG_RAM: *mut message_ram::RegisterBlock = (0x4000_a400 as *mut _); + } + unsafe impl fdcan::Instance for FDCAN1 { + const REGISTERS: *mut stm32::fdcan::RegisterBlock = FDCAN1::ptr() as *mut _; + } + } + + #[cfg(any( + feature = "stm32g471", + feature = "stm32g473", + feature = "stm32g474", + feature = "stm32g483", + feature = "stm32g484", + feature = "stm32g491", + feature = "stm32g4a1", + ))] + mod fdcan2 { + use crate::fdcan; + use crate::fdcan::message_ram; + use crate::gpio::{ + gpiob::{PB12, PB13, PB5, PB6}, + AF9, + }; + use crate::stm32::{self, FDCAN2}; + + pins! { + FDCAN2 => ( + tx: [ + PB6, + PB13, + ], + rx: [ + PB5, + PB12, + ]) + } + + unsafe impl fdcan::Instance for FDCAN2 { + const REGISTERS: *mut stm32::fdcan::RegisterBlock = FDCAN2::ptr() as *mut _; + } + + unsafe impl message_ram::MsgRamExt for FDCAN2 { + const MSG_RAM: *mut message_ram::RegisterBlock = (0x4000_a750 as *mut _); + } + } + + #[cfg(any( + feature = "stm32g473", + feature = "stm32g474", + feature = "stm32g483", + feature = "stm32g484", + ))] + mod fdcan3 { + use crate::fdcan; + use crate::fdcan::message_ram; + use crate::gpio::{ + gpioa::{PA15, PA8}, + gpiob::{PB3, PB4}, + AF11, + }; + use crate::stm32::{self, FDCAN3}; + + pins! { + FDCAN3 => ( + tx: [ + PA15, + PB4, + ], + rx: [ + PA8, + PB3, + ]) + } + + unsafe impl fdcan::Instance for FDCAN3 { + const REGISTERS: *mut stm32::fdcan::RegisterBlock = FDCAN3::ptr() as *mut _; + } + + unsafe impl message_ram::MsgRamExt for FDCAN3 { + const MSG_RAM: *mut message_ram::RegisterBlock = (0x4000_aaa0 as *mut _); + } + } +} diff --git a/src/flash.rs b/src/flash.rs index 66baca70..2505f193 100644 --- a/src/flash.rs +++ b/src/flash.rs @@ -465,7 +465,7 @@ pub struct ACR { impl ACR { pub(crate) fn acr(&mut self) -> &flash::ACR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).acr } + unsafe { (*FLASH::ptr()).acr() } } } @@ -478,7 +478,7 @@ pub struct CR { impl CR { pub(crate) fn cr(&mut self) -> &flash::CR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).cr } + unsafe { (*FLASH::ptr()).cr() } } } @@ -491,7 +491,7 @@ pub struct ECCR { impl ECCR { pub(crate) fn eccr(&mut self) -> &flash::ECCR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).eccr } + unsafe { (*FLASH::ptr()).eccr() } } } @@ -504,7 +504,7 @@ pub struct KEYR { impl KEYR { pub(crate) fn keyr(&mut self) -> &flash::KEYR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).keyr } + unsafe { (*FLASH::ptr()).keyr() } } } @@ -517,7 +517,7 @@ pub struct OPTKEYR { impl OPTKEYR { pub(crate) fn optkeyr(&mut self) -> &flash::OPTKEYR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).optkeyr } + unsafe { (*FLASH::ptr()).optkeyr() } } } @@ -530,7 +530,7 @@ pub struct OPTR { impl OPTR { pub(crate) fn optr(&mut self) -> &flash::OPTR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).optr } + unsafe { (*FLASH::ptr()).optr() } } } @@ -543,7 +543,7 @@ pub struct PCROP1SR { impl PCROP1SR { pub(crate) fn pcrop1sr(&mut self) -> &flash::PCROP1SR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).pcrop1sr } + unsafe { (*FLASH::ptr()).pcrop1sr() } } } @@ -556,7 +556,7 @@ pub struct PCROP1ER { impl PCROP1ER { pub(crate) fn pcrop1er(&mut self) -> &flash::PCROP1ER { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).pcrop1er } + unsafe { (*FLASH::ptr()).pcrop1er() } } } @@ -569,7 +569,7 @@ pub struct PDKEYR { impl PDKEYR { pub(crate) fn pdkeyr(&mut self) -> &flash::PDKEYR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).pdkeyr } + unsafe { (*FLASH::ptr()).pdkeyr() } } } @@ -582,7 +582,7 @@ pub struct SEC1R { impl SEC1R { pub(crate) fn sec1r(&mut self) -> &flash::SEC1R { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).sec1r } + unsafe { (*FLASH::ptr()).sec1r() } } } @@ -595,7 +595,7 @@ pub struct SR { impl SR { pub(crate) fn sr(&mut self) -> &flash::SR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).sr } + unsafe { (*FLASH::ptr()).sr() } } } @@ -608,7 +608,7 @@ pub struct WRP1AR { impl WRP1AR { pub(crate) fn wrp1ar(&mut self) -> &flash::WRP1AR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).wrp1ar } + unsafe { (*FLASH::ptr()).wrp1ar() } } } @@ -621,6 +621,6 @@ pub struct WRP1BR { impl WRP1BR { pub(crate) fn wrp1br(&mut self) -> &flash::WRP1BR { // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*FLASH::ptr()).wrp1br } + unsafe { (*FLASH::ptr()).wrp1br() } } } diff --git a/src/gpio.rs b/src/gpio.rs index f0ae9845..b0bac608 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -99,22 +99,22 @@ macro_rules! exti_erased { let offset = 4 * (self.i % 4); match self.i { 0..=3 => { - syscfg.exticr1.modify(|r, w| unsafe { + syscfg.exticr1().modify(|r, w| unsafe { w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset)) }); } 4..=7 => { - syscfg.exticr2.modify(|r, w| unsafe { + syscfg.exticr2().modify(|r, w| unsafe { w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset)) }); } 8..=11 => { - syscfg.exticr3.modify(|r, w| unsafe { + syscfg.exticr3().modify(|r, w| unsafe { w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset)) }); } 12..=15 => { - syscfg.exticr4.modify(|r, w| unsafe { + syscfg.exticr4().modify(|r, w| unsafe { w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset)) }); } @@ -126,21 +126,21 @@ macro_rules! exti_erased { fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: SignalEdge) { match edge { SignalEdge::Rising => { - exti.rtsr1 + exti.rtsr1() .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.i)) }); - exti.ftsr1 + exti.ftsr1() .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.i)) }); } SignalEdge::Falling => { - exti.ftsr1 + exti.ftsr1() .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.i)) }); - exti.rtsr1 + exti.rtsr1() .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.i)) }); } SignalEdge::RisingFalling => { - exti.rtsr1 + exti.rtsr1() .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.i)) }); - exti.ftsr1 + exti.ftsr1() .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.i)) }); } } @@ -148,24 +148,24 @@ macro_rules! exti_erased { /// Enable external interrupts from this pin. fn enable_interrupt(&mut self, exti: &mut EXTI) { - exti.imr1 + exti.imr1() .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.i)) }); } /// Disable external interrupts from this pin fn disable_interrupt(&mut self, exti: &mut EXTI) { - exti.imr1 + exti.imr1() .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.i)) }); } /// Clear the interrupt pending bit for this pin fn clear_interrupt_pending_bit(&mut self) { - unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << self.i)) }; + unsafe { (*EXTI::ptr()).pr1().write(|w| w.bits(1 << self.i)) }; } /// Reads the interrupt pending bit for this pin fn check_interrupt(&self) -> bool { - unsafe { ((*EXTI::ptr()).pr1.read().bits() & (1 << self.i)) != 0 } + unsafe { ((*EXTI::ptr()).pr1().read().bits() & (1 << self.i)) != 0 } } } }; @@ -177,7 +177,7 @@ macro_rules! exti { /// Configure EXTI Line $i to trigger from this pin. fn make_interrupt_source(&mut self, syscfg: &mut SysCfg) { let offset = 4 * ($i % 4); - syscfg.$exticri.modify(|r, w| unsafe { + syscfg.$exticri().modify(|r, w| unsafe { let mut exticr = r.bits(); exticr = (exticr & !(0xf << offset)) | ($extigpionr << offset); //FIXME: clears other pins w.bits(exticr) @@ -188,21 +188,21 @@ macro_rules! exti { fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: SignalEdge) { match edge { SignalEdge::Rising => { - exti.rtsr1 + exti.rtsr1() .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); - exti.ftsr1 + exti.ftsr1() .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) }); } SignalEdge::Falling => { - exti.ftsr1 + exti.ftsr1() .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); - exti.rtsr1 + exti.rtsr1() .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) }); } SignalEdge::RisingFalling => { - exti.rtsr1 + exti.rtsr1() .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); - exti.ftsr1 + exti.ftsr1() .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); } } @@ -210,24 +210,24 @@ macro_rules! exti { /// Enable external interrupts from this pin. fn enable_interrupt(&mut self, exti: &mut EXTI) { - exti.imr1 + exti.imr1() .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); } /// Disable external interrupts from this pin fn disable_interrupt(&mut self, exti: &mut EXTI) { - exti.imr1 + exti.imr1() .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) }); } /// Clear the interrupt pending bit for this pin fn clear_interrupt_pending_bit(&mut self) { - unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << $i)) }; + unsafe { (*EXTI::ptr()).pr1().write(|w| w.bits(1 << $i)) }; } /// Reads the interrupt pending bit for this pin fn check_interrupt(&self) -> bool { - unsafe { ((*EXTI::ptr()).pr1.read().bits() & (1 << $i)) != 0 } + unsafe { ((*EXTI::ptr()).pr1().read().bits() & (1 << $i)) != 0 } } } }; @@ -257,7 +257,7 @@ macro_rules! gpio { type Parts = Parts; fn split(self, rcc: &mut Rcc) -> Parts { - rcc.rb.ahb2enr.modify(|_, w| w.$iopxenr().set_bit()); + rcc.rb.ahb2enr().modify(|_, w| w.$iopxenr().set_bit()); Parts { $( $pxi: $PXi { _mode: PhantomData }, @@ -277,13 +277,13 @@ macro_rules! gpio { fn set_high(&mut self) -> Result<(), ()> { // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }; + unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.bs(self.i).set_bit()) }; Ok(()) } fn set_low(&mut self) -> Result<(), ()> { // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (self.i + 16))) }; + unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.br(self.i).set_bit()) }; Ok(()) } } @@ -295,13 +295,13 @@ macro_rules! gpio { impl embedded_hal::digital::OutputPin for $PXx> { fn 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)) }; + unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.bs(self.i).set_bit()) }; Ok(()) } fn 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))) }; + unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.br(self.i).set_bit()) }; Ok(()) } } @@ -314,7 +314,7 @@ macro_rules! gpio { fn is_set_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_set_low = unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 }; + let is_set_low = unsafe { (*$GPIOX::ptr()).odr().read().odr(self.i).is_low()}; Ok(is_set_low) } } @@ -327,7 +327,7 @@ macro_rules! gpio { fn is_set_low(&mut self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_set_low = unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 }; + let is_set_low = unsafe { (*$GPIOX::ptr()).odr().read().odr(self.i).is_low() }; Ok(is_set_low) } } @@ -344,7 +344,7 @@ macro_rules! gpio { fn is_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }; + let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr(self.i).is_low() }; Ok(is_low) } } @@ -357,7 +357,7 @@ macro_rules! gpio { fn is_low(&mut self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }; + let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr(self.i).is_low() }; Ok(is_low) } } @@ -373,7 +373,7 @@ macro_rules! gpio { fn is_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }; + let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr(self.i).is_low() }; Ok(is_low) } } @@ -390,7 +390,7 @@ macro_rules! gpio { fn is_low(&mut self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }; + let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr(self.i).is_low() }; Ok(is_low) } } @@ -446,10 +446,10 @@ macro_rules! gpio { let offset = 2 * $i; unsafe { let gpio = &(*$GPIOX::ptr()); - gpio.pupdr.modify(|r, w| { + gpio.pupdr().modify(|r, w| { w.bits(r.bits() & !(0b11 << offset)) }); - gpio.moder.modify(|r, w| { + gpio.moder().modify(|r, w| { w.bits(r.bits() & !(0b11 << offset)) }) }; @@ -461,10 +461,10 @@ macro_rules! gpio { let offset = 2 * $i; unsafe { let gpio = &(*$GPIOX::ptr()); - gpio.pupdr.modify(|r, w| { + gpio.pupdr().modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset)) }); - gpio.moder.modify(|r, w| { + gpio.moder().modify(|r, w| { w.bits(r.bits() & !(0b11 << offset)) }) }; @@ -476,10 +476,10 @@ macro_rules! gpio { let offset = 2 * $i; unsafe { let gpio = &(*$GPIOX::ptr()); - gpio.pupdr.modify(|r, w| { + gpio.pupdr().modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset)) }); - gpio.moder.modify(|r, w| { + gpio.moder().modify(|r, w| { w.bits(r.bits() & !(0b11 << offset)) }) }; @@ -491,10 +491,10 @@ macro_rules! gpio { let offset = 2 * $i; unsafe { let gpio = &(*$GPIOX::ptr()); - gpio.pupdr.modify(|r, w| { + gpio.pupdr().modify(|r, w| { w.bits(r.bits() & !(0b11 << offset)) }); - gpio.moder.modify(|r, w| { + gpio.moder().modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b11 << offset)) }); } @@ -506,13 +506,13 @@ macro_rules! gpio { let offset = 2 * $i; unsafe { let gpio = &(*$GPIOX::ptr()); - gpio.pupdr.modify(|r, w| { + gpio.pupdr().modify(|r, w| { w.bits(r.bits() & !(0b11 << offset)) }); - gpio.otyper.modify(|r, w| { + gpio.otyper().modify(|r, w| { w.bits(r.bits() | (0b1 << $i)) }); - gpio.moder.modify(|r, w| { + gpio.moder().modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset)) }) }; @@ -524,13 +524,13 @@ macro_rules! gpio { let offset = 2 * $i; unsafe { let gpio = &(*$GPIOX::ptr()); - gpio.pupdr.modify(|r, w| { + gpio.pupdr().modify(|r, w| { w.bits(r.bits() & !(0b11 << offset)) }); - gpio.otyper.modify(|r, w| { + gpio.otyper().modify(|r, w| { w.bits(r.bits() & !(0b1 << $i)) }); - gpio.moder.modify(|r, w| { + gpio.moder().modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset)) }) }; @@ -547,9 +547,9 @@ macro_rules! gpio { pub fn set_speed(self, speed: Speed) -> Self { let offset = 2 * $i; unsafe { - (*$GPIOX::ptr()).ospeedr.modify(|r, w| { + (*$GPIOX::ptr()).ospeedr().modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset)) - }) + }); } self } @@ -561,19 +561,19 @@ macro_rules! gpio { unsafe { let gpio = &(*$GPIOX::ptr()); if offset2 < 32 { - gpio.afrl.modify(|r, w| { + gpio.afrl().modify(|r, w| { w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2)) }); } else { let offset2 = offset2 - 32; - gpio.afrh.modify(|r, w| { + gpio.afrh().modify(|r, w| { w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2)) }); } - gpio.moder.modify(|r, w| { + gpio.moder().modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset)) }); - gpio.otyper.modify(|r, w| { + gpio.otyper().modify(|r, w| { w.bits(r.bits() & !(0b1 << $i)) }); } @@ -587,19 +587,19 @@ macro_rules! gpio { unsafe { let gpio = &(*$GPIOX::ptr()); if offset2 < 32 { - gpio.afrl.modify(|r, w| { + gpio.afrl().modify(|r, w| { w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2)) }); } else { let offset2 = offset2 - 32; - gpio.afrh.modify(|r, w| { + gpio.afrh().modify(|r, w| { w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2)) }); } - gpio.otyper.modify(|r, w| { + gpio.otyper().modify(|r, w| { w.bits(r.bits() | (0b1 << $i)) }); - gpio.moder.modify(|r, w| { + gpio.moder().modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset)) }); } @@ -622,13 +622,13 @@ macro_rules! gpio { fn set_high(&mut self) -> Result<(), ()> { // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }; + unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.bs($i).set_bit()) }; Ok(()) } fn set_low(&mut self) -> Result<(), ()>{ // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << ($i + 16))) }; + unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.br($i).set_bit()) }; Ok(()) } } @@ -640,13 +640,13 @@ macro_rules! gpio { impl embedded_hal::digital::OutputPin for $PXi> { fn 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)) }; + unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.bs($i).set_bit()) }; Ok(()) } fn 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))) }; + unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.br($i).set_bit()) }; Ok(()) } } @@ -659,7 +659,7 @@ macro_rules! gpio { fn is_set_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_set_low = unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }; + let is_set_low = unsafe { (*$GPIOX::ptr()).odr().read().odr($i).is_low()}; Ok(is_set_low) } } @@ -672,7 +672,7 @@ macro_rules! gpio { fn is_set_low(&mut self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_set_low = unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }; + let is_set_low = unsafe { (*$GPIOX::ptr()).odr().read().odr($i).is_low() }; Ok(is_set_low) } } @@ -689,7 +689,7 @@ macro_rules! gpio { fn is_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }; + let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr($i).is_low() }; Ok(is_low) } } @@ -702,7 +702,7 @@ macro_rules! gpio { fn is_low(&mut self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }; + let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr($i).is_low() }; Ok(is_low) } } @@ -729,7 +729,7 @@ macro_rules! gpio { fn is_low(&mut self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }; + let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr($i).is_low()}; Ok(is_low) } } @@ -744,7 +744,7 @@ macro_rules! gpio { fn is_low(&self) -> Result { // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }; + let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr($i).is_low()}; Ok(is_low) } } diff --git a/src/i2c.rs b/src/i2c.rs index c93f1c64..f2ae9cac 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -151,13 +151,15 @@ pub trait I2cExt { macro_rules! flush_txdr { ($i2c:expr) => { // If a pending TXIS flag is set, write dummy data to TXDR - if $i2c.isr.read().txis().bit_is_set() { - $i2c.txdr.write(|w| w.txdata().bits(0)); + if $i2c.isr().read().txis().bit_is_set() { + unsafe { + $i2c.txdr().write(|w| w.txdata().bits(0)); + } } // If TXDR is not flagged as empty, write 1 to flush it - if $i2c.isr.read().txe().bit_is_set() { - $i2c.isr.write(|w| w.txe().set_bit()); + if $i2c.isr().read().txe().bit_is_set() { + $i2c.isr().write(|w| w.txe().set_bit()); } }; } @@ -165,18 +167,19 @@ macro_rules! flush_txdr { macro_rules! busy_wait { ($i2c:expr, $flag:ident, $variant:ident) => { loop { - let isr = $i2c.isr.read(); + let isr = $i2c.isr().read(); if isr.$flag().$variant() { break; } else if isr.berr().bit_is_set() { - $i2c.icr.write(|w| w.berrcf().set_bit()); + $i2c.icr().write(|w| w.berrcf().set_bit()); return Err(Error::BusError); } else if isr.arlo().bit_is_set() { - $i2c.icr.write(|w| w.arlocf().set_bit()); + $i2c.icr().write(|w| w.arlocf().set_bit()); return Err(Error::ArbitrationLost); } else if isr.nackf().bit_is_set() { - $i2c.icr.write(|w| w.stopcf().set_bit().nackcf().set_bit()); + $i2c.icr() + .write(|w| w.stopcf().set_bit().nackcf().set_bit()); flush_txdr!($i2c); return Err(Error::Nack); } else { @@ -235,21 +238,23 @@ macro_rules! i2c { } // Make sure the I2C unit is disabled so we can configure it - i2c.cr1.modify(|_, w| w.pe().clear_bit()); + i2c.cr1().modify(|_, w| w.pe().clear_bit()); // Setup protocol timings let timing_bits = config.timing_bits(<$I2CX as RccBus>::Bus::get_frequency(&rcc.clocks)); - i2c.timingr.write(|w| unsafe { w.bits(timing_bits) }); + i2c.timingr().write(|w| unsafe { w.bits(timing_bits) }); // Enable the I2C processing - i2c.cr1.modify(|_, w| { - w.pe() - .set_bit() - .dnf() - .bits(config.digital_filter) - .anfoff() - .bit(!config.analog_filter) - }); + unsafe { + i2c.cr1().modify(|_, w| { + w.pe() + .set_bit() + .dnf() + .bits(config.digital_filter) + .anfoff() + .bit(!config.analog_filter) + }); + } I2c { i2c, sda, scl } } @@ -276,14 +281,14 @@ macro_rules! i2c { // Process 255 bytes at a time for (i, buffer) in buffer.chunks_mut(0xFF).enumerate() { // Prepare to receive `bytes` - self.i2c.cr2.modify(|_, w| { + self.i2c.cr2().modify(|_, w| { if i == 0 { w.add10().bit(addr_10b); - w.sadd().bits(addr); + w.sadd().set(addr); w.rd_wrn().read(); w.start().start(); } - w.nbytes().bits(buffer.len() as u8); + w.nbytes().set(buffer.len() as u8); if i == end { w.reload().completed().autoend().automatic() } else { @@ -294,7 +299,7 @@ macro_rules! i2c { for byte in buffer { // Wait until we have received something busy_wait!(self.i2c, rxne, is_not_empty); - *byte = self.i2c.rxdr.read().rxdata().bits(); + *byte = self.i2c.rxdr().read().rxdata().bits(); } if i != end { @@ -306,7 +311,9 @@ macro_rules! i2c { // Wait until the last transmission is finished // auto stop is set busy_wait!(self.i2c, stopf, is_stop); - Ok(self.i2c.icr.write(|w| w.stopcf().clear())) + self.i2c.icr().write(|w| w.stopcf().clear()); + + Ok(()) } fn write_inner(&mut self, mut addr: u16, addr_10b: bool, buffer: &[u8]) -> Result<(), Error> { @@ -315,11 +322,11 @@ macro_rules! i2c { if buffer.is_empty() { // 0 byte write - self.i2c.cr2.modify(|_, w| { + self.i2c.cr2().modify(|_, w| { w.add10().bit(addr_10b); - w.sadd().bits(addr); + w.sadd().set(addr); w.rd_wrn().write(); - w.nbytes().bits(0); + w.nbytes().set(0); w.reload().completed(); w.autoend().automatic(); w.start().start() @@ -329,14 +336,14 @@ macro_rules! i2c { // Process 255 bytes at a time for (i, buffer) in buffer.chunks(0xFF).enumerate() { // Prepare to receive `bytes` - self.i2c.cr2.modify(|_, w| { + self.i2c.cr2().modify(|_, w| { if i == 0 { w.add10().bit(addr_10b); - w.sadd().bits(addr); + w.sadd().set(addr); w.rd_wrn().write(); w.start().start(); } - w.nbytes().bits(buffer.len() as u8); + w.nbytes().set(buffer.len() as u8); if i == end { w.reload().completed().autoend().automatic() } else { @@ -348,7 +355,7 @@ macro_rules! i2c { // Wait until we are allowed to send data // (START has been ACKed or last byte went through) busy_wait!(self.i2c, txis, is_empty); - self.i2c.txdr.write(|w| w.txdata().bits(*byte)); + self.i2c.txdr().write(|w| w.txdata().set(*byte)); } if i != end { @@ -360,7 +367,8 @@ macro_rules! i2c { // Wait until the last transmission is finished // auto stop is set busy_wait!(self.i2c, stopf, is_stop); - Ok(self.i2c.icr.write(|w| w.stopcf().clear())) + self.i2c.icr().write(|w| w.stopcf().clear()); + Ok(()) } } @@ -378,7 +386,7 @@ macro_rules! i2c { Ok(for op in operation { // Wait for any operation on the bus to finish // for example in the case of another bus master having claimed the bus - while self.i2c.isr.read().busy().bit_is_set() {}; + while self.i2c.isr().read().busy().bit_is_set() {}; match op { Operation::Read(data) => self.read_inner(address as u16, false, data)?, Operation::Write(data) => self.write_inner(address as u16, false, data)?, @@ -395,7 +403,7 @@ macro_rules! i2c { Ok(for op in operation { // Wait for any operation on the bus to finish // for example in the case of another bus master having claimed the bus - while self.i2c.isr.read().busy().bit_is_set() {}; + while self.i2c.isr().read().busy().bit_is_set() {}; match op { Operation::Read(data) => self.read_inner(address, true, data)?, Operation::Write(data) => self.write_inner(address, true, data)?, diff --git a/src/independent_watchdog.rs b/src/independent_watchdog.rs index 051047cb..3462f92a 100644 --- a/src/independent_watchdog.rs +++ b/src/independent_watchdog.rs @@ -12,7 +12,7 @@ //! //! Originally from stm32h7-hal, adapted for stm32g4xx-hal use crate::{ - stm32::{iwdg::pr::PR_A, IWDG}, + stm32::{iwdg::pr::PR, IWDG}, time::MicroSecond, }; use fugit::ExtU32; @@ -25,37 +25,33 @@ pub struct IndependentWatchdog { impl IndependentWatchdog { const CLOCK_SPEED: u32 = 32000; const MAX_COUNTER_VALUE: u32 = 0x00000FFF; - const MAX_MILLIS_FOR_PRESCALER: [(PR_A, u32); 8] = [ + const MAX_MILLIS_FOR_PRESCALER: [(PR, u32); 7] = [ ( - PR_A::DivideBy4, + PR::DivideBy4, (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 4), ), ( - PR_A::DivideBy8, + PR::DivideBy8, (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 8), ), ( - PR_A::DivideBy16, + PR::DivideBy16, (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 16), ), ( - PR_A::DivideBy32, + PR::DivideBy32, (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 32), ), ( - PR_A::DivideBy64, + PR::DivideBy64, (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 64), ), ( - PR_A::DivideBy128, + PR::DivideBy128, (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 128), ), ( - PR_A::DivideBy256, - (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 256), - ), - ( - PR_A::DivideBy256bis, + PR::DivideBy256, (Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 256), ), ]; @@ -67,7 +63,7 @@ impl IndependentWatchdog { /// Feed the watchdog, resetting the timer to 0 pub fn feed(&mut self) { - self.iwdg.kr.write(|w| w.key().reset()); + self.iwdg.kr().write(|w| w.key().feed()); } /// Start the watchdog where it must be fed before the max time is over and @@ -77,27 +73,27 @@ impl IndependentWatchdog { let max_window_time: MicroSecond = max_window_time.into(); // Start the watchdog - self.iwdg.kr.write(|w| w.key().start()); + self.iwdg.kr().write(|w| w.key().start()); // Enable register access - self.iwdg.kr.write(|w| w.key().enable()); + self.iwdg.kr().write(|w| w.key().unlock()); // Set the prescaler let (prescaler, _) = Self::MAX_MILLIS_FOR_PRESCALER .iter() .find(|(_, max_millis)| *max_millis >= max_window_time.to_millis()) .expect("IWDG max time is greater than is possible"); - while self.iwdg.sr.read().pvu().bit_is_set() { + while self.iwdg.sr().read().pvu().bit_is_set() { cortex_m::asm::nop(); } - self.iwdg.pr.write(|w| w.pr().variant(*prescaler)); + self.iwdg.pr().write(|w| w.pr().variant(*prescaler)); // Reset the window value - while self.iwdg.sr.read().wvu().bit_is_set() { + while self.iwdg.sr().read().wvu().bit_is_set() { cortex_m::asm::nop(); } self.iwdg - .winr - .write(|w| w.win().bits(Self::MAX_COUNTER_VALUE as u16)); + .winr() + .write(|w| unsafe { w.win().bits(Self::MAX_COUNTER_VALUE as u16) }); // Calculate the counter values let reload_value = max_window_time.to_millis() * (Self::CLOCK_SPEED / 1000) @@ -106,25 +102,27 @@ impl IndependentWatchdog { / Self::get_prescaler_divider(prescaler); // Set the reload value - while self.iwdg.sr.read().rvu().bit_is_set() { + while self.iwdg.sr().read().rvu().bit_is_set() { cortex_m::asm::nop(); } - self.iwdg.rlr.write(|w| w.rl().bits(reload_value as u16)); + self.iwdg + .rlr() + .write(|w| unsafe { w.rl().bits(reload_value as u16) }); self.feed(); // Enable register access - self.iwdg.kr.write(|w| w.key().enable()); + self.iwdg.kr().write(|w| w.key().unlock()); // Set the window value - while self.iwdg.sr.read().wvu().bit_is_set() { + while self.iwdg.sr().read().wvu().bit_is_set() { cortex_m::asm::nop(); } self.iwdg - .winr - .write(|w| w.win().bits((reload_value - window_value) as u16)); + .winr() + .write(|w| unsafe { w.win().bits((reload_value - window_value) as u16) }); // Wait until everything is set - while self.iwdg.sr.read().bits() != 0 { + while self.iwdg.sr().read().bits() != 0 { cortex_m::asm::nop(); } @@ -136,16 +134,15 @@ impl IndependentWatchdog { self.start_windowed(0_u32.millis(), max_time.into()); } - fn get_prescaler_divider(prescaler: &PR_A) -> u32 { + fn get_prescaler_divider(prescaler: &PR) -> u32 { match prescaler { - PR_A::DivideBy4 => 4, - PR_A::DivideBy8 => 8, - PR_A::DivideBy16 => 16, - PR_A::DivideBy32 => 32, - PR_A::DivideBy64 => 64, - PR_A::DivideBy128 => 128, - PR_A::DivideBy256 => 256, - PR_A::DivideBy256bis => 256, + PR::DivideBy4 => 4, + PR::DivideBy8 => 8, + PR::DivideBy16 => 16, + PR::DivideBy32 => 32, + PR::DivideBy64 => 64, + PR::DivideBy128 => 128, + PR::DivideBy256 => 256, } } } diff --git a/src/opamp.rs b/src/opamp.rs index 0b549229..98cf644b 100644 --- a/src/opamp.rs +++ b/src/opamp.rs @@ -290,36 +290,36 @@ macro_rules! opamps { pub struct $opamp; impl LookupPgaGain for $opamp { - type PgaGainReg = crate::stm32::opamp::[<$opampreg _csr>]::PGA_GAIN_A; + type PgaGainReg = crate::stm32::opamp::[<$opampreg _csr>]::PGA_GAIN; fn pga_gain(mode: PgaMode, gain: Gain) -> Self::PgaGainReg { - use crate::stm32::opamp::[<$opampreg _csr>]::PGA_GAIN_A; + use crate::stm32::opamp::[<$opampreg _csr>]::PGA_GAIN; match (mode, gain) { - (PgaMode::Pga, Gain::Gain2) => PGA_GAIN_A::Gain2, - (PgaMode::Pga, Gain::Gain4) => PGA_GAIN_A::Gain4, - (PgaMode::Pga, Gain::Gain8) => PGA_GAIN_A::Gain8, - (PgaMode::Pga, Gain::Gain16) => PGA_GAIN_A::Gain16, - (PgaMode::Pga, Gain::Gain32) => PGA_GAIN_A::Gain32, - (PgaMode::Pga, Gain::Gain64) => PGA_GAIN_A::Gain64, - (PgaMode::PgaExternalFilter, Gain::Gain2) => PGA_GAIN_A::Gain2FilteringVinm0, - (PgaMode::PgaExternalFilter, Gain::Gain4) => PGA_GAIN_A::Gain4FilteringVinm0, - (PgaMode::PgaExternalFilter, Gain::Gain8) => PGA_GAIN_A::Gain8FilteringVinm0, - (PgaMode::PgaExternalFilter, Gain::Gain16) => PGA_GAIN_A::Gain16FilteringVinm0, - (PgaMode::PgaExternalFilter, Gain::Gain32) => PGA_GAIN_A::Gain32FilteringVinm0, - (PgaMode::PgaExternalFilter, Gain::Gain64) => PGA_GAIN_A::Gain64FilteringVinm0, - (PgaMode::PgaExternalBias, Gain::Gain2) => PGA_GAIN_A::Gain2InputVinm0, - (PgaMode::PgaExternalBias, Gain::Gain4) => PGA_GAIN_A::Gain4InputVinm0, - (PgaMode::PgaExternalBias, Gain::Gain8) => PGA_GAIN_A::Gain8InputVinm0, - (PgaMode::PgaExternalBias, Gain::Gain16) => PGA_GAIN_A::Gain16InputVinm0, - (PgaMode::PgaExternalBias, Gain::Gain32) => PGA_GAIN_A::Gain32InputVinm0, - (PgaMode::PgaExternalBias, Gain::Gain64) => PGA_GAIN_A::Gain64InputVinm0, - (PgaMode::PgaExternalBiasAndFilter, Gain::Gain2) => PGA_GAIN_A::Gain2InputVinm0filteringVinm1, - (PgaMode::PgaExternalBiasAndFilter, Gain::Gain4) => PGA_GAIN_A::Gain4InputVinm0filteringVinm1, - (PgaMode::PgaExternalBiasAndFilter, Gain::Gain8) => PGA_GAIN_A::Gain8InputVinm0filteringVinm1, - (PgaMode::PgaExternalBiasAndFilter, Gain::Gain16) => PGA_GAIN_A::Gain16InputVinm0filteringVinm1, - (PgaMode::PgaExternalBiasAndFilter, Gain::Gain32) => PGA_GAIN_A::Gain32InputVinm0filteringVinm1, - (PgaMode::PgaExternalBiasAndFilter, Gain::Gain64) => PGA_GAIN_A::Gain64InputVinm0filteringVinm1, + (PgaMode::Pga, Gain::Gain2) => PGA_GAIN::Gain2, + (PgaMode::Pga, Gain::Gain4) => PGA_GAIN::Gain4, + (PgaMode::Pga, Gain::Gain8) => PGA_GAIN::Gain8, + (PgaMode::Pga, Gain::Gain16) => PGA_GAIN::Gain16, + (PgaMode::Pga, Gain::Gain32) => PGA_GAIN::Gain32, + (PgaMode::Pga, Gain::Gain64) => PGA_GAIN::Gain64, + (PgaMode::PgaExternalFilter, Gain::Gain2) => PGA_GAIN::Gain2FilteringVinm0, + (PgaMode::PgaExternalFilter, Gain::Gain4) => PGA_GAIN::Gain4FilteringVinm0, + (PgaMode::PgaExternalFilter, Gain::Gain8) => PGA_GAIN::Gain8FilteringVinm0, + (PgaMode::PgaExternalFilter, Gain::Gain16) => PGA_GAIN::Gain16FilteringVinm0, + (PgaMode::PgaExternalFilter, Gain::Gain32) => PGA_GAIN::Gain32FilteringVinm0, + (PgaMode::PgaExternalFilter, Gain::Gain64) => PGA_GAIN::Gain64FilteringVinm0, + (PgaMode::PgaExternalBias, Gain::Gain2) => PGA_GAIN::Gain2InputVinm0, + (PgaMode::PgaExternalBias, Gain::Gain4) => PGA_GAIN::Gain4InputVinm0, + (PgaMode::PgaExternalBias, Gain::Gain8) => PGA_GAIN::Gain8InputVinm0, + (PgaMode::PgaExternalBias, Gain::Gain16) => PGA_GAIN::Gain16InputVinm0, + (PgaMode::PgaExternalBias, Gain::Gain32) => PGA_GAIN::Gain32InputVinm0, + (PgaMode::PgaExternalBias, Gain::Gain64) => PGA_GAIN::Gain64InputVinm0, + (PgaMode::PgaExternalBiasAndFilter, Gain::Gain2) => PGA_GAIN::Gain2InputVinm0filteringVinm1, + (PgaMode::PgaExternalBiasAndFilter, Gain::Gain4) => PGA_GAIN::Gain4InputVinm0filteringVinm1, + (PgaMode::PgaExternalBiasAndFilter, Gain::Gain8) => PGA_GAIN::Gain8InputVinm0filteringVinm1, + (PgaMode::PgaExternalBiasAndFilter, Gain::Gain16) => PGA_GAIN::Gain16InputVinm0filteringVinm1, + (PgaMode::PgaExternalBiasAndFilter, Gain::Gain32) => PGA_GAIN::Gain32InputVinm0filteringVinm1, + (PgaMode::PgaExternalBiasAndFilter, Gain::Gain64) => PGA_GAIN::Gain64InputVinm0filteringVinm1, } } } @@ -327,32 +327,32 @@ macro_rules! opamps { impl $opamp { #[inline(always)] unsafe fn _reset() { - (*crate::stm32::OPAMP::ptr()).[<$opampreg _csr>].reset() + (*crate::stm32::OPAMP::ptr()).[<$opampreg _csr>]().reset() } #[inline(always)] unsafe fn _disable_output() { - (*crate::stm32::OPAMP::ptr()).[<$opampreg _csr>].modify(|_, w| - w.opaintoen().adcchannel()) + (*crate::stm32::OPAMP::ptr()).[<$opampreg _csr>]().modify(|_, w| + w.opaintoen().adcchannel()); } #[inline(always)] unsafe fn _enable_output() { - (*crate::stm32::OPAMP::ptr()).[<$opampreg _csr>].modify(|_, w| - w.opaintoen().output_pin()) + (*crate::stm32::OPAMP::ptr()).[<$opampreg _csr>]().modify(|_, w| + w.opaintoen().output_pin()); } #[inline(always)] unsafe fn _lock() { // Write the lock bit - (*crate::stm32::OPAMP::ptr()).[<$opampreg _csr>].modify(|_, w| + (*crate::stm32::OPAMP::ptr()).[<$opampreg _csr>]().modify(|_, w| w.lock().set_bit()); // Write the lock bit for the corresponding TCMR register. // We don't currently expose TCMR functionality, but presumably // the user doesn't want anything changing if they care to set // the lock bit. - (*crate::stm32::OPAMP::ptr()).[<$opampreg _tcmr>].modify(|_, w| - w.lock().set_bit()) + (*crate::stm32::OPAMP::ptr()).[<$opampreg _tcmr>]().modify(|_, w| + w.lock().set_bit()); } } @@ -531,7 +531,7 @@ macro_rules! opamps { ) -> ( $(Disabled::<$opamp>,)* ) { - rcc.rb.apb2enr.modify(|_, w| w.syscfgen().set_bit()); + rcc.rb.apb2enr().modify(|_, w| w.syscfgen().set_bit()); ( $(Disabled::<$opamp> { opamp: PhantomData },)* @@ -581,9 +581,9 @@ macro_rules! opamps { ) -> Follower<$opamp, $input, InternalOutput> { let input = input.into(); unsafe { - use crate::stm32::opamp::[<$opampreg _csr>]::OPAINTOEN_A; + use crate::stm32::opamp::[<$opampreg _csr>]::OPAINTOEN; (*crate::stm32::OPAMP::ptr()) - .[<$opampreg _csr>] + .[<$opampreg _csr>]() .write(|csr_w| csr_w .vp_sel() @@ -591,7 +591,7 @@ macro_rules! opamps { .vm_sel() .output() .opaintoen() - .variant(OPAINTOEN_A::Adcchannel) + .variant(OPAINTOEN::Adcchannel) .opaen() .enabled() ); @@ -665,16 +665,16 @@ macro_rules! opamps { let non_inverting = non_inverting.into(); let inverting = inverting.into(); unsafe { - use crate::stm32::opamp::[<$opampreg _csr>]::OPAINTOEN_A; + use crate::stm32::opamp::[<$opampreg _csr>]::OPAINTOEN; (*crate::stm32::OPAMP::ptr()) - .[<$opampreg _csr>] + .[<$opampreg _csr>]() .write(|csr_w| csr_w.vp_sel() .$non_inverting_mask() .vm_sel() .$inverting_mask() .opaintoen() - .variant(OPAINTOEN_A::Adcchannel) + .variant(OPAINTOEN::Adcchannel) .opaen() .enabled() ); @@ -725,10 +725,10 @@ macro_rules! opamps { /// Configures the opamp for programmable gain operation. unsafe fn write_pga_reg(gain: Gain, mode: PgaMode, output_enable: bool) { - use crate::stm32::opamp::[<$opampreg _csr>]::OPAINTOEN_A; + use crate::stm32::opamp::[<$opampreg _csr>]::OPAINTOEN; (*crate::stm32::OPAMP::ptr()) - .[<$opampreg _csr>] + .[<$opampreg _csr>]() .write(|csr_w| csr_w.vp_sel() .$non_inverting_mask() @@ -738,8 +738,8 @@ macro_rules! opamps { .variant($opamp::pga_gain(mode, gain)) .opaintoen() .variant(match output_enable { - true => OPAINTOEN_A::OutputPin, - false => OPAINTOEN_A::Adcchannel, + true => OPAINTOEN::OutputPin, + false => OPAINTOEN::Adcchannel, }) .opaen() .enabled() @@ -864,7 +864,8 @@ macro_rules! opamps { }; } -#[cfg(any(feature = "stm32g431", feature = "stm32g441", feature = "stm32g471",))] +// TODO: Figure out a way to not duplicate this 3 times +#[cfg(any(feature = "stm32g431", feature = "stm32g441"))] opamps! { Opamp1 => opamp1: { vinm0: crate::gpio::gpioa::PA3, @@ -911,6 +912,67 @@ opamps! { }, } +#[cfg(any(feature = "stm32g471", feature = "stm32g491", feature = "stm32g4a1"))] +opamps! { + Opamp1 => opamp1: { + vinm0: crate::gpio::gpioa::PA3, + vinm1: crate::gpio::gpioc::PC5, + inverting: { + crate::gpio::gpioa::PA3: vinm0, + crate::gpio::gpioc::PC5: vinm1, + }, + non_inverting: { + crate::gpio::gpioa::PA1: vinp0, + crate::gpio::gpioa::PA3: vinp1, + crate::gpio::gpioa::PA7: vinp2, + }, + output: crate::gpio::gpioa::PA2, + }, + Opamp2 => opamp2: { + vinm0: crate::gpio::gpioa::PA5, + vinm1: crate::gpio::gpioc::PC5, + inverting: { + crate::gpio::gpioa::PA5: vinm0, + crate::gpio::gpioc::PC5: vinm1, + }, + non_inverting: { + crate::gpio::gpioa::PA7: vinp0, + crate::gpio::gpiob::PB14: vinp1, + crate::gpio::gpiob::PB0: vinp2, + crate::gpio::gpiod::PD14: vinp3, + }, + output: crate::gpio::gpioa::PA6, + }, + Opamp3 => opamp3: { + vinm0: crate::gpio::gpiob::PB2, + vinm1: crate::gpio::gpiob::PB10, + inverting: { + crate::gpio::gpiob::PB2: vinm0, + crate::gpio::gpiob::PB10: vinm1, + }, + non_inverting: { + crate::gpio::gpiob::PB0: vinp0, + crate::gpio::gpiob::PB13: vinp1, + crate::gpio::gpioa::PA1: vinp2, + }, + output: crate::gpio::gpiob::PB1, + }, + Opamp6 => opamp6: { + vinm0: crate::gpio::gpioa::PA1, + vinm1: crate::gpio::gpiob::PB1, + inverting: { + crate::gpio::gpioa::PA1: vinm0, + crate::gpio::gpiob::PB1: vinm1, + }, + non_inverting: { + crate::gpio::gpiob::PB12: vinp0, + crate::gpio::gpiod::PD9: vinp1, + crate::gpio::gpiob::PB13: vinp2, + }, + output: crate::gpio::gpiob::PB11, + }, +} + #[cfg(any( feature = "stm32g473", feature = "stm32g474", diff --git a/src/pwm.rs b/src/pwm.rs index e25d8a82..c5c86e07 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -875,7 +875,7 @@ pins! { feature = "stm32g483", feature = "stm32g484", feature = "stm32g491", - feature = "stm32g4a1" + feature = "stm32g4a1", ))] pins! { TIM20: @@ -1175,21 +1175,21 @@ macro_rules! tim_hal { }; // Write prescale - tim.psc.write(|w| { unsafe { w.psc().bits(prescale as u16) } }); + tim.psc().write(|w| { unsafe { w.psc().bits(prescale as u16) } }); // Write period - tim.arr.write(|w| { unsafe { w.arr().bits(period.into()) } }); + tim.arr().write(|w| { unsafe { w.arr().bits(period.into()) } }); // BDTR: Advanced-control timers $( // Set CCxP = OCxREF / CCxNP = !OCxREF // Refer to RM0433 Rev 6 - Table 324. - tim.$bdtr.write(|w| + tim.$bdtr().write(|w| w.moe().$moe_set() ); )* - tim.cr1.write(|w| w.cen().set_bit()); + tim.cr1().write(|w| w.cen().set_bit()); unsafe { MaybeUninit::::uninit().assume_init() } } @@ -1247,20 +1247,20 @@ macro_rules! tim_hal { }; // Write prescaler - tim.psc.write(|w| unsafe { w.psc().bits(prescaler as u16) }); + tim.psc().write(|w| unsafe { w.psc().bits(prescaler as u16) }); // Write period - tim.arr.write(|w| unsafe { w.arr().bits(period.into()) }); + tim.arr().write(|w| unsafe { w.arr().bits(period.into()) }); $( let (dtg, ckd) = calculate_deadtime(self.base_freq, self.deadtime); match ckd { - 1 => tim.cr1.modify(|_, w| unsafe { w.ckd().bits(0) }), - 2 => tim.cr1.modify(|_, w| unsafe { w.ckd().bits(1) }), - 4 => tim.cr1.modify(|_, w| unsafe { w.ckd().bits(2) }), + 1 => tim.cr1().modify(|_, w| unsafe { w.ckd().bits(0) }), + 2 => tim.cr1().modify(|_, w| unsafe { w.ckd().bits(1) }), + 4 => tim.cr1().modify(|_, w| unsafe { w.ckd().bits(2) }), _ => panic!("Should be unreachable, invalid deadtime prescaler"), - } + }; let bkp = match self.fault_polarity { Polarity::ActiveLow => false, @@ -1274,12 +1274,12 @@ macro_rules! tim_hal { // BKE = 1 -> break is enabled // BKP = 0 for active low, 1 for active high // Safety: bkf is set to a constant value (1) that is a valid value for the field per the reference manual - unsafe { tim.$bdtr.write(|w| w.dtg().bits(dtg).bkf().bits(1).aoe().clear_bit().bke().set_bit().bkp().bit(bkp).moe().$moe_set()); } + unsafe { tim.$bdtr().write(|w| w.dtg().bits(dtg).bkf().bits(1).aoe().clear_bit().bke().set_bit().bkp().bit(bkp).moe().$moe_set()); } // AF1: // BKINE = 1 -> break input enabled // BKINP should make input active high (BDTR BKP will set polarity), bit value varies timer to timer - tim.$af1.write(|w| w.bkine().set_bit().bkinp().$bkinp_setting()); + tim.$af1().write(|w| w.bkine().set_bit().bkinp().$bkinp_setting()); } $( // Not all timers that have break inputs have break2 inputs @@ -1290,37 +1290,37 @@ macro_rules! tim_hal { // BK2E = 1 -> break is enabled // BK2P = 0 for active low, 1 for active high // Safety: bkf is set to a constant value (1) that is a valid value for the field per the reference manual - unsafe { tim.$bdtr.write(|w| w.dtg().bits(dtg).bk2f().bits(1).aoe().clear_bit().bk2e().set_bit().bk2p().bit(bkp).moe().$moe_set()); } + unsafe { tim.$bdtr().write(|w| w.dtg().bits(dtg).bk2f().bits(1).aoe().clear_bit().bk2e().set_bit().bk2p().bit(bkp).moe().$moe_set()); } // AF2: // BKINE = 1 -> break input enabled // BKINP should make input active high (BDTR BKP will set polarity), bit value varies timer to timer - tim.af2.write(|w| w.bkine().set_bit().bk2inp().$bk2inp_setting()); + tim.af2().write(|w| w.bkine().set_bit().bk2inp().$bk2inp_setting()); } )* else { // Safety: the DTG field of BDTR allows any 8-bit deadtime value and the dtg variable is u8 unsafe { - tim.$bdtr.write(|w| w.dtg().bits(dtg).aoe().clear_bit().moe().$moe_set()); + tim.$bdtr().write(|w| w.dtg().bits(dtg).aoe().clear_bit().moe().$moe_set()); } } // BDTR: Advanced-control timers // Set CCxP = OCxREF / CCxNP = !OCxREF // Refer to RM0433 Rev 6 - Table 324. - tim.$bdtr.modify(|_, w| w.moe().$moe_set()); + tim.$bdtr().modify(|_, w| w.moe().$moe_set()); )* $( match self.alignment { Alignment::Left => { }, - Alignment::Right => { tim.cr1.modify(|_, w| w.dir().set_bit()); }, // Downcounter - Alignment::Center => { tim.cr1.modify(|_, w| unsafe { w.$cms().bits(3) }); } // Center-aligned mode 3 + Alignment::Right => { tim.cr1().modify(|_, w| w.dir().set_bit()); }, // Downcounter + Alignment::Center => { tim.cr1().modify(|_, w| unsafe { w.$cms().bits(3) }); } // Center-aligned mode 3 } )* - tim.cr1.modify(|_, w| w.cen().set_bit()); + tim.cr1().modify(|_, w| w.cen().set_bit()); unsafe { MaybeUninit::<(PwmControl<$TIMX, FAULT>, PINS::Channel)>::uninit() @@ -1428,19 +1428,19 @@ macro_rules! tim_hal { fn is_fault_active(&self) -> bool { let tim = unsafe { &*$TIMX::ptr() }; - !tim.$bdtr.read().moe().bit() + !tim.$bdtr().read().moe().bit() } fn clear_fault(&mut self) { let tim = unsafe { &*$TIMX::ptr() }; - tim.$bdtr.modify(|_, w| w.moe().set_bit()); + tim.$bdtr().modify(|_, w| w.moe().set_bit()); } fn set_fault(&mut self) { let tim = unsafe { &*$TIMX::ptr() }; - tim.$bdtr.modify(|_, w| w.moe().clear_bit()); + tim.$bdtr().modify(|_, w| w.moe().clear_bit()); } } )* @@ -1546,7 +1546,7 @@ macro_rules! tim_pin_hal { // Even though the field is 20 bits long for 16-bit counters, only 16 bits are // valid, so we convert to the appropriate type. - let arr = tim.arr.read().arr().bits() as $typ; + let arr = tim.arr().read().arr().bits() as $typ; // One PWM cycle is ARR+1 counts long // Valid PWM duty cycles are 0 to ARR+1 @@ -1574,7 +1574,7 @@ macro_rules! tim_pin_hal { where Pwm<$TIMX, $CH, COMP, POL, NPOL>: PwmPinEnable { fn max_duty_cycle(&self) -> u16 { let tim = unsafe { &*$TIMX::ptr() }; - let arr = tim.arr.read().arr().bits() as $typ; + let arr = tim.arr().read().arr().bits() as $typ; let arr = (arr >> (8*(size_of::<$typ>() - size_of::()))) as u16; // see note above if arr == u16::MAX { @@ -1587,7 +1587,8 @@ macro_rules! tim_pin_hal { // hal trait always has 16 bit resolution let duty = (duty as $typ) << (8*(size_of::<$typ>() - size_of::())); let tim = unsafe { &*$TIMX::ptr() }; - Ok(tim.$ccrx().write(|w| unsafe { w.ccr().bits(duty.into()) })) + tim.$ccrx().write(|w| unsafe { w.ccr().bits(duty.into()) }); + Ok(()) } } @@ -1596,12 +1597,12 @@ macro_rules! tim_pin_hal { fn ccer_enable(&mut self) { let tim = unsafe { &*$TIMX::ptr() }; - tim.ccer.modify(|_, w| w.$ccxe().set_bit()); + tim.ccer().modify(|_, w| w.$ccxe().set_bit()); } fn ccer_disable(&mut self) { let tim = unsafe { &*$TIMX::ptr() }; - tim.ccer.modify(|_, w| w.$ccxe().clear_bit()); + tim.ccer().modify(|_, w| w.$ccxe().clear_bit()); } } @@ -1609,7 +1610,7 @@ macro_rules! tim_pin_hal { pub fn into_active_low(self) -> Pwm<$TIMX, $CH, COMP, ActiveLow, NPOL> { let tim = unsafe { &*$TIMX::ptr() }; - tim.ccer.modify(|_, w| w.$ccxp().set_bit()); + tim.ccer().modify(|_, w| w.$ccxp().set_bit()); Pwm { _channel: PhantomData, @@ -1625,7 +1626,7 @@ macro_rules! tim_pin_hal { pub fn into_active_high(self) -> Pwm<$TIMX, $CH, COMP, ActiveHigh, NPOL> { let tim = unsafe { &*$TIMX::ptr() }; - tim.ccer.modify(|_, w| w.$ccxp().clear_bit()); + tim.ccer().modify(|_, w| w.$ccxp().clear_bit()); Pwm { _channel: PhantomData, @@ -1644,12 +1645,12 @@ macro_rules! tim_pin_hal { fn ccer_enable(&mut self) { let tim = unsafe { &*$TIMX::ptr() }; - tim.ccer.modify(|_, w| w.$ccxe().set_bit()); + tim.ccer().modify(|_, w| w.$ccxe().set_bit()); } fn ccer_disable(&mut self) { let tim = unsafe { &*$TIMX::ptr() }; - tim.ccer.modify(|_, w| w.$ccxe().clear_bit()); + tim.ccer().modify(|_, w| w.$ccxe().clear_bit()); } } @@ -1658,12 +1659,12 @@ macro_rules! tim_pin_hal { fn ccer_enable(&mut self) { let tim = unsafe { &*$TIMX::ptr() }; - tim.ccer.modify(|_, w| w.$ccxe().set_bit().$ccxne().set_bit()); + tim.ccer().modify(|_, w| w.$ccxe().set_bit().$ccxne().set_bit()); } fn ccer_disable(&mut self) { let tim = unsafe { &*$TIMX::ptr() }; - tim.ccer.modify(|_, w| w.$ccxe().clear_bit().$ccxne().clear_bit()); + tim.ccer().modify(|_, w| w.$ccxe().clear_bit().$ccxne().clear_bit()); } } @@ -1673,7 +1674,7 @@ macro_rules! tim_pin_hal { // Make sure we aren't switching to complementary after we enable the channel let tim = unsafe { &*$TIMX::ptr() }; - let enabled = tim.ccer.read().$ccxe().bit(); + let enabled = tim.ccer().read().$ccxe().bit(); assert!(!enabled); @@ -1691,7 +1692,7 @@ macro_rules! tim_pin_hal { pub fn into_comp_active_low(self) -> Pwm<$TIMX, $CH, ComplementaryEnabled, POL, ActiveLow> { let tim = unsafe { &*$TIMX::ptr() }; - tim.ccer.modify(|_, w| w.$ccxnp().set_bit()); + tim.ccer().modify(|_, w| w.$ccxnp().set_bit()); Pwm { _channel: PhantomData, @@ -1707,7 +1708,7 @@ macro_rules! tim_pin_hal { pub fn into_comp_active_high(self) -> Pwm<$TIMX, $CH, ComplementaryEnabled, POL, ActiveHigh> { let tim = unsafe { &*$TIMX::ptr() }; - tim.ccer.modify(|_, w| w.$ccxnp().clear_bit()); + tim.ccer().modify(|_, w| w.$ccxnp().clear_bit()); Pwm { _channel: PhantomData, @@ -1844,19 +1845,19 @@ macro_rules! lptim_hal { assert!(arr > 0); // CFGR - tim.cfgr.modify(|_, w| unsafe { w.presc().bits(prescale) }); + tim.cfgr().modify(|_, w| unsafe { w.presc().bits(prescale) }); // Enable - tim.cr.modify(|_, w| w.enable().set_bit()); + tim.cr().modify(|_, w| w.enable().set_bit()); // Write ARR: LPTIM must be enabled - tim.arr.write(|w| unsafe { w.arr().bits(arr as u16) }); - while !tim.isr.read().arrok().bit_is_set() {} - tim.icr.write(|w| w.arrokcf().set_bit()); + tim.arr().write(|w| unsafe { w.arr().bits(arr as u16) }); + while !tim.isr().read().arrok().bit_is_set() {} + tim.icr().write(|w| w.arrokcf().set_bit()); // PWM output is disabled by default, disable the // entire timer - tim.cr.modify(|_, w| w.enable().clear_bit()); + tim.cr().modify(|_, w| w.enable().clear_bit()); unsafe { MaybeUninit::::uninit().assume_init() } } @@ -1872,33 +1873,33 @@ macro_rules! lptim_hal { // LPTIM only has one output, so we disable the // entire timer - tim.cr.modify(|_, w| w.enable().clear_bit()); + tim.cr().modify(|_, w| w.enable().clear_bit()); } fn enable(&mut self) { let tim = unsafe { &*$TIMX::ptr() }; - tim.cr.modify(|_, w| w.cntstrt().set_bit().enable().set_bit()); + tim.cr().modify(|_, w| w.cntstrt().set_bit().enable().set_bit()); } fn get_duty(&self) -> u16 { let tim = unsafe { &*$TIMX::ptr() }; - tim.cmp.read().cmp().bits() + tim.cmp().read().cmp().bits() } fn get_max_duty(&self) -> u16 { let tim = unsafe { &*$TIMX::ptr() }; - tim.arr.read().arr().bits() + tim.arr().read().arr().bits() } fn set_duty(&mut self, duty: u16) { let tim = unsafe { &*$TIMX::ptr() }; - tim.cmp.write(|w| unsafe { w.cmp().bits(duty) }); - while !tim.isr.read().cmpok().bit_is_set() {} - tim.icr.write(|w| w.cmpokcf().set_bit()); + tim.cmp().write(|w| unsafe { w.cmp().bits(duty) }); + while !tim.isr().read().cmpok().bit_is_set() {} + tim.icr().write(|w| w.cmpokcf().set_bit()); } } @@ -1908,14 +1909,16 @@ macro_rules! lptim_hal { impl embedded_hal::pwm::SetDutyCycle for Pwm<$TIMX, C1, ComplementaryImpossible, ActiveHigh, ActiveHigh> { fn max_duty_cycle(&self) -> u16 { let tim = unsafe { &*$TIMX::ptr() }; - tim.arr.read().arr().bits() + tim.arr().read().arr().bits() } fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { let tim = unsafe { &*$TIMX::ptr() }; - tim.cmp.write(|w| unsafe { w.cmp().bits(duty) }); - while !tim.isr.read().cmpok().bit_is_set() {} - Ok(tim.icr.write(|w| w.cmpokcf().set_bit())) + tim.cmp().write(|w| unsafe { w.cmp().bits(duty) }); + while !tim.isr().read().cmpok().bit_is_set() {} + tim.icr().write(|w| w.cmpokcf().set_bit()); + + Ok(()) } } )+ diff --git a/src/pwr.rs b/src/pwr.rs index bc5d8d0d..f451fbc7 100644 --- a/src/pwr.rs +++ b/src/pwr.rs @@ -103,10 +103,10 @@ pub(crate) fn current_vos() -> VoltageScale { // NOTE(unsafe): Read-only access let pwr = unsafe { &*PWR::ptr() }; - match pwr.cr1.read().vos().bits() { + match pwr.cr1().read().vos().bits() { 0b00 => unreachable!(), 0b01 => VoltageScale::Range1 { - enable_boost: pwr.cr5.read().r1mode().bit(), + enable_boost: pwr.cr5().read().r1mode().bit(), }, 0b10 => VoltageScale::Range2, 0b11 => unreachable!(), @@ -129,10 +129,10 @@ pub(crate) unsafe fn set_vos(vos: VoltageScale) { VoltageScale::Range1 { .. } => 0b01, VoltageScale::Range2 => 0b10, }; - pwr.cr1.modify(|_r, w| w.vos().bits(vos)); + pwr.cr1().modify(|_r, w| w.vos().bits(vos)); // Wait for ready - while pwr.sr2.read().vosf().bit() {} + while pwr.sr2().read().vosf().bit() {} } /// Set new voltage scale @@ -143,5 +143,5 @@ pub(crate) unsafe fn set_vos(vos: VoltageScale) { pub(crate) unsafe fn set_boost(enable_boost: bool) { let pwr = unsafe { &*PWR::ptr() }; let r1mode = !enable_boost; - pwr.cr5.modify(|_r, w| w.r1mode().bit(r1mode)); + pwr.cr5().modify(|_r, w| w.r1mode().bit(r1mode)); } diff --git a/src/rcc/clockout.rs b/src/rcc/clockout.rs index 07a3cdd9..b9f49944 100644 --- a/src/rcc/clockout.rs +++ b/src/rcc/clockout.rs @@ -11,12 +11,12 @@ pub struct Lsco { impl Lsco { pub fn enable(&self) { let rcc = unsafe { &(*RCC::ptr()) }; - rcc.bdcr.modify(|_, w| w.lscoen().set_bit()); + rcc.bdcr().modify(|_, w| w.lscoen().set_bit()); } pub fn disable(&self) { let rcc = unsafe { &(*RCC::ptr()) }; - rcc.bdcr.modify(|_, w| w.lscoen().clear_bit()); + rcc.bdcr().modify(|_, w| w.lscoen().clear_bit()); } pub fn release(self) -> LscoPin { @@ -41,7 +41,7 @@ impl LSCOExt for LscoPin { false } }; - rcc.rb.bdcr.modify(|_, w| w.lscosel().bit(src_select_bit)); + rcc.rb.bdcr().modify(|_, w| w.lscosel().bit(src_select_bit)); Lsco { pin: self.into_alternate(), } @@ -56,13 +56,13 @@ pub struct Mco { impl Mco { pub fn enable(&self) { let rcc = unsafe { &(*RCC::ptr()) }; - rcc.cfgr + rcc.cfgr() .modify(|_, w| unsafe { w.mcosel().bits(self.src_bits) }); } pub fn disable(&self) { let rcc = unsafe { &(*RCC::ptr()) }; - rcc.cfgr.modify(|_, w| unsafe { w.mcosel().bits(0) }); + rcc.cfgr().modify(|_, w| unsafe { w.mcosel().bits(0) }); } pub fn release(self) -> PIN { @@ -89,7 +89,7 @@ macro_rules! mco { Prescaler::Div64 => 0b110, _ => 0b111, }; - rcc.rb.cfgr.modify(|r, w| unsafe { + rcc.rb.cfgr().modify(|r, w| unsafe { w.bits((r.bits() & !(0b111 << 28)) | (psc_bits << 28)) }); diff --git a/src/rcc/config.rs b/src/rcc/config.rs index 6998eafa..79eb7124 100644 --- a/src/rcc/config.rs +++ b/src/rcc/config.rs @@ -46,6 +46,16 @@ pub enum PllSrc { HSE_BYPASS(Hertz), } +impl PllSrc { + pub const fn frequency(self) -> Hertz { + match self { + PllSrc::HSI => Hertz::MHz(16), + PllSrc::HSE(f) => f, + PllSrc::HSE_BYPASS(f) => f, + } + } +} + /// Divider for the PLL clock input (M) /// This must be set based on the input clock to keep the PLL input frequency within the limits /// specified in the datasheet. @@ -70,11 +80,11 @@ pub enum PllMDiv { } impl PllMDiv { - pub fn divisor(&self) -> u32 { + pub const fn divisor(&self) -> u32 { (*self as u32) + 1 } - pub fn register_setting(&self) -> u8 { + pub const fn register_setting(&self) -> u8 { *self as u8 } } @@ -89,11 +99,11 @@ pub enum PllQDiv { } impl PllQDiv { - pub fn divisor(&self) -> u32 { + pub const fn divisor(&self) -> u32 { ((*self as u32) + 1) * 2 } - pub fn register_setting(&self) -> u8 { + pub const fn register_setting(&self) -> u8 { *self as u8 } } @@ -108,11 +118,11 @@ pub enum PllRDiv { } impl PllRDiv { - pub fn divisor(&self) -> u32 { + pub const fn divisor(&self) -> u32 { ((*self as u32) + 1) * 2 } - pub fn register_setting(&self) -> u8 { + pub const fn register_setting(&self) -> u8 { *self as u8 } } @@ -157,11 +167,11 @@ pub enum PllPDiv { } impl PllPDiv { - pub fn divisor(&self) -> u32 { + pub const fn divisor(&self) -> u32 { *self as u32 } - pub fn register_setting(&self) -> u8 { + pub const fn register_setting(&self) -> u8 { *self as u8 } } @@ -292,11 +302,11 @@ pub enum PllNMul { } impl PllNMul { - pub fn multiplier(&self) -> u32 { + pub const fn multiplier(&self) -> u32 { *self as u32 } - pub fn register_setting(&self) -> u8 { + pub const fn register_setting(&self) -> u8 { *self as u8 } } @@ -312,8 +322,8 @@ pub struct PllConfig { pub p: Option, } -impl Default for PllConfig { - fn default() -> PllConfig { +impl PllConfig { + pub const fn new() -> Self { PllConfig { mux: PllSrc::HSI, m: PllMDiv::DIV_2, @@ -325,6 +335,12 @@ impl Default for PllConfig { } } +impl Default for PllConfig { + fn default() -> PllConfig { + Self::new() + } +} + /// FDCAN Clock Source #[allow(clippy::upper_case_acronyms)] pub enum FdCanClockSource { @@ -352,49 +368,61 @@ pub struct Config { } impl Config { - pub fn new(mux: SysClockSrc) -> Self { - Config::default().clock_src(mux) + pub const fn new(sys_mux: SysClockSrc) -> Self { + Config { + sys_mux, + pll_cfg: PllConfig::new(), + ahb_psc: Prescaler::NotDivided, + apb1_psc: Prescaler::NotDivided, + apb2_psc: Prescaler::NotDivided, + enable_boost: false, + fdcansel: FdCanClockSource::HSE, + } } - pub fn pll() -> Self { - Config::default().clock_src(SysClockSrc::PLL) + pub const fn const_default() -> Self { + Self::new(SysClockSrc::HSI) } - pub fn hsi() -> Self { - Config::default().clock_src(SysClockSrc::HSI) + pub const fn pll() -> Self { + Config::const_default().clock_src(SysClockSrc::PLL) } - pub fn clock_src(mut self, mux: SysClockSrc) -> Self { + pub const fn hsi() -> Self { + Config::const_default().clock_src(SysClockSrc::HSI) + } + + pub const fn clock_src(mut self, mux: SysClockSrc) -> Self { self.sys_mux = mux; self } - pub fn pll_cfg(mut self, cfg: PllConfig) -> Self { + pub const fn pll_cfg(mut self, cfg: PllConfig) -> Self { self.pll_cfg = cfg; self } - pub fn ahb_psc(mut self, psc: Prescaler) -> Self { + pub const fn ahb_psc(mut self, psc: Prescaler) -> Self { self.ahb_psc = psc; self } - pub fn apb1_psc(mut self, psc: Prescaler) -> Self { + pub const fn apb1_psc(mut self, psc: Prescaler) -> Self { self.apb1_psc = psc; self } - pub fn apb2_psc(mut self, psc: Prescaler) -> Self { + pub const fn apb2_psc(mut self, psc: Prescaler) -> Self { self.apb2_psc = psc; self } - pub fn boost(mut self, enable_boost: bool) -> Self { + pub const fn boost(mut self, enable_boost: bool) -> Self { self.enable_boost = enable_boost; self } - pub fn fdcan_src(mut self, mux: FdCanClockSource) -> Self { + pub const fn fdcan_src(mut self, mux: FdCanClockSource) -> Self { self.fdcansel = mux; self } @@ -402,14 +430,6 @@ impl Config { impl Default for Config { fn default() -> Config { - Config { - sys_mux: SysClockSrc::HSI, - pll_cfg: PllConfig::default(), - ahb_psc: Prescaler::NotDivided, - apb1_psc: Prescaler::NotDivided, - apb2_psc: Prescaler::NotDivided, - enable_boost: false, - fdcansel: FdCanClockSource::HSE, - } + Config::const_default() } } diff --git a/src/rcc/enable.rs b/src/rcc/enable.rs index 4ab3d330..c8696746 100644 --- a/src/rcc/enable.rs +++ b/src/rcc/enable.rs @@ -89,7 +89,9 @@ bus! { feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", - feature = "stm32g484" + feature = "stm32g484", + feature = "stm32g491", + feature = "stm32g4a1", ))] bus! { ADC3 => (AHB2, 14), @@ -158,6 +160,16 @@ bus! { FDCAN2 => (APB1_1, 25), } +#[cfg(any( + feature = "stm32g473", + feature = "stm32g474", + feature = "stm32g483", + feature = "stm32g484", +))] +bus! { + FDCAN3 => (APB1_1, 25), +} + #[cfg(any( feature = "stm32g471", feature = "stm32g473", @@ -167,10 +179,22 @@ bus! { ))] bus! { TIM5 => (APB1_1, 3), - UART5 => (APB1_1, 20), I2C4 => (APB1_2, 1), } +#[cfg(any( + feature = "stm32g471", + feature = "stm32g473", + feature = "stm32g474", + feature = "stm32g483", + feature = "stm32g484", + feature = "stm32g491", + feature = "stm32g4a1", +))] +bus! { + UART5 => (APB1_1, 20), +} + bus! { SYSCFG => (APB2, 0), TIM1 => (APB2, 11), @@ -198,10 +222,11 @@ bus! { feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", - feature = "stm32g484" + feature = "stm32g484", + feature = "stm32g491", + feature = "stm32g4a1", ))] bus! { - FDCAN3 => (APB1_1, 25), TIM20 => (APB2, 20), } @@ -214,3 +239,8 @@ bus! { HRTIM_TIME => (APB2, 26), HRTIM_TIMF => (APB2, 26), } + +#[cfg(any(feature = "stm32g474", feature = "stm32g484"))] +bus! { + HRTIM_COMMON => (APB2, 26), +} diff --git a/src/rcc/mod.rs b/src/rcc/mod.rs index 368130b1..4e32dd63 100644 --- a/src/rcc/mod.rs +++ b/src/rcc/mod.rs @@ -190,7 +190,7 @@ impl Rcc { Self::configure_wait_states(&pwr_cfg, sys_freq); - self.rb.cfgr.modify(|_, w| unsafe { + self.rb.cfgr().modify(|_, w| unsafe { w.hpre() .bits(ahb_psc_bits) .ppre1() @@ -201,7 +201,7 @@ impl Rcc { .bits(sw_bits) }); - while self.rb.cfgr.read().sws().bits() != sw_bits {} + while self.rb.cfgr().read().sws().bits() != sw_bits {} // From RM: // The timer clock frequencies are automatically defined by hardware. There are two cases: @@ -219,7 +219,7 @@ impl Rcc { }; // Configure FDCAN clock source. - self.rb.ccipr.modify(|_, w| unsafe { + self.rb.ccipr().modify(|_, w| unsafe { // This is sound, as `FdCanClockSource` only contains valid values for this field. w.fdcansel().bits(rcc_cfg.fdcansel as u8) }); @@ -240,15 +240,15 @@ impl Rcc { } pub fn unlock_rtc(&mut self) { - self.rb.apb1enr1.modify(|_, w| w.pwren().set_bit()); + self.rb.apb1enr1().modify(|_, w| w.pwren().set_bit()); let pwr = unsafe { &(*PWR::ptr()) }; - pwr.cr1.modify(|_, w| w.dbp().set_bit()); + pwr.cr1().modify(|_, w| w.dbp().set_bit()); } fn config_pll(&self, pll_cfg: PllConfig) -> PLLClocks { // Disable PLL - self.rb.cr.modify(|_, w| w.pllon().clear_bit()); - while self.rb.cr.read().pllrdy().bit_is_set() {} + self.rb.cr().modify(|_, w| w.pllon().clear_bit()); + while self.rb.cr().read().pllrdy().bit_is_set() {} // Enable the input clock feeding the PLL let (pll_input_freq, pll_src_bits) = match pll_cfg.mux { @@ -283,7 +283,7 @@ impl Rcc { .map(|r| ((pll_freq / r.divisor()).Hz(), r.register_setting())); // Set the M input divider, the N multiplier for the PLL, and the PLL source. - self.rb.pllcfgr.modify(|_, w| unsafe { + self.rb.pllcfgr().modify(|_, w| unsafe { // Set N, M, and source let w = w .plln() @@ -317,8 +317,8 @@ impl Rcc { }); // Enable PLL - self.rb.cr.modify(|_, w| w.pllon().set_bit()); - while self.rb.cr.read().pllrdy().bit_is_clear() {} + self.rb.cr().modify(|_, w| w.pllon().set_bit()); + while self.rb.cr().read().pllrdy().bit_is_clear() {} PLLClocks { r: r.map(|r| r.0), @@ -370,7 +370,7 @@ impl Rcc { unsafe { // Adjust flash wait states let flash = &(*FLASH::ptr()); - flash.acr.modify(|_, w| w.latency().bits(latency)) + flash.acr().modify(|_, w| w.latency().bits(latency)); } } @@ -387,11 +387,11 @@ impl Rcc { // The sequence to switch from Range11 normal mode to Range1 boost mode is: // 1. The system clock must be divided by 2 using the AHB prescaler before switching to a // higher system frequency. - let half_apb = (self.rb.cfgr.read().hpre().bits() + 1).clamp(0b1000, 0b1111); + let half_apb = (self.rb.cfgr().read().hpre().bits() + 1).clamp(0b1000, 0b1111); self.rb - .cfgr + .cfgr() .modify(|_r, w| unsafe { w.hpre().bits(half_apb) }); - while self.rb.cfgr.read().hpre().bits() != half_apb {} + while self.rb.cfgr().read().hpre().bits() != half_apb {} // 2. Clear the R1MODE bit is in the PWR_CR5 register. unsafe { pwr::set_boost(true) }; @@ -400,7 +400,7 @@ impl Rcc { Self::configure_wait_states(pwr_cfg, sys_freq); // 4. Configure and switch to new system frequency. - self.rb.cfgr.modify(|_, w| unsafe { + self.rb.cfgr().modify(|_, w| unsafe { w.ppre1() .bits(apb1_psc_bits) .ppre2() @@ -409,7 +409,7 @@ impl Rcc { .bits(sw_bits) }); - while self.rb.cfgr.read().sws().bits() != sw_bits {} + while self.rb.cfgr().read().sws().bits() != sw_bits {} // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK // clock frequency. @@ -420,41 +420,41 @@ impl Rcc { cortex_m::asm::delay(delay_cycles); self.rb - .cfgr + .cfgr() .modify(|_, w| unsafe { w.hpre().bits(ahb_psc_bits) }); } pub(crate) fn enable_hsi(&self) { - self.rb.cr.modify(|_, w| w.hsion().set_bit()); - while self.rb.cr.read().hsirdy().bit_is_clear() {} + self.rb.cr().modify(|_, w| w.hsion().set_bit()); + while self.rb.cr().read().hsirdy().bit_is_clear() {} } pub(crate) fn enable_hse(&self, bypass: bool) { self.rb - .cr + .cr() .modify(|_, w| w.hseon().set_bit().hsebyp().bit(bypass)); - while self.rb.cr.read().hserdy().bit_is_clear() {} + while self.rb.cr().read().hserdy().bit_is_clear() {} } pub(crate) fn enable_lse(&self, bypass: bool) { self.rb - .bdcr + .bdcr() .modify(|_, w| w.lseon().set_bit().lsebyp().bit(bypass)); - while self.rb.bdcr.read().lserdy().bit_is_clear() {} + while self.rb.bdcr().read().lserdy().bit_is_clear() {} } pub(crate) fn enable_lsi(&self) { - self.rb.csr.modify(|_, w| w.lsion().set_bit()); - while self.rb.csr.read().lsirdy().bit_is_clear() {} + self.rb.csr().modify(|_, w| w.lsion().set_bit()); + while self.rb.csr().read().lsirdy().bit_is_clear() {} } pub fn enable_hsi48(&self) { - self.rb.crrcr.modify(|_, w| w.hsi48on().set_bit()); - while self.rb.crrcr.read().hsi48rdy().bit_is_clear() {} + self.rb.crrcr().modify(|_, w| w.hsi48on().set_bit()); + while self.rb.crrcr().read().hsi48rdy().bit_is_clear() {} } pub fn get_reset_reason(&self) -> ResetReason { - let csr = self.rb.csr.read(); + let csr = self.rb.csr().read(); ResetReason { low_power: csr.lpwrstf().bit(), @@ -468,7 +468,7 @@ impl Rcc { } pub fn clear_reset_reason(&mut self) { - self.rb.csr.modify(|_, w| w.rmvf().set_bit()); + self.rb.csr().modify(|_, w| w.rmvf().set_bit()); } } @@ -539,16 +539,16 @@ pub struct AHB1 { impl AHB1 { #[inline(always)] fn enr(rcc: &RccRB) -> &rcc::AHB1ENR { - &rcc.ahb1enr + rcc.ahb1enr() } #[inline(always)] fn rstr(rcc: &RccRB) -> &rcc::AHB1RSTR { - &rcc.ahb1rstr + rcc.ahb1rstr() } #[allow(unused)] #[inline(always)] fn smenr(rcc: &RccRB) -> &rcc::AHB1SMENR { - &rcc.ahb1smenr + rcc.ahb1smenr() } } @@ -558,16 +558,16 @@ pub struct AHB2 { impl AHB2 { #[inline(always)] fn enr(rcc: &RccRB) -> &rcc::AHB2ENR { - &rcc.ahb2enr + rcc.ahb2enr() } #[inline(always)] fn rstr(rcc: &RccRB) -> &rcc::AHB2RSTR { - &rcc.ahb2rstr + rcc.ahb2rstr() } #[allow(unused)] #[inline(always)] fn smenr(rcc: &RccRB) -> &rcc::AHB2SMENR { - &rcc.ahb2smenr + rcc.ahb2smenr() } } @@ -578,17 +578,17 @@ impl AHB3 { #[allow(unused)] #[inline(always)] fn enr(rcc: &RccRB) -> &rcc::AHB3ENR { - &rcc.ahb3enr + rcc.ahb3enr() } #[allow(unused)] #[inline(always)] fn rstr(rcc: &RccRB) -> &rcc::AHB3RSTR { - &rcc.ahb3rstr + rcc.ahb3rstr() } #[allow(unused)] #[inline(always)] fn smenr(rcc: &RccRB) -> &rcc::AHB3SMENR { - &rcc.ahb3smenr + rcc.ahb3smenr() } } @@ -598,16 +598,16 @@ pub struct APB1_1 { impl APB1_1 { #[inline(always)] fn enr(rcc: &RccRB) -> &rcc::APB1ENR1 { - &rcc.apb1enr1 + rcc.apb1enr1() } #[inline(always)] fn rstr(rcc: &RccRB) -> &rcc::APB1RSTR1 { - &rcc.apb1rstr1 + rcc.apb1rstr1() } #[allow(unused)] #[inline(always)] fn smenr(rcc: &RccRB) -> &rcc::APB1SMENR1 { - &rcc.apb1smenr1 + rcc.apb1smenr1() } } @@ -617,16 +617,16 @@ pub struct APB1_2 { impl APB1_2 { #[inline(always)] fn enr(rcc: &RccRB) -> &rcc::APB1ENR2 { - &rcc.apb1enr2 + rcc.apb1enr2() } #[inline(always)] fn rstr(rcc: &RccRB) -> &rcc::APB1RSTR2 { - &rcc.apb1rstr2 + rcc.apb1rstr2() } #[allow(unused)] #[inline(always)] fn smenr(rcc: &RccRB) -> &rcc::APB1SMENR2 { - &rcc.apb1smenr2 + rcc.apb1smenr2() } } @@ -636,16 +636,16 @@ pub struct APB2 { impl APB2 { #[inline(always)] fn enr(rcc: &RccRB) -> &rcc::APB2ENR { - &rcc.apb2enr + rcc.apb2enr() } #[inline(always)] fn rstr(rcc: &RccRB) -> &rcc::APB2RSTR { - &rcc.apb2rstr + rcc.apb2rstr() } #[allow(unused)] #[inline(always)] fn smenr(rcc: &RccRB) -> &rcc::APB2SMENR { - &rcc.apb2smenr + rcc.apb2smenr() } } diff --git a/src/serial/usart.rs b/src/serial/usart.rs index f4a5dc12..da10901f 100644 --- a/src/serial/usart.rs +++ b/src/serial/usart.rs @@ -180,25 +180,25 @@ macro_rules! uart_shared { /// Starts listening for an interrupt event pub fn listen(&mut self) { let usart = unsafe { &(*$USARTX::ptr()) }; - usart.cr1.modify(|_, w| w.rxneie().set_bit()); + usart.cr1().modify(|_, w| w.rxneie().set_bit()); } /// Stop listening for an interrupt event pub fn unlisten(&mut self) { let usart = unsafe { &(*$USARTX::ptr()) }; - usart.cr1.modify(|_, w| w.rxneie().clear_bit()); + usart.cr1().modify(|_, w| w.rxneie().clear_bit()); } /// Return true if the rx register is not empty (and can be read) pub fn is_rxne(&self) -> bool { let usart = unsafe { &(*$USARTX::ptr()) }; - usart.isr.read().rxne().bit_is_set() + usart.isr().read().rxne().bit_is_set() } /// Returns true if the rx fifo threshold has been reached. pub fn fifo_threshold_reached(&self) -> bool { let usart = unsafe { &(*$USARTX::ptr()) }; - usart.isr.read().rxft().bit_is_set() + usart.isr().read().rxft().bit_is_set() } } @@ -206,7 +206,7 @@ macro_rules! uart_shared { pub fn enable_dma(self) -> Rx<$USARTX, Pin, DMA> { // NOTE(unsafe) critical section prevents races cortex_m::interrupt::free(|_| unsafe { - let cr3 = &(*$USARTX::ptr()).cr3; + let cr3 = &(*$USARTX::ptr()).cr3(); cr3.modify(|_, w| w.dmar().set_bit()); }); @@ -218,19 +218,19 @@ macro_rules! uart_shared { } fn data_ready(&mut self) -> nb::Result<(), Error> { let usart = unsafe { &(*$USARTX::ptr()) }; - let isr = usart.isr.read(); + let isr = usart.isr().read(); Err( if isr.pe().bit_is_set() { - usart.icr.write(|w| w.pecf().set_bit()); + usart.icr().write(|w| w.pecf().set_bit()); nb::Error::Other(Error::Parity) } else if isr.fe().bit_is_set() { - usart.icr.write(|w| w.fecf().set_bit()); + usart.icr().write(|w| w.fecf().set_bit()); nb::Error::Other(Error::Framing) } else if isr.nf().bit_is_set() { - usart.icr.write(|w| w.ncf().set_bit()); + usart.icr().write(|w| w.ncf().set_bit()); nb::Error::Other(Error::Noise) } else if isr.ore().bit_is_set() { - usart.icr.write(|w| w.orecf().set_bit()); + usart.icr().write(|w| w.orecf().set_bit()); nb::Error::Other(Error::Overrun) } else if isr.rxne().bit_is_set() { return Ok(()) @@ -245,7 +245,7 @@ macro_rules! uart_shared { pub fn disable_dma(self) -> Rx<$USARTX, Pin, NoDMA> { // NOTE(unsafe) critical section prevents races interrupt::free(|_| unsafe { - let cr3 = &(*$USARTX::ptr()).cr3; + let cr3 = &(*$USARTX::ptr()).cr3(); cr3.modify(|_, w| w.dmar().clear_bit()); }); @@ -262,7 +262,7 @@ macro_rules! uart_shared { fn read(&mut self) -> nb::Result { let usart = unsafe { &(*$USARTX::ptr()) }; - self.data_ready().map(|_| usart.rdr.read().bits() as u8) + self.data_ready().map(|_| usart.rdr().read().bits() as u8) } } @@ -278,25 +278,25 @@ macro_rules! uart_shared { /// Starts listening for an interrupt event pub fn listen(&mut self) { let usart = unsafe { &(*$USARTX::ptr()) }; - usart.cr1.modify(|_, w| w.txeie().set_bit()); + usart.cr1().modify(|_, w| w.txeie().set_bit()); } /// Stop listening for an interrupt event pub fn unlisten(&mut self) { let usart = unsafe { &(*$USARTX::ptr()) }; - usart.cr1.modify(|_, w| w.txeie().clear_bit()); + usart.cr1().modify(|_, w| w.txeie().clear_bit()); } /// Return true if the tx register is empty (and can accept data) pub fn is_txe(&self) -> bool { let usart = unsafe { &(*$USARTX::ptr()) }; - usart.isr.read().txe().bit_is_set() + usart.isr().read().txe().bit_is_set() } /// Returns true if the tx fifo threshold has been reached. pub fn fifo_threshold_reached(&self) -> bool { let usart = unsafe { &(*$USARTX::ptr()) }; - usart.isr.read().txft().bit_is_set() + usart.isr().read().txft().bit_is_set() } } @@ -304,7 +304,7 @@ macro_rules! uart_shared { pub fn enable_dma(self) -> Tx<$USARTX, Pin, DMA> { // NOTE(unsafe) critical section prevents races interrupt::free(|_| unsafe { - let cr3 = &(*$USARTX::ptr()).cr3; + let cr3 = &(*$USARTX::ptr()).cr3(); cr3.modify(|_, w| w.dmat().set_bit()); }); @@ -320,7 +320,7 @@ macro_rules! uart_shared { pub fn disable_dma(self) -> Tx<$USARTX, Pin, NoDMA> { // NOTE(unsafe) critical section prevents races interrupt::free(|_| unsafe { - let cr3 = &(*$USARTX::ptr()).cr3; + let cr3 = &(*$USARTX::ptr()).cr3(); cr3.modify(|_, w| w.dmat().clear_bit()); }); @@ -337,7 +337,7 @@ macro_rules! uart_shared { fn flush(&mut self) -> nb::Result<(), Self::Error> { let usart = unsafe { &(*$USARTX::ptr()) }; - if usart.isr.read().tc().bit_is_set() { + if usart.isr().read().tc().bit_is_set() { Ok(()) } else { Err(nb::Error::WouldBlock) @@ -346,8 +346,8 @@ macro_rules! uart_shared { fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { let usart = unsafe { &(*$USARTX::ptr()) }; - if usart.isr.read().txe().bit_is_set() { - usart.tdr.write(|w| unsafe { w.bits(byte as u32) }); + if usart.isr().read().txe().bit_is_set() { + usart.tdr().write(|w| unsafe { w.bits(byte as u32) }); Ok(()) } else { Err(nb::Error::WouldBlock) @@ -373,7 +373,7 @@ macro_rules! uart_shared { impl WriteReady for Tx<$USARTX, Pin, NoDMA> { fn write_ready(&mut self) -> Result { let usart = unsafe { &(*$USARTX::ptr()) }; - Ok(usart.isr.read().txe().bit_is_set()) + Ok(usart.isr().read().txe().bit_is_set()) } } // writes until fifo (or tdr) is full @@ -386,8 +386,8 @@ macro_rules! uart_shared { } // can't know fifo capacity in advance let count = buf.into_iter() - .take_while(|_| usart.isr.read().txe().bit_is_set()) - .map(|b| usart.tdr.write(|w| unsafe { w.tdr().bits(*b as u16) })) + .take_while(|_| usart.isr().read().txe().bit_is_set()) + .map(|b| usart.tdr().write(|w| unsafe { w.tdr().bits(*b as u16) })) .count(); Ok(count) @@ -419,7 +419,7 @@ macro_rules! uart_shared { core::hint::spin_loop() } while self.read_ready()? && count < buf.len() { - buf[count] = usart.rdr.read().bits() as u8; + buf[count] = usart.rdr().read().bits() as u8; count += 1 } Ok(count) @@ -482,7 +482,7 @@ macro_rules! uart_shared { /// changes. pub fn release(self) -> ($USARTX, TX, RX) { // Disable the UART as well as its clock. - self.tx.usart.cr1.modify(|_, w| w.ue().clear_bit()); + self.tx.usart.cr1().modify(|_, w| w.ue().clear_bit()); unsafe { let rcc_ptr = &(*RCC::ptr()); $USARTX::disable(rcc_ptr); @@ -495,7 +495,7 @@ macro_rules! uart_shared { #[inline(always)] fn address(&self) -> u32 { // unsafe: only the Tx part accesses the Tx register - &unsafe { &*<$USARTX>::ptr() }.tdr as *const _ as u32 + &unsafe { &*<$USARTX>::ptr() }.tdr() as *const _ as u32 } type MemSize = u8; @@ -507,7 +507,7 @@ macro_rules! uart_shared { #[inline(always)] fn address(&self) -> u32 { // unsafe: only the Rx part accesses the Rx register - &unsafe { &*<$USARTX>::ptr() }.rdr as *const _ as u32 + &unsafe { &*<$USARTX>::ptr() }.rdr() as *const _ as u32 } type MemSize = u8; @@ -567,21 +567,21 @@ macro_rules! uart_lp { // We need 16x oversampling. return Err(InvalidConfig); } - usart.brr.write(|w| unsafe { w.bits(div as u32) }); + usart.brr().write(|w| unsafe { w.bits(div as u32) }); // Reset the UART and disable it (UE=0) - usart.cr1.reset(); + usart.cr1().reset(); // Reset other registers to disable advanced USART features - usart.cr2.reset(); - usart.cr3.reset(); + usart.cr2().reset(); + usart.cr3().reset(); - usart.cr2.write(|w| unsafe { + usart.cr2().write(|w| unsafe { w.stop() .bits(config.stopbits.bits()) .swap() .bit(config.swap) }); - usart.cr3.write(|w| unsafe { + usart.cr3().write(|w| unsafe { w.txftcfg() .bits(config.tx_fifo_threshold.bits()) .rxftcfg() @@ -593,7 +593,7 @@ macro_rules! uart_lp { }); // Enable the UART and perform remaining configuration. - usart.cr1.write(|w| { + usart.cr1().write(|w| { w.ue() .set_bit() .te() @@ -629,26 +629,26 @@ macro_rules! uart_lp { /// Starts listening for an interrupt event pub fn listen(&mut self, event: Event) { match event { - Event::Rxne => self.tx.usart.cr1.modify(|_, w| w.rxneie().set_bit()), - Event::Txe => self.tx.usart.cr1.modify(|_, w| w.txeie().set_bit()), - Event::Idle => self.tx.usart.cr1.modify(|_, w| w.idleie().set_bit()), - _ => {} - } + Event::Rxne => self.tx.usart.cr1().modify(|_, w| w.rxneie().set_bit()), + Event::Txe => self.tx.usart.cr1().modify(|_, w| w.txeie().set_bit()), + Event::Idle => self.tx.usart.cr1().modify(|_, w| w.idleie().set_bit()), + _ => unimplemented!(), + }; } /// Stop listening for an interrupt event pub fn unlisten(&mut self, event: Event) { match event { - Event::Rxne => self.tx.usart.cr1.modify(|_, w| w.rxneie().clear_bit()), - Event::Txe => self.tx.usart.cr1.modify(|_, w| w.txeie().clear_bit()), - Event::Idle => self.tx.usart.cr1.modify(|_, w| w.idleie().clear_bit()), - _ => {} - } + Event::Rxne => self.tx.usart.cr1().modify(|_, w| w.rxneie().clear_bit()), + Event::Txe => self.tx.usart.cr1().modify(|_, w| w.txeie().clear_bit()), + Event::Idle => self.tx.usart.cr1().modify(|_, w| w.idleie().clear_bit()), + _ => unimplemented!(), + }; } /// Check if interrupt event is pending pub fn is_pending(&mut self, event: Event) -> bool { - (self.tx.usart.isr.read().bits() & event.val()) != 0 + (self.tx.usart.isr().read().bits() & event.val()) != 0 } /// Clear pending interrupt @@ -657,7 +657,7 @@ macro_rules! uart_lp { let mask: u32 = 0x123BFF; self.tx .usart - .icr + .icr() .write(|w| unsafe { w.bits(event.val() & mask) }); } } @@ -715,14 +715,14 @@ macro_rules! uart_full { // We need 16x oversampling. return Err(InvalidConfig); } - usart.brr.write(|w| unsafe { w.bits(div as u32) }); + usart.brr().write(|w| unsafe { w.bits(div as u32) }); // Reset the UART and disable it (UE=0) - usart.cr1.reset(); - usart.cr2.reset(); - usart.cr3.reset(); + usart.cr1().reset(); + usart.cr2().reset(); + usart.cr3().reset(); - usart.cr2.write(|w| unsafe { + usart.cr2().write(|w| unsafe { w.stop() .bits(config.stopbits.bits()) .swap() @@ -730,12 +730,12 @@ macro_rules! uart_full { }); if let Some(timeout) = config.receiver_timeout { - usart.cr1.write(|w| w.rtoie().set_bit()); - usart.cr2.modify(|_, w| w.rtoen().set_bit()); - usart.rtor.write(|w| unsafe { w.rto().bits(timeout) }); + usart.cr1().write(|w| w.rtoie().set_bit()); + usart.cr2().modify(|_, w| w.rtoen().set_bit()); + usart.rtor().write(|w| unsafe { w.rto().bits(timeout) }); } - usart.cr3.write(|w| unsafe { + usart.cr3().write(|w| unsafe { w.txftcfg() .bits(config.tx_fifo_threshold.bits()) .rxftcfg() @@ -747,7 +747,7 @@ macro_rules! uart_full { }); // Enable the UART and perform remaining configuration. - usart.cr1.modify(|_, w| { + usart.cr1().modify(|_, w| { w.ue() .set_bit() .te() @@ -783,26 +783,26 @@ macro_rules! uart_full { /// Starts listening for an interrupt event pub fn listen(&mut self, event: Event) { match event { - Event::Rxne => self.tx.usart.cr1.modify(|_, w| w.rxneie().set_bit()), - Event::Txe => self.tx.usart.cr1.modify(|_, w| w.txeie().set_bit()), - Event::Idle => self.tx.usart.cr1.modify(|_, w| w.idleie().set_bit()), - _ => {} - } + Event::Rxne => self.tx.usart.cr1().modify(|_, w| w.rxneie().set_bit()), + Event::Txe => self.tx.usart.cr1().modify(|_, w| w.txeie().set_bit()), + Event::Idle => self.tx.usart.cr1().modify(|_, w| w.idleie().set_bit()), + _ => unimplemented!(), + }; } /// Stop listening for an interrupt event pub fn unlisten(&mut self, event: Event) { match event { - Event::Rxne => self.tx.usart.cr1.modify(|_, w| w.rxneie().clear_bit()), - Event::Txe => self.tx.usart.cr1.modify(|_, w| w.txeie().clear_bit()), - Event::Idle => self.tx.usart.cr1.modify(|_, w| w.idleie().clear_bit()), - _ => {} - } + Event::Rxne => self.tx.usart.cr1().modify(|_, w| w.rxneie().clear_bit()), + Event::Txe => self.tx.usart.cr1().modify(|_, w| w.txeie().clear_bit()), + Event::Idle => self.tx.usart.cr1().modify(|_, w| w.idleie().clear_bit()), + _ => unimplemented!(), + }; } /// Check if interrupt event is pending pub fn is_pending(&mut self, event: Event) -> bool { - (self.tx.usart.isr.read().bits() & event.val()) != 0 + (self.tx.usart.isr().read().bits() & event.val()) != 0 } /// Clear pending interrupt @@ -811,7 +811,7 @@ macro_rules! uart_full { let mask: u32 = 0x123BFF; self.tx .usart - .icr + .icr() .write(|w| unsafe { w.bits(event.val() & mask) }); } } @@ -821,13 +821,13 @@ macro_rules! uart_full { /// Returns the current state of the ISR RTOF bit pub fn timeout_lapsed(&self) -> bool { let usart = unsafe { &(*$USARTX::ptr()) }; - usart.isr.read().rtof().bit_is_set() + usart.isr().read().rtof().bit_is_set() } /// Clear pending receiver timeout interrupt pub fn clear_timeout(&mut self) { let usart = unsafe { &(*$USARTX::ptr()) }; - usart.icr.write(|w| w.rtocf().set_bit()); + usart.icr().write(|w| w.rtocf().set_bit()); } } }; diff --git a/src/spi.rs b/src/spi.rs index c08e66fa..37de2169 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -21,7 +21,6 @@ use crate::rcc::{Enable, GetBusFreq, Rcc, RccBus, Reset}; use crate::stm32::SPI4; use crate::stm32::{RCC, SPI1, SPI2, SPI3}; use crate::time::Hertz; -use core::cell::UnsafeCell; use core::ptr; use embedded_hal::spi::ErrorKind; @@ -140,7 +139,7 @@ macro_rules! spi { } // disable SS output - spi.cr2.write(|w| w.ssoe().clear_bit()); + spi.cr2().write(|w| w.ssoe().clear_bit()); let spi_freq = speed.into().raw(); let bus_freq = <$SPIX as RccBus>::Bus::get_frequency(&rcc.clocks).raw(); @@ -156,11 +155,11 @@ macro_rules! spi { _ => 0b111, }; - spi.cr2.write(|w| unsafe { + spi.cr2().write(|w| unsafe { w.frxth().set_bit().ds().bits(0b111).ssoe().clear_bit() }); - spi.cr1.write(|w| unsafe { + spi.cr1().write(|w| unsafe { w.cpha() .bit(mode.phase == Phase::CaptureOnSecondTransition) .cpol() @@ -195,7 +194,7 @@ macro_rules! spi { } pub fn enable_tx_dma(self) -> Spi<$SPIX, PINS> { - self.spi.cr2.modify(|_, w| w.txdmaen().set_bit()); + self.spi.cr2().modify(|_, w| w.txdmaen().set_bit()); Spi { spi: self.spi, pins: self.pins, @@ -205,7 +204,7 @@ macro_rules! spi { impl Spi<$SPIX, PINS> { fn nb_read(&mut self) -> nb::Result { - let sr = self.spi.sr.read(); + 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() { @@ -216,14 +215,14 @@ macro_rules! spi { // 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 W) + ptr::read_volatile(&self.spi.dr() as *const _ as *const W) }); } else { nb::Error::WouldBlock }) } fn nb_write(&mut self, word: W) -> nb::Result<(), Error> { - let sr = self.spi.sr.read(); + 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() { @@ -231,9 +230,9 @@ macro_rules! spi { } else if sr.crcerr().bit_is_set() { nb::Error::Other(Error::Crc) } else if sr.txe().bit_is_set() { - let dr = &self.spi.dr as *const _ as *const UnsafeCell; + let dr = self.spi.dr().as_ptr() as *mut W; // NOTE(write_volatile) see note above - unsafe { ptr::write_volatile(UnsafeCell::raw_get(dr), word) }; + unsafe { ptr::write_volatile(dr, word) }; return Ok(()); } else { nb::Error::WouldBlock @@ -241,12 +240,12 @@ macro_rules! spi { } fn set_tx_only(&mut self) { self.spi - .cr1 + .cr1() .modify(|_, w| w.bidimode().set_bit().bidioe().set_bit()); } fn set_bidi(&mut self) { self.spi - .cr1 + .cr1() .modify(|_, w| w.bidimode().clear_bit().bidioe().clear_bit()); } } @@ -336,7 +335,7 @@ macro_rules! spi { // stop receiving data self.set_tx_only(); // wait for tx fifo to be drained by the peripheral - while self.spi.sr.read().ftlvl() != 0 { core::hint::spin_loop() }; + while self.spi.sr().read().ftlvl() != 0 { core::hint::spin_loop() }; // drain rx fifo Ok(while match self.nb_read::() { Ok(_) => true, @@ -361,7 +360,7 @@ macro_rules! spi { #[inline(always)] fn address(&self) -> u32 { // unsafe: only the Tx part accesses the Tx register - &unsafe { &*<$SPIX>::ptr() }.dr as *const _ as u32 + &unsafe { &*<$SPIX>::ptr() }.dr() as *const _ as u32 } type MemSize = u8; diff --git a/src/syscfg.rs b/src/syscfg.rs index 19427bd8..b13833bb 100644 --- a/src/syscfg.rs +++ b/src/syscfg.rs @@ -15,7 +15,7 @@ impl SysCfgExt for SYSCFG { let rcc = &(*RCC::ptr()); // Enable clock. - bb::set(&rcc.apb2enr, 0); + bb::set(&rcc.apb2enr(), 0); // Stall the pipeline to work around erratum 2.1.13 (DM00037591) cortex_m::asm::dsb(); diff --git a/src/timer.rs b/src/timer.rs index ff0ff892..dc92dc9f 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -232,7 +232,7 @@ macro_rules! hal_ext_trgo { $( impl Timer<$TIM> { pub fn set_trigger_source(&mut self, trigger_source: TriggerSource) { - self.tim.cr2.modify(|_, w| unsafe {w.$mms().bits(trigger_source as u8)}); + self.tim.cr2().modify(|_, w| unsafe {w.$mms().bits(trigger_source as u8)}); } } )+ @@ -253,7 +253,7 @@ macro_rules! hal { match event { Event::TimeOut => { // Enable update event interrupt - self.tim.dier.write(|w| w.uie().set_bit()); + self.tim.dier().write(|w| w.uie().set_bit()); } } } @@ -266,7 +266,7 @@ macro_rules! hal { match event { Event::TimeOut => { // Clear interrupt flag - self.tim.sr.write(|w| w.uif().clear_bit()); + self.tim.sr().write(|w| w.uif().clear_bit()); } } } @@ -276,7 +276,7 @@ macro_rules! hal { match event { Event::TimeOut => { // Enable update event interrupt - self.tim.dier.write(|w| w.uie().clear_bit()); + self.tim.dier().write(|w| w.uie().clear_bit()); } } } @@ -284,7 +284,7 @@ macro_rules! hal { /// Releases the TIM peripheral pub fn release(self) -> $TIM { // pause counter - self.tim.cr1.modify(|_, w| w.cen().clear_bit()); + self.tim.cr1().modify(|_, w| w.cen().clear_bit()); self.tim } @@ -301,33 +301,33 @@ macro_rules! hal { T: Into, { // pause - self.tim.cr1.modify(|_, w| w.cen().clear_bit()); + self.tim.cr1().modify(|_, w| w.cen().clear_bit()); // reset counter - self.tim.cnt.reset(); + self.tim.cnt().reset(); let ticks = crate::time::cycles(timeout.into(), self.clk); let psc = u16((ticks - 1) / (1 << 16)).unwrap(); - self.tim.psc.write(|w| unsafe {w.psc().bits(psc)} ); + self.tim.psc().write(|w| unsafe {w.psc().bits(psc)} ); // TODO: TIM2 and TIM5 are 32 bit let arr = u16(ticks / u32(psc + 1)).unwrap(); - self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) }); + self.tim.arr().write(|w| unsafe { w.bits(u32(arr)) }); // Trigger update event to load the registers - self.tim.cr1.modify(|_, w| w.urs().set_bit()); - self.tim.egr.write(|w| w.ug().set_bit()); - self.tim.cr1.modify(|_, w| w.urs().clear_bit()); + self.tim.cr1().modify(|_, w| w.urs().set_bit()); + self.tim.egr().write(|w| w.ug().set_bit()); + self.tim.cr1().modify(|_, w| w.urs().clear_bit()); // start counter - self.tim.cr1.modify(|_, w| w.cen().set_bit()); + self.tim.cr1().modify(|_, w| w.cen().set_bit()); } fn wait(&mut self) -> nb::Result<(), Void> { - if self.tim.sr.read().uif().bit_is_clear() { + if self.tim.sr().read().uif().bit_is_clear() { Err(nb::Error::WouldBlock) } else { - self.tim.sr.modify(|_, w| w.uif().clear_bit()); + self.tim.sr().modify(|_, w| w.uif().clear_bit()); Ok(()) } } @@ -345,14 +345,14 @@ macro_rules! hal { type Error = Error; fn cancel(&mut self) -> Result<(), Self::Error> { - // let is_counter_enabled = self.tim.cr1.read().cen().is_enabled(); - let is_counter_enabled = self.tim.cr1.read().cen().bit_is_set(); + // let is_counter_enabled = self.tim.cr1().read().cen().is_enabled(); + let is_counter_enabled = self.tim.cr1().read().cen().bit_is_set(); if !is_counter_enabled { return Err(Self::Error::Disabled); } // disable counter - self.tim.cr1.modify(|_, w| w.cen().clear_bit()); + self.tim.cr1().modify(|_, w| w.cen().clear_bit()); Ok(()) } } diff --git a/tests/pwm.rs b/tests/pwm.rs new file mode 100644 index 00000000..35d4d4cf --- /dev/null +++ b/tests/pwm.rs @@ -0,0 +1,113 @@ +#![no_std] +#![no_main] + +#[path ="../examples/utils/mod.rs"] +mod utils; + +use utils::logger::println; + +use core::ops::FnMut; +use core::result::Result; +use fugit::{ExtU32, MicrosDurationU32}; +use hal::delay::{DelayExt, SystDelay}; +use hal::stm32; +use stm32g4xx_hal as hal; + +#[defmt_test::tests] +mod tests { + use embedded_hal::pwm::SetDutyCycle; + use fugit::RateExtU32; + use stm32g4xx_hal::{ + delay::SYSTDelayExt, gpio::{GpioExt, AF6}, pwm::PwmExt, rcc::RccExt, stm32::GPIOA, + }; + + #[test] + fn foo() { + use super::*; + + let cp = stm32::CorePeripherals::take().expect("cannot take peripherals"); + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let mut rcc = dp.RCC.constrain(); + let mut delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + let pin: stm32g4xx_hal::gpio::gpioa::PA8> = gpioa.pa8.into_alternate(); + + //let mut pwm = dp.TIM1.pwm(pin, 1000u32.Hz(), &mut rcc); + + //pwm.set_duty_cycle_percent(50).unwrap(); + //pwm.enable(); + + + let gpioa = unsafe { &*GPIOA::PTR }; + + let get_pin_state = || unsafe { (0x4800_0004 as *const u32).read_volatile() }; + + // TODO: This is a very bad way to measure time + let min: MicrosDurationU32 = 490u32.micros();// Some extra on min for cpu overhead + let max: MicrosDurationU32 = 505u32.micros(); + + { + println!("Awaiting first rising edge..."); + //println!("{}", gpioa.odr().read().odr(8).is_high()); + println!("{}", get_pin_state()); + //let duration_until_lo = await_lo(&gpioa, &mut delay, max);//.unwrap(); + } + /* + //println!("Low..., Waited ~{}us until low", duration_until_lo); + let lo_duration = await_hi(&gpioa, &mut delay, max);//.unwrap(); + //println!("High..., Low half period: {}us", lo_duration); + } + + for _ in 0..10 { + // Make sure the timer half periods are within 490-505us + + let hi_duration = await_lo(&gpioa, &mut delay, max);//.unwrap(); + println!("Low..., High half period: {}us", hi_duration); + //assert!(hi_duration > min, "{} > {}", hi_duration, min); + + let lo_duration = await_hi(&gpioa, &mut delay, max);//.unwrap(); + println!("High..., Low half period: {}us", lo_duration); + //assert!(lo_duration > min, "{} > {}", lo_duration, min); + } + + println!("Done!"); + for i in (0..5).rev() { + println!("{}", i); + delay.delay(1000.millis()); + }*/ + } +} + +#[derive(Debug, defmt::Format)] +struct ErrorTimedOut; + +fn await_lo( + gpioa: &stm32::gpioa::RegisterBlock, + delay: &mut SystDelay, + timeout: MicrosDurationU32, +) -> Result { + await_p(|| gpioa.idr().read().idr(8).is_low(), delay, timeout) +} + +fn await_hi( + gpioa: &stm32::gpioa::RegisterBlock, + delay: &mut SystDelay, + timeout: MicrosDurationU32, +) -> Result { + await_p(|| gpioa.idr().read().idr(8).is_high(), delay, timeout) +} + +fn await_p( + mut p: impl FnMut() -> bool, + delay: &mut SystDelay, + timeout: MicrosDurationU32, +) -> Result { + for i in 0..timeout.ticks() { + if p() { + return Ok(i.micros()); + } + //delay.delay(1_u32.micros()); + } + Err(ErrorTimedOut) +}