diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db7b1060..61c78cb6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,8 +22,8 @@ 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? diff --git a/Cargo.toml b/Cargo.toml index b78d4e2b..6ceb5c27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,8 @@ version = "0.0.2" [dependencies] nb = "0.1.1" -stm32g4 = "0.15.1" +#stm32g4 = { git = "https://github.com/stm32-rs/stm32-rs-nightlies" } #"0.15.1" +stm32g4 = { version = "0.17.0", package = "stm32g4-staging" } paste = "1.0" bitflags = "1.2" vcell = "0.1" @@ -21,6 +22,7 @@ static_assertions = "1.1" fugit = "0.3.5" stm32-usbd = { version = "0.7.0", optional = true } fixed = { version = "1.28.0", optional = true } +embedded-io = "0.6.1" [dependencies.cortex-m] version = "0.7.7" @@ -85,11 +87,12 @@ stm32g431 = ["stm32g4/stm32g431"] stm32g441 = ["stm32g4/stm32g441"] stm32g471 = ["stm32g4/stm32g471"] stm32g473 = ["stm32g4/stm32g473"] -stm32g474 = ["stm32g4/stm32g474"] +stm32g474 = ["stm32g4/stm32g474", "hrtim"] stm32g483 = ["stm32g4/stm32g483"] -stm32g484 = ["stm32g4/stm32g484"] +stm32g484 = ["stm32g4/stm32g484", "hrtim"] stm32g491 = ["stm32g4/stm32g491"] stm32g4a1 = ["stm32g4/stm32g4a1"] +hrtim = [] log-itm = ["cortex-m-log/itm"] log-rtt = [] log-semihost = ["cortex-m-log/semihosting"] @@ -119,3 +122,43 @@ required-features = ["usb"] [[example]] name = "cordic" required-features = ["cordic"] + +[[example]] +name = "hrtim-adc-trigger" +required-features = ["hrtim"] +path = "examples/hrtim/adc-trigger.rs" + +[[example]] +name = "hrtim-capture" +required-features = ["hrtim"] +path = "examples/hrtim/capture.rs" + +[[example]] +name = "hrtim-eev-comp" +required-features = ["hrtim"] +path = "examples/hrtim/eev-comp.rs" + +[[example]] +name = "hrtim-eev" +required-features = ["hrtim"] +path = "examples/hrtim/eev.rs" + +[[example]] +name = "hrtim-flt-comp" +required-features = ["hrtim"] +path = "examples/hrtim/flt-comp.rs" + +[[example]] +name = "hrtim-flt" +required-features = ["hrtim"] +path = "examples/hrtim/flt.rs" + +[[example]] +name = "hrtim" +required-features = ["hrtim"] +path = "examples/hrtim/hrtim.rs" + +[[example]] +name = "hrtim-master" +required-features = ["hrtim"] +path = "examples/hrtim/master.rs" \ No newline at end of file diff --git a/examples/adc-one-shot.rs b/examples/adc-one-shot.rs index 7e727430..d67e338d 100644 --- a/examples/adc-one-shot.rs +++ b/examples/adc-one-shot.rs @@ -13,7 +13,7 @@ use stm32g4xx_hal as hal; use cortex_m_rt::entry; -use log::info; +use utils::logger::info; #[macro_use] mod utils; diff --git a/examples/flash_with_rtic.rs b/examples/flash_with_rtic.rs index 9e2d00e8..9db939d1 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/hrtim/adc-trigger.rs b/examples/hrtim/adc-trigger.rs new file mode 100644 index 00000000..f2b7fc83 --- /dev/null +++ b/examples/hrtim/adc-trigger.rs @@ -0,0 +1,157 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral to trigger the ADC at various points of the switch cycle off HRTIM_TIMA + +#[path = "../utils/mod.rs"] +mod utils; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[entry] +fn main() -> ! { + use hal::adc; + use stm32g4xx_hal as hal; + + use hal::{ + adc::{ + config::{Continuous, Dma as AdcDma, SampleTime, Sequence}, + AdcClaim, ClockSource, Temperature, Vref, + }, + delay::SYSTDelayExt, + dma::{self, config::DmaConfig, stream::DMAExt, TransferExt}, + gpio::GpioExt, + hrtim::compare_register::HrCompareRegister, + hrtim::control::HrControltExt, + hrtim::output::HrOutput, + hrtim::timer::HrTimer, + hrtim::HrPwmAdvExt, + hrtim::Pscl4, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::Peripherals, + }; + + const VREF: f32 = 3.3; + + info!("start"); + + let dp = Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals"); + + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + info!("rcc"); + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + + ..Default::default() + }), + pwr, + ); + + let mut delay = cp.SYST.delay(&rcc.clocks); + + let dma::stream::StreamsTuple(dma1ch1, ..) = dp.DMA1.split(&rcc); + let config = DmaConfig::default() + .transfer_complete_interrupt(true) + .circular_buffer(true) + .memory_increment(true); + + info!("Setup Gpio"); + let gpioa = dp.GPIOA.split(&mut rcc); + let pa0 = gpioa.pa0.into_analog(); + + let pin_a = gpioa.pa8; + let pin_b = gpioa.pa9; + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz + // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... + let prescaler = Pscl4; + + // . . + // . 50% . + // ------ ------ + //out1 | | | | + // | | | | + // -------- ---------- -------- + // . ^ ^ + // . | | + //AD samlp pa0 temp + let period = 0xFFFF; + let (hr_control, ..) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + let (mut timer, (mut cr1, _cr2, mut cr3, mut cr4), (mut out1, mut out2), ..) = dp + .HRTIM_TIMA + .pwm_advanced((pin_a, pin_b), &mut rcc) + .prescaler(prescaler) + .period(period) + .finalize(&mut hr_control); + + cr1.set_duty(period / 2); + cr3.set_duty(period / 3); + cr4.set_duty((2 * u32::from(period) / 3) as u16); + + hr_control.adc_trigger1.enable_source(&cr3); + hr_control.adc_trigger1.enable_source(&cr4); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out2.enable_rst_event(&cr1); + + out1.enable_set_event(&timer); // Set high at new period + out2.enable_set_event(&timer); + + info!("Setup Adc1"); + let mut adc = dp + .ADC1 + .claim(ClockSource::SystemClock, &rcc, &mut delay, true); + + adc.set_external_trigger(( + adc::config::TriggerMode::RisingEdge, + &hr_control.adc_trigger1, + )); + adc.enable_temperature(&dp.ADC12_COMMON); + adc.set_continuous(Continuous::Discontinuous); + adc.reset_sequence(); + adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_640_5); + adc.configure_channel(&Temperature, Sequence::Two, SampleTime::Cycles_640_5); + + info!("Setup DMA"); + let first_buffer = cortex_m::singleton!(: [u16; 10] = [0; 10]).unwrap(); + + let mut transfer = dma1ch1.into_circ_peripheral_to_memory_transfer( + adc.enable_dma(AdcDma::Continuous), + &mut first_buffer[..], + config, + ); + + transfer.start(|adc| adc.start_conversion()); + + out1.enable(); + out2.enable(); + + timer.start(&mut hr_control.control); + + loop { + let mut b = [0_u16; 4]; + let r = transfer.read_exact(&mut b); + + info!("read: {}", r); + assert!(r == b.len()); + + let millivolts = Vref::sample_to_millivolts((b[0] + b[2]) / 2); + info!("pa3: {}mV", millivolts); + let temp = Temperature::temperature_to_degrees_centigrade( + (b[1] + b[3]) / 2, + VREF, + adc::config::Resolution::Twelve, + ); + info!("temp: {}℃C", temp); + } +} diff --git a/examples/hrtim/capture-dma.rs b/examples/hrtim/capture-dma.rs new file mode 100644 index 00000000..175a670e --- /dev/null +++ b/examples/hrtim/capture-dma.rs @@ -0,0 +1,130 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral's capture function to detect phase shift between a digital event and the output of HRTIM_TIMA + +#[path = "../utils/mod.rs"] +mod utils; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[entry] +fn main() -> ! { + use stm32g4xx_hal as hal; + + use hal::{ + dma::{config::DmaConfig, stream::DMAExt, TransferExt}, + gpio::{GpioExt, AF13}, + hrtim::{ + capture, compare_register::HrCompareRegister, control::HrControltExt, external_event, + external_event::ToExternalEventSource, output::HrOutput, timer::HrSlaveTimerCpt, + timer::HrTimer, HrPwmAdvExt, Pscl128, + }, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::Peripherals, + }; + use info; + + info!("start"); + + let dp = Peripherals::take().unwrap(); + + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + info!("rcc"); + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PLLSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + + ..Default::default() + }), + pwr, + ); + + info!("Setup Gpio"); + let gpioa = dp.GPIOA.split(&mut rcc); + let gpiob = dp.GPIOB.split(&mut rcc); + + // PA8 (D7 on Nucleo G474RE) + let pin_a = gpioa.pa8; + + // PB5 (D4 on Nucleo G474RE) + let input = gpiob.pb5.into_pull_down_input(); + + // ...with a prescaler of 128 this gives us a HrTimer with a tick rate of 30MHz + // With max the max period set, this would be 30MHz/2^16 ~= 458Hz... + let prescaler = Pscl128; + + // t1 t2 . + // | | . + // v v . + // . . + // . 50% . + // ------ ------ + //out1 | | | | + // | | | | + // -------- ---------- -------- + let period = 0xFFFF; + let (mut hr_control, _flt_inputs, eev_inputs) = + dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + + let eev_input6 = eev_inputs + .eev_input6 + .bind(input) + .edge_or_polarity(external_event::EdgeOrPolarity::Edge( + external_event::Edge::Both, + )) + .finalize(&mut hr_control); + + let mut hr_control = hr_control.constrain(); + let (timer, (mut cr1, _cr2, _cr3, _cr4), mut out1, dma_ch) = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .period(period) + .finalize(&mut hr_control); + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out1.enable_set_event(&timer); // Set high at new period + cr1.set_duty(period / 2); + + let (mut timer, mut capture, _capture_ch2) = timer.split_capture(); + timer.start(&mut hr_control.control); + out1.enable(); + + capture.enable_interrupt(true, &mut hr_control); + capture.add_event(&eev_input6); + + info!("Setup DMA"); + let streams = dp.DMA1.split(&rcc); + let config = DmaConfig::default() + .transfer_complete_interrupt(false) + .circular_buffer(true) + .memory_increment(true); + + let first_buffer = cortex_m::singleton!(: [u32; 16] = [0; 16]).unwrap(); + let mut transfer = streams.0.into_circ_peripheral_to_memory_transfer( + capture.enable_dma(dma_ch), + &mut first_buffer[..], + config, + ); + + transfer.start(|_| ()); + + let mut old_duty = 0; + loop { + for duty in (u32::from(period) / 10)..(9 * u32::from(period) / 10) { + let mut data = [0; 2]; + transfer.read_exact(&mut data); + let [t1, t2] = data.map(capture::dma_value_to_signed); + cr1.set_duty(duty as u16); + info!("Capture: t1: {}, t2: {}, duty: {}, ", t1, t2, old_duty); + old_duty = duty; + } + } +} diff --git a/examples/hrtim/capture.rs b/examples/hrtim/capture.rs new file mode 100644 index 00000000..90d3bc05 --- /dev/null +++ b/examples/hrtim/capture.rs @@ -0,0 +1,115 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral's capture function to detect phase shift between a digital event and the output of HRTIM_TIMA + +#[path = "../utils/mod.rs"] +mod utils; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[entry] +fn main() -> ! { + use stm32g4xx_hal as hal; + + use hal::{ + gpio::GpioExt, + hrtim::{ + capture::HrCapture, compare_register::HrCompareRegister, control::HrControltExt, + external_event, external_event::ToExternalEventSource, output::HrOutput, + timer::HrSlaveTimerCpt, timer::HrTimer, HrPwmAdvExt, Pscl128, + }, + pwr::PwrExt, + rcc::{self, RccExt}, + stm32::Peripherals, + }; + use info; + + info!("start"); + + let dp = Peripherals::take().unwrap(); + + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + info!("rcc"); + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + + ..Default::default() + }), + pwr, + ); + + info!("Setup Gpio"); + let gpioa = dp.GPIOA.split(&mut rcc); + let gpiob = dp.GPIOB.split(&mut rcc); + + // PA8 (D7 on Nucleo G474RE) + let pin_a = gpioa.pa8; + + // PB5 (D4 on Nucleo G474RE) + let input = gpiob.pb5.into_pull_down_input(); + + // ...with a prescaler of 128 this gives us a HrTimer with a tick rate of 30MHz + // With max the max period set, this would be 30MHz/2^16 ~= 458Hz... + let prescaler = Pscl128; + + // . . + // . 50% . + // ------ ------ + //out1 | | | | + // | | | | + // -------- ---------- -------- + let period = 0xFFFF; + let (mut hr_control, _flt_inputs, eev_inputs) = + dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + + let eev_input6 = eev_inputs + .eev_input6 + .bind(input) + .edge_or_polarity(external_event::EdgeOrPolarity::Edge( + external_event::Edge::Falling, + )) + .finalize(&mut hr_control); + + let mut hr_control = hr_control.constrain(); + let (mut timer, (mut cr1, _cr2, _cr3, _cr4), mut out1, ..) = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .period(period) + .finalize(&mut hr_control); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out1.enable_set_event(&timer); // Set high at new period + + cr1.set_duty(period / 2); + timer.start(&mut hr_control.control); + out1.enable(); + + let capture = timer.capture_ch1(); + capture.enable_interrupt(true, &mut hr_control); + capture.add_event(&eev_input6); + + let mut old_duty = 0; + loop { + for duty in (u32::from(period) / 10)..(9 * u32::from(period) / 10) { + if let Some(value) = capture.get_signed(period) { + info!( + "Capture: {:?}, duty: {}, diff: {}", + value, + old_duty, + value - old_duty as i32 + ); + cr1.set_duty(duty as u16); + old_duty = duty; + } + } + } +} diff --git a/examples/hrtim/eev-comp.rs b/examples/hrtim/eev-comp.rs new file mode 100644 index 00000000..ee1d44fb --- /dev/null +++ b/examples/hrtim/eev-comp.rs @@ -0,0 +1,135 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral together with a comparator to implement a cycle by cycle current limit. +/// Once the comparator input exceeds the reference set by the DAC, the output is set low thus limiting the pulse width and in turn the current. + +#[path = "../utils/mod.rs"] +mod utils; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[entry] +fn main() -> ! { + use hal::comparator; + use hal::comparator::{ComparatorExt, ComparatorSplit, Hysteresis}; + use hal::dac::{self, DacExt, DacOut}; + use hal::gpio::SignalEdge; + use hal::hrtim::compare_register::HrCompareRegister; + use hal::hrtim::external_event::{self, ToExternalEventSource}; + use hal::hrtim::timer::HrTimer; + use hal::hrtim::timer_eev_cfg::{EevCfg, EevCfgs}; + use hal::hrtim::HrPwmAdvExt; + use hal::hrtim::Pscl4; + use hal::hrtim::{control::HrControltExt, output::HrOutput}; + use hal::prelude::*; + use hal::pwm; + use hal::pwr::PwrExt; + use hal::rcc; + use hal::stm32; + use stm32g4xx_hal as hal; + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let cp = stm32::CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 75/4/2 = 150MHz + // This would lead to HrTim running at 150MHz * 32 = 4.8GHz... + let pwr = dp.PWR.constrain().freeze(); + + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_75, + m: rcc::PllMDiv::DIV_4, + r: Some(rcc::PllRDiv::DIV_2), + ..Default::default() + }), + pwr, + ); + + let exti = dp.EXTI; + + let mut delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + + let input = gpioa.pa1.into_analog(); + let pin_a = gpioa.pa8; + + let dac1ch1 = dp.DAC1.constrain(dac::Dac1IntSig1, &mut rcc); + let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable(); + + // Use dac to define the fault threshold + // 2^12 / 2 = 2^11 for about half of VCC + let limit = 1 << 11; + dac.set_value(limit); + + let (comp1, ..) = dp.COMP.split(&mut rcc); + + let comp1 = comp1.comparator( + &input, + &dac, + comparator::Config::default().hysteresis(Hysteresis::None), + //.output_inverted(), + &rcc.clocks, + ); + comp1.listen(SignalEdge::Rising, &exti); + let comp1 = comp1.enable().lock(); + + let (mut hr_control, _flt_inputs, eev_inputs) = + dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + + let eev_input4 = eev_inputs + .eev_input4 + .bind(&comp1) + .edge_or_polarity(external_event::EdgeOrPolarity::Polarity( + pwm::Polarity::ActiveHigh, + )) + .finalize(&mut hr_control); + + let mut hr_control = hr_control.constrain(); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1.2GHz + // With max the max period set, this would be 1.2GHz/2^16 ~= 18kHz... + let prescaler = Pscl4; + + // . . * . + // . 33% . * . . . + // .-----. .--* . .-----. .----- + //out1 | | | | . | | | + // | | | * . | | | + // ------ ----------- ------------------------------ ----------- + // . . * . . . + // . . * . . . + // . . *-------------* . . + //eev . . | .| . . + // . . | .| . . + // ------------------------- .-------------------------------------- + // . . * . . . + // . . * . . . + let (mut timer, (mut cr1, _cr2, _cr3, _cr4), mut out1, ..) = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .eev_cfg(EevCfgs::default().eev4(EevCfg::default())) + .period(0xFFFF) + .finalize(&mut hr_control); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out1.enable_rst_event(&eev_input4); + out1.enable_set_event(&timer); // Set high at new period + cr1.set_duty(timer.get_period() / 3); + + out1.enable(); + timer.start(&mut hr_control.control); + + info!("Started"); + + loop { + info!( + "Comp: {}, pending: {}", + comp1.output(), + comp1.is_pending(&exti) + ); + } +} diff --git a/examples/hrtim/eev.rs b/examples/hrtim/eev.rs new file mode 100644 index 00000000..3dd4a1e7 --- /dev/null +++ b/examples/hrtim/eev.rs @@ -0,0 +1,103 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral together with a digital input to implement a cycle by cycle current limit. +/// Once the digital input goes high, the output is set low thus limiting the pulse width and in turn the current. + +#[path = "../utils/mod.rs"] +mod utils; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[entry] +fn main() -> ! { + use hal::hrtim::compare_register::HrCompareRegister; + use hal::hrtim::external_event; + use hal::hrtim::external_event::ToExternalEventSource; + use hal::hrtim::timer::HrTimer; + use hal::hrtim::timer_eev_cfg::EevCfgs; + use hal::hrtim::HrPwmAdvExt; + use hal::hrtim::Pscl4; + use hal::hrtim::{control::HrControltExt, output::HrOutput}; + use hal::prelude::*; + use hal::pwm; + use hal::pwr::PwrExt; + use hal::rcc; + use hal::stm32; + use stm32g4xx_hal as hal; + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + // Set system frequency to 16MHz * 75/4/2 = 150MHz + // This would lead to HrTim running at 150MHz * 32 = 4.8GHz... + let pwr = dp.PWR.constrain().freeze(); + + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_75, + m: rcc::PllMDiv::DIV_4, + r: Some(rcc::PllRDiv::DIV_2), + ..Default::default() + }), + pwr, + ); + + let gpioa = dp.GPIOA.split(&mut rcc); + let gpiob = dp.GPIOB.split(&mut rcc); + + let (mut hr_control, _flt_inputs, eev_inputs) = + dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + + let eev_input3 = eev_inputs + .eev_input3 + .bind(gpiob.pb7.into_pull_down_input()) + .edge_or_polarity(external_event::EdgeOrPolarity::Polarity( + pwm::Polarity::ActiveHigh, + )) + .finalize(&mut hr_control); + + let mut hr_control = hr_control.constrain(); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1.2GHz + // With max the max period set, this would be 1.2GHz/2^16 ~= 18kHz... + let prescaler = Pscl4; + + let pin_a = gpioa.pa8; + + // . . * . + // . 33% . * . . . + // .-----. .--* .-----. .-----. .----- + //out1 | | | | | | | | | + // | | | * | | | | | + // ------ ----------- -------------- ----------- ----------- + // . . * . . . + // . . * . . . + // . . *--------* . . . + //eev . . | | . . . + // . . | | . . . + // ------------------------- ------------------------------------------ + // . . * . . . + // . . * . . . + let (mut timer, (mut cr1, _cr2, _cr3, _cr4), mut out1, ..) = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .eev_cfg(EevCfgs::default()) + .period(0xFFFF) + .finalize(&mut hr_control); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out1.enable_rst_event(&eev_input3); + out1.enable_set_event(&timer); // Set high at new period + cr1.set_duty(timer.get_period() / 3); + + out1.enable(); + timer.start(&mut hr_control.control); + + info!("Started"); + + loop { + cortex_m::asm::nop() + } +} diff --git a/examples/hrtim/flt-comp.rs b/examples/hrtim/flt-comp.rs new file mode 100644 index 00000000..4a83a476 --- /dev/null +++ b/examples/hrtim/flt-comp.rs @@ -0,0 +1,147 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral together with a comparator to implement a current fault. +/// Once the comparator input exceeds the reference set by the DAC, the output is forced low and put into a fault state. + +#[path = "../utils/mod.rs"] +mod utils; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[entry] +fn main() -> ! { + use hal::comparator::{ComparatorExt, ComparatorSplit, Config, Hysteresis}; + use hal::dac::{Dac3IntSig1, DacExt, DacOut}; + use hal::hrtim::compare_register::HrCompareRegister; + use hal::hrtim::fault::{FaultAction, FaultMonitor}; + use hal::hrtim::timer::HrTimer; + use hal::hrtim::HrPwmAdvExt; + use hal::hrtim::Pscl4; + use hal::hrtim::{control::HrControltExt, output::HrOutput}; + use hal::prelude::*; + use hal::rcc; + use hal::stm32; + use stm32g4xx_hal as hal; + use stm32g4xx_hal::adc::AdcClaim; + use stm32g4xx_hal::pwr::PwrExt; + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let cp = stm32::CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84GHz... + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + ..Default::default() + }), + pwr, + ); + + let mut delay = cp.SYST.delay(&rcc.clocks); + + let mut adc1 = dp.ADC1.claim_and_configure( + hal::adc::ClockSource::SystemClock, + &rcc, + hal::adc::config::AdcConfig::default() + .clock_mode(hal::adc::config::ClockMode::Synchronous_Div_4), + &mut delay, + false, + ); + + let gpioa = dp.GPIOA.split(&mut rcc); + let gpioc = dp.GPIOC.split(&mut rcc); + + let dac3ch1 = dp.DAC3.constrain(Dac3IntSig1, &mut rcc); + let mut dac = dac3ch1.enable(); + + // Use dac to define the fault threshold + // 2^12 / 2 = 2^11 for about half of VCC + let fault_limit = 60; + dac.set_value(fault_limit); + + let (_comp1, _comp2, comp3, ..) = dp.COMP.split(&mut rcc); + + let pc1 = gpioc.pc1.into_analog(); + let comp3 = comp3 + .comparator( + &pc1, + &dac, + Config::default() + .hysteresis(Hysteresis::None) + .output_inverted(), + &rcc.clocks, + ) + .enable(); + + let (hr_control, flt_inputs, _) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + + let fault_source5 = flt_inputs + .fault_input5 + .bind_comp(&comp3) + .polarity(hal::pwm::Polarity::ActiveHigh) + .finalize(&mut hr_control); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1.2GHz + // With max the max period set, this would be 1.2GHz/2^16 ~= 18kHz... + let prescaler = Pscl4; + + let pin_a = gpioa.pa8; + + // . . . * + // . 33% . . * . . + // .-----. .-----. .--. . . + //out1 | | | | | | . . + // | | | | | | . . + // ------ ----------- ----------- ----------------------------------- + // . . . * . . + // . . . * . . + // . . . *-------- . . + //fault . . . | | . . + // . . . | | . . + // ----------------------------------------- -------------------------- + // . . . * . . + // . . . * . . + let (mut timer, (mut cr1, _cr2, _cr3, _cr4), mut out1, ..) = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .period(0xFFFF) + .with_fault_source(fault_source5) // Set fault source + .fault_action1(FaultAction::ForceInactive) + .fault_action2(FaultAction::ForceInactive) + .finalize(&mut hr_control); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out1.enable_set_event(&timer); // Set high at new period + cr1.set_duty(timer.get_period() / 3); + //unsafe {((HRTIM_COMMON::ptr() as *mut u8).offset(0x14) as *mut u32).write_volatile(1); } + out1.enable(); + timer.start(&mut hr_control.control); + + info!("Started"); + + loop { + for _ in 0..5 { + //delay.delay(500_u32.millis()); + info!( + "State: {:?}, comp: {}, is_fault_active: {}, pc1: {}", + out1.get_state(), + comp3.output(), + hr_control.fault_5.is_fault_active(), + adc1.convert(&pc1, hal::adc::config::SampleTime::Cycles_92_5) + ); + } + if hr_control.fault_5.is_fault_active() { + hr_control.fault_5.clear_fault(); // Clear fault every 5s + out1.enable(); + info!("failt cleared, and output reenabled"); + } + } +} diff --git a/examples/hrtim/flt.rs b/examples/hrtim/flt.rs new file mode 100644 index 00000000..cad59c53 --- /dev/null +++ b/examples/hrtim/flt.rs @@ -0,0 +1,115 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral together with a comparator to implement a current fault. +/// Once the digital input goes high, the output is forced low and put into a fault state. + +#[path = "../utils/mod.rs"] +mod utils; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[entry] +fn main() -> ! { + use hal::hrtim::compare_register::HrCompareRegister; + use hal::hrtim::fault::{FaultAction, FaultMonitor}; + use hal::hrtim::timer::HrTimer; + use hal::hrtim::HrPwmAdvExt; + use hal::hrtim::Pscl4; + use hal::hrtim::{control::HrControltExt, output::HrOutput}; + use hal::prelude::*; + use hal::pwr::PwrExt; + use hal::rcc; + use hal::stm32; + use hal::time::ExtU32; + use stm32g4xx_hal as hal; + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let cp = stm32::CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 75/4/2 = 150MHz + // This would lead to HrTim running at 150MHz * 32 = 4.8GHz... + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_75, + m: rcc::PllMDiv::DIV_4, + r: Some(rcc::PllRDiv::DIV_2), + ..Default::default() + }), + pwr, + ); + + let mut delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + let gpiob = dp.GPIOB.split(&mut rcc); + let (hr_control, flt_inputs, _) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + + let fault_source3 = flt_inputs + .fault_input3 + .bind_pin(gpiob.pb10.into_pull_down_input()) + .polarity(hal::pwm::Polarity::ActiveHigh) + .finalize(&mut hr_control); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 1.2GHz + // With max the max period set, this would be 1.2GHz/2^16 ~= 18kHz... + let prescaler = Pscl4; + + let pin_a = gpioa.pa8; + + // . . . * + // . 33% . . * . . + // .-----. .-----. .--. . . + //out1 | | | | | | . . + // | | | | | | . . + // ------ ----------- ----------- ----------------------------------- + // . . . * . . + // . . . * . . + // . . . *-------- . . + //fault . . . | | . . + // . . . | | . . + // ----------------------------------------- -------------------------- + // . . . * . . + // . . . * . . + let (mut timer, (mut cr1, _cr2, _cr3, _cr4), mut out1, ..) = dp + .HRTIM_TIMA + .pwm_advanced(pin_a, &mut rcc) + .prescaler(prescaler) + .period(0xFFFF) + //.with_fault_source(fault_source1) + //.with_fault_source(fault_source2) + .with_fault_source(fault_source3) // Set fault source + //.with_fault_source(fault_source4) + //.with_fault_source(fault_source5) + //.with_fault_source(fault_source6) + .fault_action1(FaultAction::ForceInactive) + .fault_action2(FaultAction::ForceInactive) + // alternated every period with one being + // inactive and the other getting to output its wave form + // as normal + .finalize(&mut hr_control); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out1.enable_set_event(&timer); // Set high at new period + cr1.set_duty(timer.get_period() / 3); + //unsafe {((HRTIM_COMMON::ptr() as *mut u8).offset(0x14) as *mut u32).write_volatile(1); } + out1.enable(); + timer.start(&mut hr_control.control); + + info!("Started"); + + loop { + for _ in 0..5 { + delay.delay(500_u32.millis()); + info!("State: {:?}", out1.get_state()); + } + if hr_control.fault_3.is_fault_active() { + hr_control.fault_3.clear_fault(); // Clear fault every 5s + out1.enable(); + info!("failt cleared, and output reenabled"); + } + } +} diff --git a/examples/hrtim/hrtim.rs b/examples/hrtim/hrtim.rs new file mode 100644 index 00000000..f55caa94 --- /dev/null +++ b/examples/hrtim/hrtim.rs @@ -0,0 +1,103 @@ +#![no_std] +#![no_main] + +/// Add description + +#[path = "../utils/mod.rs"] +mod utils; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[entry] +fn main() -> ! { + use fugit::ExtU32; + use hal::hrtim::compare_register::HrCompareRegister; + use hal::hrtim::control::HrControltExt; + use hal::hrtim::output::HrOutput; + use hal::hrtim::timer::HrTimer; + use hal::hrtim::HrPwmAdvExt; + use hal::hrtim::Pscl4; + use hal::prelude::*; + use hal::pwr::PwrExt; + use hal::rcc; + use hal::stm32; + use stm32g4xx_hal as hal; + extern crate cortex_m_rt as rt; + + info!("Initializing..."); + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let cp = stm32::CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + + ..Default::default() + }), + pwr, + ); + + let mut delay = cp.SYST.delay(&rcc.clocks); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz + // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... + let prescaler = Pscl4; + + let gpioa = dp.GPIOA.split(&mut rcc); + let pin_a = gpioa.pa8; + let pin_b = gpioa.pa9; + + // . . . . + // . 30% . . . + // ---- . .---- . + //out1 | | . | | . + // | | . | | . + // -------- ---------------------------- -------------------- + // . .---- . .---- + //out2 . | | . | | + // . | | . | | + // ------------------------ ---------------------------- ---- + // . . . . + // . . . . + let (hr_control, ..) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + + let (mut timer, (mut cr1, _cr2, _cr3, _cr4), (mut out1, mut out2), ..) = dp + .HRTIM_TIMA + .pwm_advanced((pin_a, pin_b), &mut rcc) + .prescaler(prescaler) + .period(0xFFFF) + .push_pull_mode(true) // Set push pull mode, out1 and out2 are + // alternated every period with one being + // inactive and the other getting to output its wave form + // as normal + .finalize(&mut hr_control); + + out1.enable_rst_event(&cr1); // Set low on compare match with cr1 + out2.enable_rst_event(&cr1); + + out1.enable_set_event(&timer); // Set high at new period + out2.enable_set_event(&timer); + + out1.enable(); + out2.enable(); + + loop { + // Step frequency from 18kHz to about 180kHz(half of that when only looking at one pin) + for i in 1..10 { + let new_period = u16::MAX / i; + + cr1.set_duty(new_period / 3); + timer.set_period(new_period); + + delay.delay(500_u32.millis()); + } + } +} diff --git a/examples/hrtim/master.rs b/examples/hrtim/master.rs new file mode 100644 index 00000000..cf432a6e --- /dev/null +++ b/examples/hrtim/master.rs @@ -0,0 +1,126 @@ +#![no_std] +#![no_main] + +/// Add description + +#[path = "../utils/mod.rs"] +mod utils; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[entry] +fn main() -> ! { + use fugit::ExtU32; + use hal::hrtim::compare_register::HrCompareRegister; + use hal::hrtim::control::HrControltExt; + use hal::hrtim::output::HrOutput; + use hal::hrtim::timer::HrSlaveTimer; + use hal::hrtim::timer::HrTimer; + use hal::hrtim::HrPwmAdvExt; + use hal::hrtim::{HrTimerMode, MasterPreloadSource, PreloadSource, Pscl4}; + use hal::prelude::*; + use hal::pwr::PwrExt; + use hal::rcc; + use hal::stm32; + use stm32g4xx_hal as hal; + extern crate cortex_m_rt as rt; + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let cp = stm32::CorePeripherals::take().expect("cannot take core"); + // Set system frequency to 16MHz * 15/1/2 = 120MHz + // This would lead to HrTim running at 120MHz * 32 = 3.84... + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PllSrc::HSI, + n: rcc::PllNMul::MUL_15, + m: rcc::PllMDiv::DIV_1, + r: Some(rcc::PllRDiv::DIV_2), + + ..Default::default() + }), + pwr, + ); + + let mut delay = cp.SYST.delay(&rcc.clocks); + + // ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz + // With max the max period set, this would be 960MHz/2^16 ~= 15kHz... + let prescaler = Pscl4; + + let gpioa = dp.GPIOA.split(&mut rcc); + let pin_a = gpioa.pa8; + let pin_b = gpioa.pa9; + + // . . . . + // . 30% . . . + // ---- . .---- . + //out1 | | . | | . + // | | . | | . + // -------- ---------------------------- -------------------- + // . .---- . .---- + //out2 . | | . | | + // . | | . | | + // ------------------------ ---------------------------- ---- + // . . . . + // . . . . + let (hr_control, ..) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + + let (mut timer, (mut cr1, _cr2, _cr3, _cr4), (mut out1, mut out2), ..) = dp + .HRTIM_TIMA + .pwm_advanced((pin_a, pin_b), &mut rcc) + .prescaler(prescaler) + .push_pull_mode(true) // Set push pull mode, out1 and out2 are + // alternated every period with one being + // inactive and the other getting to output its wave form + // as normal + .preload(PreloadSource::OnMasterTimerUpdate) + .timer_mode(HrTimerMode::SingleShotRetriggerable) + .finalize(&mut hr_control); + + let (mut mtimer, (mut mcr1, _mcr2, _mcr3, _mcr4), ..) = dp + .HRTIM_MASTER + .pwm_advanced((), &mut rcc) + .prescaler(prescaler) + .preload(MasterPreloadSource::OnMasterRepetitionUpdate) + .period(0xFFFF) + .finalize(&mut hr_control); + + // Run in sync with master timer + timer.enable_reset_event(&mtimer); + + out1.enable_rst_event(&mcr1); // Set low on compare match with cr1 + out2.enable_rst_event(&mcr1); + + out1.enable_set_event(&mtimer); // Set high at new period + out2.enable_set_event(&mtimer); + + out1.enable(); + out2.enable(); + + info!("Running"); + + loop { + // Step frequency from 18kHz to about 180kHz(half of that when only looking at one pin) + for i in 1..10 { + let new_period = u16::MAX / i; + + mcr1.set_duty(new_period / 3); + cr1.set_duty(new_period / 3 - 1000); + mtimer.set_period(new_period); + timer.set_period(new_period - 1000); + + info!( + "period: {}, duty: {}, get_duty: {}, get_period: {}", + new_period, + new_period / 3, + mcr1.get_duty(), + mtimer.get_period() + ); + + delay.delay(500_u32.millis()); + } + } +} diff --git a/examples/hrtim/simple.rs b/examples/hrtim/simple.rs new file mode 100644 index 00000000..14d60812 --- /dev/null +++ b/examples/hrtim/simple.rs @@ -0,0 +1,81 @@ +#![no_std] +#![no_main] + +/// Example showcasing the use of the HRTIM peripheral generating two 20kHz pwm signals. One with 33% duty and the other with 50% + +#[path = "../utils/mod.rs"] +mod utils; + +use cortex_m_rt::entry; +use utils::logger::info; + +#[entry] +fn main() -> ! { + use hal::gpio::gpioa::PA8; + use hal::gpio::gpioa::PA9; + use hal::gpio::AF13; + use hal::hrtim::{control::HrControltExt, HrPwmExt}; + use hal::prelude::*; + use hal::pwr::PwrExt; + use hal::rcc; + use hal::stm32; + use hal::time::RateExtU32; + use stm32g4xx_hal as hal; + extern crate cortex_m_rt as rt; + + info!("Initializing..."); + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + // Set system frequency to 16MHz * 75/4/2 = 150MHz + // This would lead to HrTim running at 150MHz * 32 = 4.8GHz... + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze( + rcc::Config::pll().pll_cfg(rcc::PllConfig { + mux: rcc::PLLSrc::HSI, + n: rcc::PllNMul::MUL_75, + m: rcc::PllMDiv::DIV_4, + r: Some(rcc::PllRDiv::DIV_2), + ..Default::default() + }), + pwr, + ); + + let gpioa = dp.GPIOA.split(&mut rcc); + let pin_a = gpioa.pa8; + let pin_b = gpioa.pa9; + + // . . . + // . 33% . . + // ---- .---- .---- + //out1 | | | | | | + // | | | | | | + // ------ ------------ ------------ --------- + // . . + // 50% . . + // -------- .-------- .-------- + //out2 | | | | | | + // | | | | | | + // ------ -------- -------- ----- + // . . . + // . . . + + let (hr_control, ..) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration(); + let mut hr_control = hr_control.constrain(); + let (mut p1, mut p2) = + dp.HRTIM_TIMA + .pwm((pin_a, pin_b), 20_u32.kHz(), &mut hr_control, &mut rcc); + let max_duty = p1.get_max_duty(); + + p1.set_duty(max_duty / 3); // Set output 1 to about 33% + p2.set_duty(max_duty / 2); // Set output 2 to 50% + + // Enable the outputs + p1.enable(); + p2.enable(); + + info!("Running"); + + loop { + cortex_m::asm::nop() + } +} diff --git a/examples/uart-dma-tx.rs b/examples/uart-dma-tx.rs index 78abeb4f..2f56eea0 100644 --- a/examples/uart-dma-tx.rs +++ b/examples/uart-dma-tx.rs @@ -5,9 +5,9 @@ extern crate cortex_m_rt as rt; -use core::fmt::Write; - -use hal::dma::{config::DmaConfig, stream::DMAExt, TransferExt}; +use core::fmt::Write as _; +use embedded_io::Write as _; +use hal::dma::stream::DMAExt; use hal::prelude::*; use hal::pwr::PwrExt; use hal::serial::*; @@ -33,10 +33,6 @@ fn main() -> ! { let mut rcc = rcc.freeze(rcc::Config::hsi(), pwr); let streams = dp.DMA1.split(&rcc); - let config = DmaConfig::default() - .transfer_complete_interrupt(false) - .circular_buffer(false) - .memory_increment(true); info!("Init UART"); let gpioa = dp.GPIOA.split(&mut rcc); @@ -53,28 +49,44 @@ fn main() -> ! { .unwrap(); let mut delay_syst = cp.SYST.delay(&rcc.clocks); - let mut led = gpioa.pa5.into_push_pull_output(); + let mut led1 = gpioa.pa5.into_push_pull_output(); + let mut led2 = gpioa.pa6.into_push_pull_output(); info!("Start writing"); writeln!(usart, "Hello without DMA\r").unwrap(); - let tx_buffer = cortex_m::singleton!(: [u8; 17] = *b"Hello with DMA!\r\n").unwrap(); + let tx_buffer = cortex_m::singleton!(: [u8; 64] = [0; 64]).unwrap(); 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 tx = tx.enable_dma(streams.0, &mut tx_buffer[..]); - transfer.start(|_tx| {}); loop { - while !transfer.get_transfer_complete_flag() {} - - delay_syst.delay(1000.millis()); - led.toggle().unwrap(); - transfer.restart(|_tx| {}); + for i in 0.. { + // This will write to the DMA buffer and return directly, proveded the buffer is empty + // and there is enough room in the buffer for the entire message. Otherwise it will block. + led1.set_high().unwrap(); + writeln!(&mut tx, "Hello with DMA").unwrap(); + led1.set_low().unwrap(); + + delay_syst.delay(100.millis()); + + // This will not block due the message above since we have a delay. However do watch out for the + // `{i}` since this will invoke another DMA transfer. This will block until the first part of + // the message before the `{i}` has been flushed. Same thing for the part after the `{i}`. + led2.set_high().unwrap(); + writeln!(&mut tx, "Partially blocking DMA write: {i}!").unwrap(); + led2.set_low().unwrap(); + + // Something like this ensures there is only one DMA transfer. This, assuming the DMA buffer is empty and + // the data fits, guarantees a non blocking write: + //let mut bytes = heapless::Vec::<_, 64>::new(); + //writeln!(&mut bytes, "Non blocking write of complex message: {i} % 10 = {}!", i % 10); + //tx.write(bytes.as_slice()).unwrap(); + + delay_syst.delay(1000.millis()); + } } } diff --git a/src/adc.rs b/src/adc.rs index b40df49a..45f775bf 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -1301,7 +1301,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 @@ -1313,14 +1313,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)] @@ -1413,7 +1413,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()); @@ -1427,7 +1427,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()); @@ -1608,21 +1608,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 DelayUs) { - 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 @@ -1634,13 +1634,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. @@ -1650,11 +1650,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 @@ -1663,14 +1663,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(); } @@ -1709,7 +1709,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())); } } @@ -1719,7 +1719,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())); } } @@ -1727,30 +1727,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()) }); @@ -1760,14 +1764,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) ); @@ -1777,7 +1781,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 @@ -1789,7 +1795,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 @@ -1808,7 +1814,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) ); @@ -1818,7 +1824,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. @@ -1834,7 +1840,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() ) @@ -1861,35 +1867,40 @@ 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 #[inline(always)] pub fn calibrate(&mut self, it: config::InputType) { + let cr = self.adc_reg.cr().read(); + assert!(cr.aden().bit_is_clear()); + assert!(cr.adstart().bit_is_clear()); + assert!(cr.jadstart().bit_is_clear()); + 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 @@ -1912,7 +1923,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()) @@ -1925,47 +1936,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 @@ -1975,12 +1988,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 ); @@ -2005,116 +2020,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()); } } @@ -2326,8 +2341,8 @@ macro_rules! adc { /// 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.adc.set_external_trigger( (edge, extsel) ) + pub fn set_external_trigger>(&mut self, (edge, extsel): (config::TriggerMode, T)) { + self.adc.set_external_trigger( (edge, extsel.into()) ) } /// Sets auto delay to true or false @@ -2834,6 +2849,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/can.rs b/src/can.rs index 697df9c4..15d171a2 100644 --- a/src/can.rs +++ b/src/can.rs @@ -55,9 +55,9 @@ where { Self::enable(&rcc.rb); - if rcc.rb.ccipr.read().fdcansel().is_hse() { + if rcc.rb.ccipr().read().fdcansel().is_hse() { // Select P clock as FDCAN clock source - rcc.rb.ccipr.modify(|_, w| { + 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); 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/dac.rs b/src/dac.rs index 109374c0..991e8467 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 { T: DelayUs, { 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/config.rs b/src/dma/config.rs index 21b3bd02..6c854c58 100644 --- a/src/dma/config.rs +++ b/src/dma/config.rs @@ -38,7 +38,6 @@ pub struct DmaConfig { pub(crate) transfer_complete_interrupt: bool, pub(crate) half_transfer_interrupt: bool, pub(crate) transfer_error_interrupt: bool, - pub(crate) double_buffer: bool, } impl DmaConfig { @@ -84,10 +83,4 @@ impl DmaConfig { self.transfer_error_interrupt = transfer_error_interrupt; self } - /// Set the double_buffer. - #[inline(always)] - pub fn double_buffer(mut self, double_buffer: bool) -> Self { - self.double_buffer = double_buffer; - self - } } diff --git a/src/dma/stream.rs b/src/dma/stream.rs index 18dc4085..76cf60c6 100644 --- a/src/dma/stream.rs +++ b/src/dma/stream.rs @@ -131,13 +131,13 @@ pub trait DMAExt { 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() { + if !rcc.rb.ahb1enr().read().dmamuxen().bit_is_set() { // Enable peripheral - rcc.rb.ahb1enr.modify(|_, w| w.dmamuxen().set_bit()); + rcc.rb.ahb1enr().modify(|_, w| w.dmamuxen().set_bit()); } // Enable peripheral - rcc.rb.ahb1enr.modify(|_, w| w.dma1en().set_bit()); + rcc.rb.ahb1enr().modify(|_, w| w.dma1en().set_bit()); StreamsTuple::new(self) } @@ -146,13 +146,13 @@ impl DMAExt for DMA1 { 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() { + if !rcc.rb.ahb1enr().read().dmamuxen().bit_is_set() { // Enable peripheral - rcc.rb.ahb1enr.modify(|_, w| w.dmamuxen().set_bit()); + rcc.rb.ahb1enr().modify(|_, w| w.dmamuxen().set_bit()); } // Enable peripheral - rcc.rb.ahb1enr.modify(|_, w| w.dma2en().set_bit()); + rcc.rb.ahb1enr().modify(|_, w| w.dma2en().set_bit()); StreamsTuple::new(self) } @@ -181,11 +181,7 @@ impl StreamsTuple { // 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, ) - ),+$(,)*) => { + ($(($name:ident, $number:expr, $x:literal)),+$(,)*) => { $( impl Stream for $name { @@ -205,21 +201,23 @@ macro_rules! dma_stream { self.set_transfer_error_interrupt_enable( config.transfer_error_interrupt ); - } + } #[inline(always)] fn clear_interrupts(&mut self) { + let num = Self::NUMBER as u8; + //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 + dma.ifcr().write(|w| w + .ctcif(num).set_bit() //Clear transfer complete interrupt flag + .chtif(num).set_bit() //Clear half transfer interrupt flag + .cteif(num).set_bit() //Clear transfer error interrupt flag + .cgif(num).set_bit() //Clear global interrupt flag ); - let _ = dma.isr.read(); - let _ = dma.isr.read(); // Delay 2 peripheral clocks + let _ = dma.isr().read(); + let _ = dma.isr().read(); // Delay 2 peripheral clocks } #[inline(always)] @@ -227,7 +225,7 @@ macro_rules! dma_stream { //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()); + dma.ifcr().write(|w| w.ctcif(Self::NUMBER as u8).set_bit()); } #[inline(always)] @@ -235,8 +233,8 @@ macro_rules! dma_stream { 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 + let _ = dma.isr().read(); + let _ = dma.isr().read(); // Delay 2 peripheral clocks } #[inline(always)] @@ -244,50 +242,50 @@ macro_rules! dma_stream { //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 + dma.ifcr().write(|w| w.ctcif(Self::NUMBER as u8).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() + dma.isr().read().tcif(Self::NUMBER as u8).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() + dma.isr().read().tcif(Self::NUMBER as u8).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()); + let dma_ch = &unsafe { &*I::ptr() }.ch(Self::NUMBER); + dma_ch.cr().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() + let dma_ch = &unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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 StreamX - let dma = unsafe { &*I::ptr() }; + let dma_ch = &unsafe { &*I::ptr() }.ch(Self::NUMBER); // 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()); + dma_ch.cr().modify(|_, w| w.en().clear_bit()); while Self::is_enabled() {} self.clear_interrupts(); @@ -300,27 +298,22 @@ macro_rules! dma_stream { //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)); - }; + dmamux.ccr($number) + .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()) }); + let dma_ch = &unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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 StreamX - let dmacr = &unsafe { &*I::ptr() }.$ccr; + let dmacr = &unsafe { &*I::ptr() }.ch(Self::NUMBER).cr(); dmacr.modify(|_, w| w .tcie().clear_bit() .teie().clear_bit() @@ -332,19 +325,19 @@ macro_rules! dma_stream { #[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) + let dma_ch = &unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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::Interrupts { //NOTE(unsafe) We only access the registers that belongs to the StreamX - let dma = unsafe { &*I::ptr() }; - let cr = dma.$ccr.read(); + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + let cr = dma_ch.cr().read(); DmaInterrupts { transfer_complete: cr.tcie().bit_is_set(), @@ -357,7 +350,7 @@ macro_rules! dma_stream { #[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; + let dmacr = &unsafe { &*I::ptr() }.ch(Self::NUMBER).cr(); dmacr.modify(|_, w| w.tcie().bit(transfer_complete_interrupt)); let _ = dmacr.read(); let _ = dmacr.read(); // Delay 2 peripheral clocks @@ -366,7 +359,7 @@ macro_rules! dma_stream { #[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; + let dmacr = &unsafe { &*I::ptr() }.ch(Self::NUMBER).cr(); dmacr.modify(|_, w| w.teie().bit(transfer_error_interrupt)); let _ = dmacr.read(); let _ = dmacr.read(); // Delay 2 peripheral clocks @@ -375,7 +368,7 @@ macro_rules! dma_stream { #[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; + let dmacr = &unsafe { &*I::ptr() }.ch(Self::NUMBER).cr(); dmacr.modify(|_, w| w.htie().bit(half_transfer_interrupt)); let _ = dmacr.read(); let _ = dmacr.read(); // Delay 2 peripheral clocks @@ -385,7 +378,7 @@ macro_rules! dma_stream { 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() + dma.isr().read().htif(Self::NUMBER as u8).bit_is_set() } #[inline(always)] @@ -393,78 +386,78 @@ macro_rules! dma_stream { //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 + dma.ifcr().write(|w| w.chtif(Self::NUMBER as u8).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)); + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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 StreamX - let dma = &*I::ptr(); - dma.$cmarX.write(|w| w.ma().bits(value) ); + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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 StreamX - let dma = unsafe { &*I::ptr() }; - dma.$cmarX.read().ma().bits() + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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 StreamX - let dma = unsafe { &*I::ptr() }; - dma.$cndtrX.write(|w| unsafe {w.ndt().bits(value) }); + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + dma_ch.ndtr().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() + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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 StreamX - let dma = &*I::ptr(); - dma.$ccr.modify(|_, w| w.msize().bits(size)); + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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 StreamX - let dma = &*I::ptr(); - dma.$ccr.modify(|_, w| w.psize().bits(size)); + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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 StreamX - let dma = unsafe { &*I::ptr() }; - dma.$ccr.modify(|_, w| w.minc().bit(increment)); + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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 StreamX - let dma = unsafe { &*I::ptr() }; - dma.$ccr.modify(|_, w| w.pinc().bit(increment)); + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + 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 StreamX - let dma = unsafe { &*I::ptr() }; - dma.$ccr.modify(|_, w| { + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + dma_ch.cr().modify(|_, w| { match direction { DmaDirection::PeripheralToMemory => w.dir().clear_bit().mem2mem().clear_bit(), @@ -479,8 +472,8 @@ macro_rules! dma_stream { #[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)); + let dma_ch = unsafe { &*I::ptr() }.ch(Self::NUMBER); + dma_ch.cr().modify(|_, w| w.circ().bit(circular_buffer)); } } @@ -490,22 +483,22 @@ macro_rules! dma_stream { //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 + dma.ifcr().write(|w| w.chtif(Self::NUMBER as u8).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() + dma.isr().read().htif(Self::NUMBER as u8).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; + let dmacr = &unsafe { &*I::ptr() }.ch(Self::NUMBER).cr(); dmacr.modify(|_, w| w.htie().bit(half_transfer_interrupt)); let _ = dmacr.read(); let _ = dmacr.read(); // Delay 2 peripheral clocks @@ -515,6 +508,17 @@ macro_rules! dma_stream { }; } +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, 1), + (Stream1, 1, 2), + (Stream2, 2, 3), + (Stream3, 3, 4), + (Stream4, 4, 5), + (Stream5, 5, 6), +); + // Cat 3 and 4 devices #[cfg(any( feature = "stm32g471", @@ -528,95 +532,6 @@ macro_rules! dma_stream { 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, - ), + (Stream6, 6, 7), + (Stream7, 7, 8), ); diff --git a/src/dma/transfer.rs b/src/dma/transfer.rs index 2c0d2f3d..399abe87 100644 --- a/src/dma/transfer.rs +++ b/src/dma/transfer.rs @@ -383,14 +383,38 @@ where read } + /// Read all immediately available values without blocking pub fn read_available<'a>( &mut self, - data: &'a mut [>::MemSize], + dst: &'a mut [>::MemSize], + ) -> &'a mut [>::MemSize] { + self.read_available_multiple(1, dst) + } + + /// Same as [`CircTransfer::read_available`] but only read a whole multiple number of elements + /// + /// Example: + /// ``` + /// ... + /// // There are 7 values in the buffer + /// assert_eq!(transfer.read_available_multiple(3, &mut dst).len(), 6); + /// + /// // There are 3 values in the buffer + /// assert_eq!(transfer.read_available_multiple(2, &mut dst).len(), 2); + /// + /// // There are 1 values in the buffer + /// assert_eq!(transfer.read_available_multiple(2, &mut dst).len(), 0); + /// ``` + pub fn read_available_multiple<'a>( + &mut self, + multiple: u8, + dst: &'a mut [>::MemSize], ) -> &'a mut [>::MemSize] { let blen = unsafe { self.transfer.buf.static_write_buffer().1 }; let available = self.elements_available(); - let len = data.len().min(available).min(blen - 1); - let result = &mut data[0..len]; + let len = dst.len().min(available).min(blen - 1); + let len = len - (len % usize::from(multiple)); + let result = &mut dst[0..len]; self.read_exact(result); result @@ -512,7 +536,7 @@ impl_adc_overrun!(ADC4, ADC5,); macro_rules! impl_serial_timeout { ($($uart:ident, )*) => {$( - impl CircTransfer, BUF> + impl CircTransfer, BUF> where STREAM: Stream, /*BUF: StaticWriteBuffer + Deref*/ { 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 index 24e42088..997e11b9 100644 --- a/src/fdcan.rs +++ b/src/fdcan.rs @@ -286,9 +286,9 @@ where 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()); + 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 @@ -311,20 +311,20 @@ where self.set_bus_monitoring_mode(mon); let can = self.registers(); - can.test.modify(|_, w| w.lbck().bit(lbck)); + 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)); + 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)); + can.cccr().modify(|_, w| w.asm().bit(enabled)); } #[inline] @@ -335,14 +335,14 @@ where #[inline] fn set_test_mode(&mut self, enabled: bool) { let can = self.registers(); - can.cccr.modify(|_, w| w.test().bit(enabled)); + 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 {} + can.cccr().modify(|_, w| w.csr().bit(enabled)); + while can.cccr().read().csa().bit() != enabled {} } /// Enable/Disable the specific Interrupt Line @@ -350,8 +350,8 @@ where 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)), + InterruptLine::_0 => can.ile().modify(|_, w| w.eint1().bit(enabled)), + InterruptLine::_1 => can.ile().modify(|_, w| w.eint0().bit(enabled)), } } @@ -422,7 +422,7 @@ where /// Retrieve the current protocol status pub fn get_protocol_status(&self) -> ProtocolStatus { - let psr = self.registers().psr.read(); + 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(), @@ -526,9 +526,9 @@ where { I::enable(&rcc.rb); - if rcc.rb.ccipr.read().fdcansel().is_hse() { + if rcc.rb.ccipr().read().fdcansel().is_hse() { // Select P clock as FDCAN clock source - rcc.rb.ccipr.modify(|_, w| { + 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); @@ -541,7 +541,7 @@ where let can = Self::create_can(FdCanConfig::default(), can_instance); let reg = can.registers(); - assert!(reg.endn.read().bits() == 0x87654321_u32); + assert!(reg.endn().read().bits() == 0x87654321_u32); can } @@ -562,7 +562,7 @@ where TX: sealed::Tx, RX: sealed::Rx, { - rcc.rb.ccipr.modify(|_, w| { + 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); @@ -588,17 +588,17 @@ where // set TxBuffer to Queue Mode; // TODO: don't require this. - // can.txbc.write(|w| w.tfqm().set_bit()); + // 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) }); + 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 { + can.rxgfc().modify(|_, w| unsafe { w.lse() .bits(EXTENDED_FILTER_MAX) .lss() @@ -635,9 +635,9 @@ where 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() {} + 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 @@ -736,7 +736,7 @@ where self.control.config.nbtr = btr; let can = self.registers(); - can.nbtp.write(|w| unsafe { + can.nbtp().write(|w| unsafe { w.nbrp() .bits(btr.nbrp() - 1) .ntseg1() @@ -755,7 +755,7 @@ where self.control.config.dbtr = btr; let can = self.registers(); - can.dbtp.write(|w| unsafe { + can.dbtp().write(|w| unsafe { w.dbrp() .bits(btr.dbrp() - 1) .dtseg1() @@ -776,7 +776,7 @@ where #[inline] pub fn set_automatic_retransmit(&mut self, enabled: bool) { let can = self.registers(); - can.cccr.modify(|_, w| w.dar().bit(!enabled)); + can.cccr().modify(|_, w| w.dar().bit(!enabled)); self.control.config.automatic_retransmit = enabled; } @@ -785,7 +785,7 @@ where #[inline] pub fn set_transmit_pause(&mut self, enabled: bool) { let can = self.registers(); - can.cccr.modify(|_, w| w.dar().bit(!enabled)); + can.cccr().modify(|_, w| w.dar().bit(!enabled)); self.control.config.transmit_pause = enabled; } @@ -794,7 +794,7 @@ where #[inline] pub fn set_non_iso_mode(&mut self, enabled: bool) { let can = self.registers(); - can.cccr.modify(|_, w| w.niso().bit(enabled)); + can.cccr().modify(|_, w| w.niso().bit(enabled)); self.control.config.non_iso_mode = enabled; } @@ -803,7 +803,7 @@ where #[inline] pub fn set_edge_filtering(&mut self, enabled: bool) { let can = self.registers(); - can.cccr.modify(|_, w| w.efbi().bit(enabled)); + can.cccr().modify(|_, w| w.efbi().bit(enabled)); self.control.config.edge_filtering = enabled; } @@ -818,7 +818,7 @@ where }; let can = self.registers(); - can.cccr.modify(|_, w| w.fdoe().bit(fdoe).brse().bit(brse)); + can.cccr().modify(|_, w| w.fdoe().bit(fdoe).brse().bit(brse)); self.control.config.frame_transmit = fts; } @@ -829,7 +829,7 @@ where pub fn set_interrupt_line_config(&mut self, l0int: Interrupts) { let can = self.registers(); - can.ils.modify(|_, w| unsafe { w.bits(l0int.bits()) }); + can.ils().modify(|_, w| unsafe { w.bits(l0int.bits()) }); self.control.config.interrupt_line_config = l0int; } @@ -839,7 +839,7 @@ where pub fn set_protocol_exception_handling(&mut self, enabled: bool) { let can = self.registers(); - can.cccr.modify(|_, w| w.pxhd().bit(!enabled)); + can.cccr().modify(|_, w| w.pxhd().bit(!enabled)); self.control.config.protocol_exception_handling = enabled; } @@ -850,7 +850,7 @@ where pub fn set_clock_divider(&mut self, div: ClockDivider) { let can = self.registers(); - can.ckdiv.write(|w| unsafe { w.pdiv().bits(div as u8) }); + can.ckdiv().write(|w| unsafe { w.pdiv().bits(div as u8) }); self.control.config.clock_divider = div; } @@ -873,7 +873,7 @@ where /// Configures the global filter settings #[inline] pub fn set_global_filter(&mut self, filter: GlobalFilter) { - self.registers().rxgfc.modify(|_, w| { + self.registers().rxgfc().modify(|_, w| { unsafe { w.anfs() .bits(filter.handle_standard_frames as u8) @@ -993,7 +993,7 @@ where pub fn get_receive_pin(&mut self) -> bool { let can = self.registers(); - can.test.read().rx().bit_is_set() + can.test().read().rx().bit_is_set() } /// Sets the state of the transmit pin according to TestTransmitPinState @@ -1001,7 +1001,7 @@ where 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) }); + can.test().modify(|_, w| unsafe { w.tx().bits(state as u8) }); } } @@ -1159,10 +1159,11 @@ where #[inline] pub fn error_counters(&self) -> ErrorCounters { let can = self.registers(); - let cel: u8 = can.ecr.read().cel().bits(); - let rp: bool = can.ecr.read().rp().bit(); - let rec: u8 = can.ecr.read().rec().bits(); - let tec: u8 = can.ecr.read().tec().bits(); + 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, @@ -1177,28 +1178,28 @@ where /// Returns the current FdCan Timestamp counter #[inline] pub fn timestamp(&self) -> u16 { - self.registers().tscv.read().tsc().bits() + 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 + 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) }); + 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()) }); + can.ir().write(|w| unsafe { w.bits(interrupts.bits()) }); } } @@ -1310,7 +1311,7 @@ where } } else { // Read the Write Pointer - let idx = can.txfqs.read().tfqpi().bits(); + let idx = can.txfqs().read().tfqpi().bits(); (Mailbox::new(idx), None) }; @@ -1323,7 +1324,7 @@ where /// 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() + self.registers().txfqs().read().tfqf().bit() } /// Returns `Ok` when the mailbox is free or if it contains pending frame with a @@ -1405,13 +1406,13 @@ where let idx = 1u8 << idx; // Abort Request - can.txbcr.write(|w| unsafe { w.cr().bits(idx) }); + 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 { + if can.txbcf().read().cf().bits() & idx != 0 { // Return false when a transmission has occured - break can.txbto.read().to().bits() & idx == 0; + break can.txbto().read().to().bits() & idx == 0; } } } else { @@ -1425,28 +1426,28 @@ where let idx: u8 = idx.into(); let idx = 1u8 << idx; - can.txbrp.read().trp().bits() & idx != 0 + 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 + 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()); + 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()); + can.ir().write(|w| w.tcf().set_bit()); } } @@ -1570,8 +1571,8 @@ where fn has_overrun(&self) -> bool { let can = self.registers(); match FIFONR::NR { - 0 => can.rxf0s.read().rf0l().bit(), - 1 => can.rxf1s.read().rf1l().bit(), + 0 => can.rxf0s().read().rf0l().bit(), + 1 => can.rxf1s().read().rf1l().bit(), _ => unreachable!(), } } @@ -1581,8 +1582,8 @@ where 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, + 0 => can.rxf0s().read().f0fl().bits() == 0, + 1 => can.rxf1s().read().f1fl().bits() == 0, _ => unreachable!(), } } @@ -1595,8 +1596,8 @@ where 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()) }), + 0 => can.rxf0a().write(|w| unsafe { w.f0ai().bits(idx.into()) }), + 1 => can.rxf1a().write(|w| unsafe { w.f1ai().bits(idx.into()) }), _ => unreachable!(), } } @@ -1605,8 +1606,8 @@ where 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(), + 0 => can.rxf0s().read().f0gi().bits(), + 1 => can.rxf1s().read().f1gi().bits(), _ => unreachable!(), }; Mailbox::new(idx) @@ -1712,7 +1713,7 @@ mod impls { feature = "stm32g483", feature = "stm32g484", feature = "stm32g491", - feature = "stm32g4A1", + feature = "stm32g4a1", ))] mod fdcan2 { use crate::fdcan; diff --git a/src/flash.rs b/src/flash.rs index 26b60484..9edf1bfa 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 bd43df0c..7bb05cef 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.bits(1 << self.i)) }; 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.bits(1 << (self.i + 16))) }; Ok(()) } } @@ -296,7 +296,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().bits() & (1 << self.i) == 0 }; Ok(is_set_low) } } @@ -314,7 +314,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().bits() & (1 << self.i) == 0 }; Ok(is_low) } } @@ -329,7 +329,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().bits() & (1 << self.i) == 0 }; Ok(is_low) } } @@ -385,10 +385,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)) }) }; @@ -400,10 +400,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)) }) }; @@ -415,10 +415,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)) }) }; @@ -430,10 +430,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)) }); } @@ -445,13 +445,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)) }) }; @@ -463,13 +463,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)) }) }; @@ -486,9 +486,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 } @@ -500,19 +500,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)) }); } @@ -526,19 +526,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)) }); } @@ -561,13 +561,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.bits(1 << $i)) }; 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.bits(1 << ($i + 16))) }; Ok(()) } } @@ -580,7 +580,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().bits() & (1 << $i) == 0 }; Ok(is_set_low) } } @@ -598,7 +598,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().bits() & (1 << $i) == 0 }; Ok(is_low) } } @@ -623,7 +623,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().bits() & (1 << $i) == 0 }; Ok(is_low) } } diff --git a/src/hrtim/adc_trigger.rs b/src/hrtim/adc_trigger.rs new file mode 100644 index 00000000..6238501f --- /dev/null +++ b/src/hrtim/adc_trigger.rs @@ -0,0 +1,23 @@ +use core::marker::PhantomData; + +pub trait Adc13Trigger { + const BITS: u32; +} + +pub trait Adc24Trigger { + const BITS: u32; +} + +pub trait Adc579Trigger { + const BITS: u32; +} + +pub trait Adc6810Trigger { + const BITS: u32; +} + +/// Handle to timers reset/roll-over event +pub struct TimerReset(pub(crate) PhantomData); + +/// Handle to timers period event +pub struct TimerPeriod(pub(crate) PhantomData); diff --git a/src/hrtim/capture.rs b/src/hrtim/capture.rs new file mode 100644 index 00000000..f2081344 --- /dev/null +++ b/src/hrtim/capture.rs @@ -0,0 +1,264 @@ +use super::timer; +use crate::dma::mux::DmaMuxResources; +use crate::dma::traits::TargetAddress; +use crate::dma::PeripheralToMemory; +use crate::stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF}; +use core::marker::PhantomData; + +pub struct Ch1; +pub struct Ch2; + +pub struct Dma; +pub struct NoDma; + +pub struct HrCapt { + _x: PhantomData<(TIM, PSCL, CH, DMA)>, +} + +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Copy, Clone, Debug)] +pub enum CountingDirection { + Up = 0, + Down = 1, +} + +/// Implemented for +/// * TIM's update event +/// * EEVT1-10 +/// TODO: This sould be implemeted +/// * All neighbor timers CMP1, CPM2, OUT1_RST and OUT1_SET events +pub trait CaptureEvent { + const BITS: u32; +} + +/// Trait for capture channels used for capturing edges +/// +/// ``` +/// let capture: HrCapt<_, _, _> = todo!(); +/// if capture.is_pending() { +/// let (value, dir) = capture.get_last(); +/// capture.clear_interrupt(); +/// defmt::info!("Edge captured at counter value: {}, with: {}", value, dir); +/// } +/// ``` +/// +/// or alternatively +/// +/// ``` +/// let capture: HrCapt<_, _, _> = todo!(); +/// if let Some((value, dir)) = capture.get() { +/// defmt::info!("Edge captured at counter value: {}, with: {}", value, dir); +/// } +/// ``` +pub trait HrCapture { + /// Try to get the capture value + /// + /// Returns none if edge has been captured since last time + /// + /// NOTE: This function will use [`Self::is_pending`] to chech if there is a value available and + /// [`Self::clear_interrupt`] to clear it. + fn get(&mut self) -> Option<(u16, CountingDirection)> { + if self.is_pending() { + let value = self.get_last(); + self.clear_interrupt(); + Some(value) + } else { + None + } + } + + /// Get number of ticks relative to beginning of upcounting + /// + /// where captures during down counting count as negative (before the upcount) + /// + /// ```txt + /// Counter + /// ---------------------------------- <--- period + /// \ ^ / + /// \ | / + /// \ | / + /// \ | / + /// Down count \ | / Up count + /// \|/ + /// <-------------- 0 --------------> t + /// Negative result | positive result + /// ``` + /// + /// NOTE: This function will use [`Self::is_pending`] to chech if there is a value available and + /// [`Self::clear_interrupt`] to clear it. + fn get_signed(&mut self, period: u16) -> Option { + if self.is_pending() { + let value = self.get_last_signed(period); + self.clear_interrupt(); + Some(value) + } else { + None + } + } + + fn get_last(&self) -> (u16, CountingDirection); + + /// Get number of ticks relative to beginning of upcounting + /// + /// where captures during down counting count as negative (before the upcount) + /// + /// ``` + /// Counter + /// ---------------------------------- <--- period + /// \ ^ / + /// \ | / + /// \ | / + /// \ | / + /// Down count \ | / Up count + /// \|/ + /// <-------------- 0 --------------> t + /// Negative result | positive result + /// ``` + fn get_last_signed(&self, period: u16) -> i32 { + let (value, dir) = self.get_last(); + + // The capture counter always counts up and restarts at period + match dir { + CountingDirection::Up => i32::from(value), + CountingDirection::Down => i32::from(value) - i32::from(period), + } + } + + fn clear_interrupt(&mut self); + + fn is_pending(&self) -> bool; +} + +pub fn dma_value_to_dir_and_value(x: u32) -> (u16, CountingDirection) { + let value = (x & 0xFFFF) as u16; + match x & (1 << 16) != 0 { + true => (value, CountingDirection::Down), + false => (value, CountingDirection::Up), + } +} + +pub fn dma_value_to_signed(x: u32, period: u16) -> i32 { + let (value, dir) = dma_value_to_dir_and_value(x); + + // The capture counter always counts up and restarts at period + match dir { + CountingDirection::Up => i32::from(value), + CountingDirection::Down => i32::from(value) - i32::from(period), + } +} + +macro_rules! impl_capture { + ($($TIMX:ident: $CH:ident, $cptXYr:ident, $cptXYcr:ident, $cptXx:ident, $dier:ident, $icr:ident, $isr:ident, $cptXie:ident, $cptXde:ident, $cptXc:ident, $cptX:ident, $mux:expr),+) => {$( + impl HrCapt<$TIMX, PSCL, $CH, NoDma> { + /// Add event to capture + /// + /// If multiple events are added, they will be ORed together meaning + /// that a capture will be trigger if any one of the events triggers + pub fn add_event>(&mut self, _event: &E) { + let tim = unsafe { &*$TIMX::ptr() }; + + // SAFETY: We are the only one with access to cptXYcr + unsafe { + tim.$cptXYcr().modify(|r, w| w.bits(r.bits() | E::BITS)); + } + } + + /// Remove event to capture + pub fn remove_event>(&mut self, _event: &E) { + let tim = unsafe { &*$TIMX::ptr() }; + + // SAFETY: We are the only one with access to cptXYcr + unsafe { + tim.$cptXYcr().modify(|r, w| w.bits(r.bits() & !E::BITS)); + } + } + + /// Force capture trigger now + pub fn trigger_now(&mut self) { + // SAFETY: We are the only one with access to cptXYcr + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$cptXYcr().modify(|_, w| w.swcpt().set_bit()); + } + + // TODO: It would be sufficient to instead of hr_control only require exclusive access to the owning timer + // however that would be hard to do since typically the capture device is a field of that same timer. + // Would it make more sense to have this method direcly on HrTim instead? + pub fn enable_interrupt(&mut self, enable: bool, _hr_control: &mut super::HrPwmControl) { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$dier().modify(|_r, w| w.$cptXie().bit(enable)); + } + + pub fn enable_dma(self, _ch: timer::DmaChannel<$TIMX>) -> HrCapt<$TIMX, PSCL, $CH, Dma> { + // SAFETY: We own the only insance of this timers dma channel, no one else can do this + let tim = unsafe { &*$TIMX::ptr() }; + tim.$dier().modify(|_r, w| w.$cptXde().set_bit()); + HrCapt { + _x: PhantomData + } + } + } + + impl HrCapture for HrCapt<$TIMX, PSCL, $CH, DMA> { + fn get_last(&self) -> (u16, CountingDirection) { + let tim = unsafe { &*$TIMX::ptr() }; + let data = tim.$cptXYr().read(); + + let dir = match data.dir().bit() { + true => CountingDirection::Down, + false => CountingDirection::Up, + }; + let value = data.$cptXx().bits(); + + (value, dir) + } + + fn clear_interrupt(&mut self) { + let tim = unsafe { &*$TIMX::ptr() }; + + // No need for exclusive access since this is a write only register + tim.$icr().write(|w| w.$cptXc().set_bit()); + } + + fn is_pending(&self) -> bool { + let tim = unsafe { &*$TIMX::ptr() }; + + // No need for exclusive access since this is a read only register + tim.$isr().read().$cptX().bit() + } + } + + unsafe impl TargetAddress for HrCapt<$TIMX, PSCL, $CH, Dma> { + #[inline(always)] + fn address(&self) -> u32 { + let tim = unsafe { &*$TIMX::ptr() }; + &tim.$cptXYr() as *const _ as u32 + } + + type MemSize = u32; + + const REQUEST_LINE: Option = Some($mux as u8); + } + )+}; +} + +impl_capture! { + HRTIM_TIMA: Ch1, cpt1ar, cpt1acr, cpt1x, timadier, timaicr, timaisr, cpt1ie, cpt1de, cpt1c, cpt1, DmaMuxResources::HRTIM_TIMA, + HRTIM_TIMA: Ch2, cpt2ar, cpt2acr, cpt2x, timadier, timaicr, timaisr, cpt2ie, cpt2de, cpt2c, cpt2, DmaMuxResources::HRTIM_TIMA, + + HRTIM_TIMB: Ch1, cpt1br, cpt1bcr, cpt1x, timbdier, timbicr, timbisr, cpt1ie, cpt1de, cpt1c, cpt1, DmaMuxResources::HRTIM_TIMB, + HRTIM_TIMB: Ch2, cpt2br, cpt2bcr, cpt2x, timbdier, timbicr, timbisr, cpt2ie, cpt2de, cpt2c, cpt2, DmaMuxResources::HRTIM_TIMB, + + HRTIM_TIMC: Ch1, cpt1cr, cpt1ccr, cpt1x, timcdier, timcicr, timcisr, cpt1ie, cpt1de, cpt1c, cpt1, DmaMuxResources::HRTIM_TIMC, + HRTIM_TIMC: Ch2, cpt2cr, cpt2ccr, cpt2x, timcdier, timcicr, timcisr, cpt2ie, cpt2de, cpt2c, cpt2, DmaMuxResources::HRTIM_TIMC, + + HRTIM_TIMD: Ch1, cpt1dr, cpt1dcr, cpt1x, timddier, timdicr, timdisr, cpt1ie, cpt1de, cpt1c, cpt1, DmaMuxResources::HRTIM_TIMD, + HRTIM_TIMD: Ch2, cpt2dr, cpt2dcr, cpt2x, timddier, timdicr, timdisr, cpt2ie, cpt2de, cpt2c, cpt2, DmaMuxResources::HRTIM_TIMD, + + HRTIM_TIME: Ch1, cpt1er, cpt1ecr, cpt1x, timedier, timeicr, timeisr, cpt1ie, cpt1de, cpt1c, cpt1, DmaMuxResources::HRTIM_TIME, + HRTIM_TIME: Ch2, cpt2er, cpt2ecr, cpt2x, timedier, timeicr, timeisr, cpt2ie, cpt2de, cpt2c, cpt2, DmaMuxResources::HRTIM_TIME, + + HRTIM_TIMF: Ch1, cpt1fr, cpt1fcr, cpt1x, timfdier, timficr, timfisr, cpt1ie, cpt1de, cpt1c, cpt1, DmaMuxResources::HRTIM_TIMF, + HRTIM_TIMF: Ch2, cpt2fr, cpt2fcr, cpt2x, timfdier, timficr, timfisr, cpt2ie, cpt2de, cpt2c, cpt2, DmaMuxResources::HRTIM_TIMF +} diff --git a/src/hrtim/compare_register.rs b/src/hrtim/compare_register.rs new file mode 100644 index 00000000..1cdaf69c --- /dev/null +++ b/src/hrtim/compare_register.rs @@ -0,0 +1,186 @@ +use core::marker::PhantomData; + +use crate::stm32::{ + HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF, +}; + +pub trait HrCompareRegister { + fn get_duty(&self) -> u16; + fn set_duty(&mut self, duty: u16); +} + +pub struct HrCr1(PhantomData<(TIM, PSCL)>); +pub struct HrCr2(PhantomData<(TIM, PSCL)>); +pub struct HrCr3(PhantomData<(TIM, PSCL)>); +pub struct HrCr4(PhantomData<(TIM, PSCL)>); + +use super::adc_trigger::Adc13Trigger as Adc13; +use super::adc_trigger::Adc24Trigger as Adc24; +use super::adc_trigger::Adc579Trigger as Adc579; +use super::adc_trigger::Adc6810Trigger as Adc6810; + +macro_rules! hrtim_cr_helper { + (HRTIM_MASTER: $cr_type:ident: + $cmpXYr:ident, $cmpYx:ident, + [$(($Trigger:ty: $trigger_bits:expr)),*], + [$(($event_dst:ident, $tim_event_index:expr)),*], + $bit_index:literal + ) => { + // Strip bit_index since master timer has other bits that are common across all destinations + hrtim_cr_helper!(HRTIM_MASTER: $cr_type: $cmpXYr, $cmpYx, [$(($Trigger: $trigger_bits)),*], [$(($event_dst, $tim_event_index)),*]); + }; + + ($TIMX:ident: $cr_type:ident: + $cmpXYr:ident, $cmpYx:ident, + [$(($Trigger:ty: $trigger_bits:expr)),*], + [$(($event_dst:ident, $tim_event_index:expr)),*] + $(, $bit_index:literal)* + ) => { + impl HrCompareRegister for $cr_type<$TIMX, PSCL> { + fn get_duty(&self) -> u16 { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$cmpXYr().read().$cmpYx().bits() + } + fn set_duty(&mut self, duty: u16) { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$cmpXYr().write(|w| unsafe { w.$cmpYx().bits(duty) }); + } + } + + $( + /// Compare match event + impl super::event::EventSource<$TIMX, PSCL> for $cr_type<$TIMX, PSCL> { + const BITS: u32 = 1 << $bit_index; + } + )* + + $( + /// Compare match event for neighbor timer + impl super::event::EventSource<$event_dst, PSCL> for $cr_type<$TIMX, PSCL> { + const BITS: u32 = 1 << ($tim_event_index + 11); // TIMEVNT1 is at bit 12, TIMEVNT2 at bit 13 etc + } + )* + + $( + impl $Trigger for $cr_type<$TIMX, PSCL> { + const BITS: u32 = $trigger_bits; + } + )* + }; +} + +macro_rules! hrtim_cr { + ($($TIMX:ident: [ + [$cmpX1r:ident, $cmp1x:ident, [$(($cr1_trigger:ident: $cr1_trigger_bits:expr)),*], [$(($cr1_event_dst:ident, $cr1_tim_event_index:expr)),*]], + [$cmpX2r:ident, $cmp2x:ident, [$(($cr2_trigger:ident: $cr2_trigger_bits:expr)),*], [$(($cr2_event_dst:ident, $cr2_tim_event_index:expr)),*]], + [$cmpX3r:ident, $cmp3x:ident, [$(($cr3_trigger:ident: $cr3_trigger_bits:expr)),*], [$(($cr3_event_dst:ident, $cr3_tim_event_index:expr)),*]], + [$cmpX4r:ident, $cmp4x:ident, [$(($cr4_trigger:ident: $cr4_trigger_bits:expr)),*], [$(($cr4_event_dst:ident, $cr4_tim_event_index:expr)),*]] + ]),+) => {$( + hrtim_cr_helper!($TIMX: HrCr1: $cmpX1r, $cmp1x, [$(($cr1_trigger: $cr1_trigger_bits)),*], [$(($cr1_event_dst, $cr1_tim_event_index)),*], 3); + hrtim_cr_helper!($TIMX: HrCr2: $cmpX2r, $cmp2x, [$(($cr2_trigger: $cr2_trigger_bits)),*], [$(($cr2_event_dst, $cr2_tim_event_index)),*], 4); + hrtim_cr_helper!($TIMX: HrCr3: $cmpX3r, $cmp3x, [$(($cr3_trigger: $cr3_trigger_bits)),*], [$(($cr3_event_dst, $cr3_tim_event_index)),*], 5); + hrtim_cr_helper!($TIMX: HrCr4: $cmpX4r, $cmp4x, [$(($cr4_trigger: $cr4_trigger_bits)),*], [$(($cr4_event_dst, $cr4_tim_event_index)),*], 6); + )+}; +} + +// See RM0440 Table 218. 'Events mapping across timer A to F' +hrtim_cr! { + HRTIM_MASTER: [ + [mcmp1r, mcmp1, [(Adc13: 1 << 0), (Adc24: 1 << 0), (Adc579: 0), (Adc6810: 0) ], []], + [mcmp2r, mcmp2, [(Adc13: 1 << 1), (Adc24: 1 << 1), (Adc579: 1), (Adc6810: 1) ], []], + [mcmp3r, mcmp3, [(Adc13: 1 << 2), (Adc24: 1 << 2), (Adc579: 2), (Adc6810: 2) ], []], + [mcmp4r, mcmp4, [(Adc13: 1 << 3), (Adc24: 1 << 3), (Adc579: 3), (Adc6810: 3) ], []] + ], + + HRTIM_TIMA: [ + [cmp1ar, cmp1x, [ ], [(HRTIM_TIMB, 1), (HRTIM_TIMD, 1) ]], + [cmp2ar, cmp2x, [ (Adc24: 1 << 10), (Adc6810: 10)], [(HRTIM_TIMB, 2), (HRTIM_TIMC, 1) ]], + [cmp3ar, cmp3x, [(Adc13: 1 << 11), (Adc579: 10) ], [(HRTIM_TIMC, 2), (HRTIM_TIMF, 1) ]], + [cmp4ar, cmp4x, [(Adc13: 1 << 12), (Adc24: 1 << 12), (Adc579: 11), (Adc6810: 11)], [(HRTIM_TIMD, 2), (HRTIM_TIME, 1) ]] + ], + + HRTIM_TIMB: [ + [cmp1br, cmp1x, [ ], [(HRTIM_TIMA, 1), (HRTIM_TIMF, 2) ]], + [cmp2br, cmp2x, [ (Adc24: 1 << 14), (Adc6810: 13)], [(HRTIM_TIMA, 2), (HRTIM_TIMC, 3), (HRTIM_TIMD, 3)]], + [cmp3br, cmp3x, [(Adc13: 1 << 16), (Adc579: 14) ], [(HRTIM_TIMC, 4), (HRTIM_TIME, 2) ]], + [cmp4br, cmp4x, [(Adc13: 1 << 17), (Adc24: 1 << 16), (Adc579: 15), (Adc6810: 14)], [(HRTIM_TIMD, 4), (HRTIM_TIME, 3), (HRTIM_TIMF, 3)]] + ], + + HRTIM_TIMC: [ + [cmp1cr, cmp1x, [ ], [(HRTIM_TIME, 4), (HRTIM_TIMF, 4) ]], + [cmp2cr, cmp2x, [ (Adc24: 1 << 18), (Adc6810: 16)], [(HRTIM_TIMA, 3), (HRTIM_TIME, 5) ]], + [cmp3cr, cmp3x, [(Adc13: 1 << 21), (Adc579: 18) ], [(HRTIM_TIMA, 4), (HRTIM_TIMB, 3) ]], + [cmp4cr, cmp4x, [(Adc13: 1 << 22), (Adc24: 1 << 20), (Adc579: 19), (Adc6810: 17)], [(HRTIM_TIMB, 4), (HRTIM_TIMD, 5), (HRTIM_TIMF, 5)]] + ], + + HRTIM_TIMD: [ + [cmp1dr, cmp1x, [ ], [(HRTIM_TIMA, 5), (HRTIM_TIME, 6) ]], + [cmp2dr, cmp2x, [ (Adc24: 1 << 23), (Adc6810: 20)], [(HRTIM_TIMA, 6), (HRTIM_TIMC, 5), (HRTIM_TIME, 7)]], + [cmp3dr, cmp3x, [(Adc13: 1 << 25), (Adc579: 21) ], [(HRTIM_TIMB, 5), (HRTIM_TIMF, 6) ]], + [cmp4dr, cmp4x, [(Adc13: 1 << 26), (Adc24: 1 << 25), (Adc579: 22), (Adc6810: 21)], [(HRTIM_TIMB, 6), (HRTIM_TIMC, 6), (HRTIM_TIMF, 7)]] + ], + + HRTIM_TIME: [ + [cmp1er, cmp1x, [ ], [(HRTIM_TIMB, 7), (HRTIM_TIMD, 6) ]], + [cmp2er, cmp2x, [ (Adc24: 1 << 28), (Adc6810: 24)], [(HRTIM_TIMB, 8), (HRTIM_TIMF, 8) ]], + [cmp3er, cmp3x, [(Adc13: 1 << 29), (Adc24: 1 << 29), (Adc579: 24), (Adc6810: 25)], [(HRTIM_TIMA, 7), (HRTIM_TIMC, 7), (HRTIM_TIMF, 9)]], + [cmp4er, cmp4x, [(Adc13: 1 << 30), (Adc24: 1 << 30), (Adc579: 25), (Adc6810: 26)], [(HRTIM_TIMA, 8), (HRTIM_TIMC, 8), (HRTIM_TIMD, 7)]] + ], + + HRTIM_TIMF: [ + [cmp1fr, cmp1x, [ (Adc24: 1 << 15) ], [(HRTIM_TIMD, 8) ]], + [cmp2fr, cmp2x, [(Adc13: 1 << 10), (Adc24: 1 << 11), (Adc579: 27), (Adc6810: 28)], [(HRTIM_TIMC, 9) ]], + [cmp3fr, cmp3x, [(Adc13: 1 << 15), (Adc579: 28), (Adc6810: 29)], [(HRTIM_TIMB, 9), (HRTIM_TIMD, 9), (HRTIM_TIME, 8)]], + [cmp4fr, cmp4x, [(Adc13: 1 << 20), (Adc24: 1 << 19), (Adc579: 29), (Adc6810: 30)], [(HRTIM_TIMA, 9), (HRTIM_TIME, 9) ]] + ] +} + +macro_rules! hrtim_master_cr { + ($($cr_type:ident: $cr_index:expr),*) => {$( + /// Compare match event for neighbor timer + impl super::event::EventSource for $cr_type { + const BITS: u32 = 1 << ($cr_index + 7); // MSTCMP1 is at bit 8 etc + } + + impl super::event::TimerResetEventSource for $cr_type { + const BITS: u32 = 1 << ($cr_index + 4); // MSTCMP1 is at bit 5 + } + )*}; +} + +hrtim_master_cr! { + HrCr1: 1, + HrCr2: 2, + HrCr3: 3, + HrCr4: 4 +} + +macro_rules! hrtim_timer_rst { + ($($TIMX:ident: $cr_type:ident: $bit_index:literal),*) => {$( + impl super::event::TimerResetEventSource for $cr_type<$TIMX, PSCL> { + const BITS: u32 = 1 << $bit_index; + } + )*}; +} + +hrtim_timer_rst! { + HRTIM_TIMA: HrCr2: 2, + HRTIM_TIMA: HrCr4: 3, + + HRTIM_TIMB: HrCr2: 2, + HRTIM_TIMB: HrCr4: 3, + + HRTIM_TIMC: HrCr2: 2, + HRTIM_TIMC: HrCr4: 3, + + HRTIM_TIMD: HrCr2: 2, + HRTIM_TIMD: HrCr4: 3, + + HRTIM_TIME: HrCr2: 2, + HRTIM_TIME: HrCr4: 3, + + HRTIM_TIMF: HrCr2: 2, + HRTIM_TIMF: HrCr4: 3 +} diff --git a/src/hrtim/control.rs b/src/hrtim/control.rs new file mode 100644 index 00000000..234d25d1 --- /dev/null +++ b/src/hrtim/control.rs @@ -0,0 +1,387 @@ +use core::marker::PhantomData; + +use crate::{ + hrtim::fault::{ + FltMonitor1, FltMonitor2, FltMonitor3, FltMonitor4, FltMonitor5, FltMonitor6, FltMonitorSys, + }, + rcc::{Enable, Rcc, Reset}, + stm32::{HRTIM_COMMON, RCC}, +}; + +use super::{external_event::EevInputs, fault::FaultInputs}; + +pub trait HrControltExt { + fn hr_control(self, _rcc: &mut Rcc) -> HrTimOngoingCalibration; +} + +impl HrControltExt for HRTIM_COMMON { + fn hr_control(self, _rcc: &mut Rcc) -> HrTimOngoingCalibration { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + + unsafe { + let rcc_ptr = &*RCC::ptr(); + + HRTIM_COMMON::enable(rcc_ptr); + HRTIM_COMMON::reset(rcc_ptr); + } + + // Start calibration procedure + common + .dllcr() + .write(|w| w.cal().set_bit().calen().clear_bit()); + + HrTimOngoingCalibration { + adc_trigger1_postscaler: AdcTriggerPostscaler::None, + adc_trigger2_postscaler: AdcTriggerPostscaler::None, + adc_trigger3_postscaler: AdcTriggerPostscaler::None, + adc_trigger4_postscaler: AdcTriggerPostscaler::None, + + adc_trigger5_postscaler: AdcTriggerPostscaler::None, + adc_trigger6_postscaler: AdcTriggerPostscaler::None, + adc_trigger7_postscaler: AdcTriggerPostscaler::None, + adc_trigger8_postscaler: AdcTriggerPostscaler::None, + adc_trigger9_postscaler: AdcTriggerPostscaler::None, + adc_trigger10_postscaler: AdcTriggerPostscaler::None, + + flt_divider: SamplingClkDiv::None, + eev_divider: SamplingClkDiv::None, + } + } +} + +pub struct HrTimOngoingCalibration { + adc_trigger1_postscaler: AdcTriggerPostscaler, + adc_trigger2_postscaler: AdcTriggerPostscaler, + adc_trigger3_postscaler: AdcTriggerPostscaler, + adc_trigger4_postscaler: AdcTriggerPostscaler, + + adc_trigger5_postscaler: AdcTriggerPostscaler, + adc_trigger6_postscaler: AdcTriggerPostscaler, + adc_trigger7_postscaler: AdcTriggerPostscaler, + adc_trigger8_postscaler: AdcTriggerPostscaler, + adc_trigger9_postscaler: AdcTriggerPostscaler, + adc_trigger10_postscaler: AdcTriggerPostscaler, + + flt_divider: SamplingClkDiv, + eev_divider: SamplingClkDiv, +} + +impl HrTimOngoingCalibration { + /// SAFETY: Calibration needs to be done before calling this + unsafe fn init(self) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + + let Self { + adc_trigger1_postscaler, + adc_trigger2_postscaler, + adc_trigger3_postscaler, + adc_trigger4_postscaler, + + adc_trigger5_postscaler, + adc_trigger6_postscaler, + adc_trigger7_postscaler, + adc_trigger8_postscaler, + adc_trigger9_postscaler, + adc_trigger10_postscaler, + + flt_divider, + eev_divider, + } = self; + + unsafe { + // Enable periodic calibration + // with f_hrtim at 170MHz, these settings leads to + // a period of about 6.2ms + common + .dllcr() + .modify(|_r, w| w.calrte().bits(0b00).cal().set_bit().calen().clear_bit()); + common + .fltinr2() + .write(|w| w.fltsd().bits(flt_divider as u8)); + common.eecr3().write(|w| w.eevsd().bits(eev_divider as u8)); + + common.adcps1().write(|w| { + w.adc1psc() + .bits(adc_trigger1_postscaler as u8) + .adc2psc() + .bits(adc_trigger2_postscaler as u8) + .adc3psc() + .bits(adc_trigger3_postscaler as u8) + .adc4psc() + .bits(adc_trigger4_postscaler as u8) + .adc5psc() + .bits(adc_trigger5_postscaler as u8) + }); + + common.adcps2().write(|w| { + w.adc6psc() + .bits(adc_trigger6_postscaler as u8) + .adc7psc() + .bits(adc_trigger7_postscaler as u8) + .adc8psc() + .bits(adc_trigger8_postscaler as u8) + .adc9psc() + .bits(adc_trigger9_postscaler as u8) + .adc10psc() + .bits(adc_trigger10_postscaler as u8) + }); + + // TODO: Adc trigger 5-10 + } + } + + pub fn wait_for_calibration(self) -> (HrTimCalibrated, FaultInputs, EevInputs) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + while common.isr().read().dllrdy().bit_is_clear() { + // Wait until ready + } + + // Calibration is now done, it is safe to continue + unsafe { self.init() }; + + ( + HrTimCalibrated { _x: PhantomData }, + unsafe { FaultInputs::new() }, + unsafe { EevInputs::new() }, + ) + } + + pub fn set_adc1_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { + self.adc_trigger1_postscaler = post_scaler; + self + } + + pub fn set_adc2_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { + self.adc_trigger2_postscaler = post_scaler; + self + } + + pub fn set_adc3_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { + self.adc_trigger3_postscaler = post_scaler; + self + } + + pub fn set_adc4_trigger_psc(mut self, post_scaler: AdcTriggerPostscaler) -> Self { + self.adc_trigger4_postscaler = post_scaler; + self + } + + pub fn set_fault_sampling_division(mut self, divider: SamplingClkDiv) -> Self { + self.flt_divider = divider; + self + } + + pub fn set_eev_sampling_division(mut self, divider: SamplingClkDiv) -> Self { + self.eev_divider = divider; + self + } +} + +/// This object may be used for things that needs to be done before any timers have been started but after the calibration has been completed. Its existence is proof that no timers have started. +/// +/// Once done with setup, use the `constrain` to get a `HrPwmControl` which can be used to start the timers. +pub struct HrTimCalibrated { + _x: PhantomData<()>, +} + +impl HrTimCalibrated { + pub fn constrain(self) -> HrPwmControl { + HrPwmControl { + _x: PhantomData, + control: HrPwmCtrl { _x: PhantomData }, + fault_sys: FltMonitorSys { _x: PhantomData }, + fault_1: FltMonitor1 { _x: PhantomData }, + fault_2: FltMonitor2 { _x: PhantomData }, + fault_3: FltMonitor3 { _x: PhantomData }, + fault_4: FltMonitor4 { _x: PhantomData }, + fault_5: FltMonitor5 { _x: PhantomData }, + fault_6: FltMonitor6 { _x: PhantomData }, + + adc_trigger1: Adc1Trigger { _x: PhantomData }, + adc_trigger2: Adc2Trigger { _x: PhantomData }, + adc_trigger3: Adc3Trigger { _x: PhantomData }, + adc_trigger4: Adc4Trigger { _x: PhantomData }, + adc_trigger5: Adc5Trigger { _x: PhantomData }, + adc_trigger6: Adc6Trigger { _x: PhantomData }, + adc_trigger7: Adc7Trigger { _x: PhantomData }, + adc_trigger8: Adc8Trigger { _x: PhantomData }, + adc_trigger9: Adc9Trigger { _x: PhantomData }, + adc_trigger10: Adc10Trigger { _x: PhantomData }, + } + } +} + +impl<'a> Into<&'a mut HrPwmCtrl> for &'a mut HrPwmControl { + fn into(self) -> &'a mut HrPwmCtrl { + &mut self.control + } +} + +/// Used as a token to guarantee unique access to resources common to multiple timers +/// +/// An instance of this object can be obtained from [`HrPwmControl`].control +pub struct HrPwmCtrl { + _x: PhantomData<()>, +} + +/// Used as a token to guarantee unique access to resources common to multiple timers +pub struct HrPwmControl { + _x: PhantomData<()>, + + pub control: HrPwmCtrl, + + pub fault_sys: FltMonitorSys, + pub fault_1: FltMonitor1, + pub fault_2: FltMonitor2, + pub fault_3: FltMonitor3, + pub fault_4: FltMonitor4, + pub fault_5: FltMonitor5, + pub fault_6: FltMonitor6, + + pub adc_trigger1: Adc1Trigger, + pub adc_trigger2: Adc2Trigger, + pub adc_trigger3: Adc3Trigger, + pub adc_trigger4: Adc4Trigger, + + pub adc_trigger5: Adc5Trigger, + pub adc_trigger6: Adc6Trigger, + pub adc_trigger7: Adc7Trigger, + pub adc_trigger8: Adc8Trigger, + pub adc_trigger9: Adc9Trigger, + pub adc_trigger10: Adc10Trigger, +} + +macro_rules! impl_adc1234_trigger { + ($($t:ident: [$trait_:ident, $adcXr:ident, $variant345:ident $(, $variant12:ident)*]),*) => {$( + pub struct $t { + _x: PhantomData<()>, + } + + impl $t { + pub fn enable_source(&mut self, _trigger: &T) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + unsafe { + common.$adcXr().modify(|r, w| w.bits(r.bits() | T::BITS)); + } + } + } + + $(impl From<&$t> for crate::adc::config::ExternalTrigger12 { + fn from(_val: &$t) -> Self { + crate::adc::config::ExternalTrigger12::$variant12 + } + })* + + impl From<&$t> for crate::adc::config::ExternalTrigger345 { + fn from(_val: &$t) -> Self { + crate::adc::config::ExternalTrigger345::$variant345 + } + } + )*} +} + +macro_rules! impl_adc5678910_trigger { + ($($t:ident: [$trait_:ident, $adcXtrg:ident, $variant345:ident, $variant12:ident]),*) => {$( + pub struct $t { + _x: PhantomData<()>, + } + + impl $t { + pub fn enable_source(&mut self, _trigger: &T) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common + .adcer() + .modify(|_r, w| unsafe { w.$adcXtrg().bits(T::BITS as u8) }); + } + } + + impl From<&$t> for crate::adc::config::ExternalTrigger12 { + fn from(_val: &$t) -> Self { + crate::adc::config::ExternalTrigger12::$variant12 + } + } + + impl From<&$t> for crate::adc::config::ExternalTrigger345 { + fn from(_val: &$t) -> Self { + crate::adc::config::ExternalTrigger345::$variant345 + } + } + + )*} +} + +impl_adc1234_trigger! {// reg adc345, adc12 + Adc1Trigger: [Adc13Trigger, adc1r, Hrtim_adc_trg_1, Hrtim_adc_trg_1], + Adc2Trigger: [Adc24Trigger, adc2r, Hrtim_adc_trg_2], + Adc3Trigger: [Adc13Trigger, adc3r, Hrtim_adc_trg_3, Hrtim_adc_trg_3], + Adc4Trigger: [Adc24Trigger, adc4r, Hrtim_adc_trg_4] +} + +impl_adc5678910_trigger! { + Adc5Trigger: [Adc579Trigger, adc5trg, Hrtim_adc_trg_5, Hrtim_adc_trg_5], + Adc6Trigger: [Adc6810Trigger, adc6trg, Hrtim_adc_trg_6, Hrtim_adc_trg_6], + Adc7Trigger: [Adc579Trigger, adc7trg, Hrtim_adc_trg_7, Hrtim_adc_trg_7], + Adc8Trigger: [Adc6810Trigger, adc8trg, Hrtim_adc_trg_8, Hrtim_adc_trg_8], + Adc9Trigger: [Adc579Trigger, adc9trg, Hrtim_adc_trg_9, Hrtim_adc_trg_9], + Adc10Trigger: [Adc6810Trigger, adc10trg, Hrtim_adc_trg_10, Hrtim_adc_trg_10] +} + +use super::adc_trigger::{Adc13Trigger, Adc24Trigger, Adc579Trigger, Adc6810Trigger}; + +pub enum AdcTriggerPostscaler { + None = 0, + Div2 = 1, + Div3 = 2, + Div4 = 3, + Div5 = 4, + Div6 = 5, + Div7 = 6, + Div8 = 7, + Div9 = 8, + Div10 = 9, + Div11 = 10, + Div12 = 11, + Div13 = 12, + Div14 = 13, + Div15 = 14, + Div16 = 15, + Div17 = 16, + Div18 = 17, + Div19 = 18, + Div20 = 19, + Div21 = 20, + Div22 = 21, + Div23 = 22, + Div24 = 23, + Div25 = 24, + Div26 = 25, + Div27 = 26, + Div28 = 27, + Div29 = 28, + Div30 = 29, + Div31 = 30, + Div32 = 31, +} + +/// The divsion ratio between f_hrtim and the fault signal sampling clock for digital filters +pub enum SamplingClkDiv { + /// No division + /// + /// fault signal sampling clock f_flts = f_hrtim + None = 0b00, + + /// 1/2 + /// + /// fault signal sampling clock f_flts = f_hrtim / 2 + Two = 0b01, + + /// 1/4 + /// + /// fault signal sampling clock f_flts = f_hrtim / 4 + Four = 0b10, + + /// 1/8 + /// + /// fault signal sampling clock f_flts = f_hrtim / 8 + Eight = 0b11, +} diff --git a/src/hrtim/deadtime.rs b/src/hrtim/deadtime.rs new file mode 100644 index 00000000..c59c0641 --- /dev/null +++ b/src/hrtim/deadtime.rs @@ -0,0 +1,79 @@ +#[derive(Copy, Clone, Debug)] +pub struct DeadtimeConfig { + /// Prescaler for both rising and falling deadtime + pub(crate) prescaler: DeadtimePrescaler, + + /// 9-bits + pub(crate) deadtime_rising_value: u16, + + /// Is deadtime negative + pub(crate) deadtime_rising_sign: bool, + + /// 9-bits + pub(crate) deadtime_falling_value: u16, + + /// Is deadtime negative + pub(crate) deadtime_falling_sign: bool, +} + +impl DeadtimeConfig { + /// See RM0440 Table 221 'Deadtime resolution and max absolute values' + pub fn prescaler(mut self, value: DeadtimePrescaler) -> Self { + self.prescaler = value; + self + } + + /// Panic if value can not fit in 9 bits + pub fn deadtime_rising_value(mut self, value: u16) -> Self { + // 9 bits + assert!(value < (1 << 9)); + + self.deadtime_rising_value = value; + + self + } + + pub fn deadtime_rising_sign(mut self, is_negative: bool) -> Self { + self.deadtime_rising_sign = is_negative; + self + } + + /// Panic if value can not fit in 9 bits + pub fn deadtime_falling_value(mut self, value: u16) -> Self { + // 9 bits + assert!(value < (1 << 9)); + + self.deadtime_falling_value = value; + + self + } + + pub fn deadtime_falling_sign(mut self, is_negative: bool) -> Self { + self.deadtime_falling_sign = is_negative; + self + } +} + +impl Default for DeadtimeConfig { + fn default() -> Self { + Self { + prescaler: DeadtimePrescaler::Thrtim, + deadtime_rising_value: 170, // about 1us when f_sys = 170MHz + deadtime_rising_sign: false, + deadtime_falling_value: 170, // about 1us when f_sys = 170MHz + deadtime_falling_sign: false, + } + } +} + +#[derive(Copy, Clone, Debug)] +pub enum DeadtimePrescaler { + ThrtimDiv8 = 0b000, + ThrtimDiv4 = 0b001, + ThrtimDiv2 = 0b010, + Thrtim = 0b011, + ThrtimMul2 = 0b100, + ThrtimMul4 = 0b101, + ThrtimMul8 = 0b110, + ThrtimMul16 = 0b111, +} diff --git a/src/hrtim/event.rs b/src/hrtim/event.rs new file mode 100644 index 00000000..5c472809 --- /dev/null +++ b/src/hrtim/event.rs @@ -0,0 +1,16 @@ +/// Event that can be used to set/reset an output +pub trait EventSource { + const BITS: u32; +} + +/// Done: +/// * [x] Eev1-10 +/// * [x] Master period +/// * [x] Master CMP1-4 +/// * [x] Cmp2, Cmp4 +/// * [x] Timer Update +/// * [ ] Neighbor timers compare events +/// Event that can be used reset the timer counter +pub trait TimerResetEventSource { + const BITS: u32; +} diff --git a/src/hrtim/external_event.rs b/src/hrtim/external_event.rs new file mode 100644 index 00000000..ee88262e --- /dev/null +++ b/src/hrtim/external_event.rs @@ -0,0 +1,371 @@ +use core::marker::PhantomData; + +use crate::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7}; +use crate::gpio::gpiob::{PB3, PB4, PB5, PB6, PB7, PB8, PB9}; +use crate::gpio::gpioc::{PC11, PC12, PC5, PC6}; +use crate::gpio::{self, AF13, AF3}; +use crate::pwm::Polarity; +use crate::stm32::HRTIM_COMMON; + +use super::control::HrTimCalibrated; + +#[derive(Copy, Clone, PartialEq)] +pub struct ExternalEventSource { + _x: PhantomData<()>, +} + +pub struct EevInputs { + pub eev_input1: EevInput<1>, + pub eev_input2: EevInput<2>, + pub eev_input3: EevInput<3>, + pub eev_input4: EevInput<4>, + pub eev_input5: EevInput<5>, + pub eev_input6: EevInput<6>, + pub eev_input7: EevInput<7>, + pub eev_input8: EevInput<8>, + pub eev_input9: EevInput<9>, + pub eev_input10: EevInput<10>, +} + +impl EevInputs { + pub(crate) unsafe fn new() -> Self { + EevInputs { + eev_input1: EevInput { _x: PhantomData }, + eev_input2: EevInput { _x: PhantomData }, + eev_input3: EevInput { _x: PhantomData }, + eev_input4: EevInput { _x: PhantomData }, + eev_input5: EevInput { _x: PhantomData }, + eev_input6: EevInput { _x: PhantomData }, + eev_input7: EevInput { _x: PhantomData }, + eev_input8: EevInput { _x: PhantomData }, + eev_input9: EevInput { _x: PhantomData }, + eev_input10: EevInput { _x: PhantomData }, + } + } +} + +pub struct EevInput { + _x: PhantomData<()>, +} + +/// This is implemented for types that can be used as inputs to the eev +/// # Safety +/// Only implement for types that can be used as sources to eev number `EEV_N` with src bits `SRC_BITS` +pub unsafe trait EevSrcBits: Sized { + const SRC_BITS: u8; + fn cfg(self) {} +} + +macro_rules! impl_eev_input { + ($N:literal: COMP=[$compX:ident $(, ($compY:ident, $compY_src_bits:literal))*], PINS=[$(($pin:ident, $af:ident)),*]) => { + $(unsafe impl EevSrcBits<$N> for $pin>{ + const SRC_BITS: u8 = 0b00; + fn cfg(self) { + self.into_alternate::<$af>(); + } + })* + + unsafe impl EevSrcBits<$N> for &crate::comparator::Comparator<$compX, ED> + where ED: crate::comparator::EnabledState + { + const SRC_BITS: u8 = 0b01; + } + + $( + unsafe impl EevSrcBits<$N> for &crate::comparator::Comparator<$compY, ED> + where ED: crate::comparator::EnabledState + { + const SRC_BITS: u8 = $compY_src_bits; + } + )* + + impl EevInput<$N> { + pub fn bind(self, src: SRC) -> SourceBuilder<$N, IS_FAST> + where SRC: EevSrcBits<$N> + { + src.cfg(); + unsafe { SourceBuilder::new(SRC::SRC_BITS) } + } + } + }; +} + +impl_eev_input!(1: COMP = [COMP2], PINS = [(PC12, AF3)]); +impl_eev_input!(2: COMP = [COMP4], PINS = [(PC11, AF3)]); +impl_eev_input!(3: COMP = [COMP6], PINS = [(PB7, AF13)]); +impl_eev_input!(4: COMP = [COMP1, (COMP5, 0b10)], PINS = [(PB6, AF13)]); +impl_eev_input!(5: COMP = [COMP3, (COMP7, 0b10)], PINS = [(PB9, AF13)]); +impl_eev_input!(6: COMP = [COMP2, (COMP1, 0b10)], PINS = [(PB5, AF13)]); +impl_eev_input!(7: COMP = [COMP4], PINS = [(PB4, AF13)]); +impl_eev_input!(8: COMP = [COMP6, (COMP3, 0b10)], PINS = [(PB8, AF13)]); +impl_eev_input!(9: COMP = [COMP5, (COMP4, 0b11)], PINS = [(PB3, AF13)]); +impl_eev_input!(10: COMP = [COMP7], PINS = [(PC5, AF13), (PC6, AF3)]); + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum EdgeOrPolarity { + Edge(Edge), + Polarity(Polarity), +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Edge { + Rising = 0b01, + Falling = 0b10, + Both = 0b11, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum EevSamplingFilter { + /// No filtering, fault acts asynchronously + /// + /// Note that this bypasses any f_eevs (FaultSamplingClkDiv) + None = 0b0000, + + /// Sample directly at rate f_hrtim, with a count of 2 + /// + /// Note that this bypasses: any f_eevs (FaultSamplingClkDiv) + HrtimN2 = 0b0001, + + /// Sample directly at rate f_hrtim, with a count of 4 + /// + /// Note that this bypasses any f_eevs (FaultSamplingClkDiv) + HrtimN4 = 0b0010, + + /// Sample directly at rate f_hrtim, with a count of 8 + /// + /// Note that this bypasses any f_eevs (FaultSamplingClkDiv) + HrtimN8 = 0b0011, + + /// Sample at rate f_eevs / 2, with a count of 6 + EevsDiv2N6 = 0b0100, + + /// Sample at rate f_eevs / 2, with a count of 8 + EevsDiv2N8 = 0b0101, + + /// Sample at rate f_eevs / 4, with a count of 6 + EevsDiv4N6 = 0b0110, + + /// Sample at rate f_eevs / 4, with a count of 8 + EevsDiv4N8 = 0b0111, + + /// Sample at rate f_eevs / 8, with a count of 6 + EevsDiv8N6 = 0b1000, + + /// Sample at rate f_eevs / 8, with a count of 8 + EevsDiv8N8 = 0b1001, + + /// Sample at rate f_eevs / 16, with a count of 5 + EevsDiv16N5 = 0b1010, + + /// Sample at rate f_eevs / 16, with a count of 6 + EevsDiv16N6 = 0b1011, + + /// Sample at rate f_eevs / 16, with a count of 8 + EevsDiv16N8 = 0b1100, + + /// Sample at rate f_eevs / 32, with a count of 5 + EevsDiv32N5 = 0b1101, + + /// Sample at rate f_eevs / 32, with a count of 6 + EevsDiv32N6 = 0b1110, + + /// Sample at rate f_eevs / 32, with a count of 8 + EevsDiv32N8 = 0b1111, +} + +pub trait ExternalEventBuilder1To5 {} +pub trait ExternalEventBuilder6To10 {} +pub struct SourceBuilder { + /// EExSRC + src_bits: u8, + + /// EExSNS + edge_or_polarity_bits: u8, + + /// EExPOL + polarity_bit: bool, + + /// EExF + filter_bits: u8, +} + +impl SourceBuilder { + unsafe fn new(src_bits: u8) -> Self { + Self { + src_bits, + edge_or_polarity_bits: 0, // Level sensitive + polarity_bit: false, // Active high + filter_bits: 0, // No filter + } + } +} + +impl SourceBuilder { + pub fn edge_or_polarity(mut self, edge_or_polarity: EdgeOrPolarity) -> Self { + (self.edge_or_polarity_bits, self.polarity_bit) = match edge_or_polarity { + EdgeOrPolarity::Polarity(Polarity::ActiveHigh) => (0b00, false), + EdgeOrPolarity::Polarity(Polarity::ActiveLow) => (0b00, true), + EdgeOrPolarity::Edge(Edge::Rising) => (0b01, false), + EdgeOrPolarity::Edge(Edge::Falling) => (0b10, false), + EdgeOrPolarity::Edge(Edge::Both) => (0b11, false), + }; + + self + } +} + +impl SourceBuilder { + /// Edge sensitivity not available in fast mode + pub fn polarity(mut self, polarity: Polarity) -> Self { + (self.edge_or_polarity_bits, self.polarity_bit) = match polarity { + Polarity::ActiveHigh => (0b00, false), + Polarity::ActiveLow => (0b00, true), + }; + + self + } +} + +impl SourceBuilder +where + SourceBuilder: ExternalEventBuilder6To10, +{ + pub fn filter(mut self, filter: EevSamplingFilter) -> Self { + self.filter_bits = filter as _; + self + } +} + +pub trait ToExternalEventSource { + fn finalize(self, _calibrated: &mut HrTimCalibrated) -> ExternalEventSource; +} + +macro_rules! impl_eev1_5_to_es { + ($eev:ident, $N:literal, $eeXsrc:ident, $eeXpol:ident, $eeXsns:ident, $eeXfast:ident) => { + impl ExternalEventBuilder1To5 for SourceBuilder<$N, IS_FAST> {} + + impl SourceBuilder<$N, false> { + pub fn fast(self) -> SourceBuilder<$N, true> { + let SourceBuilder { + src_bits, + edge_or_polarity_bits, + polarity_bit, + filter_bits, + } = self; + + SourceBuilder { + src_bits, + edge_or_polarity_bits, + polarity_bit, + filter_bits, + } + } + } + + impl ToExternalEventSource<$N, IS_FAST> + for SourceBuilder<$N, IS_FAST> + { + fn finalize( + self, + _calibrated: &mut HrTimCalibrated, + ) -> ExternalEventSource<$N, IS_FAST> { + let SourceBuilder { + src_bits, + edge_or_polarity_bits, + polarity_bit, + filter_bits: _, + } = self; + + let common = unsafe { &*HRTIM_COMMON::ptr() }; + + // SAFETY: Thanks to, `HrTimCalibrated`, we know we have exclusive access to the register, + // we also know no timers are started. + unsafe { + common.eecr1().modify(|_r, w| { + w.$eeXsrc() + .bits(src_bits) + .$eeXpol() + .bit(polarity_bit) + .$eeXsns() + .bits(edge_or_polarity_bits) + .$eeXfast() + .bit(IS_FAST) + }); + } + + ExternalEventSource { _x: PhantomData } + } + } + + /// EEV$1 event + impl super::event::EventSource + for ExternalEventSource<$N, IS_FAST> + { + const BITS: u32 = 1 << ($N + 20); // EEV1 is at bit 21 + } + }; +} + +macro_rules! impl_eev6_10_to_es { + ($eev:ident, $N:literal, $eeXsrc:ident, $eeXpol:ident, $eeXsns:ident, $eeXf:ident) => { + impl ExternalEventBuilder6To10 for SourceBuilder<$N, false> {} + + impl ToExternalEventSource<$N, false> for SourceBuilder<$N, false> { + fn finalize(self, _calibrated: &mut HrTimCalibrated) -> ExternalEventSource<$N, false> { + let SourceBuilder { + src_bits, + edge_or_polarity_bits, + polarity_bit, + filter_bits, + } = self; + + let common = unsafe { &*HRTIM_COMMON::ptr() }; + + // SAFETY: Thanks to, `HrTimCalibrated`, we know we have exclusive access to the register, + // we also know no timers are started. + unsafe { + common.eecr2().modify(|_r, w| { + w.$eeXsrc() + .bits(src_bits) + .$eeXpol() + .bit(polarity_bit) + .$eeXsns() + .bits(edge_or_polarity_bits) + }); + common.eecr3().modify(|_r, w| w.$eeXf().bits(filter_bits)); + } + + ExternalEventSource { _x: PhantomData } + } + } + + /// EEV$1 event + impl super::event::EventSource for ExternalEventSource<$N, false> { + const BITS: u32 = 1 << ($N + 20); // EEV1 is at bit 21 + } + }; +} + +impl_eev1_5_to_es!(Eevnt1, 1, ee1src, ee1pol, ee1sns, ee1fast); +impl_eev1_5_to_es!(Eevnt2, 2, ee2src, ee2pol, ee2sns, ee2fast); +impl_eev1_5_to_es!(Eevnt3, 3, ee3src, ee3pol, ee3sns, ee3fast); +impl_eev1_5_to_es!(Eevnt4, 4, ee4src, ee4pol, ee4sns, ee4fast); +impl_eev1_5_to_es!(Eevnt5, 5, ee5src, ee5pol, ee5sns, ee5fast); + +impl_eev6_10_to_es!(Eevnt6, 6, ee6src, ee6pol, ee6sns, ee6f); +impl_eev6_10_to_es!(Eevnt7, 7, ee7src, ee7pol, ee7sns, ee7f); +impl_eev6_10_to_es!(Eevnt8, 8, ee8src, ee8pol, ee8sns, ee8f); +impl_eev6_10_to_es!(Eevnt9, 9, ee9src, ee9pol, ee9sns, ee9f); +impl_eev6_10_to_es!(Eevnt10, 10, ee10src, ee10pol, ee10sns, ee10f); + +impl super::capture::CaptureEvent + for ExternalEventSource +{ + const BITS: u32 = 1 << (N + 1); // EEV1 is at bit #2 etc +} + +impl super::event::TimerResetEventSource + for ExternalEventSource +{ + const BITS: u32 = 1 << (N + 8); // EEV1 is at bit 9 +} diff --git a/src/hrtim/fault.rs b/src/hrtim/fault.rs new file mode 100644 index 00000000..2447c793 --- /dev/null +++ b/src/hrtim/fault.rs @@ -0,0 +1,277 @@ +use core::marker::PhantomData; + +use crate::comparator::{COMP1, COMP2, COMP3, COMP4, COMP5, COMP6}; +use crate::gpio::gpioa::{PA12, PA15}; +use crate::gpio::gpiob::{PB0, PB10, PB11}; +use crate::gpio::gpioc::{PC10, PC7}; +use crate::gpio::{self, AF13, AF3}; +use crate::hrtim::control::HrPwmControl; +use crate::stm32::HRTIM_COMMON; + +use super::control::HrPwmCtrl; + +/// Allows a FaultMonitor to monitor faults +pub trait FaultMonitor { + fn enable_interrupt(&mut self, hr_control: &mut HrPwmCtrl); + + /// Returns true if a fault is preventing PWM output + fn is_fault_active(&self) -> bool; + + /// Clear the fault interrupt flag + /// + /// This will *NOT* resume normal PWM operation. The affected outputs need to be re-enabled to resume operation; + /// This will do nothing if the fault is still active. + fn clear_fault(&mut self); +} + +pub enum FaultAction { + /// Output never enters fault mode + None = 0b00, + + /// Output forced to `active` level on fault + ForceActive = 0b01, + + /// Output forced to `inactive` level on fault + ForceInactive = 0b10, + + /// The output is floating/tri stated on fault + Floating = 0b11, +} + +/// # Safety +/// Only implement for actual fault sources with correct `ENABLE_BITS` +pub unsafe trait FaultSource: Copy { + const ENABLE_BITS: u8; +} + +pub struct SourceBuilder { + _input: I, + src_bits: u8, + + /// FLTxP + is_active_high: bool, + + /// FLTxF[3:0] + filter_bits: u8, +} + +impl SourceBuilder { + unsafe fn new(input: I, src_bits: u8) -> Self { + SourceBuilder { + _input: input, + src_bits, + is_active_high: false, + filter_bits: 0b0000, + } + } +} + +macro_rules! impl_faults { + ($( + $input:ident => $source:ident: + PINS=[($pin:ident, $af:ident) $(,($pin_b:ident, $af_b:ident))*], + COMP=$compX:ident, $enable_bits:literal, + $fltinrZ:ident, $fltWsrc_0:ident, $fltWsrc_1:ident, $fltWp:ident, $fltWf:ident, $fltWe:ident, $fltWlck:ident, + )+) => {$( + + // This should NOT be Copy/Clone + pub struct $input { + pub(crate) _x: PhantomData<()> + } + + #[derive(Copy, Clone)] + pub struct $source { + _x: PhantomData<()> + } + + impl $input { + pub fn bind_pin(self, pin: $pin>) -> SourceBuilder<$input> { + pin.into_alternate::<$af>(); + unsafe { SourceBuilder::new(self, 0b00) } + } + + $( + // TODO: Is there a nicer way to do this? + pub fn bind_pin_b(self, pin: $pin_b>) -> SourceBuilder<$input> { + pin.into_alternate::<$af_b>(); + unsafe { SourceBuilder::new(self, 0b00) } + } + )* + + pub fn bind_comp(self, _comp: &crate::comparator::Comparator<$compX, crate::comparator::Enabled>) -> SourceBuilder<$input> { + unsafe { SourceBuilder::new(self, 0b01) } + } + + /*pub fn bind_external(?) { + SourceBuilder::new(self, 0b10); + }*/ + } + + impl SourceBuilder<$input> { + pub fn finalize(self, _control: &mut HrPwmControl) -> $source { + let SourceBuilder{ _input, src_bits, is_active_high, filter_bits } = self; + + // Setup fault source + unsafe { + let common = &*HRTIM_COMMON::ptr(); + + common.fltinr2().modify(|_r, w| w.$fltWsrc_1().bit(src_bits & 0b10 != 0)); + common.$fltinrZ().modify(|_r, w| w + .$fltWsrc_0().bit(src_bits & 0b01 != 0) + .$fltWp().bit(is_active_high) + .$fltWf().bits(filter_bits) + .$fltWe().set_bit() // Enable + ); + + // ... and lock configuration + common.$fltinrZ().modify(|_r, w| w.$fltWlck().set_bit()); + } + + $source { + _x: PhantomData + } + } + + pub fn polarity(mut self, polarity: super::Polarity) -> Self { + self.is_active_high = polarity == super::Polarity::ActiveHigh; + self + } + + // TODO: add more settings + /* pub fn blanking(?) -> Self */ + + pub fn filter(mut self, filter: FaultSamplingFilter) -> Self { + self.filter_bits = filter as u8; + self + } + } + + unsafe impl FaultSource for $source { + const ENABLE_BITS: u8 = $enable_bits; + } + )+} +} + +impl_faults!( + FaultInput1 => FaultSource1: PINS=[(PA12, AF13)], COMP=COMP2, 0b000001, fltinr1, flt1src, flt1src_1, flt1p, flt1f, flt1e, flt1lck, + FaultInput2 => FaultSource2: PINS=[(PA15, AF13)], COMP=COMP4, 0b000010, fltinr1, flt2src, flt2src_1, flt2p, flt2f, flt2e, flt2lck, + FaultInput3 => FaultSource3: PINS=[(PB10, AF13)], COMP=COMP6, 0b000100, fltinr1, flt3src, flt3src_1, flt3p, flt3f, flt3e, flt3lck, + FaultInput4 => FaultSource4: PINS=[(PB11, AF13)], COMP=COMP1, 0b001000, fltinr1, flt4src, flt4src_1, flt4p, flt4f, flt4e, flt4lck, + FaultInput5 => FaultSource5: PINS=[(PB0, AF13), (PC7, AF3)], COMP=COMP3, 0b010000, fltinr2, flt5src, flt5src_1, flt5p, flt5f, flt5e, flt5lck, + FaultInput6 => FaultSource6: PINS=[(PC10, AF13)], COMP=COMP5, 0b100000, fltinr2, flt6src_0, flt6src_1, flt6p, flt6f, flt6e, flt6lck, +); + +pub struct FaultInputs { + pub fault_input1: FaultInput1, + pub fault_input2: FaultInput2, + pub fault_input3: FaultInput3, + pub fault_input4: FaultInput4, + pub fault_input5: FaultInput5, + pub fault_input6: FaultInput6, +} + +impl FaultInputs { + pub(crate) unsafe fn new() -> Self { + FaultInputs { + fault_input1: FaultInput1 { _x: PhantomData }, + fault_input2: FaultInput2 { _x: PhantomData }, + fault_input3: FaultInput3 { _x: PhantomData }, + fault_input4: FaultInput4 { _x: PhantomData }, + fault_input5: FaultInput5 { _x: PhantomData }, + fault_input6: FaultInput6 { _x: PhantomData }, + } + } +} + +pub enum FaultSamplingFilter { + /// No filtering, fault acts asynchronously + /// + /// Note that this bypasses any f_flts (SamplingClkDiv) + None = 0b0000, + + /// Sample directly at rate f_hrtim, with a count of 2 + /// + /// Note that this bypasses: any f_flts (SamplingClkDiv) + HrtimN2 = 0b0001, + + /// Sample directly at rate f_hrtim, with a count of 4 + /// + /// Note that this bypasses any f_flts (SamplingClkDiv) + HrtimN4 = 0b0010, + + /// Sample directly at rate f_hrtim, with a count of 8 + /// + /// Note that this bypasses any f_flts (SamplingClkDiv) + HrtimN8 = 0b0011, + + /// Sample at rate f_flts / 2, with a count of 6 + FltsDiv2N6 = 0b0100, + + /// Sample at rate f_flts / 2, with a count of 8 + FltsDiv2N8 = 0b0101, + + /// Sample at rate f_flts / 4, with a count of 6 + FltsDiv4N6 = 0b0110, + + /// Sample at rate f_flts / 4, with a count of 8 + FltsDiv4N8 = 0b0111, + + /// Sample at rate f_flts / 8, with a count of 6 + FltsDiv8N6 = 0b1000, + + /// Sample at rate f_flts / 8, with a count of 8 + FltsDiv8N8 = 0b1001, + + /// Sample at rate f_flts / 16, with a count of 5 + FltsDiv16N5 = 0b1010, + + /// Sample at rate f_flts / 16, with a count of 6 + FltsDiv16N6 = 0b1011, + + /// Sample at rate f_flts / 16, with a count of 8 + FltsDiv16N8 = 0b1100, + + /// Sample at rate f_flts / 32, with a count of 5 + FltsDiv32N5 = 0b1101, + + /// Sample at rate f_flts / 32, with a count of 6 + FltsDiv32N6 = 0b1110, + + /// Sample at rate f_flts / 32, with a count of 8 + FltsDiv32N8 = 0b1111, +} + +macro_rules! impl_flt_monitor { + ($($t:ident: ($fltx:ident, $fltxc:ident, $fltxie:ident),)+) => {$( + pub struct $t { + pub(crate) _x: PhantomData<()> + } + + impl FaultMonitor for $t { + fn enable_interrupt(&mut self, _hr_control: &mut HrPwmCtrl) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.ier().modify(|_r, w| w.$fltxie().set_bit()); + } + + fn is_fault_active(&self) -> bool { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.isr().read().$fltx().bit() + } + + fn clear_fault(&mut self) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.icr().write(|w| w.$fltxc().set_bit()); + } + } + )+}; +} + +impl_flt_monitor!( + FltMonitorSys: (sysflt, sysfltc, sysflte), + FltMonitor1: (flt1, flt1c, flt1ie), + FltMonitor2: (flt2, flt2c, flt2ie), + FltMonitor3: (flt3, flt3c, flt3ie), + FltMonitor4: (flt4, flt4c, flt4ie), + FltMonitor5: (flt5, flt5c, flt5ie), + FltMonitor6: (flt6, flt6c, flt6ie), +); diff --git a/src/hrtim/mod.rs b/src/hrtim/mod.rs new file mode 100644 index 00000000..d0666197 --- /dev/null +++ b/src/hrtim/mod.rs @@ -0,0 +1,799 @@ +pub mod adc_trigger; +pub mod capture; +pub mod compare_register; +pub mod control; +pub mod deadtime; +pub mod event; +pub mod external_event; +pub mod fault; +pub mod output; +pub mod timer; +pub mod timer_eev_cfg; + +use core::marker::PhantomData; +use core::mem::MaybeUninit; + +use crate::hrtim::capture::HrCapt; +use crate::hrtim::compare_register::{HrCr1, HrCr2, HrCr3, HrCr4}; +use crate::hrtim::fault::{FaultAction, FaultSource}; +use crate::hrtim::timer::HrTim; +use crate::stm32::{ + HRTIM_COMMON, HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, + HRTIM_TIMF, +}; +use fugit::HertzU64; + +use self::control::HrPwmControl; + +use self::deadtime::DeadtimeConfig; +use self::output::ToHrOut; +use self::timer_eev_cfg::EevCfgs; + +use crate::pwm::{self, Alignment, Polarity, TimerType}; +use crate::rcc::{GetBusFreq, Rcc}; +use crate::time::Hertz; + +/// Internal enum that keeps track of the count settings before PWM is finalized +enum CountSettings { + Frequency(Hertz), + Period(u16), +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum HrTimerMode { + SingleShotNonRetriggerable, + SingleShotRetriggerable, + Continuous, +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum HrCountingDirection { + /// Asymetrical up counting mode + /// + /// + + /// * * + /// Counting up * | * | + /// * * + /// * | * | + /// * * + /// * | * | + /// * * + /// -------------------------------------- + /// + /// ```txt + /// | *-------* *------ + /// | | | + /// | | | | + /// | | | + /// ----------* *------------------* + /// ``` + /// + /// This is the most common mode with least amount of quirks + Up, + + /// Symmetrical up-down counting mode + /// + /// + /// ```txt + /// Period--> * Counting * + /// Counting up * | * Counting Up * | + /// * * down * + /// * | * * | + /// * * * + /// * | * * | + /// 0 -->* * + /// --------------------------------------------------------------------------- + /// | *---------------* | *---------------* + /// | | | | | | + /// | | | | | | + /// | | | | | | + /// ----------* *-------------------* *--- + /// ``` + /// + /// NOTE: This is incompatible with + /// * Auto-delay + /// * Balanded Idle + /// * Triggered-half mode + /// + /// There is also differences in (including but not limited to) the following areas: + /// * Counter roll over event + /// * The events registered with `enable_set_event` will work as normal wen counting up, however when counting down, they will work as rst events. + /// * The events registered with `enable_rst_event` will work as normal wen counting up, however when counting down, they will work as set events. + UpDown, +} + +// Needed to calculate frequency +impl From for pwm::Alignment { + fn from(val: HrCountingDirection) -> Self { + match val { + HrCountingDirection::Up => pwm::Alignment::Left, + HrCountingDirection::UpDown => pwm::Alignment::Center, + } + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum InterleavedMode { + Disabled, + + /// Dual interleaved or Half mode + /// + /// Automatically force + /// * Cr1 to PERIOD / 2 (not visable through `get_duty`). + /// Automatically updates when changing period + /// + /// NOTE: Affects Cr1 + Dual, + + /// Triple interleaved mode + /// + /// Automatically force + /// * Cr1 to 1 * PERIOD / 3 and + /// * Cr2 to 2 * PERIOD / 3 + /// (not visable through `get_duty`). Automatically updates when changing period. + /// + /// NOTE: Must not be used simultaneously with other modes + /// using CMP2 (dual channel dac trigger and triggered-half modes). + Triple, + + /// Quad interleaved mode + /// + /// Automatically force + /// * Cr1 to 1 * PERIOD / 4, + /// * Cr2 to 2 * PERIOD / 4 and + /// * Cr3 to 3 * PERIOD / 4 + /// (not visable through `get_duty`). Automatically updates when changing period. + /// + /// NOTE: Must not be used simultaneously with other modes + /// using CMP2 (dual channel dac trigger and triggered-half modes). + Quad, +} + +pub trait HrPwmAdvExt: Sized { + type PreloadSource; + + fn pwm_advanced( + self, + _pins: PINS, + rcc: &mut Rcc, + ) -> HrPwmBuilder + where + PINS: ToHrOut; +} + +/// HrPwmBuilder is used to configure advanced HrTim PWM features +pub struct HrPwmBuilder { + _tim: PhantomData, + _prescaler: PhantomData, + pins: PINS, + timer_mode: HrTimerMode, + counting_direction: HrCountingDirection, + base_freq: HertzU64, + count: CountSettings, + preload_source: Option, + fault_enable_bits: u8, + fault1_bits: u8, + fault2_bits: u8, + enable_push_pull: bool, + interleaved_mode: InterleavedMode, // Also includes half mode + repetition_counter: u8, + deadtime: Option, + enable_repetition_interrupt: bool, + eev_cfg: EevCfgs, + out1_polarity: Polarity, + out2_polarity: Polarity, +} + +pub enum PreloadSource { + /// Preloaded registers are updated on counter roll over or counter reset + OnCounterReset, + + /// Preloaded registers are updated by master timer update + OnMasterTimerUpdate, + + /// Prealoaded registers are updaten when the counter rolls over and the repetition counter is 0 + OnRepetitionUpdate, +} + +pub enum MasterPreloadSource { + /// Prealoaded registers are updaten when the master counter rolls over and the master repetition counter is 0 + OnMasterRepetitionUpdate, +} + +macro_rules! hrtim_finalize_body { + ($this:expr, $PreloadSource:ident, $TIMX:ident: ( + $timXcr:ident, $ck_psc:ident, $perXr:ident, $perx:ident, $tXcen:ident, $rep:ident, $repx:ident, $dier:ident, $repie:ident + $(, $timXcr2:ident, $fltXr:ident, $eefXr1:ident, $eefXr2:ident, $Xeefr3:ident, $outXr:ident, $dtXr:ident)*), + ) => {{ + let tim = unsafe { &*$TIMX::ptr() }; + let (period, prescaler_bits) = match $this.count { + CountSettings::Period(period) => (period as u32, PSCL::BITS as u16), + CountSettings::Frequency( freq ) => { + >::calculate_frequency($this.base_freq, freq, $this.counting_direction.into()) + }, + }; + + let (half, intlvd) = match $this.interleaved_mode { + InterleavedMode::Disabled => (false, 0b00), + InterleavedMode::Dual => (true, 0b00), + InterleavedMode::Triple => (false, 0b01), + InterleavedMode::Quad => (false, 0b10), + }; + + // Write prescaler and any special modes + tim.$timXcr().modify(|_r, w| unsafe { + w + // Enable Continuous mode + .cont().bit($this.timer_mode == HrTimerMode::Continuous) + .retrig().bit($this.timer_mode == HrTimerMode::SingleShotRetriggerable) + + // TODO: add support for more modes + + // Interleaved mode + .intlvd().bits(intlvd) + + // half/double interleaved mode + .half().bit(half) + + // Set prescaler + .$ck_psc().bits(prescaler_bits as u8) + }); + + $( + tim.$timXcr2().modify(|_r, w| + // Set counting direction + w.udm().bit($this.counting_direction == HrCountingDirection::UpDown) + ); + + // Only available for timers with outputs(not HRTIM_MASTER) + let _ = tim.$outXr(); + tim.$timXcr().modify(|_r, w| + // Push-Pull mode + w.pshpll().bit($this.enable_push_pull) + ); + )* + + // Write period + tim.$perXr().write(|w| unsafe { w.$perx().bits(period as u16) }); + + // Enable fault sources and lock configuration + $(unsafe { + // Enable fault sources + let fault_enable_bits = $this.fault_enable_bits as u32; + tim.$fltXr().write(|w| w + .flt1en().bit(fault_enable_bits & (1 << 0) != 0) + .flt2en().bit(fault_enable_bits & (1 << 1) != 0) + .flt3en().bit(fault_enable_bits & (1 << 2) != 0) + .flt4en().bit(fault_enable_bits & (1 << 3) != 0) + .flt5en().bit(fault_enable_bits & (1 << 4) != 0) + .flt6en().bit(fault_enable_bits & (1 << 5) != 0) + ); + + // ... and lock configuration + tim.$fltXr().modify(|_r, w| w.fltlck().set_bit()); + + tim.$outXr().modify(|_r, w| w + // Set actions on fault for both outputs + .fault1().bits($this.fault1_bits) + .fault2().bits($this.fault2_bits) + + // Set output polarity for both outputs + .pol1().bit($this.out1_polarity == Polarity::ActiveLow) + .pol2().bit($this.out2_polarity == Polarity::ActiveLow) + ); + if let Some(deadtime) = $this.deadtime { + let DeadtimeConfig { + prescaler, + deadtime_rising_value, + deadtime_rising_sign, + deadtime_falling_value, + deadtime_falling_sign, + } = deadtime; + + // SAFETY: DeadtimeConfig makes sure rising and falling values are valid + // and DeadtimePrescaler has its own garantuee + tim.$dtXr().modify(|_r, w| w + .dtprsc().bits(prescaler as u8) + .dtrx().bits(deadtime_rising_value) + .sdtrx().bit(deadtime_rising_sign) + .dtfx().bits(deadtime_falling_value) + .sdtfx().bit(deadtime_falling_sign) + + // Lock configuration + .dtflkx().set_bit() + .dtfslkx().set_bit() + .dtrlkx().set_bit() + .dtrslkx().set_bit() + ); + tim.$outXr().modify(|_r, w| w.dten().set_bit()); + } + + // External event configs + let eev_cfg = $this.eev_cfg.clone(); + tim.$eefXr1().write(|w| w + .ee1ltch().bit(eev_cfg.eev1.latch_bit).ee1fltr().bits(eev_cfg.eev1.filter_bits) + .ee2ltch().bit(eev_cfg.eev2.latch_bit).ee2fltr().bits(eev_cfg.eev2.filter_bits) + .ee3ltch().bit(eev_cfg.eev3.latch_bit).ee3fltr().bits(eev_cfg.eev3.filter_bits) + .ee4ltch().bit(eev_cfg.eev4.latch_bit).ee4fltr().bits(eev_cfg.eev4.filter_bits) + .ee5ltch().bit(eev_cfg.eev5.latch_bit).ee5fltr().bits(eev_cfg.eev5.filter_bits) + ); + tim.$eefXr2().write(|w| w + .ee6ltch().bit(eev_cfg.eev6.latch_bit).ee6fltr().bits(eev_cfg.eev6.filter_bits) + .ee7ltch().bit(eev_cfg.eev7.latch_bit).ee7fltr().bits(eev_cfg.eev7.filter_bits) + .ee8ltch().bit(eev_cfg.eev8.latch_bit).ee8fltr().bits(eev_cfg.eev8.filter_bits) + .ee9ltch().bit(eev_cfg.eev9.latch_bit).ee9fltr().bits(eev_cfg.eev9.filter_bits) + .ee10ltch().bit(eev_cfg.eev10.latch_bit).ee10fltr().bits(eev_cfg.eev10.filter_bits) + ); + tim.$Xeefr3().write(|w| w + .eevace().bit(eev_cfg.event_counter_enable_bit) + // External Event A Counter Reset"] + //.eevacres().bit() + .eevarstm().bit(eev_cfg.event_counter_reset_mode_bit) + .eevasel().bits(eev_cfg.event_counter_source_bits) + .eevacnt().bits(eev_cfg.event_counter_threshold_bits) + ); + })* + + + hrtim_finalize_body!($PreloadSource, $this, tim, $timXcr); + + // Set repetition counter + unsafe { tim.$rep().write(|w| w.$repx().bits($this.repetition_counter)); } + + // Enable interrupts + tim.$dier().modify(|_r, w| w.$repie().bit($this.enable_repetition_interrupt)); + + // Start timer + //let master = unsafe { &*HRTIM_MASTER::ptr() }; + //master.mcr.modify(|_r, w| { w.$tXcen().set_bit() }); + + // Connect pins and let HRTIM take over control over them + $this.pins.connect_to_hrtim(); + + unsafe { + MaybeUninit::uninit().assume_init() + } + }}; + + (PreloadSource, $this:expr, $tim:expr, $timXcr:ident) => {{ + match $this.preload_source { + Some(PreloadSource::OnCounterReset) => { + $tim.$timXcr().modify(|_r, w| w + .tx_rstu().set_bit() + .preen().set_bit() + ); + }, + Some(PreloadSource::OnMasterTimerUpdate) => { + $tim.$timXcr().modify(|_r, w| w + .mstu().set_bit() + .preen().set_bit() + ); + } + Some(PreloadSource::OnRepetitionUpdate) => { + $tim.$timXcr().modify(|_r, w| w + .tx_repu().set_bit() + .preen().set_bit() + ); + } + None => () + } + }}; + + (MasterPreloadSource, $this:expr, $tim:expr, $timXcr:ident) => {{ + match $this.preload_source { + Some(MasterPreloadSource::OnMasterRepetitionUpdate) => { + $tim.$timXcr().modify(|_r, w| w + .mrepu().set_bit() + .preen().set_bit() + ); + } + None => () + } + }}; +} + +macro_rules! hrtim_common_methods { + ($TIMX:ident, $PS:ident) => { + /// Set the PWM frequency; will overwrite the previous prescaler and period + /// The requested frequency will be rounded to the nearest achievable frequency; the actual frequency may be higher or lower than requested. + pub fn frequency>(mut self, freq: T) -> Self { + self.count = CountSettings::Frequency(freq.into()); + + self + } + + /// Set the prescaler; PWM count runs at base_frequency/(prescaler+1) + pub fn prescaler

(self, _prescaler: P) -> HrPwmBuilder<$TIMX, P, $PS, PINS> + where + P: HrtimPrescaler, + { + let HrPwmBuilder { + _tim, + _prescaler: _, + pins, + timer_mode, + fault_enable_bits, + fault1_bits, + fault2_bits, + enable_push_pull, + interleaved_mode, + counting_direction, + base_freq, + count, + preload_source, + repetition_counter, + deadtime, + enable_repetition_interrupt, + eev_cfg, + out1_polarity, + out2_polarity, + } = self; + + let period = match count { + CountSettings::Frequency(_) => u16::MAX, + CountSettings::Period(period) => period, + }; + + let count = CountSettings::Period(period); + + HrPwmBuilder { + _tim, + _prescaler: PhantomData, + pins, + timer_mode, + fault_enable_bits, + fault1_bits, + fault2_bits, + enable_push_pull, + interleaved_mode, + counting_direction, + base_freq, + count, + preload_source, + repetition_counter, + deadtime, + enable_repetition_interrupt, + eev_cfg, + out1_polarity, + out2_polarity, + } + } + + pub fn timer_mode(mut self, timer_mode: HrTimerMode) -> Self { + self.timer_mode = timer_mode; + self + } + + // TODO: Allow setting multiple? + pub fn preload(mut self, preload_source: $PS) -> Self { + self.preload_source = Some(preload_source); + self + } + + /// Set the period; PWM count runs from 0 to period, repeating every (period+1) counts + pub fn period(mut self, period: u16) -> Self { + self.count = CountSettings::Period(period); + self + } + + /// Set repetition counter, useful to reduce interrupts generated + /// from timer by a factor (repetition_counter + 1) + pub fn repetition_counter(mut self, repetition_counter: u8) -> Self { + self.repetition_counter = repetition_counter; + self + } + + pub fn enable_repetition_interrupt(mut self) -> Self { + self.enable_repetition_interrupt = true; + self + } + + pub fn eev_cfg(mut self, eev_cfg: EevCfgs<$TIMX>) -> Self { + self.eev_cfg = eev_cfg; + self + } + }; +} + +// Implement PWM configuration for timer +macro_rules! hrtim_hal { + ($($TIMX:ident: ($timXcr:ident, $timXcr2:ident, $perXr:ident, $tXcen:ident, $rep:ident, $repx:ident, $dier:ident, $repie:ident, + $fltXr:ident, $eefXr1:ident, $eefXr2:ident, $Xeefr3:ident, $outXr:ident, $dtXr:ident),)+) => { + $( + impl HrPwmAdvExt for $TIMX { + type PreloadSource = PreloadSource; + + fn pwm_advanced( + self, + pins: PINS, + rcc: &mut Rcc, + ) -> HrPwmBuilder + where + PINS: ToHrOut<$TIMX>, + { + // TODO: That 32x factor... Is that included below, or should we + // do that? Also that will likely risk overflowing u32 since + // 170MHz * 32 = 5.44GHz > u32::MAX.Hz() + let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32; + + HrPwmBuilder { + _tim: PhantomData, + _prescaler: PhantomData, + pins, + timer_mode: HrTimerMode::Continuous, + fault_enable_bits: 0b000000, + fault1_bits: 0b00, + fault2_bits: 0b00, + counting_direction: HrCountingDirection::Up, + base_freq: clk, + count: CountSettings::Period(u16::MAX), + preload_source: None, + enable_push_pull: false, + interleaved_mode: InterleavedMode::Disabled, + repetition_counter: 0, + deadtime: None, + enable_repetition_interrupt: false, + eev_cfg: EevCfgs::default(), + out1_polarity: Polarity::ActiveHigh, + out2_polarity: Polarity::ActiveHigh, + } + } + } + + impl + HrPwmBuilder<$TIMX, PSCL, PreloadSource, PINS> + where + PSCL: HrtimPrescaler, + PINS: ToHrOut<$TIMX>, + { + pub fn finalize(self, _control: &mut HrPwmControl) -> ( + HrTim<$TIMX, PSCL, + HrCapt<$TIMX, PSCL, capture::Ch1, capture::NoDma>, + HrCapt<$TIMX, PSCL, capture::Ch2, capture::NoDma> + >, ( + HrCr1<$TIMX, PSCL>, + HrCr2<$TIMX, PSCL>, + HrCr3<$TIMX, PSCL>, + HrCr4<$TIMX, PSCL> + ), + PINS::Out, + timer::DmaChannel<$TIMX>, + ) { + + hrtim_finalize_body!( + self, PreloadSource, + $TIMX: ($timXcr, ck_pscx, $perXr, perx, $tXcen, $rep, $repx, $dier, $repie, $timXcr2, $fltXr, $eefXr1, $eefXr2, $Xeefr3, $outXr, $dtXr), + ) + } + + hrtim_common_methods!($TIMX, PreloadSource); + + pub fn with_fault_source(mut self, _fault_source: FS) -> Self + where FS: FaultSource + { + self.fault_enable_bits |= FS::ENABLE_BITS; + + self + } + + pub fn fault_action1(mut self, fault_action1: FaultAction) -> Self { + self.fault1_bits = fault_action1 as _; + + self + } + + pub fn fault_action2(mut self, fault_action2: FaultAction) -> Self { + self.fault2_bits = fault_action2 as _; + + self + } + + pub fn out1_polarity(mut self, polarity: Polarity) -> Self { + self.out1_polarity = polarity; + + self + } + + pub fn out2_polarity(mut self, polarity: Polarity) -> Self { + self.out2_polarity = polarity; + + self + } + + /// Enable or disable Push-Pull mode + /// + /// Enabling Push-Pull mode will make output 1 and 2 + /// alternate every period with one being + /// inactive and the other getting to output its wave form + /// as normal + /// + /// ---- . ---- + ///out1 | | . | | + /// | | . | | + /// -------- ---------------------------- -------------------- + /// . ------ . ------ + ///out2 . | | . | | + /// . | | . | | + /// ------------------------ ---------------------------- -- + /// + /// NOTE: setting this will overide any 'Swap Mode' set + pub fn push_pull_mode(mut self, enable: bool) -> Self { + // TODO: add check for incompatible modes + self.enable_push_pull = enable; + + self + } + + /// Set counting direction + /// + /// See [`HrCountingDirection`] + pub fn counting_direction(mut self, counting_direction: HrCountingDirection) -> Self { + self.counting_direction = counting_direction; + + self + } + + /// Set interleaved or half modes + /// + /// NOTE: Check [`InterleavedMode`] for more info about special cases + pub fn interleaved_mode(mut self, mode: InterleavedMode) -> Self { + self.interleaved_mode = mode; + + self + } + + pub fn deadtime(mut self, deadtime: DeadtimeConfig) -> Self { + self.deadtime = Some(deadtime); + + self + } + + //pub fn swap_mode(mut self, enable: bool) -> Self + } + )+ + }; +} + +macro_rules! hrtim_hal_master { + ($($TIMX:ident: ($timXcr:ident, $ck_psc:ident, $perXr:ident, $perx:ident, $rep:ident, $tXcen:ident, $dier:ident, $repie:ident),)+) => {$( + impl HrPwmAdvExt for $TIMX { + type PreloadSource = MasterPreloadSource; + + fn pwm_advanced( + self, + pins: PINS, + rcc: &mut Rcc, + ) -> HrPwmBuilder + where + PINS: ToHrOut<$TIMX>, + { + // TODO: That 32x factor... Is that included below, or should we + // do that? Also that will likely risk overflowing u32 since + // 170MHz * 32 = 5.44GHz > u32::MAX.Hz() + let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32; + + HrPwmBuilder { + _tim: PhantomData, + _prescaler: PhantomData, + pins, + timer_mode: HrTimerMode::Continuous, + fault_enable_bits: 0b000000, + fault1_bits: 0b00, + fault2_bits: 0b00, + counting_direction: HrCountingDirection::Up, + base_freq: clk, + count: CountSettings::Period(u16::MAX), + preload_source: None, + enable_push_pull: false, + interleaved_mode: InterleavedMode::Disabled, + repetition_counter: 0, + deadtime: None, + enable_repetition_interrupt: false, + eev_cfg: EevCfgs::default(), + out1_polarity: Polarity::ActiveHigh, + out2_polarity: Polarity::ActiveHigh, + } + } + } + + impl + HrPwmBuilder<$TIMX, PSCL, MasterPreloadSource, PINS> + where + PSCL: HrtimPrescaler, + PINS: ToHrOut<$TIMX>, + { + pub fn finalize(self, _control: &mut HrPwmControl) -> ( + HrTim<$TIMX, PSCL, + HrCapt<$TIMX, PSCL, capture::Ch1, capture::NoDma>, + HrCapt<$TIMX, PSCL, capture::Ch2, capture::NoDma>, + >, ( + HrCr1<$TIMX, PSCL>, + HrCr2<$TIMX, PSCL>, + HrCr3<$TIMX, PSCL>, + HrCr4<$TIMX, PSCL> + ), + timer::DmaChannel<$TIMX>, + ) { + + hrtim_finalize_body!(self, MasterPreloadSource, $TIMX: ($timXcr, $ck_psc, $perXr, $perx, $tXcen, $rep, $rep, $dier, $repie),) + } + + hrtim_common_methods!($TIMX, MasterPreloadSource); + } + )*} +} + +hrtim_hal! { + HRTIM_TIMA: (timacr, timacr2, perar, tacen, repar, repx, timadier, repie, fltar, eefar1, eefar2, aeefr3, outar, dtar), + HRTIM_TIMB: (timbcr, timbcr2, perbr, tbcen, repbr, repx, timbdier, repie, fltbr, eefbr1, eefbr2, beefr3, outbr, dtbr), + HRTIM_TIMC: (timccr, timccr2, percr, tccen, repcr, repx, timcdier, repie, fltcr, eefcr1, eefcr2, ceefr3, outcr, dtcr), + HRTIM_TIMD: (timdcr, timdcr2, perdr, tdcen, repdr, repx, timddier, repie, fltdr, eefdr1, eefdr2, deefr3, outdr, dtdr), + HRTIM_TIME: (timecr, timecr2, perer, tecen, reper, repx, timedier, repie, flter, eefer1, eefer2, eeefr3, outer, dter), + HRTIM_TIMF: (timfcr, timfcr2, perfr, tfcen, repfr, repx, timfdier, repie, fltfr, eeffr1, eeffr2, feefr3, outfr, dtfr), +} + +hrtim_hal_master! { + HRTIM_MASTER: (mcr, ck_psc, mper, mper, mrep, mcen, mdier, mrepie), +} + +/// # Safety +/// Only implement for valid prescalers with correct values +pub unsafe trait HrtimPrescaler: Default { + const BITS: u8; + const VALUE: u8; + + /// Minimum allowed value for compare registers used with the timer with this prescaler + /// + /// NOTE: That for CR1 and CR3, 0 is also allowed + const MIN_CR: u16; + + /// Maximum allowed value for compare registers used with the timer with this prescaler + const MAX_CR: u16; +} + +macro_rules! impl_pscl { + ($($t:ident => $b:literal, $v:literal, $min:literal, $max:literal)+) => {$( + #[derive(Copy, Clone, Default)] + pub struct $t; + unsafe impl HrtimPrescaler for $t { + const BITS: u8 = $b; + const VALUE: u8 = $v; + const MIN_CR: u16 = $min; + const MAX_CR: u16 = $max; + } + )+}; +} + +impl_pscl! { + Pscl1 => 0b000, 1, 0x0060, 0xFFDF + Pscl2 => 0b001, 2, 0x0030, 0xFFEF + Pscl4 => 0b010, 4, 0x0018, 0xFFF7 + Pscl8 => 0b011, 8, 0x000C, 0xFFFB + Pscl16 => 0b100, 16, 0x0006, 0xFFFD + Pscl32 => 0b101, 32, 0x0003, 0xFFFD + Pscl64 => 0b110, 64, 0x0003, 0xFFFD + Pscl128 => 0b111, 128, 0x0003, 0xFFFD +} + +/// HrTim timer +struct TimerHrTim(PhantomData); + +impl pwm::TimerType for TimerHrTim { + // Period calculator for 16-bit hrtimers + // + // NOTE: This function will panic if the calculated period can not fit into 16 bits + fn calculate_frequency(base_freq: HertzU64, freq: Hertz, alignment: Alignment) -> (u32, u16) { + let ideal_period = pwm::Timer32Bit::calculate_frequency(base_freq, freq, alignment).0 + 1; + + let prescale = u32::from(PSC::VALUE); + + // Round to the nearest period + let period = (ideal_period + (prescale >> 1)) / prescale - 1; + + // It IS possible to fail this assert + assert!(period <= 0xFFFF); + + (period, PSC::BITS.into()) + } +} diff --git a/src/hrtim/output.rs b/src/hrtim/output.rs new file mode 100644 index 00000000..f0d140d2 --- /dev/null +++ b/src/hrtim/output.rs @@ -0,0 +1,222 @@ +use crate::stm32::{HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF}; +use core::marker::PhantomData; + +use super::event::EventSource; +use crate::{ + gpio::{ + self, + gpioa::{PA10, PA11, PA8, PA9}, + gpiob::{PB12, PB13, PB14, PB15}, + gpioc::{PC6, PC7, PC8, PC9}, + Alternate, AF13, AF3, + }, + pwm::{ComplementaryImpossible, Pins}, + stm32::HRTIM_COMMON, +}; + +macro_rules! hrtim_out { + ($($TIMX:ident: $out_type:ident: $tXYoen:ident, $tXYodis:ident, $tXYods:ident, $setXYr:ident, $rstXYr:ident,)+) => {$( + impl HrOutput<$TIMX, PSCL> for $out_type<$TIMX, PSCL> { + fn enable(&mut self) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.oenr().write(|w| { w.$tXYoen().set_bit() }); + } + + fn disable(&mut self) { + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.odisr().write(|w| { w.$tXYodis().set_bit() }); + } + + fn enable_set_event>(&mut self, _set_event: &ES) { + let tim = unsafe { &*$TIMX::ptr() }; + unsafe { tim.$setXYr().modify(|r, w| w.bits(r.bits() | ES::BITS)); } + } + fn disable_set_event>(&mut self, _set_event: &ES) { + let tim = unsafe { &*$TIMX::ptr() }; + unsafe { tim.$setXYr().modify(|r, w| w.bits(r.bits() & !ES::BITS)); } + } + + fn enable_rst_event>(&mut self, _reset_event: &ES) { + let tim = unsafe { &*$TIMX::ptr() }; + unsafe { tim.$rstXYr().modify(|r, w| w.bits(r.bits() | ES::BITS)); } + } + fn disable_rst_event>(&mut self, _reset_event: &ES) { + let tim = unsafe { &*$TIMX::ptr() }; + unsafe { tim.$rstXYr().modify(|r, w| w.bits(r.bits() & !ES::BITS)); } + } + + fn get_state(&self) -> State { + let ods; + let oen; + + unsafe { + let common = &*HRTIM_COMMON::ptr(); + ods = common.odsr().read().$tXYods().bit_is_set(); + oen = common.oenr().read().$tXYoen().bit_is_set(); + } + + match (oen, ods) { + (true, _) => State::Running, + (false, false) => State::Idle, + (false, true) => State::Fault + } + } + } + )+}; +} + +hrtim_out! { + HRTIM_TIMA: HrOut1: ta1oen, ta1odis, ta1ods, seta1r, rsta1r, + HRTIM_TIMA: HrOut2: ta2oen, ta2odis, ta2ods, seta2r, rsta2r, + + HRTIM_TIMB: HrOut1: tb1oen, tb1odis, tb1ods, setb1r, rstb1r, + HRTIM_TIMB: HrOut2: tb2oen, tb2odis, tb2ods, setb2r, rstb2r, + + HRTIM_TIMC: HrOut1: tc1oen, tc1odis, tc1ods, setc1r, rstc1r, + HRTIM_TIMC: HrOut2: tc2oen, tc2odis, tc2ods, setc2r, rstc2r, + + HRTIM_TIMD: HrOut1: td1oen, td1odis, td1ods, setd1r, rstd1r, + HRTIM_TIMD: HrOut2: td2oen, td2odis, td2ods, setd2r, rstd2r, + + HRTIM_TIME: HrOut1: te1oen, te1odis, te1ods, sete1r, rste1r, + HRTIM_TIME: HrOut2: te2oen, te2odis, te2ods, sete2r, rste2r, + + HRTIM_TIMF: HrOut1: tf1oen, tf1odis, tf1ods, setf1r, rstf1r, + HRTIM_TIMF: HrOut2: tf2oen, tf2odis, tf2ods, setf2r, rstf2r, +} + +pub trait HrOutput { + /// Enable this output + fn enable(&mut self); + + /// Disable this output + fn disable(&mut self); + + /// Set this output to active every time the specified event occurs + /// + /// NOTE: Enabling the same event for both SET and RESET + /// will make that event TOGGLE the output + fn enable_set_event>(&mut self, set_event: &ES); + + /// Stop listening to the specified event + fn disable_set_event>(&mut self, set_event: &ES); + + /// Set this output to *not* active every time the specified event occurs + /// + /// NOTE: Enabling the same event for both SET and RESET + /// will make that event TOGGLE the output + fn enable_rst_event>(&mut self, reset_event: &ES); + + /// Stop listening to the specified event + fn disable_rst_event>(&mut self, reset_event: &ES); + + /// Get current state of the output + fn get_state(&self) -> State; +} + +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum State { + Idle, + Running, + Fault, +} + +impl State { + pub fn is_idle(self) -> bool { + matches!(self, State::Idle) + } + + pub fn is_running(self) -> bool { + matches!(self, State::Running) + } + + pub fn is_fault(self) -> bool { + matches!(self, State::Fault) + } +} + +pub unsafe trait ToHrOut { + type Out; + + fn connect_to_hrtim(self); +} + +unsafe impl ToHrOut for (PA, PB) +where + PA: ToHrOut, + PB: ToHrOut, +{ + type Out = (PA::Out, PB::Out); + + fn connect_to_hrtim(self) { + self.0.connect_to_hrtim(); + self.1.connect_to_hrtim(); + } +} + +pub struct HrOut1(PhantomData<(TIM, PSCL)>); +pub struct HrOut2(PhantomData<(TIM, PSCL)>); + +macro_rules! pins { + ($($TIMX:ty: CH1: $CH1:ident<$CH1_AF:ident>, CH2: $CH2:ident<$CH2_AF:ident>)+) => { + $( + /*impl Pins<$TIMX, CH1, ComplementaryImpossible> for $CH1 { + type Channel = Pwm<$TIMX, CH1, ComplementaryImpossible, ActiveHigh, ActiveHigh>; + } + + impl Pins<$TIMX, CH2, ComplementaryImpossible> for $CH2 { + type Channel = Pwm<$TIMX, CH2, ComplementaryImpossible, ActiveHigh, ActiveHigh>; + } + + */ + unsafe impl ToHrOut<$TIMX> for $CH1> { + type Out = HrOut1<$TIMX, PSCL>; + + fn connect_to_hrtim(self) { + let _: $CH1> = self.into_alternate(); + } + } + + unsafe impl ToHrOut<$TIMX> for $CH2> { + type Out = HrOut2<$TIMX, PSCL>; + + fn connect_to_hrtim(self) { + let _: $CH2> = self.into_alternate(); + } + } + + /*unsafe impl ToHrOut for HrOut1<$TIMX, PSCL> { + type Out

= HrOut1<$TIMX, P>; + } + + unsafe impl ToHrOut for HrOut2<$TIMX, PSCL> { + type Out

= HrOut2<$TIMX, P>; + }*/ + )+ + } +} + +pins! { + HRTIM_TIMA: CH1: PA8, CH2: PA9 + + HRTIM_TIMB: CH1: PA10, CH2: PA11 + HRTIM_TIMC: CH1: PB12, CH2: PB13 + HRTIM_TIMD: CH1: PB14, CH2: PB15 + + HRTIM_TIME: CH1: PC8, CH2: PC9 + HRTIM_TIMF: CH1: PC6, CH2: PC7 +} + +impl Pins for () { + type Channel = (); +} + +unsafe impl ToHrOut for () { + type Out = (); + + fn connect_to_hrtim(self) {} +} + +pub struct CH1(PhantomData); +pub struct CH2(PhantomData); diff --git a/src/hrtim/timer.rs b/src/hrtim/timer.rs new file mode 100644 index 00000000..689d7bd7 --- /dev/null +++ b/src/hrtim/timer.rs @@ -0,0 +1,365 @@ +use crate::stm32::{ + HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME, HRTIM_TIMF, +}; +use core::marker::PhantomData; + +use super::{ + capture::{self, HrCapt, HrCapture}, + control::HrPwmCtrl, + HrtimPrescaler, +}; + +pub struct HrTim { + _timer: PhantomData, + _prescaler: PhantomData, + capture_ch1: CPT1, + capture_ch2: CPT2, +} + +/// This is the DMA channel of a HRTIM timer +/// +/// Every HRTIM timer including the master timer has a DMA channel +pub struct DmaChannel { + _x: PhantomData, +} + +pub trait HrTimer { + type Timer; + type Prescaler: HrtimPrescaler; + + /// Get period of timer in number of ticks + /// + /// This is also the maximum duty usable for `HrCompareRegister::set_duty` + /// + /// NOTE: The effective period in number of ticks will be twice as large as + /// returned by this function when running in UpDown mode or PushPull mode. + /// 4 times as large when having both modes active + fn get_period(&self) -> u16; + + /// Set period of timer in number of ticks + /// + /// NOTE: This will affect the maximum duty usable for `HrCompareRegister::set_duty` + fn set_period(&mut self, period: u16); + + /// Start timer + fn start(&mut self, _hr_control: &mut HrPwmCtrl); + + /// Stop timer + fn stop(&mut self, _hr_control: &mut HrPwmCtrl); + + /// Stop timer and reset counter + fn stop_and_reset(&mut self, _hr_control: &mut HrPwmCtrl); + + fn clear_repetition_interrupt(&mut self); + + /// Make a handle to this timers reset/roll-over event to use as adc trigger + fn as_reset_adc_trigger(&self) -> super::adc_trigger::TimerReset; + + /// Make a handle to this timers period event to use as adc trigger + fn as_period_adc_trigger(&self) -> super::adc_trigger::TimerPeriod; + + /// Disable register updates + /// + /// Calling this function temporarily disables the transfer from preload to active registers, + /// whatever the selected update event. This allows to modify several registers. + /// The regular update event takes place once [`Self::enable_register_updates`] is called. + fn disable_register_updates(&mut self, _hr_control: &mut HrPwmCtrl); + + /// Enable register updates + /// + /// See [`Self::disable_register_updates`]. + /// + /// NOTE: Register updates are enabled by default, no need to call this + /// unless [`Self::disable_register_updates`] has been called. + fn enable_register_updates(&mut self, _hr_control: &mut HrPwmCtrl); +} + +pub trait HrSlaveTimer: HrTimer { + type CptCh1; + type CptCh2; + + /// Start listening to the specified event + fn enable_reset_event>( + &mut self, + _event: &E, + ); + + /// Stop listening to the specified event + fn disable_reset_event>( + &mut self, + _event: &E, + ); +} + +/// Trait for unsplit slave timer which still contains its capture modules +pub trait HrSlaveTimerCpt: HrSlaveTimer { + type CaptureCh1: HrCapture; + type CaptureCh2: HrCapture; + + fn capture_ch1(&mut self) -> &mut ::CaptureCh1; + fn capture_ch2(&mut self) -> &mut ::CaptureCh2; + fn split_capture( + self, + ) -> ( + HrTim, + HrCapt, + HrCapt, + ); +} + +macro_rules! hrtim_timer { + ($( + $TIMX:ident: + $cntXr:ident, + $cntx:ident, + $perXr:ident, + $tXcen:ident, + $perx:ident, + $rep:ident, + $repx:ident, + $dier:ident, + $repie:ident, + $icr:ident, + $repc:ident, + $tXudis:ident, + $(($rstXr:ident))*, + )+) => {$( + impl HrTimer for HrTim<$TIMX, PSCL, CPT1, CPT2> { + type Prescaler = PSCL; + type Timer = $TIMX; + + fn get_period(&self) -> u16 { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$perXr().read().$perx().bits() + } + fn set_period(&mut self, period: u16) { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$perXr().write(|w| unsafe { w.$perx().bits(period as u16) }); + } + + /// Start timer + fn start(&mut self, _hr_control: &mut HrPwmCtrl) { + // Start timer + + // SAFETY: Since we hold _hr_control there is no risk for a race condition + let master = unsafe { &*HRTIM_MASTER::ptr() }; + master.mcr().modify(|_r, w| { w.$tXcen().set_bit() }); + } + + /// Stop timer + fn stop(&mut self, _hr_control: &mut HrPwmCtrl) { + // Stop counter + // SAFETY: Since we hold _hr_control there is no risk for a race condition + let master = unsafe { &*HRTIM_MASTER::ptr() }; + master.mcr().modify(|_r, w| { w.$tXcen().set_bit() }); + } + + /// Stop timer and reset counter + fn stop_and_reset(&mut self, _hr_control: &mut HrPwmCtrl) { + self.stop(_hr_control); + + // Reset counter + let tim = unsafe { &*$TIMX::ptr() }; + unsafe { tim.$cntXr().write(|w| w.$cntx().bits(0)); } + } + + /// Make a handle to this timers reset event to use as adc trigger + fn as_reset_adc_trigger(&self) -> super::adc_trigger::TimerReset { + super::adc_trigger::TimerReset(PhantomData) + } + + /// Make a handle to this timers period event to use as adc trigger + fn as_period_adc_trigger(&self) -> super::adc_trigger::TimerPeriod { + super::adc_trigger::TimerPeriod(PhantomData) + } + + fn clear_repetition_interrupt(&mut self) { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$icr().write(|w| w.$repc().set_bit()); + } + + /// Disable register updates + /// + /// Calling this function temporarily disables the transfer from preload to active registers, + /// whatever the selected update event. This allows to modify several registers. + /// The regular update event takes place once [`Self::enable_register_updates`] is called. + fn disable_register_updates(&mut self, _hr_control: &mut HrPwmCtrl) { + use super::HRTIM_COMMON; + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.cr1().modify(|_r, w| w.$tXudis().set_bit()); + } + + /// Enable register updates + /// + /// See [`Self::disable_register_updates`]. + /// + /// NOTE: Register updates are enabled by default, no need to call this + /// unless [`Self::disable_register_updates`] has been called. + fn enable_register_updates<'a>(&mut self, _hr_control: &mut HrPwmCtrl) { + use super::HRTIM_COMMON; + let common = unsafe { &*HRTIM_COMMON::ptr() }; + common.cr1().modify(|_r, w| w.$tXudis().clear_bit()); + } + } + + impl HrTim<$TIMX, PSCL, CPT1, CPT2> { + pub fn set_repetition_counter(&mut self, repetition_counter: u8) { + let tim = unsafe { &*$TIMX::ptr() }; + + unsafe { tim.$rep().write(|w| w.$repx().bits(repetition_counter)); } + } + + pub fn enable_repetition_interrupt(&mut self, enable: bool) { + let tim = unsafe { &*$TIMX::ptr() }; + + tim.$dier().modify(|_r, w| w.$repie().bit(enable)); + } + } + + $( + impl HrSlaveTimer for HrTim<$TIMX, PSCL, CPT1, CPT2> { + type CptCh1 = HrCapt; + type CptCh2 = HrCapt; + + /// Reset this timer every time the specified event occurs + /// + /// Behaviour depends on `timer_mode`: + /// + /// * `HrTimerMode::SingleShotNonRetriggable`: Enabling the timer enables it but does not start it. + /// A first reset event starts the counting and any subsequent reset is ignored until the counter + /// reaches the PER value. The PER event is then generated and the counter is stopped. A reset event + /// restarts the counting from 0x0000. + /// * `HrTimerMode:SingleShotRetriggable`: Enabling the timer enables it but does not start it. + /// A reset event starts the counting if the counter is stopped, otherwise it clears the counter. + /// When the counter reaches the PER value, the PER event is generated and the counter is stopped. + /// A reset event restarts the counting from 0x0000. + /// * `HrTimerMode::Continuous`: Enabling the timer enables and starts it simultaneously. + /// When the counter reaches the PER value, it rolls-over to 0x0000 and resumes counting. + /// The counter can be reset at any time + fn enable_reset_event>(&mut self, _event: &E) { + let tim = unsafe { &*$TIMX::ptr() }; + + unsafe { tim.$rstXr().modify(|r, w| w.bits(r.bits() | E::BITS)); } + } + + /// Stop listening to the specified event + fn disable_reset_event>(&mut self, _event: &E) { + let tim = unsafe { &*$TIMX::ptr() }; + + unsafe { tim.$rstXr().modify(|r, w| w.bits(r.bits() & !E::BITS)); } + } + } + + impl HrSlaveTimerCpt for HrTim<$TIMX, PSCL, HrCapt<$TIMX, PSCL, capture::Ch1, capture::NoDma>, HrCapt<$TIMX, PSCL, capture::Ch2, capture::NoDma>> { + type CaptureCh1 = ::CptCh1; + type CaptureCh2 = ::CptCh2; + + /// Access the timers first capture channel + fn capture_ch1(&mut self) -> &mut Self::CaptureCh1 { + &mut self.capture_ch1 + } + + /// Access the timers second capture channel + fn capture_ch2(&mut self) -> &mut Self::CaptureCh2 { + &mut self.capture_ch2 + } + + fn split_capture(self) -> (HrTim<$TIMX, PSCL, (), ()>, HrCapt<$TIMX, PSCL, capture::Ch1, capture::NoDma>, HrCapt<$TIMX, PSCL, capture::Ch2, capture::NoDma>) { + let HrTim{ + _timer, + _prescaler, + capture_ch1, + capture_ch2, + } = self; + + ( + HrTim{ + _timer, + _prescaler, + capture_ch1: (), + capture_ch2: (), + }, + capture_ch1, + capture_ch2, + ) + } + } + + /// Timer Period event + impl super::event::EventSource for HrTim<$TIMX, PSCL, CPT1, CPT2> { + // $rstXr + const BITS: u32 = 1 << 2; + } + + /// Timer Update event + /// + /// TODO: What dows this mean? + impl super::capture::CaptureEvent<$TIMX, PSCL> for HrTim<$TIMX, PSCL, CPT1, CPT2> { + const BITS: u32 = 1 << 1; + } + )* + )+} +} + +macro_rules! hrtim_timer_adc_trigger { + ($($TIMX:ident: + [$(($AdcTrigger:ident: [ + $((PER: $adc_trigger_bits_period:expr),)* + $((RST: $adc_trigger_bits_reset:expr)),* + ])),+] + ),+) => { + $($( + $(impl $AdcTrigger for super::adc_trigger::TimerReset<$TIMX> { + const BITS: u32 = $adc_trigger_bits_reset; + })* + + $(impl $AdcTrigger for super::adc_trigger::TimerPeriod<$TIMX> { + const BITS: u32 = $adc_trigger_bits_period; + })* + )*)* + } +} + +use super::adc_trigger::Adc13Trigger as Adc13; +use super::adc_trigger::Adc24Trigger as Adc24; +use super::adc_trigger::Adc579Trigger as Adc579; +use super::adc_trigger::Adc6810Trigger as Adc6810; + +hrtim_timer! { + HRTIM_MASTER: mcntr, mcnt, mper, mcen, mper, mrep, mrep, mdier, mrepie, micr, mrepc, mudis,, + + HRTIM_TIMA: cntar, cntx, perar, tacen, perx, repar, repx, timadier, repie, timaicr, repc, taudis, (rstar), + HRTIM_TIMB: cntr, cntx, perbr, tbcen, perx, repbr, repx, timbdier, repie, timbicr, repc, tbudis, (rstbr), + HRTIM_TIMC: cntcr, cntx, percr, tccen, perx, repcr, repx, timcdier, repie, timcicr, repc, tcudis, (rstcr), + HRTIM_TIMD: cntdr, cntx, perdr, tdcen, perx, repdr, repx, timddier, repie, timdicr, repc, tdudis, (rstdr), + HRTIM_TIME: cnter, cntx, perer, tecen, perx, reper, repx, timedier, repie, timeicr, repc, teudis, (rster), + HRTIM_TIMF: cntfr, cntx, perfr, tfcen, perx, repfr, repx, timfdier, repie, timficr, repc, tfudis, (rstfr), +} + +hrtim_timer_adc_trigger! { + HRTIM_MASTER: [(Adc13: [(PER: 1 << 4),]), (Adc24: [(PER: 1 << 4),]), (Adc579: [(PER: 4),]), (Adc6810: [(PER: 4),])], + + HRTIM_TIMA: [(Adc13: [(PER: 1 << 13), (RST: 1 << 14)]), (Adc24: [(PER: 1 << 13), ]), (Adc579: [(PER: 12), (RST: 13)]), (Adc6810: [(PER: 12), ])], + HRTIM_TIMB: [(Adc13: [(PER: 1 << 18), (RST: 1 << 19)]), (Adc24: [(PER: 1 << 17), ]), (Adc579: [(PER: 16), (RST: 17)]), (Adc6810: [(PER: 15), ])], + HRTIM_TIMC: [(Adc13: [(PER: 1 << 23), ]), (Adc24: [(PER: 1 << 21), (RST: 1 << 22)]), (Adc579: [(PER: 20), ]), (Adc6810: [(PER: 18), (RST: 19)])], + HRTIM_TIMD: [(Adc13: [(PER: 1 << 27), ]), (Adc24: [(PER: 1 << 26), (RST: 1 << 27)]), (Adc579: [(PER: 23), ]), (Adc6810: [(PER: 22), (RST: 23)])], + HRTIM_TIME: [(Adc13: [(PER: 1 << 31), ]), (Adc24: [ (RST: 1 << 31)]), (Adc579: [(PER: 26), ]), (Adc6810: [ ])], + HRTIM_TIMF: [(Adc13: [(PER: 1 << 24), (RST: 1 << 28)]), (Adc24: [(PER: 1 << 24), ]), (Adc579: [(PER: 30), (RST: 31)]), (Adc6810: [(PER: 31), ])] +} + +/// Master Timer Period event +impl super::event::TimerResetEventSource + for HrTim +{ + const BITS: u32 = 1 << 4; // MSTPER +} + +/// Master Timer Period event +impl super::event::EventSource + for HrTim +{ + const BITS: u32 = 1 << 7; // MSTPER +} diff --git a/src/hrtim/timer_eev_cfg.rs b/src/hrtim/timer_eev_cfg.rs new file mode 100644 index 00000000..96f79bde --- /dev/null +++ b/src/hrtim/timer_eev_cfg.rs @@ -0,0 +1,194 @@ +use core::marker::PhantomData; + +pub struct EevCfgs { + pub eev1: EevCfg, + pub eev2: EevCfg, + pub eev3: EevCfg, + pub eev4: EevCfg, + pub eev5: EevCfg, + pub eev6: EevCfg, + pub eev7: EevCfg, + pub eev8: EevCfg, + pub eev9: EevCfg, + pub eev10: EevCfg, + + // TODO: Expose these + // TODO: Note there are some peculiarities here with fast mode + // One way to prevent missuse would be to require a borrowed ExternalEventSource when setting + // filter/latching as well as the event_counter related settings below. + pub(crate) event_counter_enable_bit: bool, + pub(crate) event_counter_reset_mode_bit: bool, + pub(crate) event_counter_source_bits: u8, + pub(crate) event_counter_threshold_bits: u8, +} + +macro_rules! impl_setter { + ($eevX:ident) => { + pub fn $eevX(mut self, cfg: EevCfg) -> Self { + self.$eevX = cfg; + self + } + }; +} + +impl EevCfgs { + impl_setter!(eev1); + impl_setter!(eev2); + impl_setter!(eev3); + impl_setter!(eev4); + impl_setter!(eev5); + impl_setter!(eev6); + impl_setter!(eev7); + impl_setter!(eev8); + impl_setter!(eev9); + impl_setter!(eev10); +} + +impl Clone for EevCfgs { + fn clone(&self) -> Self { + Self { + eev1: self.eev1.clone(), + eev2: self.eev2.clone(), + eev3: self.eev3.clone(), + eev4: self.eev4.clone(), + eev5: self.eev5.clone(), + eev6: self.eev6.clone(), + eev7: self.eev7.clone(), + eev8: self.eev8.clone(), + eev9: self.eev9.clone(), + eev10: self.eev10.clone(), + event_counter_enable_bit: self.event_counter_enable_bit, + event_counter_reset_mode_bit: self.event_counter_reset_mode_bit, + event_counter_source_bits: self.event_counter_source_bits, + event_counter_threshold_bits: self.event_counter_threshold_bits, + } + } +} + +pub struct EevCfg { + _x: PhantomData, + pub(crate) filter_bits: u8, + pub(crate) latch_bit: bool, +} + +impl Clone for EevCfg { + fn clone(&self) -> Self { + Self { + _x: PhantomData, + filter_bits: self.filter_bits, + latch_bit: self.latch_bit, + } + } +} + +impl EevCfg { + /// NOTE: This can not be set if eev is in fast mode AND using `EevCfg::latching` + pub fn filter(mut self, filter: EventFilter) -> Self { + self.filter_bits = filter as u8; + self + } + + /// NOTE: This can not be set if eev is in fast mode AND using a `EevCfg::filter` + pub fn latching(mut self) -> Self { + self.latch_bit = true; + self + } +} + +/// Note: Whenever a compare register is used for filtering, the value must be strictly above 0. +pub enum EventFilter { + /// No filtering + None = 0b0000, + + /// Blanking from reset/rollover to Cmp1 + BlankingResetToCmp1 = 0b0001, + + /// This depends on counter mode: + /// * Up-counting mode: Blanking from reset/rollover to Cmp2 + /// * Up-down mode: Blanking from Cmp1 to Cmp2(only during up counting) + BlankingResetToCmp2OrCmp1ToCmp2InUdm = 0b0010, + + /// Blanking from reset/rollover to Cmp3 + BlankingResetToCmp3 = 0b0011, + + /// This depends on counter mode: + /// * Up-counting mode: Blanking from reset/rollover to Cmp4 + /// * Up-down mode: Blanking from Cmp3 to Cmp4(only during up counting) + BlankingResetToCmp4OrCmp3ToCmp4InUdm = 0b0100, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource1 = 0b0101, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource2 = 0b0110, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource3 = 0b0111, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource4 = 0b1000, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource5 = 0b1001, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource6 = 0b1010, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource7 = 0b1011, + + /// (RM 0440 table 226 'Filtering signals mapping per timer') + BlankingSource8 = 0b1100, + + /// This depends on counter mode: + /// * Up-counting mode: Windowing from reset/rollover to Cmp2 + /// * Up-down mode: Windowing from Cmp2 to Cmp3(only during up counting) + WindowingResetToCmp2OrCmp2ToCmp3InUdm = 0b1101, + + /// This depends on counter mode: + /// * Up-counting mode: Windowing from reset/rollover to Cmp3 + /// * Up-down mode: Windowing from Cmp2 to Cmp3(only during down counting) + WindowingResetToCmp3OrCmp2ToCmp3InUdm = 0b1110, + + /// This depends on counter mode: + /// * Up-counting mode: Windowing from reset/rollover to other timer `TIMWIN`'s Cmp2 event + /// * Up-down mode: Windowing from other timer `TIMWIN`'s Cmp2 during up counting to Cmp3 during down counting + /// + /// `TIMWIN` (RM 0440 table 227 'Windowing signals mapping per timer'): + /// + /// | Destination |`TIMA`|`TIMB`|`TIMC`|`TIMD`|`TIME`|`TIMF`| + /// |-------------|------|------|------|------|------|------| + /// | TIMWIN |`TIMB`|`TIMA`|`TIMD`|`TIMC`|`TIMF`|`TIME`| + WindowingResetToOtherCmp2OrCmp2UpToCmp3DownInUdm = 0b1111, +} + +impl Default for EevCfg { + fn default() -> Self { + Self { + _x: PhantomData, + filter_bits: EventFilter::None as u8, + latch_bit: false, + } + } +} + +impl Default for EevCfgs { + fn default() -> Self { + Self { + eev1: EevCfg::default(), + eev2: Default::default(), + eev3: Default::default(), + eev4: Default::default(), + eev5: Default::default(), + eev6: Default::default(), + eev7: Default::default(), + eev8: Default::default(), + eev9: Default::default(), + eev10: Default::default(), + event_counter_enable_bit: false, + event_counter_reset_mode_bit: false, + event_counter_source_bits: 0, + event_counter_threshold_bits: 0, + } + } +} diff --git a/src/i2c.rs b/src/i2c.rs index 33fa7a65..09477d9a 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -136,13 +136,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()); } }; } @@ -150,18 +152,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 { @@ -220,21 +223,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 } } @@ -267,12 +272,12 @@ macro_rules! i2c { // Wait for any previous address sequence to end automatically. // This could be up to 50% of a bus cycle (ie. up to 0.5/freq) - while self.i2c.cr2.read().start().bit_is_set() {}; + while self.i2c.cr2().read().start().bit_is_set() {}; // Set START and prepare to send `bytes`. // The START bit can be set even if the bus is BUSY or // I2C is in slave mode. - self.i2c.cr2.write(|w| { + self.i2c.cr2().write(|w| unsafe { w // Start transfer .start().set_bit() @@ -294,14 +299,14 @@ macro_rules! i2c { busy_wait!(self.i2c, txis, bit_is_set); // Put byte on the wire - self.i2c.txdr.write(|w| { w.txdata().bits(*byte) }); + self.i2c.txdr().write(|w| unsafe { w.txdata().bits(*byte) }); } // Wait until the write finishes before beginning to read. busy_wait!(self.i2c, tc, bit_is_set); // reSTART and prepare to receive bytes into `buffer` - self.i2c.cr2.write(|w| { + self.i2c.cr2().write(|w| unsafe { w // Start transfer .start().set_bit() @@ -321,7 +326,7 @@ macro_rules! i2c { // Wait until we have received something busy_wait!(self.i2c, rxne, bit_is_set); - *byte = self.i2c.rxdr.read().rxdata().bits(); + *byte = self.i2c.rxdr().read().rxdata().bits(); } // automatic STOP @@ -336,7 +341,7 @@ macro_rules! i2c { fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { assert!(bytes.len() < 256 && bytes.len() > 0); - self.i2c.cr2.modify(|_, w| { + self.i2c.cr2().modify(|_, w| unsafe { w // Start transfer .start().set_bit() @@ -356,7 +361,7 @@ macro_rules! i2c { busy_wait!(self.i2c, txis, bit_is_set); // Put byte on the wire - self.i2c.txdr.write(|w| w.txdata().bits(*byte) ); + self.i2c.txdr().write(|w| unsafe { w.txdata().bits(*byte) } ); } // automatic STOP @@ -374,12 +379,12 @@ macro_rules! i2c { // Wait for any previous address sequence to end automatically. // This could be up to 50% of a bus cycle (ie. up to 0.5/freq) - while self.i2c.cr2.read().start().bit_is_set() {}; + while self.i2c.cr2().read().start().bit_is_set() {}; // Set START and prepare to receive bytes into `buffer`. // The START bit can be set even if the bus // is BUSY or I2C is in slave mode. - self.i2c.cr2.modify(|_, w| { + self.i2c.cr2().modify(|_, w| unsafe { w // Start transfer .start().set_bit() @@ -397,7 +402,7 @@ macro_rules! i2c { // Wait until we have received something busy_wait!(self.i2c, rxne, bit_is_set); - *byte = self.i2c.rxdr.read().rxdata().bits(); + *byte = self.i2c.rxdr().read().rxdata().bits(); } // automatic STOP 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/lib.rs b/src/lib.rs index 93c12d07..3e2382e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,6 @@ feature = "stm32g491", feature = "stm32g4a1" )))] - compile_error!( "This crate requires one of the following features enabled: stm32g431 @@ -83,6 +82,9 @@ pub mod dma; pub mod exti; pub mod flash; pub mod gpio; + +#[cfg(feature = "hrtim")] +pub mod hrtim; pub mod i2c; pub mod opamp; pub mod prelude; 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 5f27211d..e88748e3 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -172,6 +172,8 @@ use core::marker::PhantomData; use core::mem::MaybeUninit; +use fugit::HertzU64; + use crate::hal; use crate::stm32::LPTIMER1; use crate::stm32::RCC; @@ -253,6 +255,7 @@ pub struct ComplementaryDisabled; pub struct ComplementaryEnabled; /// Enum for IO polarity +#[derive(Copy, Clone, Debug, PartialEq)] pub enum Polarity { ActiveHigh, ActiveLow, @@ -874,7 +877,7 @@ pins! { feature = "stm32g483", feature = "stm32g484", feature = "stm32g491", - feature = "stm32g4a1" + feature = "stm32g4a1", ))] pins! { TIM20: @@ -1025,40 +1028,58 @@ pins! { ] } -// Period and prescaler calculator for 32-bit timers -// Returns (arr, psc) -fn calculate_frequency_32bit(base_freq: Hertz, freq: Hertz, alignment: Alignment) -> (u32, u16) { - let divisor = if let Alignment::Center = alignment { - freq * 2 - } else { - freq - }; +pub(crate) trait TimerType { + /// Returns (arr, psc) bits + fn calculate_frequency(base_freq: HertzU64, freq: Hertz, alignment: Alignment) -> (u32, u16); +} + +/// Any 32-bit timer +pub(crate) struct Timer32Bit; + +impl TimerType for Timer32Bit { + // Period and prescaler calculator for 32-bit timers + // Returns (arr, psc) bits + fn calculate_frequency(base_freq: HertzU64, freq: Hertz, alignment: Alignment) -> (u32, u16) { + let freq = HertzU64::from(freq); + let divisor = if let Alignment::Center = alignment { + freq * 2 + } else { + freq + }; - // Round to the nearest period - let arr = (base_freq + (divisor / 2)) / divisor - 1; + // Round to the nearest period + let arr = (base_freq + (divisor / 2)) / divisor - 1; - (arr, 0) + assert!(arr <= u32::MAX as u64); + + (arr as u32, 0) + } } -// Period and prescaler calculator for 16-bit timers -// Returns (arr, psc) -// Returns as (u32, u16) to be compatible but arr will always be a valid u16 -fn calculate_frequency_16bit(base_freq: Hertz, freq: Hertz, alignment: Alignment) -> (u32, u16) { - let ideal_period = calculate_frequency_32bit(base_freq, freq, alignment).0 + 1; +/// Any 16-bit timer except for HrTim +struct Timer16Bit; + +impl TimerType for Timer16Bit { + // Period and prescaler calculator for 16-bit timers + // Returns (arr, psc) + // Returns as (u32, u16) to be compatible but arr will always be a valid u16 + fn calculate_frequency(base_freq: HertzU64, freq: Hertz, alignment: Alignment) -> (u32, u16) { + let ideal_period = Timer32Bit::calculate_frequency(base_freq, freq, alignment).0 + 1; - // Division factor is (PSC + 1) - let prescale = (ideal_period - 1) / (1 << 16); + // Division factor is (PSC + 1) + let prescale = (ideal_period - 1) / (1 << 16); - // This will always fit in a 16-bit value because u32::MAX / (1 << 16) fits in a 16 bit + // This will always fit in a 16-bit value because u32::MAX / (1 << 16) fits in a 16 bit - // Round to the nearest period - let period = (ideal_period + (prescale >> 1)) / (prescale + 1) - 1; + // Round to the nearest period + let period = (ideal_period + (prescale >> 1)) / (prescale + 1) - 1; - // It should be impossible to fail these asserts - assert!(period <= 0xFFFF); - assert!(prescale <= 0xFFFF); + // It should be impossible to fail these asserts + assert!(period <= 0xFFFF); + assert!(prescale <= 0xFFFF); - (period, prescale as u16) + (period, prescale as u16) + } } // Deadtime calculator helper function @@ -1130,68 +1151,82 @@ pub trait PwmAdvExt: Sized { // Implement PwmExt trait for timer macro_rules! pwm_ext_hal { - ($TIMX:ident: $timX:ident) => { - impl PwmExt for $TIMX { + ($TIMX:ident: $timX:ident $(, $HrTimPsc:tt)*) => { + impl $(<$HrTimPsc>)* PwmExt for $TIMX { fn pwm(self, pins: PINS, frequency: T, rcc: &mut Rcc) -> PINS::Channel where PINS: Pins, T: Into, { - $timX(self, pins, frequency.into(), rcc) + $timX::<_, _, _ $(, $HrTimPsc )*>(self, pins, frequency.into(), rcc) } } }; } -// Implement PWM configuration for timer -macro_rules! tim_hal { - ($($TIMX:ident: ($timX:ident, - $typ:ty, $bits:expr $(, DIR: $cms:ident)* $(, BDTR: $bdtr:ident, $moe_set:ident, $af1:ident, $bkinp_setting:ident $(, $bk2inp_setting:ident)*)*),)+) => { - $( - pwm_ext_hal!($TIMX: $timX); +macro_rules! simple_tim_hal { + ($TIMX:ident: ( + $timX:ident, + $bits:ident, + $(, BDTR: $bdtr:ident, $moe_set:ident)* + )) => { + pwm_ext_hal!($TIMX: $timX); + + /// Configures PWM + fn $timX( + tim: $TIMX, + _pins: PINS, + freq: Hertz, + rcc: &mut Rcc, + ) -> PINS::Channel + where + PINS: Pins<$TIMX, T, U>, + { + unsafe { + let rcc_ptr = &(*RCC::ptr()); + $TIMX::enable(rcc_ptr); + $TIMX::reset(rcc_ptr); + } - /// Configures PWM - fn $timX( - tim: $TIMX, - _pins: PINS, - freq: Hertz, - rcc: &mut Rcc, - ) -> PINS::Channel - where - PINS: Pins<$TIMX, T, U>, - { - unsafe { - let rcc_ptr = &(*RCC::ptr()); - $TIMX::enable(rcc_ptr); - $TIMX::reset(rcc_ptr); - } + let clk = $TIMX::get_timer_frequency(&rcc.clocks); - let clk = $TIMX::get_timer_frequency(&rcc.clocks); + let (period, prescale) = <$bits>::calculate_frequency(clk.into(), freq, Alignment::Left); - let (period, prescale) = match $bits { - 16 => calculate_frequency_16bit(clk, freq, Alignment::Left), - _ => calculate_frequency_32bit(clk, freq, Alignment::Left), - }; + // Write prescale + tim.psc().write(|w| { unsafe { w.psc().bits(prescale as u16) } }); - // Write prescale - tim.psc.write(|w| { unsafe { w.psc().bits(prescale as u16) } }); + // Write period + tim.arr().write(|w| { unsafe { w.arr().bits(period.into()) } }); - // Write period - 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| + w.moe().$moe_set() + ); + )* - // BDTR: Advanced-control timers - $( - // Set CCxP = OCxREF / CCxNP = !OCxREF - // Refer to RM0433 Rev 6 - Table 324. - 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() } + } + }; +} - unsafe { MaybeUninit::::uninit().assume_init() } - } +// Implement PWM configuration for timer +macro_rules! tim_hal { + ($($TIMX:ident: ( + $timX:ident, + $typ:ty, $bits:ident $( <$HrTimPsc:tt> )* $(, DIR: $cms:ident)* + $(, BDTR: $bdtr:ident, $moe_set:ident, $af1:ident, $bkinp_setting:ident $(, $bk2inp_setting:ident)*)* + ),)+) => { + $( + simple_tim_hal!($TIMX: ( + $timX, + $bits, + $(, BDTR: $bdtr, $moe_set)* + )); impl PwmAdvExt<$typ> for $TIMX { fn pwm_advanced( @@ -1238,28 +1273,25 @@ macro_rules! tim_hal { let (period, prescaler) = match self.count { CountSettings::Explicit { period, prescaler } => (period as u32, prescaler), CountSettings::Frequency( freq ) => { - match $bits { - 16 => calculate_frequency_16bit(self.base_freq, freq, self.alignment), - _ => calculate_frequency_32bit(self.base_freq, freq, self.alignment), - } + <$bits>::calculate_frequency(self.base_freq.into(), freq, self.alignment) }, }; // 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, @@ -1273,12 +1305,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 @@ -1289,37 +1321,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() @@ -1427,19 +1459,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()); } } )* @@ -1448,10 +1480,10 @@ macro_rules! tim_hal { } tim_hal! { - TIM1: (tim1, u16, 16, DIR: cms, BDTR: bdtr, set_bit, af1, clear_bit, clear_bit), - TIM2: (tim2, u32, 32, DIR: cms), - TIM3: (tim3, u16, 16, DIR: cms), - TIM4: (tim4, u16, 16, DIR: cms), + TIM1: (tim1, u16, Timer16Bit, DIR: cms, BDTR: bdtr, set_bit, af1, clear_bit, clear_bit), + TIM2: (tim2, u32, Timer32Bit, DIR: cms), + TIM3: (tim3, u16, Timer16Bit, DIR: cms), + TIM4: (tim4, u16, Timer16Bit, DIR: cms), } #[cfg(any( feature = "stm32g471", @@ -1461,13 +1493,13 @@ tim_hal! { feature = "stm32g484" ))] tim_hal! { - TIM5: (tim5, u32, 32, DIR: cms), + TIM5: (tim5, u32, Timer32Bit, DIR: cms), } tim_hal! { - TIM8: (tim8, u16, 16, DIR: cms, BDTR: bdtr, set_bit, af1, clear_bit, clear_bit), - TIM15: (tim15, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), - TIM16: (tim16, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), - TIM17: (tim17, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), + TIM8: (tim8, u16, Timer16Bit, DIR: cms, BDTR: bdtr, set_bit, af1, clear_bit, clear_bit), + TIM15: (tim15, u16, Timer16Bit, BDTR: bdtr, set_bit, af1, set_bit), + TIM16: (tim16, u16, Timer16Bit, BDTR: bdtr, set_bit, af1, set_bit), + TIM17: (tim17, u16, Timer16Bit, BDTR: bdtr, set_bit, af1, set_bit), } #[cfg(any( @@ -1479,7 +1511,7 @@ tim_hal! { feature = "stm32g4a1" ))] tim_hal! { - TIM20: (tim20, u16, 16, BDTR: bdtr, set_bit, af1, set_bit), + TIM20: (tim20, u16, Timer16Bit, BDTR: bdtr, set_bit, af1, set_bit), } pub trait PwmPinEnable { @@ -1532,7 +1564,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 @@ -1558,12 +1590,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()); } } @@ -1571,7 +1603,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, @@ -1587,7 +1619,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, @@ -1606,12 +1638,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()); } } @@ -1620,12 +1652,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()); } } @@ -1635,7 +1667,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); @@ -1653,7 +1685,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, @@ -1669,7 +1701,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, @@ -1806,19 +1838,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() } } @@ -1834,33 +1866,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()); } } )+ 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 a2ab3443..5e1c4393 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 } } @@ -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,7 +302,7 @@ pub enum PllNMul { } impl PllNMul { - pub fn multiplier(&self) -> u32 { + pub const fn multiplier(&self) -> u32 { *self as u32 } diff --git a/src/rcc/enable.rs b/src/rcc/enable.rs index 4ab3d330..8bd3db1d 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,19 +222,15 @@ bus! { feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", - feature = "stm32g484" + feature = "stm32g484", + feature = "stm32g491", + feature = "stm32g4a1", ))] bus! { - FDCAN3 => (APB1_1, 25), TIM20 => (APB2, 20), } #[cfg(any(feature = "stm32g474", feature = "stm32g484"))] bus! { - HRTIM_TIMA => (APB2, 26), - HRTIM_TIMB => (APB2, 26), - HRTIM_TIMC => (APB2, 26), - HRTIM_TIMD => (APB2, 26), - HRTIM_TIME => (APB2, 26), - HRTIM_TIMF => (APB2, 26), + HRTIM_COMMON => (APB2, 26), } diff --git a/src/rcc/mod.rs b/src/rcc/mod.rs index c901ee7e..0503f574 100644 --- a/src/rcc/mod.rs +++ b/src/rcc/mod.rs @@ -188,7 +188,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() @@ -199,7 +199,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: @@ -232,15 +232,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 { @@ -275,7 +275,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() @@ -309,8 +309,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), @@ -362,7 +362,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)); } } @@ -379,11 +379,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) }; @@ -392,7 +392,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() @@ -401,7 +401,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. @@ -412,41 +412,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(), @@ -460,7 +460,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()); } } @@ -531,16 +531,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() } } @@ -550,16 +550,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() } } @@ -570,17 +570,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() } } @@ -590,16 +590,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() } } @@ -609,16 +609,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() } } @@ -628,16 +628,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 d5779131..e89a3451 100644 --- a/src/serial/usart.rs +++ b/src/serial/usart.rs @@ -1,6 +1,8 @@ +use core::convert::Infallible; use core::fmt; use core::marker::PhantomData; +use crate::dma::traits::Stream; use crate::dma::{ mux::DmaMuxResources, traits::TargetAddress, MemoryToPeripheral, PeripheralToMemory, }; @@ -84,7 +86,7 @@ pub struct Rx { pub struct Tx { pin: Pin, usart: USART, - _dma: PhantomData, + dma: Dma, } /// Serial abstraction @@ -108,7 +110,12 @@ impl TxPin for NoTx {} pub struct NoDMA; /// Type state for Tx/Rx, indicating configuration for DMA #[derive(Debug)] -pub struct DMA; +pub struct DMA { + stream: T, + memory: M, +} + +pub struct DMAOld; pub trait SerialExt { fn usart( @@ -133,9 +140,9 @@ where } } -impl fmt::Write for Tx +impl fmt::Write for Tx where - Tx: hal::serial::Write, + Tx: hal::serial::Write, { fn write_str(&mut self, s: &str) -> fmt::Result { let _ = s.as_bytes().iter().map(|c| block!(self.write(*c))).last(); @@ -143,6 +150,10 @@ where } } +impl embedded_io::ErrorType for Tx> { + type Error = Infallible; +} + macro_rules! uart_shared { ($USARTX:ident, $dmamux_rx:ident, $dmamux_tx:ident, tx: [ $($( #[ $pmeta1:meta ] )* ($PTX:ident, $TAF:expr),)+ ], @@ -166,33 +177,33 @@ 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() } } impl Rx<$USARTX, Pin, NoDMA> { - pub fn enable_dma(self) -> Rx<$USARTX, Pin, DMA> { + pub fn enable_dma(self) -> Rx<$USARTX, Pin, DMAOld> { // 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()); }); @@ -204,11 +215,11 @@ macro_rules! uart_shared { } } - impl Rx<$USARTX, Pin, DMA> { + impl Rx<$USARTX, Pin, DMAOld> { 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()); }); @@ -225,22 +236,22 @@ macro_rules! uart_shared { fn read(&mut self) -> nb::Result { 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(usart.rdr.read().bits() as u8) + return Ok(usart.rdr().read().bits() as u8) } else { nb::Error::WouldBlock } @@ -260,57 +271,148 @@ 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() + } + + pub fn clear_transmission_complete(&mut self) { + let usart = unsafe { &(*$USARTX::ptr()) }; + usart.icr().write(|w| w.tccf().set_bit()); } } impl Tx<$USARTX, Pin, NoDMA> { - pub fn enable_dma(self) -> Tx<$USARTX, Pin, DMA> { + pub fn enable_dma(self, mut stream: STREAM, memory: BUF) -> Tx<$USARTX, Pin, DMA> + where + STREAM: crate::dma::traits::Stream, + BUF: embedded_dma::StaticReadBuffer + { // 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()); }); + stream.disable(); + + core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst); + + // Set peripheral to memory mode + stream.set_direction(crate::dma::DmaDirection::MemoryToPeripheral); + + // NOTE(unsafe) We now own this buffer and we won't call any &mut + // methods on it until the end of the DMA transfer + let (buf_ptr, buf_len) = unsafe { memory.read_buffer() }; + + // Set the memory address + // + // # Safety + // + // Must be a valid memory address + unsafe { + stream.set_memory_address( + buf_ptr as u32, + ); + } + + // Set the peripheral address or the source address in memory-to-memory mode + // + // # Safety + // + // Must be a valid peripheral address or source address + let write_register_address = &unsafe { &*<$USARTX>::ptr() }.tdr() as *const _ as u32; + unsafe { stream.set_peripheral_address(write_register_address); } + + assert!( + buf_len <= 65535, + "Hardware does not support more than 65535 transfers" + ); + + // Set the DMAMUX request line + stream.set_request_line(DmaMuxResources::$dmamux_tx as u8); + + let msize = core::mem::size_of::() / 2; + + stream.clear_interrupts(); + + // NOTE(unsafe) These values are correct because of the + // invariants of TargetAddress + unsafe { + stream.set_memory_size(msize as u8); + stream.set_peripheral_size(msize as u8); + } + + let config = crate::dma::config::DmaConfig::default() + .transfer_complete_interrupt(false) + .circular_buffer(false) + .memory_increment(true) + .priority(crate::dma::config::Priority::Low); + stream.apply_config(config); + Tx { pin: self.pin, usart: self.usart, - _dma: PhantomData, + dma: DMA{ stream, memory }, } } } - impl Tx<$USARTX, Pin, DMA> { - pub fn disable_dma(self) -> Tx<$USARTX, Pin, NoDMA> { - // NOTE(unsafe) critical section prevents races - interrupt::free(|_| unsafe { - let cr3 = &(*$USARTX::ptr()).cr3; - cr3.modify(|_, w| w.dmat().clear_bit()); - }); + impl embedded_io::Write for Tx<$USARTX, Pin, DMA> + where + T: Stream, + M: embedded_dma::StaticReadBuffer + core::ops::DerefMut, + ::Target: core::ops::IndexMut, Output = [u8]>, + { + fn write(&mut self, buf: &[u8]) -> Result { + use core::sync::atomic::fence; - Tx { - pin: self.pin, - usart: self.usart, - _dma: PhantomData, + let (_p, buffer_capacity) = unsafe { self.dma.memory.read_buffer() }; + let count = buf.len().min(buffer_capacity); + + embedded_io::Write::flush(self)?; + + fence(core::sync::atomic::Ordering::SeqCst); + self.dma.stream.disable(); + + fence(core::sync::atomic::Ordering::SeqCst); + + self.dma.memory[0..count].copy_from_slice(&buf[0..count]); + self.dma.stream.set_number_of_transfers(count as u16); + + fence(core::sync::atomic::Ordering::SeqCst); + + unsafe { + self.clear_transmission_complete(); + self.dma.stream.enable(); + } + + Ok(count) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + while T::get_number_of_transfers() > 0 { + assert!(!T::get_transfer_error_flag()); } + self.dma.stream.clear_transfer_complete_interrupt(); + assert!(!T::get_transfer_error_flag()); + Ok(()) } } @@ -319,7 +421,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) @@ -328,8 +430,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) @@ -379,7 +481,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); @@ -388,11 +490,11 @@ macro_rules! uart_shared { } } - unsafe impl TargetAddress for Tx<$USARTX, Pin, DMA> { + unsafe impl TargetAddress for Tx<$USARTX, Pin, DMAOld> { #[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; @@ -400,11 +502,11 @@ macro_rules! uart_shared { const REQUEST_LINE: Option = Some(DmaMuxResources::$dmamux_tx as u8); } - unsafe impl TargetAddress for Rx<$USARTX, Pin, DMA> { + unsafe impl TargetAddress for Rx<$USARTX, Pin, DMAOld> { #[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; @@ -464,21 +566,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() @@ -490,7 +592,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() @@ -513,7 +615,7 @@ macro_rules! uart_lp { tx: Tx { pin: tx, usart, - _dma: PhantomData, + dma: NoDMA, }, rx: Rx { pin: rx, @@ -526,26 +628,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 @@ -554,7 +656,7 @@ macro_rules! uart_lp { let mask: u32 = 0x123BFF; self.tx .usart - .icr + .icr() .write(|w| unsafe { w.bits(event.val() & mask) }); } } @@ -612,14 +714,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() @@ -627,12 +729,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() @@ -644,7 +746,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() @@ -667,7 +769,7 @@ macro_rules! uart_full { tx: Tx { pin: tx, usart, - _dma: PhantomData, + dma: NoDMA, }, rx: Rx { pin: rx, @@ -680,26 +782,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 @@ -708,7 +810,7 @@ macro_rules! uart_full { let mask: u32 = 0x123BFF; self.tx .usart - .icr + .icr() .write(|w| unsafe { w.bits(event.val() & mask) }); } } @@ -718,13 +820,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 78cda675..27d94718 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; pub use hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; @@ -118,7 +117,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(); @@ -134,11 +133,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() @@ -173,7 +172,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, @@ -195,7 +194,7 @@ macro_rules! spi { type Error = Error; fn 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) @@ -207,7 +206,7 @@ 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 u8) + ptr::read_volatile(&self.spi.dr() as *const _ as *const u8) }); } else { nb::Error::WouldBlock @@ -215,7 +214,7 @@ macro_rules! spi { } fn send(&mut self, byte: u8) -> 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) @@ -224,9 +223,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 u8; // NOTE(write_volatile) see note above - unsafe { ptr::write_volatile(UnsafeCell::raw_get(dr), byte) }; + unsafe { ptr::write_volatile(dr, byte) }; return Ok(()); } else { nb::Error::WouldBlock @@ -237,7 +236,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 b3d72267..26b89008 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 } } @@ -297,33 +297,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(()) } } @@ -341,14 +341,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(()) } }