From 07725ff076bda23f296635d04449d1900eb7df84 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 18 Dec 2021 21:52:09 +0100 Subject: [PATCH 01/35] adc1 sequence with external timer and dma / dma_irq --- examples/adc_timer2_dma_seq.rs | 128 +++++++++++++++++ src/adc.rs | 250 ++++++++++++++++++++++++++++++++- src/timer.rs | 9 +- 3 files changed, 379 insertions(+), 8 deletions(-) create mode 100644 examples/adc_timer2_dma_seq.rs diff --git a/examples/adc_timer2_dma_seq.rs b/examples/adc_timer2_dma_seq.rs new file mode 100644 index 00000000..898ef155 --- /dev/null +++ b/examples/adc_timer2_dma_seq.rs @@ -0,0 +1,128 @@ +#![no_main] +#![no_std] + +use panic_rtt_target as _; +use rtt_target::{rprintln, rtt_init_print}; +use stm32l4xx_hal::{ + adc::{DmaMode, SampleTime, Sequence, ADC}, + delay::DelayCM, + dma::{dma1, RxDma, Transfer, W}, + prelude::*, + time::Hertz, + timer::Timer, // Event, +}; + +use rtic::app; + +const SEQUENCE_LEN: usize = 4; + +#[app(device = stm32l4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] +const APP: () = { + // RTIC app is written in here! + + struct Resources { + transfer: Option>>, + } + + #[init] + fn init(cx: init::Context) -> init::LateResources { + let MEMORY = { + static mut MEMORY: [u16; SEQUENCE_LEN] = [0u16; SEQUENCE_LEN]; + unsafe { &mut MEMORY } + }; + + rtt_init_print!(); + + rprintln!("Hello from init!"); + + let cp = cx.core; + let mut dcb = cp.DCB; + let mut dwt = cp.DWT; + + dcb.enable_trace(); + dwt.enable_cycle_counter(); + + let pac = cx.device; + + let mut rcc = pac.RCC.constrain(); + let mut flash = pac.FLASH.constrain(); + let mut pwr = pac.PWR.constrain(&mut rcc.apb1r1); + let dma_channels = pac.DMA1.split(&mut rcc.ahb1); + + // + // Initialize the clocks + // + let clocks = rcc + .cfgr + .sysclk(Hertz(80_000_000)) + .freeze(&mut flash.acr, &mut pwr); + + let mut delay = DelayCM::new(clocks); + + let mut adc = ADC::new( + pac.ADC1, + pac.ADC_COMMON, + &mut rcc.ahb2, + &mut rcc.ccipr, + &mut delay, + ); + + let mut temp_pin = adc.enable_temperature(&mut delay); + + let dma1_channel = dma_channels.1; + // let adc_buffer1_addr = MEMORY.as_ptr(); + let mut gpioc = pac.GPIOC.split(&mut rcc.ahb2); + let mut pc0 = gpioc.pc0.into_analog(&mut gpioc.moder, &mut gpioc.pupdr); + + adc.configure_sequence(&mut temp_pin, Sequence::One, SampleTime::Cycles12_5); + adc.configure_sequence(&mut temp_pin, Sequence::Two, SampleTime::Cycles247_5); + adc.configure_sequence(&mut temp_pin, Sequence::Three, SampleTime::Cycles640_5); + adc.configure_sequence(&mut pc0, Sequence::Four, SampleTime::Cycles640_5); + + // optional oversampling settings + adc.set_oversampling_ratio(7); + adc.set_oversampling_shift(8); + adc.oversampling_enable(); + + adc.set_external_trigger(0b1011, 1 as u8); // Timer2_TRGO + + // Heapless boxes also work very well as buffers for DMA transfers + let transfer = Transfer::from_adc(adc, dma1_channel, MEMORY, DmaMode::ExtTrigger, true); + + // unsafe { NVIC::unmask(stm32l4xx_hal::stm32::Interrupt::TIM2) }; + let _timer = Timer::tim2(pac.TIM2, 1.hz(), clocks, &mut rcc.apb1r1); + unsafe { + // get pointer of timer 2 + let tim = &(*stm32l4::stm32l4x6::TIM2::ptr()); + // config master mode selection to TRGO to Compare Pulse of timer2 + tim.cr2.modify(|_, w| w.mms().bits(3 as u8)); + tim.dier.write(|w| w.ude().set_bit()); + } + + init::LateResources { + transfer: Some(transfer), + } + } + + #[idle] + fn idle(_cx: idle::Context) -> ! { + loop { + cortex_m::asm::nop(); + } + } + + #[task(binds = DMA1_CH1, resources = [transfer])] + fn dma1_interrupt(cx: dma1_interrupt::Context) { + let transfer = cx.resources.transfer; + if let Some(transfer_val) = transfer.take() { + let (buffer, rx_dma) = transfer_val.wait(); + rprintln!("DMA measurements: {:?}", buffer); + *transfer = Some(Transfer::from_adc_dma( + rx_dma, + buffer, + DmaMode::ExtTrigger, + true, + )); + } + } +}; diff --git a/src/adc.rs b/src/adc.rs index df3ced0a..9e1a5309 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -45,6 +45,7 @@ pub enum DmaMode { Oneshot = 1, // FIXME: Figure out how to get circular DMA to function properly (requires circbuffer?) // Circular = 2, + ExtTrigger = 3, } #[derive(PartialEq, PartialOrd, Clone, Copy)] @@ -114,6 +115,37 @@ impl Into for Sequence { } } +#[derive(PartialEq, PartialOrd, Clone, Copy)] +pub enum Jsequence { + One = 0, + Two = 1, + Three = 2, + Four = 3, +} + +impl From for Jsequence { + fn from(bits: u8) -> Self { + match bits { + 0 => Jsequence::One, + 1 => Jsequence::Two, + 2 => Jsequence::Three, + 3 => Jsequence::Four, + _ => unimplemented!(), + } + } +} + +impl Into for Jsequence { + fn into(self) -> u8 { + match self { + Jsequence::One => 0, + Jsequence::Two => 1, + Jsequence::Three => 2, + Jsequence::Four => 3, + } + } +} + #[derive(PartialEq, PartialOrd, Clone, Copy)] pub enum Event { EndOfRegularSequence, @@ -348,6 +380,52 @@ impl ADC { } } + /// Configure the channel for a specific step in the sequence. + /// + /// Automatically sets the sequence length to the farthes sequence + /// index that has been used so far. Use [`ADC::reset_sequence`] to + /// reset the sequence length. + pub fn configure_jsequence( + &mut self, + channel: &mut C, + sequence: Jsequence, + sample_time: SampleTime, + ) where + C: Channel, + { + let channel_bits = C::channel(); + channel.set_sample_time(&self.adc, sample_time); + + unsafe { + // This is sound as channel() always returns a valid channel number + match sequence { + Jsequence::One => self.adc.jsqr.modify(|_, w| w.jsq1().bits(channel_bits)), + Jsequence::Two => self.adc.jsqr.modify(|_, w| w.jsq2().bits(channel_bits)), + Jsequence::Three => self.adc.jsqr.modify(|_, w| w.jsq3().bits(channel_bits)), + Jsequence::Four => self.adc.jsqr.modify(|_, w| w.jsq4().bits(channel_bits)), + } + } + + // This will only ever extend the sequence, not shrink it. + let current_seql = self.get_jsequence_length(); + let next_seql: u8 = sequence.into(); + if next_seql >= current_seql { + // Note: sequence length of 0 = 1 conversion + self.set_jsequence_length(sequence.into()); + } + } + + /// Get the configured sequence length (= `actual sequence length - 1`) + pub(crate) fn get_jsequence_length(&self) -> u8 { + self.adc.jsqr.read().jl().bits() + } + + /// Private: length must be `actual sequence length - 1`, so not API-friendly. + /// Use [`ADC::reset_sequence`] and [`ADC::configure_sequence`] instead + fn set_jsequence_length(&mut self, length: u8) { + self.adc.jsqr.modify(|_, w| unsafe { w.jl().bits(length) }); + } + /// Get the configured sequence length (= `actual sequence length - 1`) pub(crate) fn get_sequence_length(&self) -> u8 { self.adc.sqr1.read().l().bits() @@ -432,6 +510,146 @@ impl ADC { pub fn disable(&mut self) { self.adc.cr.modify(|_, w| w.addis().set_bit()); } + + pub fn set_external_trigger(&mut self, ch: u8, edge: u8) { + /// channels for external triggers + /// TIM1_CH1 0b0000 + /// TIM1_CH2 0b0001 + /// TIM1_CH3 0b0010 + /// TIM2_CH2 0b0011 + /// TIM3_TRGO 0b0100 (not on all chips available) + /// EXTI line 11 0b0110 + /// TIM8_TRGO 0b0111 + /// TIM8_TRGO2 0b1000 + /// TIM1_TRGO 0b1001 + /// TIM1_TRGO2 0b1010 + /// TIM2_TRGO 0b1011 + /// TIM4_TRGO 0b1100 + /// TIM6_TRGO 0b1101 + /// TIM15_TRGO 0b1110 + /// TIM3_CH4 0b1111 + /// these bits are only allowed to be set, when ADC is disabled + if self.adc.cr.read().adstart().bit_is_clear() { + self.adc.cfgr.modify(|_, w| unsafe { w.extsel().bits(ch) }); + /// set edge of injected trigger by timers + /// None 0b00 + /// Positive edge 0b01 + /// Negative edge 0b10 + /// both edges 0b11 + self.adc.cfgr.modify(|_, w| unsafe { w.exten().bits(edge) }); // 1 as u8 + } + } + + pub fn set_inject_channel(&mut self, ch: u8, edge: u8) { + /// channels for injection Transmitter + /// TIM1_TRGO 0b0000 + /// TIM1_CH4 0b0001 + /// TIM2_TRGO 0b0010 + /// TIM2_CH1 0b0011 + /// TIM3_CH4 0b0100 (not on all chips available) + /// EXTI line 15 0b0110 + /// TIM1_TRGO2 0b1000 + /// TIM6_TRGO 0b1110 + /// TIM15_TRGO 0b1111 + self.adc.jsqr.modify(|_, w| unsafe { w.jextsel().bits(ch) }); + /// set edge of injected trigger by timers + /// None 0b00 + /// Positive edge 0b01 + /// Negative edge 0b10 + /// both edges 0b11 + self.adc + .jsqr + .modify(|_, w| unsafe { w.jexten().bits(edge) }); // 1 as u8 + } + + pub fn start_injected(&mut self) { + if !self.is_injected_mod_enabled() { + while self.adc.cr.read().addis().bit_is_set() {} + self.adc.ier.modify(|_, w| w.jeocie().set_bit()); // end of sequence interupt enable + self.adc.cr.modify(|_, w| w.aden().set_bit()); + self.adc.cr.modify(|_, w| w.jadstart().set_bit()); + // ADSTART bit is cleared to 0 bevor using this function + while self.adc.isr.read().adrdy().bit_is_clear() {} + } + } + + pub fn start_injected_sequence(&mut self) { + if !self.is_injected_mod_enabled() { + while self.adc.cr.read().addis().bit_is_set() {} + self.adc.ier.modify(|_, w| w.jeosie().set_bit()); // end of sequence interupt enable + + self.adc.cr.modify(|_, w| w.aden().set_bit()); + while self.adc.isr.read().adrdy().bit_is_clear() {} + self.adc.cr.modify(|_, w| w.jadstart().set_bit()); + // ADSTART bit is cleared to 0 bevor using this function + + // clear end of sequencd conversion interrupt flag + } + } + + pub fn is_injected_mod_enabled(&self) -> bool { + self.adc.cr.read().jadstart().bit_is_set() + } + + pub fn stop_injected(&mut self) { + // ?????? or is it reset after each conversion? + self.adc.cr.modify(|_, w| w.jadstp().set_bit()); + // self.adc.cr.modify(|_, w| w.jadstp().set_bit()); + // ADSTART bit is cleared to 0 bevor using this function + // disable EOS interrupt + // maybe self.rb.cr.adstp().set_bit() must be performed before interrupt is disabled + wait abortion + self.adc.ier.modify(|_, w| w.jeocie().clear_bit()); // end of sequence interupt disable + } + + pub fn stop_injected_sequence(&mut self) { + // ?????? or is it reset after each conversion? + self.adc.cr.modify(|_, w| w.jadstp().set_bit()); + // self.adc.cr.modify(|_, w| w.jadstp().set_bit()); + // ADSTART bit is cleared to 0 bevor using this function + // disable EOS interrupt + // maybe self.rb.cr.adstp().set_bit() must be performed before interrupt is disabled + wait abortion + self.adc.ier.modify(|_, w| w.jeosie().clear_bit()); // end of sequence interupt disable + } + + /// Oversampling of adc according to datasheet of stm32g0, when oversampling is enabled + /// 000: 2x + /// 001: 4x + /// 010: 8x + /// 011: 16x + /// 100: 32x + /// 101: 64x + /// 110: 128x + /// 111: 256x + pub fn set_oversampling_ratio(&mut self, multyply: u8) { + self.adc + .cfgr2 + .modify(|_, w| unsafe { w.ovsr().bits(multyply) }); + } + + /// Oversampling shif configurations + /// 0000: No shift + /// 0001: Shift 1-bit + /// 0010: Shift 2-bits + /// 0011: Shift 3-bits + /// 0100: Shift 4-bits + /// 0101: Shift 5-bits + /// 0110: Shift 6-bits + /// 0111: Shift 7-bits + /// 1000: Shift 8-bits + /// Other codes reserved + pub fn set_oversampling_shift(&mut self, nrbits: u8) { + self.adc + .cfgr2 + .modify(|_, w| unsafe { w.ovss().bits(nrbits) }); + } + + pub fn oversampling_enable(&mut self) { + self.adc.cfgr2.modify(|_, w| w.rovse().set_bit()); + } + + pub fn inject_oversampling_enable(&mut self) { + self.adc.cfgr2.modify(|_, w| w.jovse().set_bit()); + } } impl OneShot for ADC @@ -510,9 +728,10 @@ where ) -> Self { assert!(dma_mode != DmaMode::Disabled); - let (enable, circular) = match dma_mode { - DmaMode::Disabled => (false, false), - DmaMode::Oneshot => (true, false), + let (enable, circular, exttrig) = match dma_mode { + DmaMode::Disabled => (false, false, false), + DmaMode::Oneshot => (true, false, false), + DmaMode::ExtTrigger => (true, false, true), }; adc.adc @@ -524,29 +743,45 @@ where // SAFETY: since the length of BUFFER is known to be `N`, we are allowed // to perform N transfers into said buffer channel.set_memory_address(buffer.as_ptr() as u32, true); - channel.set_transfer_length(N as u16); + channel.set_transfer_length(N as u16); // N is buffer legnth channel.cselr().modify(|_, w| w.c1s().bits(0b0000)); channel.ccr().modify(|_, w| unsafe { w.mem2mem() + // clear memory to memory mode .clear_bit() - // 00: Low, 01: Medium, 10: High, 11: Very high + // dma priority: 00: Low, 01: Medium, 10: High, 11: Very high .pl() .bits(0b01) - // 00: 8-bits, 01: 16-bits, 10: 32-bits, 11: Reserved + // dma transfer size: 00: 8-bits, 01: 16-bits, 10: 32-bits, 11: Reserved .msize() .bits(0b01) - // 00: 8-bits, 01: 16-bits, 10: 32-bits, 11: Reserved + // dma periferal transer size: 00: 8-bits, 01: 16-bits, 10: 32-bits, 11: Reserved .psize() .bits(0b01) // Peripheral -> Mem .dir() .clear_bit() + // memory increment mode + .minc() + .clear_bit() + // peripheral increment mode + .pinc() + .clear_bit() + // set circual mode as defined in DMAmode .circ() .bit(circular) }); + // read ADC sequence length + let sequence_length = adc.adc.sqr1.read().l().bits(); + // buffer increment bit in memory, if dma with several sequential reads are performed + if sequence_length > 0 && exttrig { + // memory increment mode + channel.ccr().modify(|_, w| w.minc().set_bit()); + } + if transfer_complete_interrupt { channel.listen(DMAEvent::TransferComplete); } @@ -554,6 +789,7 @@ where atomic::compiler_fence(Ordering::Release); channel.start(); + adc.start_conversion(); Transfer::w( diff --git a/src/timer.rs b/src/timer.rs index 34f1996b..b8ceb47c 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -248,10 +248,17 @@ macro_rules! hal { } /// Get the count of the timer. - pub fn count() -> $width { + pub fn count(&mut self) -> $width { let cnt = unsafe { (*$TIM::ptr()).cnt.read() }; cnt.cnt().bits() } + + // not able to select compilation for timers which support this feature + // pub fn set_mms(&mut self, mms_val: u8) { + // // see chapter 27.4.2 in reference manual RM0394 + // // unsafe { (*$TIM::ptr()).mms().bits(mms_val) }; + // self.tim.cr2.modify(|_, w| unsafe{w.mms().bits(mms_val)} ); + // } /// Releases the TIM peripheral pub fn free(self) -> $TIM { From 110825308ec8de435f3b51b4f1fd5db197207d5e Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 18 Dec 2021 23:30:14 +0100 Subject: [PATCH 02/35] adde example of injected dma sequence --- examples/adc_injectedsequence.rs | 143 +++++++++++++++++++++++++++++++ src/adc.rs | 15 ++++ src/timer.rs | 2 +- 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 examples/adc_injectedsequence.rs diff --git a/examples/adc_injectedsequence.rs b/examples/adc_injectedsequence.rs new file mode 100644 index 00000000..b274c6f8 --- /dev/null +++ b/examples/adc_injectedsequence.rs @@ -0,0 +1,143 @@ +#![no_main] +#![no_std] + +extern crate stm32l4; + +use cortex_m::peripheral::NVIC; +use panic_rtt_target as _; +use rtt_target::{rprintln, rtt_init_print}; +use stm32l4xx_hal::{ + adc::{DmaMode, Jsequence, SampleTime, ADC}, + delay::DelayCM, + dma::{dma1, RxDma, Transfer, W}, + prelude::*, + time::Hertz, + timer::{Event, Timer}, +}; + +use rtic::app; + +const SEQUENCE_LEN: usize = 4; + +#[app(device = stm32l4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] +const APP: () = { + // RTIC app is written in here! + + struct Resources { + adc: stm32l4xx_hal::adc::ADC, + } + + #[init] + fn init(cx: init::Context) -> init::LateResources { + let MEMORY2 = { + static mut MEMORY2: [u16; SEQUENCE_LEN] = [0u16; SEQUENCE_LEN]; + unsafe { &mut MEMORY2 } + }; + let MEMORY = { + static mut MEMORY: [u16; SEQUENCE_LEN] = [0u16; SEQUENCE_LEN]; + unsafe { &mut MEMORY } + }; + + rtt_init_print!(); + + rprintln!("Hello from init!"); + + let cp = cx.core; + let mut dcb = cp.DCB; + let mut dwt = cp.DWT; + + dcb.enable_trace(); + dwt.enable_cycle_counter(); + + let pac = cx.device; + + let mut rcc = pac.RCC.constrain(); + let mut flash = pac.FLASH.constrain(); + let mut pwr = pac.PWR.constrain(&mut rcc.apb1r1); + let dma_channels = pac.DMA1.split(&mut rcc.ahb1); + + // + // Initialize the clocks + // + let clocks = rcc + .cfgr + .sysclk(Hertz(80_000_000)) + .freeze(&mut flash.acr, &mut pwr); + + let mut delay = DelayCM::new(clocks); + + let mut adc = ADC::new( + pac.ADC1, + pac.ADC_COMMON, + &mut rcc.ahb2, + &mut rcc.ccipr, + &mut delay, + ); + + let mut temp_pin = adc.enable_temperature(&mut delay); + + let mut gpioc = pac.GPIOC.split(&mut rcc.ahb2); + let mut pc0 = gpioc.pc0.into_analog(&mut gpioc.moder, &mut gpioc.pupdr); + + let dma1_channel = dma_channels.1; + // let adc_buffer1_addr: u32 = MEMORY.as_ptr() as u32; + let adc_buffer1_addr = MEMORY.as_ptr(); + + adc.configure_jsequence(&mut temp_pin, Jsequence::One, SampleTime::Cycles247_5); + adc.configure_jsequence(&mut pc0, Jsequence::Two, SampleTime::Cycles247_5); + adc.configure_jsequence(&mut temp_pin, Jsequence::Three, SampleTime::Cycles640_5); + adc.configure_jsequence(&mut temp_pin, Jsequence::Four, SampleTime::Cycles12_5); + + // optional oversampling settings (added, otherwise the first sampling is wrong due to adc errata in L4) + adc.set_oversampling_ratio(7); + adc.set_oversampling_shift(8); + adc.inject_oversampling_enable(); + + // set injection trigger source to timer2 TRGO and rising edge + adc.set_inject_channel(2 as u8, 1 as u8); + + adc.start_injected_sequence(); + rprintln!("Hello from init! 2"); + + // start the timer + let mut timer = Timer::tim2(pac.TIM2, 1.hz(), clocks, &mut rcc.apb1r1); + + // Set timer output to trigger signal to ADC for start of sampling sequence + unsafe { + // get pointer of timer 2 + let tim = &(*stm32l4::stm32l4x6::TIM2::ptr()); + // config master mode selection to TRGO to Compare Pulse of timer2 + tim.cr2.modify(|_, w| w.mms().bits(3 as u8)); + tim.dier.write(|w| w.ude().set_bit()); + } + + init::LateResources { adc: adc } + } + + #[idle] + fn idle(_cx: idle::Context) -> ! { + loop { + cortex_m::asm::nop(); + } + } + + // when sequence of adc has finished, the data can be fetched from the + // injected data registers + #[task(binds = ADC1_2, resources = [adc] )] + fn adc1_irg(cx: adc1_irg::Context) { + unsafe { + let adc1 = cx.resources.adc; + + let jdr1_val = adc1.get_injected_jdr(1 as u8); + let jdr2_val = adc1.get_injected_jdr(2 as u8); + let jdr3_val = adc1.get_injected_jdr(3 as u8); + let jdr4_val = adc1.get_injected_jdr(4 as u8); + rprintln!("jdr1: {}", jdr1_val); + rprintln!("jdr2: {}", jdr2_val); + rprintln!("jdr3: {}", jdr3_val); + rprintln!("jdr4: {}", jdr4_val); + + adc1.set_jeos(); + } + } +}; diff --git a/src/adc.rs b/src/adc.rs index 9e1a5309..0295e5db 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -611,6 +611,21 @@ impl ADC { self.adc.ier.modify(|_, w| w.jeosie().clear_bit()); // end of sequence interupt disable } + pub fn get_injected_jdr(&mut self, jdrx: u8) -> u16 { + match jdrx { + 1 => self.adc.jdr1.read().jdata1().bits() as u16, + 2 => self.adc.jdr2.read().jdata2().bits() as u16, + 3 => self.adc.jdr3.read().jdata3().bits() as u16, + 4 => self.adc.jdr4.read().jdata4().bits() as u16, + _ => 0xffff as u16, + } + } + + /// clear jeos interrupt flag + pub fn set_jeos(&mut self) { + self.adc.isr.modify(|_, w| w.jeos().set_bit()); + } + /// Oversampling of adc according to datasheet of stm32g0, when oversampling is enabled /// 000: 2x /// 001: 4x diff --git a/src/timer.rs b/src/timer.rs index b8ceb47c..e5081f12 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -252,7 +252,7 @@ macro_rules! hal { let cnt = unsafe { (*$TIM::ptr()).cnt.read() }; cnt.cnt().bits() } - + // not able to select compilation for timers which support this feature // pub fn set_mms(&mut self, mms_val: u8) { // // see chapter 27.4.2 in reference manual RM0394 From c989909d1fed867a8584af10ae2ceff6c867618e Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Mon, 20 Dec 2021 20:33:56 +0100 Subject: [PATCH 03/35] some fixes to compile cleaner --- Cargo.toml | 8 ++++ examples/adc_injectedsequence.rs | 54 ++++++++-------------- src/adc.rs | 78 +++++++++++++++++--------------- 3 files changed, 67 insertions(+), 73 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 769f5b15..948e12eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -197,3 +197,11 @@ required-features = ["rt"] [[example]] name = "adc_dma" required-features = ["rt"] + +[[example]] +name = "adc_timer2_dma_seq" +required-features = ["rt", "stm32l476"] + +[[example]] +name = "adc_injectedsequence" +required-features = ["rt", "stm32l476"] diff --git a/examples/adc_injectedsequence.rs b/examples/adc_injectedsequence.rs index b274c6f8..fbf67fb0 100644 --- a/examples/adc_injectedsequence.rs +++ b/examples/adc_injectedsequence.rs @@ -3,22 +3,19 @@ extern crate stm32l4; -use cortex_m::peripheral::NVIC; use panic_rtt_target as _; use rtt_target::{rprintln, rtt_init_print}; use stm32l4xx_hal::{ - adc::{DmaMode, Jsequence, SampleTime, ADC}, + adc::{Jsequence, SampleTime, ADC}, delay::DelayCM, - dma::{dma1, RxDma, Transfer, W}, prelude::*, time::Hertz, - timer::{Event, Timer}, + timer::{Timer}, + pac::TIM2, }; use rtic::app; -const SEQUENCE_LEN: usize = 4; - #[app(device = stm32l4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] const APP: () = { // RTIC app is written in here! @@ -29,14 +26,6 @@ const APP: () = { #[init] fn init(cx: init::Context) -> init::LateResources { - let MEMORY2 = { - static mut MEMORY2: [u16; SEQUENCE_LEN] = [0u16; SEQUENCE_LEN]; - unsafe { &mut MEMORY2 } - }; - let MEMORY = { - static mut MEMORY: [u16; SEQUENCE_LEN] = [0u16; SEQUENCE_LEN]; - unsafe { &mut MEMORY } - }; rtt_init_print!(); @@ -54,7 +43,6 @@ const APP: () = { let mut rcc = pac.RCC.constrain(); let mut flash = pac.FLASH.constrain(); let mut pwr = pac.PWR.constrain(&mut rcc.apb1r1); - let dma_channels = pac.DMA1.split(&mut rcc.ahb1); // // Initialize the clocks @@ -79,10 +67,6 @@ const APP: () = { let mut gpioc = pac.GPIOC.split(&mut rcc.ahb2); let mut pc0 = gpioc.pc0.into_analog(&mut gpioc.moder, &mut gpioc.pupdr); - let dma1_channel = dma_channels.1; - // let adc_buffer1_addr: u32 = MEMORY.as_ptr() as u32; - let adc_buffer1_addr = MEMORY.as_ptr(); - adc.configure_jsequence(&mut temp_pin, Jsequence::One, SampleTime::Cycles247_5); adc.configure_jsequence(&mut pc0, Jsequence::Two, SampleTime::Cycles247_5); adc.configure_jsequence(&mut temp_pin, Jsequence::Three, SampleTime::Cycles640_5); @@ -97,15 +81,14 @@ const APP: () = { adc.set_inject_channel(2 as u8, 1 as u8); adc.start_injected_sequence(); - rprintln!("Hello from init! 2"); // start the timer - let mut timer = Timer::tim2(pac.TIM2, 1.hz(), clocks, &mut rcc.apb1r1); + let mut _timer = Timer::tim2(pac.TIM2, 1.hz(), clocks, &mut rcc.apb1r1); // Set timer output to trigger signal to ADC for start of sampling sequence unsafe { // get pointer of timer 2 - let tim = &(*stm32l4::stm32l4x6::TIM2::ptr()); + let tim = &(*TIM2::ptr()); // config master mode selection to TRGO to Compare Pulse of timer2 tim.cr2.modify(|_, w| w.mms().bits(3 as u8)); tim.dier.write(|w| w.ude().set_bit()); @@ -125,19 +108,18 @@ const APP: () = { // injected data registers #[task(binds = ADC1_2, resources = [adc] )] fn adc1_irg(cx: adc1_irg::Context) { - unsafe { - let adc1 = cx.resources.adc; - - let jdr1_val = adc1.get_injected_jdr(1 as u8); - let jdr2_val = adc1.get_injected_jdr(2 as u8); - let jdr3_val = adc1.get_injected_jdr(3 as u8); - let jdr4_val = adc1.get_injected_jdr(4 as u8); - rprintln!("jdr1: {}", jdr1_val); - rprintln!("jdr2: {}", jdr2_val); - rprintln!("jdr3: {}", jdr3_val); - rprintln!("jdr4: {}", jdr4_val); - - adc1.set_jeos(); - } + + let adc1 = cx.resources.adc; + + let jdr1_val = adc1.get_injected_jdr(1 as u8); + let jdr2_val = adc1.get_injected_jdr(2 as u8); + let jdr3_val = adc1.get_injected_jdr(3 as u8); + let jdr4_val = adc1.get_injected_jdr(4 as u8); + rprintln!("jdr1: {}", jdr1_val); + rprintln!("jdr2: {}", jdr2_val); + rprintln!("jdr3: {}", jdr3_val); + rprintln!("jdr4: {}", jdr4_val); + + adc1.set_jeos(); } }; diff --git a/src/adc.rs b/src/adc.rs index 0295e5db..a65f5f58 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -511,52 +511,56 @@ impl ADC { self.adc.cr.modify(|_, w| w.addis().set_bit()); } + /// channels for external triggers + /// TIM1_CH1 0b0000 + /// TIM1_CH2 0b0001 + /// TIM1_CH3 0b0010 + /// TIM2_CH2 0b0011 + /// TIM3_TRGO 0b0100 (not on all chips available) + /// EXTI line 11 0b0110 + /// TIM8_TRGO 0b0111 + /// TIM8_TRGO2 0b1000 + /// TIM1_TRGO 0b1001 + /// TIM1_TRGO2 0b1010 + /// TIM2_TRGO 0b1011 + /// TIM4_TRGO 0b1100 + /// TIM6_TRGO 0b1101 + /// TIM15_TRGO 0b1110 + /// TIM3_CH4 0b1111 + /// these bits are only allowed to be set, when ADC is disabled + /// set edge of injected trigger by timers + /// None 0b00 + /// Positive edge 0b01 + /// Negative edge 0b10 + /// both edges 0b11 pub fn set_external_trigger(&mut self, ch: u8, edge: u8) { - /// channels for external triggers - /// TIM1_CH1 0b0000 - /// TIM1_CH2 0b0001 - /// TIM1_CH3 0b0010 - /// TIM2_CH2 0b0011 - /// TIM3_TRGO 0b0100 (not on all chips available) - /// EXTI line 11 0b0110 - /// TIM8_TRGO 0b0111 - /// TIM8_TRGO2 0b1000 - /// TIM1_TRGO 0b1001 - /// TIM1_TRGO2 0b1010 - /// TIM2_TRGO 0b1011 - /// TIM4_TRGO 0b1100 - /// TIM6_TRGO 0b1101 - /// TIM15_TRGO 0b1110 - /// TIM3_CH4 0b1111 - /// these bits are only allowed to be set, when ADC is disabled + if self.adc.cr.read().adstart().bit_is_clear() { self.adc.cfgr.modify(|_, w| unsafe { w.extsel().bits(ch) }); - /// set edge of injected trigger by timers - /// None 0b00 - /// Positive edge 0b01 - /// Negative edge 0b10 - /// both edges 0b11 + self.adc.cfgr.modify(|_, w| unsafe { w.exten().bits(edge) }); // 1 as u8 } } + /// channels for injection Transmitter + /// TIM1_TRGO 0b0000 + /// TIM1_CH4 0b0001 + /// TIM2_TRGO 0b0010 + /// TIM2_CH1 0b0011 + /// TIM3_CH4 0b0100 (not on all chips available) + /// EXTI line 15 0b0110 + /// TIM1_TRGO2 0b1000 + /// TIM6_TRGO 0b1110 + /// TIM15_TRGO 0b1111 + /// set edge of injected trigger by timers + /// None 0b00 + /// Positive edge 0b01 + /// Negative edge 0b10 + /// both edges 0b11 pub fn set_inject_channel(&mut self, ch: u8, edge: u8) { - /// channels for injection Transmitter - /// TIM1_TRGO 0b0000 - /// TIM1_CH4 0b0001 - /// TIM2_TRGO 0b0010 - /// TIM2_CH1 0b0011 - /// TIM3_CH4 0b0100 (not on all chips available) - /// EXTI line 15 0b0110 - /// TIM1_TRGO2 0b1000 - /// TIM6_TRGO 0b1110 - /// TIM15_TRGO 0b1111 + self.adc.jsqr.modify(|_, w| unsafe { w.jextsel().bits(ch) }); - /// set edge of injected trigger by timers - /// None 0b00 - /// Positive edge 0b01 - /// Negative edge 0b10 - /// both edges 0b11 + self.adc .jsqr .modify(|_, w| unsafe { w.jexten().bits(edge) }); // 1 as u8 From e8b19465c03d8c1c3d246a76d16989abb3bb3f8d Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Tue, 21 Dec 2021 21:00:48 +0100 Subject: [PATCH 04/35] DAC added which was ported from stm32g0xx-hal --- examples/dac.rs | 67 ++++++++++++ src/dac.rs | 267 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 + 3 files changed, 336 insertions(+) create mode 100644 examples/dac.rs create mode 100644 src/dac.rs diff --git a/examples/dac.rs b/examples/dac.rs new file mode 100644 index 00000000..19bb4a3c --- /dev/null +++ b/examples/dac.rs @@ -0,0 +1,67 @@ +// #![deny(warnings)] +#![deny(unsafe_code)] +#![no_main] +#![no_std] + +// use rtt_target::{rprintln, rtt_init_print}; + + +extern crate cortex_m; +extern crate cortex_m_rt as rt; +extern crate panic_halt; +extern crate stm32l4xx_hal as hal; + +use hal::dac::GeneratorConfig; +use hal::hal::Direction; +use hal::prelude::*; +use hal::delay::Delay; +// use hal::rcc::Config; +use hal::stm32; +use rt::entry; + +use crate::hal::dac::DacExt; +use crate::hal::dac::DacOut; + +#[entry] +fn main() -> ! { + + // rtt_init_print!(); + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals"); + + let mut rcc = dp.RCC.constrain(); + let mut flash = dp.FLASH.constrain(); + let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); + let clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); + let mut delay = Delay::new(cp.SYST, clocks); + + let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); + let pa4 = gpioa.pa4.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + let pa5 = gpioa.pa5.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + let (dac0, dac1) = dp.DAC.constrain((pa4, pa5), &mut rcc.apb1r1); + + let mut dac = dac0.calibrate_buffer(&mut delay).enable(); + let mut generator = dac1.enable_generator(GeneratorConfig::noise(11)); + + let mut dir = Direction::Upcounting; + let mut val = 0; + + + loop { + + generator.trigger(); + dac.set_value(val); + match val { + 0 => dir = Direction::Upcounting, + 4095 => dir = Direction::Downcounting, + _ => (), + }; + + match dir { + Direction::Upcounting => val += 1, + Direction::Downcounting => val -= 1, + } + + } +} diff --git a/src/dac.rs b/src/dac.rs new file mode 100644 index 00000000..74276777 --- /dev/null +++ b/src/dac.rs @@ -0,0 +1,267 @@ +//! DAC + +use core::marker::PhantomData; +use core::mem::MaybeUninit; + +use crate::gpio::gpioa::{PA4, PA5}; +use crate::gpio::{Analog}; +use crate::rcc::*; +use crate::stm32::DAC; +use crate::hal::blocking::delay::DelayUs; + +pub trait DacOut { + fn set_value(&mut self, val: V); + fn get_value(&mut self) -> V; +} + +pub struct GeneratorConfig { + mode: u8, + amp: u8, +} + +impl GeneratorConfig { + pub fn triangle(amplitude: u8) -> Self { + Self { + mode: 0b10, + amp: amplitude, + } + } + + pub fn noise(seed: u8) -> Self { + Self { + mode: 0b01, + amp: seed, + } + } +} + +/// Enabled DAC (type state) +pub struct Enabled; +/// Enabled DAC without output buffer (type state) +pub struct EnabledUnbuffered; +/// Enabled DAC wave generator (type state) +pub struct WaveGenerator; +/// Disabled DAC (type state) +pub struct Disabled; + +pub trait ED {} +impl ED for Enabled {} +impl ED for EnabledUnbuffered {} +impl ED for WaveGenerator {} +impl ED for Disabled {} + +pub struct Channel1 { + _enabled: PhantomData, +} +pub struct Channel2 { + _enabled: PhantomData, +} + +/// Trait for GPIO pins that can be converted to DAC output pins +pub trait Pins { + type Output; +} + +impl Pins for PA4 { + type Output = Channel1; +} + +impl Pins for PA5 { + type Output = Channel2; +} + +impl Pins for (PA4, PA5) { + type Output = (Channel1, Channel2); +} + +// pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut Rcc::APB1R1) -> PINS::Output +pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut APB1R1) -> PINS::Output +where + PINS: Pins, +{ + DAC::enable(rcc); + DAC::reset(rcc); + + #[allow(clippy::uninit_assumed_init)] + unsafe { + MaybeUninit::uninit().assume_init() + } +} + +macro_rules! dac { + ($($CX:ident: ( + $en:ident, + $cen:ident, + $cal_flag:ident, + $trim:ident, + $mode:ident, + $dhrx:ident, + $dac_dor:ident, + $daccxdhr:ident, + $wave:ident, + $mamp:ident, + $ten:ident, + $swtrig:ident + ),)+) => { + $( + impl $CX { + pub fn enable(self) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); + dac.cr.modify(|_, w| w.$en().set_bit()); + + $CX { + _enabled: PhantomData, + } + } + + pub fn enable_unbuffered(self) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(2) }); + dac.cr.modify(|_, w| w.$en().set_bit()); + + $CX { + _enabled: PhantomData, + } + } + + pub fn enable_generator(self, config: GeneratorConfig) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); + dac.cr.modify(|_, w| unsafe { + w.$wave().bits(config.mode); + w.$ten().set_bit(); + w.$mamp().bits(config.amp); + w.$en().set_bit() + }); + + $CX { + _enabled: PhantomData, + } + } + } + + impl $CX { + /// Calibrate the DAC output buffer by performing a "User + /// trimming" operation. It is useful when the VDDA/VREF+ + /// voltage or temperature differ from the factory trimming + /// conditions. + /// + /// The calibration is only valid when the DAC channel is + /// operating with the buffer enabled. If applied in other + /// modes it has no effect. + /// + /// After the calibration operation, the DAC channel is + /// disabled. + pub fn calibrate_buffer(self, delay: &mut T) -> $CX + where + T: DelayUs, + { + let dac = unsafe { &(*DAC::ptr()) }; + 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.ccr.modify(|_, w| unsafe { w.$trim().bits(trim) }); + delay.delay_us(64_u32); + if dac.sr.read().$cal_flag().bit() { + break; + } + trim += 1; + } + dac.cr.modify(|_, w| w.$cen().clear_bit()); + + $CX { + _enabled: PhantomData, + } + } + + /// Disable the DAC channel + pub fn disable(self) -> $CX { + let dac = unsafe { &(*DAC::ptr()) }; + dac.cr.modify(|_, w| unsafe { + w.$en().clear_bit().$wave().bits(0).$ten().clear_bit() + }); + + $CX { + _enabled: PhantomData, + } + } + } + + /// DacOut implementation available in any Enabled/Disabled + /// state + 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) }); + } + + fn get_value(&mut self) -> u16 { + let dac = unsafe { &(*DAC::ptr()) }; + dac.$dac_dor.read().bits() as u16 + } + } + + /// Wave generator state implementation + impl $CX { + pub fn trigger(&mut self) { + let dac = unsafe { &(*DAC::ptr()) }; + dac.swtrigr.write(|w| { w.$swtrig().set_bit() }); + } + } + )+ + }; +} + +pub trait DacExt { + fn constrain(self, pins: PINS, rcc: &mut APB1R1) -> PINS::Output + where + PINS: Pins; +} + +impl DacExt for DAC { + fn constrain(self, pins: PINS, rcc: &mut APB1R1) -> PINS::Output + where + PINS: Pins, + { + dac(self, pins, rcc) + } +} + +dac!( + Channel1: + ( + en1, + cen1, + cal_flag1, + otrim1, + mode1, + dhr12r1, + dor1, + dacc1dhr, + wave1, + mamp1, + ten1, + swtrig1 + ), + Channel2: + ( + en2, + cen2, + cal_flag2, + otrim2, + mode2, + dhr12r2, + dor2, + dacc2dhr, + wave2, + mamp2, + ten2, + swtrig2 + ), +); diff --git a/src/lib.rs b/src/lib.rs index 87ea2daf..f62301bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,6 +128,8 @@ pub mod adc; pub mod can; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod crc; +#[cfg(not(any(feature = "stm32l412", feature = "stm32l4r9", feature = "stm32l4s9",)))] +pub mod dac; pub mod datetime; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod delay; From f9283ed5ba88beddd2b9436a1cee38df2e21f415 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Tue, 28 Dec 2021 09:52:13 +0100 Subject: [PATCH 05/35] restrict dac for stm32f476, stm32f486, stm32f496, stm32f4a6. Run cargo fmt --- examples/adc_dma_seq.rs | 266 +++++++++++++++++++++++++++++++ examples/adc_injectedsequence.rs | 6 +- examples/dac.rs | 11 +- src/adc.rs | 6 +- src/dac.rs | 4 +- src/lib.rs | 7 +- 6 files changed, 283 insertions(+), 17 deletions(-) create mode 100644 examples/adc_dma_seq.rs diff --git a/examples/adc_dma_seq.rs b/examples/adc_dma_seq.rs new file mode 100644 index 00000000..c75d5108 --- /dev/null +++ b/examples/adc_dma_seq.rs @@ -0,0 +1,266 @@ +#![no_main] +#![no_std] + +use panic_rtt_target as _; +use rtt_target::{rprintln, rtt_init_print}; +use stm32l4xx_hal::{ + adc::{DmaMode, SampleTime, Sequence, ADC}, + delay::DelayCM, + dma::{dma1, RxDma, Transfer, W}, + prelude::*, + time::Hertz, +}; + +use rtic::app; + +const SEQUENCE_LEN: usize = 4; + +#[app(device = stm32l4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] +const APP: () = { + // RTIC app is written in here! + + struct Resources { + transfer: Option>>, + } + + #[init] + fn init(cx: init::Context) -> init::LateResources { + let MEMORY = { + static mut MEMORY: [u16; SEQUENCE_LEN] = [0u16; SEQUENCE_LEN]; + unsafe { &mut MEMORY } + }; + + rtt_init_print!(); + + rprintln!("Hello from init!"); + + let cp = cx.core; + let mut dcb = cp.DCB; + let mut dwt = cp.DWT; + + dcb.enable_trace(); + dwt.enable_cycle_counter(); + + let pac = cx.device; + + let mut rcc = pac.RCC.constrain(); + let mut flash = pac.FLASH.constrain(); + let mut pwr = pac.PWR.constrain(&mut rcc.apb1r1); + let dma_channels = pac.DMA1.split(&mut rcc.ahb1); + + // + // Initialize the clocks + // + let clocks = rcc + .cfgr + .sysclk(Hertz(80_000_000)) + .freeze(&mut flash.acr, &mut pwr); + + let mut delay = DelayCM::new(clocks); + + let mut adc = ADC::new( + pac.ADC1, + pac.ADC_COMMON, + &mut rcc.ahb2, + &mut rcc.ccipr, + &mut delay, + ); + + let mut temp_pin = adc.enable_temperature(&mut delay); + + let dma1_channel = dma_channels.1; + let adc_buffer1_addr = MEMORY.as_ptr(); + let mut gpioc = pac.GPIOC.split(&mut rcc.ahb2); + let mut pc0 = gpioc.pc0.into_analog(&mut gpioc.moder, &mut gpioc.pupdr); + + adc.configure_sequence(&mut temp_pin, Sequence::One, SampleTime::Cycles12_5); + adc.configure_sequence(&mut temp_pin, Sequence::Two, SampleTime::Cycles247_5); + adc.configure_sequence(&mut temp_pin, Sequence::Three, SampleTime::Cycles640_5); + adc.configure_sequence(&mut pc0, Sequence::Four, SampleTime::Cycles640_5); + + // Heapless boxes also work very well as buffers for DMA transfers + let transfer = Transfer::from_adc(adc, dma1_channel, MEMORY, DmaMode::Oneshot, true); + + unsafe { + let adc = &(*stm32l4::stm32l4x6::ADC1::ptr()); + let jdr1_val = adc.jdr1.read().jdata1().bits() as u16; + let jdr2_val = adc.jdr2.read().jdata2().bits() as u16; + let jdr3_val = adc.jdr3.read().jdata3().bits() as u16; + let jdr4_val = adc.jdr4.read().jdata4().bits() as u16; + let sqr1_val = adc.sqr1.read().l().bits(); + let enabled = adc.cr.read().aden().bit_is_set(); + let inj_end = adc.isr.read().jeoc().bit_is_set(); // injecte adc conversion finished + let inj_seq_end = adc.isr.read().jeos().bit_is_set(); // injecte sequence conversion finished + rprintln!("jdr1: {}", jdr1_val); + rprintln!("jdr2: {}", jdr2_val); + rprintln!("jdr3: {}", jdr3_val); + rprintln!("jdr4: {}", jdr4_val); + rprintln!("inj_end: {}", inj_end); + rprintln!("inj_seq_end: {}", inj_seq_end); + adc.isr.modify(|_, w| w.jeos().set_bit()); + rprintln!("DMA measurements_pointer at: {:?}", *adc_buffer1_addr); + rprintln!("DMA measurements_pointer at: {:?}", adc_buffer1_addr); + rprintln!("DMA measurements_pointer at: {:?}", adc_buffer1_addr as u32); + + let dma1 = &(*stm32l4::stm32l4x6::DMA1::ptr()); + rprintln!( + "dma1.cselr.read().c1s(): {}", + dma1.cselr.read().c1s().bits() + ); + rprintln!( + "dma1.ccr1.read().pl(): {}", + dma1.ccr1.read().pl().bits() + ); + rprintln!( + "dma1.ccr1.read().msize(): {}", + dma1.ccr1.read().msize().bits() + ); + rprintln!( + "ddma1.ccr1.read().psize(): {}", + dma1.ccr1.read().psize().bits() + ); + rprintln!( + "dma1.ccr1.read().dir(): {}", + dma1.ccr1.read().dir().bits() + ); + rprintln!( + "dma1.ccr1.read().minc(): {}", + dma1.ccr1.read().minc().bits() + ); + rprintln!( + "dma1.ccr1.read().pinc(): {}", + dma1.ccr1.read().pinc().bits() + ); + rprintln!( + "dma1.ccr1.read().en(): {}", + dma1.ccr1.read().en().bits() + ); + rprintln!( + "dma1.ccr1.read().tcie(): {}", + dma1.ccr1.read().tcie().bits() + ); + rprintln!( + "dma1.ccr1.read().htie(): {}", + dma1.ccr1.read().htie().bits() + ); + rprintln!( + "dma1.ccr1.read().teie(): {}", + dma1.ccr1.read().teie().bits() + ); + + rprintln!( + "dma1.isr.read().gif1(): {}", + dma1.isr.read().gif1().bits() + ); + rprintln!( + "dma1.isr.read().tcif1(): {}", + dma1.isr.read().tcif1().bits() + ); + rprintln!( + "dma1.isr.read().htif1(): {}", + dma1.isr.read().htif1().bits() + ); + rprintln!( + "dma1.isr.read().teif1(): {}", + dma1.isr.read().teif1().bits() + ); + rprintln!( + "dma1.cdntr1.read().ndt(): {}", + dma1.cndtr1.read().ndt().bits() + ); + + // dma1.ccr1.modify(|_, w| w.en().clear_bit()); + // dma1.ccr1.modify(|_, w| w.tcie().set_bit()); + // dma1.ccr1.modify(|_, w| w.teie().set_bit()); + + rprintln!( + "adc.cfgr.read().dmaen(): {}", + adc.cfgr.read().dmaen().bits() + ); + rprintln!( + "adc.cfgr.read().dmacfg(): {}", + adc.cfgr.read().dmacfg().bits() + ); + // rprintln!("adc.cfgr.read().dfsdmcfg(): {}", adc.cfgr.read().dfsdmcfg().bits()); + rprintln!( + "adc.isr.read().ovr(): {}", + adc.isr.read().ovr().bits() + ); + + rprintln!( + "adc.ier.read().ovrie(): {}", + adc.ier.read().ovrie().bits() + ); + rprintln!( + "adc.ier.read().adrdyie(): {}", + adc.ier.read().adrdyie().bits() + ); + rprintln!( + "adc.ier.read().eosmpie(): {}", + adc.ier.read().eosmpie().bits() + ); + rprintln!( + "adc.ier.read().eocie(): {}", + adc.ier.read().eocie().bits() + ); + rprintln!( + "adc.ier.read().eosie(): {}", + adc.ier.read().eosie().bits() + ); + rprintln!( + "adc.ier.read().eocie(): {}", + adc.ier.read().eocie().bits() + ); + rprintln!( + "adc.ier.read().jeocie(): {}", + adc.ier.read().jeocie().bits() + ); + rprintln!( + "adc.ier.read().jeosie(): {}", + adc.ier.read().jeosie().bits() + ); + rprintln!( + "adc.ier.read().awd1ie(): {}", + adc.ier.read().awd1ie().bits() + ); + rprintln!( + "adc.ier.read().awd2ie(): {}", + adc.ier.read().awd2ie().bits() + ); + rprintln!( + "adc.ier.read().awd3ie(): {}", + adc.ier.read().awd3ie().bits() + ); + rprintln!( + "adc.ier.read().jqovfie(): {}", + adc.ier.read().jqovfie().bits() + ); + // dma1.ccr1.modify(|_, w| w.en().set_bit()); + } + init::LateResources { + transfer: Some(transfer), + } + } + + #[idle] + fn idle(_cx: idle::Context) -> ! { + loop { + cortex_m::asm::nop(); + } + } + + #[task(binds = DMA1_CH1, resources = [transfer])] + fn dma1_interrupt(cx: dma1_interrupt::Context) { + let transfer = cx.resources.transfer; + if let Some(transfer_val) = transfer.take() { + let (buffer, rx_dma) = transfer_val.wait(); + rprintln!("DMA measurements: {:?}", buffer); + *transfer = Some(Transfer::from_adc_dma( + rx_dma, + buffer, + DmaMode::Oneshot, + true, + )); + } + } +}; diff --git a/examples/adc_injectedsequence.rs b/examples/adc_injectedsequence.rs index fbf67fb0..0ae31400 100644 --- a/examples/adc_injectedsequence.rs +++ b/examples/adc_injectedsequence.rs @@ -8,10 +8,10 @@ use rtt_target::{rprintln, rtt_init_print}; use stm32l4xx_hal::{ adc::{Jsequence, SampleTime, ADC}, delay::DelayCM, + pac::TIM2, prelude::*, time::Hertz, - timer::{Timer}, - pac::TIM2, + timer::Timer, }; use rtic::app; @@ -26,7 +26,6 @@ const APP: () = { #[init] fn init(cx: init::Context) -> init::LateResources { - rtt_init_print!(); rprintln!("Hello from init!"); @@ -108,7 +107,6 @@ const APP: () = { // injected data registers #[task(binds = ADC1_2, resources = [adc] )] fn adc1_irg(cx: adc1_irg::Context) { - let adc1 = cx.resources.adc; let jdr1_val = adc1.get_injected_jdr(1 as u8); diff --git a/examples/dac.rs b/examples/dac.rs index 19bb4a3c..0756301b 100644 --- a/examples/dac.rs +++ b/examples/dac.rs @@ -1,10 +1,12 @@ -// #![deny(warnings)] +#![deny(warnings)] #![deny(unsafe_code)] #![no_main] #![no_std] // use rtt_target::{rprintln, rtt_init_print}; +// currently only works with these devices +// #[cfg(any(feature = "stm32l476", feature = "stm32l486", feature = "stm32l496", feature = "stm32l4a6"))] extern crate cortex_m; extern crate cortex_m_rt as rt; @@ -12,9 +14,9 @@ extern crate panic_halt; extern crate stm32l4xx_hal as hal; use hal::dac::GeneratorConfig; +use hal::delay::Delay; use hal::hal::Direction; use hal::prelude::*; -use hal::delay::Delay; // use hal::rcc::Config; use hal::stm32; use rt::entry; @@ -24,7 +26,6 @@ use crate::hal::dac::DacOut; #[entry] fn main() -> ! { - // rtt_init_print!(); let dp = stm32::Peripherals::take().expect("cannot take peripherals"); @@ -39,6 +40,7 @@ fn main() -> ! { let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); let pa4 = gpioa.pa4.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); let pa5 = gpioa.pa5.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + let (dac0, dac1) = dp.DAC.constrain((pa4, pa5), &mut rcc.apb1r1); let mut dac = dac0.calibrate_buffer(&mut delay).enable(); @@ -46,10 +48,8 @@ fn main() -> ! { let mut dir = Direction::Upcounting; let mut val = 0; - loop { - generator.trigger(); dac.set_value(val); match val { @@ -62,6 +62,5 @@ fn main() -> ! { Direction::Upcounting => val += 1, Direction::Downcounting => val -= 1, } - } } diff --git a/src/adc.rs b/src/adc.rs index a65f5f58..d451a7dd 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -534,10 +534,9 @@ impl ADC { /// Negative edge 0b10 /// both edges 0b11 pub fn set_external_trigger(&mut self, ch: u8, edge: u8) { - if self.adc.cr.read().adstart().bit_is_clear() { self.adc.cfgr.modify(|_, w| unsafe { w.extsel().bits(ch) }); - + self.adc.cfgr.modify(|_, w| unsafe { w.exten().bits(edge) }); // 1 as u8 } } @@ -558,9 +557,8 @@ impl ADC { /// Negative edge 0b10 /// both edges 0b11 pub fn set_inject_channel(&mut self, ch: u8, edge: u8) { - self.adc.jsqr.modify(|_, w| unsafe { w.jextsel().bits(ch) }); - + self.adc .jsqr .modify(|_, w| unsafe { w.jexten().bits(edge) }); // 1 as u8 diff --git a/src/dac.rs b/src/dac.rs index 74276777..b53a20c1 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -4,10 +4,10 @@ use core::marker::PhantomData; use core::mem::MaybeUninit; use crate::gpio::gpioa::{PA4, PA5}; -use crate::gpio::{Analog}; +use crate::gpio::Analog; +use crate::hal::blocking::delay::DelayUs; use crate::rcc::*; use crate::stm32::DAC; -use crate::hal::blocking::delay::DelayUs; pub trait DacOut { fn set_value(&mut self, val: V); diff --git a/src/lib.rs b/src/lib.rs index f62301bd..56801dc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,7 +128,12 @@ pub mod adc; pub mod can; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod crc; -#[cfg(not(any(feature = "stm32l412", feature = "stm32l4r9", feature = "stm32l4s9",)))] +#[cfg(any( + feature = "stm32l476", + feature = "stm32l486", + feature = "stm32l496", + feature = "stm32l4a6" +))] pub mod dac; pub mod datetime; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] From af4e9a5c9581cda25bfd98ba3cc35a4459a21138 Mon Sep 17 00:00:00 2001 From: oldsheep68 <83419094+oldsheep68@users.noreply.github.com> Date: Tue, 4 Jan 2022 19:29:13 +0100 Subject: [PATCH 06/35] Create myAction.yaml --- .github/workflows/myAction.yaml | 84 +++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 .github/workflows/myAction.yaml diff --git a/.github/workflows/myAction.yaml b/.github/workflows/myAction.yaml new file mode 100644 index 00000000..ba1341a0 --- /dev/null +++ b/.github/workflows/myAction.yaml @@ -0,0 +1,84 @@ +on: + push: + branches: [master] + pull_request: + +name: Continuous integration + +jobs: + ci: + runs-on: ubuntu-latest + strategy: + matrix: # All permutations of {rust, mcu} + rust: + - stable + mcu: + - stm32l412 + - stm32l422 + - stm32l431 + - stm32l432 + - stm32l433 + - stm32l442 + - stm32l443 + - stm32l451 + - stm32l452 + - stm32l462 + - stm32l471 + - stm32l475 + - stm32l476 + - stm32l486 + - stm32l496 + - stm32l4a6 + #- stm32l4r9 + #- stm32l4s9 + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: thumbv7em-none-eabihf + override: true + - name: build + uses: actions-rs/cargo@v1 + with: + use-cross: true + command: build + args: --verbose --release --examples --target thumbv7em-none-eabihf --features rt,unproven,${{ matrix.mcu }} + - name: test + uses: actions-rs/cargo@v1 + with: + command: test + args: --lib --target x86_64-unknown-linux-gnu --features rt,unproven,${{ matrix.mcu }} + + ci-r9: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + mcu: + - stm32l4r9 + - stm32l4s9 + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: thumbv7em-none-eabihf + override: true + - name: build + uses: actions-rs/cargo@v1 + with: + use-cross: true + command: build + args: --verbose --release --target thumbv7em-none-eabihf --features rt,unproven,${{ matrix.mcu }} + # note that examples were not built + - name: test + uses: actions-rs/cargo@v1 + with: + command: test + args: --lib --target x86_64-unknown-linux-gnu --features rt,unproven,${{ matrix.mcu }} From 7919003e9e606e8473c7757b00d08bf62acfef99 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Tue, 4 Jan 2022 19:51:26 +0100 Subject: [PATCH 07/35] testoutput removed --- examples/adc_dma_seq.rs | 155 +--------------------------------------- 1 file changed, 1 insertion(+), 154 deletions(-) diff --git a/examples/adc_dma_seq.rs b/examples/adc_dma_seq.rs index c75d5108..1d6994b5 100644 --- a/examples/adc_dma_seq.rs +++ b/examples/adc_dma_seq.rs @@ -81,160 +81,7 @@ const APP: () = { // Heapless boxes also work very well as buffers for DMA transfers let transfer = Transfer::from_adc(adc, dma1_channel, MEMORY, DmaMode::Oneshot, true); - unsafe { - let adc = &(*stm32l4::stm32l4x6::ADC1::ptr()); - let jdr1_val = adc.jdr1.read().jdata1().bits() as u16; - let jdr2_val = adc.jdr2.read().jdata2().bits() as u16; - let jdr3_val = adc.jdr3.read().jdata3().bits() as u16; - let jdr4_val = adc.jdr4.read().jdata4().bits() as u16; - let sqr1_val = adc.sqr1.read().l().bits(); - let enabled = adc.cr.read().aden().bit_is_set(); - let inj_end = adc.isr.read().jeoc().bit_is_set(); // injecte adc conversion finished - let inj_seq_end = adc.isr.read().jeos().bit_is_set(); // injecte sequence conversion finished - rprintln!("jdr1: {}", jdr1_val); - rprintln!("jdr2: {}", jdr2_val); - rprintln!("jdr3: {}", jdr3_val); - rprintln!("jdr4: {}", jdr4_val); - rprintln!("inj_end: {}", inj_end); - rprintln!("inj_seq_end: {}", inj_seq_end); - adc.isr.modify(|_, w| w.jeos().set_bit()); - rprintln!("DMA measurements_pointer at: {:?}", *adc_buffer1_addr); - rprintln!("DMA measurements_pointer at: {:?}", adc_buffer1_addr); - rprintln!("DMA measurements_pointer at: {:?}", adc_buffer1_addr as u32); - - let dma1 = &(*stm32l4::stm32l4x6::DMA1::ptr()); - rprintln!( - "dma1.cselr.read().c1s(): {}", - dma1.cselr.read().c1s().bits() - ); - rprintln!( - "dma1.ccr1.read().pl(): {}", - dma1.ccr1.read().pl().bits() - ); - rprintln!( - "dma1.ccr1.read().msize(): {}", - dma1.ccr1.read().msize().bits() - ); - rprintln!( - "ddma1.ccr1.read().psize(): {}", - dma1.ccr1.read().psize().bits() - ); - rprintln!( - "dma1.ccr1.read().dir(): {}", - dma1.ccr1.read().dir().bits() - ); - rprintln!( - "dma1.ccr1.read().minc(): {}", - dma1.ccr1.read().minc().bits() - ); - rprintln!( - "dma1.ccr1.read().pinc(): {}", - dma1.ccr1.read().pinc().bits() - ); - rprintln!( - "dma1.ccr1.read().en(): {}", - dma1.ccr1.read().en().bits() - ); - rprintln!( - "dma1.ccr1.read().tcie(): {}", - dma1.ccr1.read().tcie().bits() - ); - rprintln!( - "dma1.ccr1.read().htie(): {}", - dma1.ccr1.read().htie().bits() - ); - rprintln!( - "dma1.ccr1.read().teie(): {}", - dma1.ccr1.read().teie().bits() - ); - - rprintln!( - "dma1.isr.read().gif1(): {}", - dma1.isr.read().gif1().bits() - ); - rprintln!( - "dma1.isr.read().tcif1(): {}", - dma1.isr.read().tcif1().bits() - ); - rprintln!( - "dma1.isr.read().htif1(): {}", - dma1.isr.read().htif1().bits() - ); - rprintln!( - "dma1.isr.read().teif1(): {}", - dma1.isr.read().teif1().bits() - ); - rprintln!( - "dma1.cdntr1.read().ndt(): {}", - dma1.cndtr1.read().ndt().bits() - ); - - // dma1.ccr1.modify(|_, w| w.en().clear_bit()); - // dma1.ccr1.modify(|_, w| w.tcie().set_bit()); - // dma1.ccr1.modify(|_, w| w.teie().set_bit()); - - rprintln!( - "adc.cfgr.read().dmaen(): {}", - adc.cfgr.read().dmaen().bits() - ); - rprintln!( - "adc.cfgr.read().dmacfg(): {}", - adc.cfgr.read().dmacfg().bits() - ); - // rprintln!("adc.cfgr.read().dfsdmcfg(): {}", adc.cfgr.read().dfsdmcfg().bits()); - rprintln!( - "adc.isr.read().ovr(): {}", - adc.isr.read().ovr().bits() - ); - - rprintln!( - "adc.ier.read().ovrie(): {}", - adc.ier.read().ovrie().bits() - ); - rprintln!( - "adc.ier.read().adrdyie(): {}", - adc.ier.read().adrdyie().bits() - ); - rprintln!( - "adc.ier.read().eosmpie(): {}", - adc.ier.read().eosmpie().bits() - ); - rprintln!( - "adc.ier.read().eocie(): {}", - adc.ier.read().eocie().bits() - ); - rprintln!( - "adc.ier.read().eosie(): {}", - adc.ier.read().eosie().bits() - ); - rprintln!( - "adc.ier.read().eocie(): {}", - adc.ier.read().eocie().bits() - ); - rprintln!( - "adc.ier.read().jeocie(): {}", - adc.ier.read().jeocie().bits() - ); - rprintln!( - "adc.ier.read().jeosie(): {}", - adc.ier.read().jeosie().bits() - ); - rprintln!( - "adc.ier.read().awd1ie(): {}", - adc.ier.read().awd1ie().bits() - ); - rprintln!( - "adc.ier.read().awd2ie(): {}", - adc.ier.read().awd2ie().bits() - ); - rprintln!( - "adc.ier.read().awd3ie(): {}", - adc.ier.read().awd3ie().bits() - ); - rprintln!( - "adc.ier.read().jqovfie(): {}", - adc.ier.read().jqovfie().bits() - ); + // dma1.ccr1.modify(|_, w| w.en().set_bit()); } init::LateResources { From e298d5f57b3f079f9c838dad33eaa64969de0112 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Tue, 4 Jan 2022 19:59:45 +0100 Subject: [PATCH 08/35] bracket error corrected --- examples/adc_dma_seq.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/adc_dma_seq.rs b/examples/adc_dma_seq.rs index 1d6994b5..b272f05e 100644 --- a/examples/adc_dma_seq.rs +++ b/examples/adc_dma_seq.rs @@ -81,9 +81,6 @@ const APP: () = { // Heapless boxes also work very well as buffers for DMA transfers let transfer = Transfer::from_adc(adc, dma1_channel, MEMORY, DmaMode::Oneshot, true); - - // dma1.ccr1.modify(|_, w| w.en().set_bit()); - } init::LateResources { transfer: Some(transfer), } From 0f576dadeb67e494fb42fda72397d5026569d9cd Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Tue, 4 Jan 2022 20:06:43 +0100 Subject: [PATCH 09/35] remove warning --- examples/adc_dma_seq.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/adc_dma_seq.rs b/examples/adc_dma_seq.rs index b272f05e..dc222bfd 100644 --- a/examples/adc_dma_seq.rs +++ b/examples/adc_dma_seq.rs @@ -69,7 +69,6 @@ const APP: () = { let mut temp_pin = adc.enable_temperature(&mut delay); let dma1_channel = dma_channels.1; - let adc_buffer1_addr = MEMORY.as_ptr(); let mut gpioc = pac.GPIOC.split(&mut rcc.ahb2); let mut pc0 = gpioc.pc0.into_analog(&mut gpioc.moder, &mut gpioc.pupdr); From 2b53e262690078c4a1a7b707c9749ce5599b5326 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Tue, 4 Jan 2022 21:01:26 +0100 Subject: [PATCH 10/35] some clippy errors in adc removed --- src/adc.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/adc.rs b/src/adc.rs index d451a7dd..1c65cd51 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -92,9 +92,10 @@ impl From for Sequence { } } -impl Into for Sequence { - fn into(self) -> u8 { - match self { + +impl From for u8 { + fn from(i: Sequence) -> u8 { + match i { Sequence::One => 0, Sequence::Two => 1, Sequence::Three => 2, @@ -135,9 +136,10 @@ impl From for Jsequence { } } -impl Into for Jsequence { - fn into(self) -> u8 { - match self { + +impl From for u8 { + fn from(i: Jsequence) -> u8 { + match i { Jsequence::One => 0, Jsequence::Two => 1, Jsequence::Three => 2, @@ -305,7 +307,7 @@ impl ADC { /// Convert a measurement to millivolts pub fn to_millivolts(&self, sample: u16) -> u16 { - ((u32::from(sample) * self.calibrated_vdda) / self.resolution.to_max_count()) as u16 + ((u32::from(sample) * self.calibrated_vdda) / self.resolution.tomax_count()) as u16 } /// Convert a raw sample from the `Temperature` to deg C @@ -619,7 +621,7 @@ impl ADC { 2 => self.adc.jdr2.read().jdata2().bits() as u16, 3 => self.adc.jdr3.read().jdata3().bits() as u16, 4 => self.adc.jdr4.read().jdata4().bits() as u16, - _ => 0xffff as u16, + _ => 0xffff_u16, } } @@ -844,7 +846,7 @@ impl Default for Resolution { } impl Resolution { - fn to_max_count(&self) -> u32 { + fn tomax_count(&self) -> u32 { match self { Resolution::Bits12 => (1 << 12) - 1, Resolution::Bits10 => (1 << 10) - 1, From af004802aeb3c441ddb1e2ae3bc87613445531b4 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Tue, 4 Jan 2022 21:09:34 +0100 Subject: [PATCH 11/35] removed clippy errors in adc_xxx examples --- examples/adc_injectedsequence.rs | 14 +++++++------- examples/adc_timer2_dma_seq.rs | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/adc_injectedsequence.rs b/examples/adc_injectedsequence.rs index 0ae31400..244167cb 100644 --- a/examples/adc_injectedsequence.rs +++ b/examples/adc_injectedsequence.rs @@ -77,7 +77,7 @@ const APP: () = { adc.inject_oversampling_enable(); // set injection trigger source to timer2 TRGO and rising edge - adc.set_inject_channel(2 as u8, 1 as u8); + adc.set_inject_channel(2_u8, 1_u8); adc.start_injected_sequence(); @@ -89,11 +89,11 @@ const APP: () = { // get pointer of timer 2 let tim = &(*TIM2::ptr()); // config master mode selection to TRGO to Compare Pulse of timer2 - tim.cr2.modify(|_, w| w.mms().bits(3 as u8)); + tim.cr2.modify(|_, w| w.mms().bits(3_u8)); tim.dier.write(|w| w.ude().set_bit()); } - init::LateResources { adc: adc } + init::LateResources { adc } } #[idle] @@ -109,10 +109,10 @@ const APP: () = { fn adc1_irg(cx: adc1_irg::Context) { let adc1 = cx.resources.adc; - let jdr1_val = adc1.get_injected_jdr(1 as u8); - let jdr2_val = adc1.get_injected_jdr(2 as u8); - let jdr3_val = adc1.get_injected_jdr(3 as u8); - let jdr4_val = adc1.get_injected_jdr(4 as u8); + let jdr1_val = adc1.get_injected_jdr(1_u8); + let jdr2_val = adc1.get_injected_jdr(2_u8); + let jdr3_val = adc1.get_injected_jdr(3_u8); + let jdr4_val = adc1.get_injected_jdr(4_u8); rprintln!("jdr1: {}", jdr1_val); rprintln!("jdr2: {}", jdr2_val); rprintln!("jdr3: {}", jdr3_val); diff --git a/examples/adc_timer2_dma_seq.rs b/examples/adc_timer2_dma_seq.rs index 898ef155..61dd46db 100644 --- a/examples/adc_timer2_dma_seq.rs +++ b/examples/adc_timer2_dma_seq.rs @@ -84,7 +84,7 @@ const APP: () = { adc.set_oversampling_shift(8); adc.oversampling_enable(); - adc.set_external_trigger(0b1011, 1 as u8); // Timer2_TRGO + adc.set_external_trigger(0b1011, 1_u8); // Timer2_TRGO // Heapless boxes also work very well as buffers for DMA transfers let transfer = Transfer::from_adc(adc, dma1_channel, MEMORY, DmaMode::ExtTrigger, true); @@ -95,7 +95,7 @@ const APP: () = { // get pointer of timer 2 let tim = &(*stm32l4::stm32l4x6::TIM2::ptr()); // config master mode selection to TRGO to Compare Pulse of timer2 - tim.cr2.modify(|_, w| w.mms().bits(3 as u8)); + tim.cr2.modify(|_, w| w.mms().bits(3_u8)); tim.dier.write(|w| w.ude().set_bit()); } From 4fd89a68151a47f46ab878a0558b1893445348f1 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Tue, 4 Jan 2022 21:50:12 +0100 Subject: [PATCH 12/35] changed cfg(any and cfg(not(any for dac selection --- examples/dac.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/examples/dac.rs b/examples/dac.rs index 0756301b..7ca9d21c 100644 --- a/examples/dac.rs +++ b/examples/dac.rs @@ -1,4 +1,4 @@ -#![deny(warnings)] +// #![deny(warnings)] #![deny(unsafe_code)] #![no_main] #![no_std] @@ -13,7 +13,7 @@ extern crate cortex_m_rt as rt; extern crate panic_halt; extern crate stm32l4xx_hal as hal; -use hal::dac::GeneratorConfig; +// use hal::dac::GeneratorConfig; use hal::delay::Delay; use hal::hal::Direction; use hal::prelude::*; @@ -41,16 +41,32 @@ fn main() -> ! { let pa4 = gpioa.pa4.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); let pa5 = gpioa.pa5.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); - let (dac0, dac1) = dp.DAC.constrain((pa4, pa5), &mut rcc.apb1r1); + #[cfg(any( + feature = "stm32l476", + feature = "stm32l486", + feature = "stm32l496", + feature = "stm32l4a6" + ))] + let (dac0, _dac1) = dp.DAC.constrain((pa4, pa5), &mut rcc.apb1r1); + + #[cfg(not(any( + // feature = "stm32l412", + feature = "stm32l476", + feature = "stm32l486", + feature = "stm32l496", + feature = "stm32l4a6" + )))] + let dac0 = dp.DAC1.constrain(pa4, &mut rcc.apb1r1); let mut dac = dac0.calibrate_buffer(&mut delay).enable(); - let mut generator = dac1.enable_generator(GeneratorConfig::noise(11)); + + // let mut generator = dac1.enable_generator(GeneratorConfig::noise(11)); let mut dir = Direction::Upcounting; let mut val = 0; loop { - generator.trigger(); + // generator.trigger(); dac.set_value(val); match val { 0 => dir = Direction::Upcounting, From 455e8ca027b440d1e9653a8ab8b612fc70912173 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Wed, 5 Jan 2022 07:48:52 +0100 Subject: [PATCH 13/35] restrict dac for example dac to stm32l476 --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 948e12eb..e3dde1a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -205,3 +205,7 @@ required-features = ["rt", "stm32l476"] [[example]] name = "adc_injectedsequence" required-features = ["rt", "stm32l476"] + +[[example]] +name = "dac" +required-features = ["rt", "stm32l476"] From e0e3b77c17aee2b4896116046620d6a27ee05c5a Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Wed, 5 Jan 2022 07:50:05 +0100 Subject: [PATCH 14/35] remove copy of github action --- .github/workflows/myAction.yaml | 84 --------------------------------- 1 file changed, 84 deletions(-) delete mode 100644 .github/workflows/myAction.yaml diff --git a/.github/workflows/myAction.yaml b/.github/workflows/myAction.yaml deleted file mode 100644 index ba1341a0..00000000 --- a/.github/workflows/myAction.yaml +++ /dev/null @@ -1,84 +0,0 @@ -on: - push: - branches: [master] - pull_request: - -name: Continuous integration - -jobs: - ci: - runs-on: ubuntu-latest - strategy: - matrix: # All permutations of {rust, mcu} - rust: - - stable - mcu: - - stm32l412 - - stm32l422 - - stm32l431 - - stm32l432 - - stm32l433 - - stm32l442 - - stm32l443 - - stm32l451 - - stm32l452 - - stm32l462 - - stm32l471 - - stm32l475 - - stm32l476 - - stm32l486 - - stm32l496 - - stm32l4a6 - #- stm32l4r9 - #- stm32l4s9 - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - target: thumbv7em-none-eabihf - override: true - - name: build - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: build - args: --verbose --release --examples --target thumbv7em-none-eabihf --features rt,unproven,${{ matrix.mcu }} - - name: test - uses: actions-rs/cargo@v1 - with: - command: test - args: --lib --target x86_64-unknown-linux-gnu --features rt,unproven,${{ matrix.mcu }} - - ci-r9: - runs-on: ubuntu-latest - strategy: - matrix: - rust: - - stable - mcu: - - stm32l4r9 - - stm32l4s9 - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - target: thumbv7em-none-eabihf - override: true - - name: build - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: build - args: --verbose --release --target thumbv7em-none-eabihf --features rt,unproven,${{ matrix.mcu }} - # note that examples were not built - - name: test - uses: actions-rs/cargo@v1 - with: - command: test - args: --lib --target x86_64-unknown-linux-gnu --features rt,unproven,${{ matrix.mcu }} From 71ef6c3b7110539d527632174cc6d85af921d0cb Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Wed, 5 Jan 2022 17:14:40 +0100 Subject: [PATCH 15/35] revert back to into trait --- src/adc.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/adc.rs b/src/adc.rs index 1c65cd51..2e7f3dba 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -92,10 +92,9 @@ impl From for Sequence { } } - -impl From for u8 { - fn from(i: Sequence) -> u8 { - match i { +impl Into for Sequence { + fn into(self) -> u8 { + match self { Sequence::One => 0, Sequence::Two => 1, Sequence::Three => 2, @@ -136,10 +135,9 @@ impl From for Jsequence { } } - -impl From for u8 { - fn from(i: Jsequence) -> u8 { - match i { +impl Into for Jsequence { + fn into(self) -> u8 { + match self { Jsequence::One => 0, Jsequence::Two => 1, Jsequence::Three => 2, From 3bed073e07f3c8ee39bf6ad494a1e9d1000ae92a Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Wed, 19 Jan 2022 21:38:11 +0100 Subject: [PATCH 16/35] opamp, work in progress, only comiling code, not tested yet. missing funktion to set in self calibration mode missing delay in calibration function --- examples/opamp_ext.rs | 48 +++++++ examples/opamp_pga.rs | 45 +++++++ src/lib.rs | 2 + src/opamp.rs | 286 ++++++++++++++++++++++++++++++++++++++++++ src/traits/mod.rs | 1 + src/traits/opamp.rs | 105 ++++++++++++++++ 6 files changed, 487 insertions(+) create mode 100644 examples/opamp_ext.rs create mode 100644 examples/opamp_pga.rs create mode 100644 src/opamp.rs create mode 100644 src/traits/opamp.rs diff --git a/examples/opamp_ext.rs b/examples/opamp_ext.rs new file mode 100644 index 00000000..aa0fa33b --- /dev/null +++ b/examples/opamp_ext.rs @@ -0,0 +1,48 @@ +#![deny(unsafe_code)] +// #![deny(warnings)] +#![no_main] +#![no_std] + +extern crate panic_halt; + +// use cortex_m::asm; +use cortex_m_rt::entry; +// use rtt_target::{rprint, rprintln}; +use stm32l4xx_hal::{opamp::*, prelude::*, pac}; + +use stm32l4xx_hal::traits::opamp::*; + +#[entry] +fn main() -> ! { + + // rtt_target::rtt_init_print!(); + // rprint!("Initializing..."); + + let _cp = pac::CorePeripherals::take().unwrap(); + let dp = pac::Peripherals::take().unwrap(); + + let mut rcc = dp.RCC.constrain(); + let mut flash = dp.FLASH.constrain(); + let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); + + let _clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); + + // set IOs to analgo mode, which are used by the Opamp + let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); + // OPAMP1_VINP + let mut _pa0 = gpioa.pa0.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + // OPAMP1_VINM + let mut _pa1 = gpioa.pa1.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + // OPAMP1_VOUT + let mut _pa3 = gpioa.pa3.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + + let ops = dp.OPAMP; + //ops.opamp1_csr.opaen; + let op1: OP1 = OP1::new(& ops.opamp1_csr, & ops.opamp1_otr, & ops.opamp1_lpotr, &rcc.apb1r1); + // set operation models + let _ret = op1.set_opamp_oper_mode(OperationMode::External); + op1.enable(true); + + loop { + } +} diff --git a/examples/opamp_pga.rs b/examples/opamp_pga.rs new file mode 100644 index 00000000..f8376eb4 --- /dev/null +++ b/examples/opamp_pga.rs @@ -0,0 +1,45 @@ +#![deny(unsafe_code)] +// #![deny(warnings)] +#![no_main] +#![no_std] + +extern crate panic_halt; + +// use cortex_m::asm; +use cortex_m_rt::entry; +// use rtt_target::{rprint, rprintln}; +use stm32l4xx_hal::{opamp::*, prelude::*, pac}; + +use stm32l4xx_hal::traits::opamp::*; + +#[entry] +fn main() -> ! { + + // rtt_target::rtt_init_print!(); + // rprint!("Initializing..."); + + let _cp = pac::CorePeripherals::take().unwrap(); + let dp = pac::Peripherals::take().unwrap(); + + let mut rcc = dp.RCC.constrain(); + let mut flash = dp.FLASH.constrain(); + let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); + + let _clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); + + // set IOs to analgo mode, which are used by the Opamp + let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); + // OPAMP1_VINP + let mut _pa0 = gpioa.pa0.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + + let ops = dp.OPAMP; + //ops.opamp1_csr.opaen; + let op1: OP1 = OP1::new(& ops.opamp1_csr, & ops.opamp1_otr, & ops.opamp1_lpotr, &rcc.apb1r1); + // set operation models + op1.set_opamp_oper_mode(OperationMode::PgaADC1); + // set pga gain to 8 + op1.set_pga_gain(PgaGain::PgaG8); + op1.enable(true); + loop { + } +} diff --git a/src/lib.rs b/src/lib.rs index 56801dc3..efad7ba1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,6 +160,8 @@ pub mod lptimer; ))] pub mod otg_fs; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] +pub mod opamp; +#[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod prelude; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod pwm; diff --git a/src/opamp.rs b/src/opamp.rs new file mode 100644 index 00000000..c07fb9bb --- /dev/null +++ b/src/opamp.rs @@ -0,0 +1,286 @@ + + +// use core::{ +// // convert::Infallible, +// ops::DerefMut, +// // sync::atomic::{self, Ordering}, +// }; + +use crate::stm32::{opamp::*}; +use crate::traits::opamp as opamp_trait; +use crate::rcc::APB1R1; //{Enable, Reset, APB1R1, CCIPR}; + +// OPAMP1_CSR::opaen +// OPAMP1_OTR +// OPAMP1_LPOTR +// OPAMP2_CSR +// OPAMP2_OTR +// OPAMP2_LPOTR + +//opamp1_csr::opaen + +#[derive(Clone, Copy)] +pub struct OP1<'a> { + csr: &'a OPAMP1_CSR, + otr: &'a OPAMP1_OTR, + lpotr: &'a OPAMP1_LPOTR, +} + +impl<'a> OP1<'a> { + pub fn new( + csr: &'a OPAMP1_CSR, + otr: &'a OPAMP1_OTR, + lpotr: &'a OPAMP1_LPOTR, + // rcc pointer and enable the clock for the configuration registers + // RCC_APB1ENR1 OPAMPEN + apb1r1: &'a APB1R1, + ) -> Self { + // enable clock for configuration registers of OPAMPS + apb1r1.enr().modify(|_, w| w.opampen().set_bit()); + OP1 { + csr: csr, + otr: otr, + lpotr: lpotr, + } + + } +} + +// s.common.ccr.modify(|_, w| w.vrefen().clear_bit()); +// self.csr.modify(|_, w| w.opaen().clear_bit()); +// .clear_bit() +// .set_bit() +// .bit_is_set() +// .bit_is_cleared() +// let en = self.csr.read().opaen().bit_is_set(); +// let mode = self.csr.read().opamode().bits() as u8; + +// let en = self.csr.read().opaen().bit_is_set(); +// self.csr.modify(|_, w| w.opaen().clear_bit()); +// let mode = self.csr.read().opamode().bits() as u8; + +impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { + fn set_opamp_oper_mode(&self, opmode: opamp_trait::OperationMode) -> opamp_trait::Result { + + match opmode { + opamp_trait::OperationMode::External => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPA_RANGE = 1 (VDDA > 2.4V) + self.csr.modify(|_, w| w.opa_range().set_bit()); + // set OPAMODE = 0 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b00)}); + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + // VM_SEL = 0 (GPIO) + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); + Ok(()) + }, + opamp_trait::OperationMode::PgaADC1 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPA_RANGE = 1 (VDDA > 2.4V) + self.csr.modify(|_, w| w.opa_range().set_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b11)}); + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + // VM_SEL = 0 (GPIO) + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b10)}); + Ok(()) + }, + opamp_trait::OperationMode::PgaADC1ExternalFiltering => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPA_RANGE = 1 (VDDA > 2.4V) + self.csr.modify(|_, w| w.opa_range().set_bit()); + // set OPAMODE = 2 // pga mode = pga, gain = 2..16 (no filtering in follower mode) + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + // VM_SEL = 0 (GPIO) for external filtering + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); + Ok(()) + }, + // opamp_trait::OperationMode::CalibrationMode => { + // // disable OPEAN (before changeing anything else) + // self.csr.modify(|_, w| w.opaen().clear_bit()); + // // set OPA_RANGE = 1 (VDDA > 2.4V) + // self.csr.modify(|_, w| w.opa_range().set_bit()); + // // set OPAMODE = 3 // pga mode = pga gain = 2 (no filtering in follower mode) + // self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // // VP_SEL = 0 (GPIO) + // self.csr.modify(|_, w| w.vp_sel().clear_bit()); + // // VM_SEL = 0 (GPIO) for external filtering + // self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); + // () + // }, + _ => Err(opamp_trait::Error::NotImplemented), + } + // Err(opamp_trait::Error::NotImplemented) + } + + fn conect_inputs(&self, vinp: opamp_trait::VINP, vinm: opamp_trait::VINM) -> opamp_trait::Result { + match vinp { + opamp_trait::VINP::ExternalPin1 => { + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + }, + opamp_trait::VINP::DAC1 => { + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().set_bit()); + }, + _ => return Err(opamp_trait::Error::NotImplemented), + }; + match vinm { + opamp_trait::VINM::ExternalPin1 => { + // VM_SEL = 0 (GPIO) for external filtering + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); + }, + opamp_trait::VINM::LeakageInputPin => { + // VM_SEL = 0 (GPIO) for external filtering + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b01)}); + }, + opamp_trait::VINM::PGA=> { + // VM_SEL = 0 (GPIO) for external filtering + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b10)}); + }, + _ => return Err(opamp_trait::Error::NotImplemented), + }; + Ok(()) + } + + fn set_pga_gain(&self, gain: opamp_trait::PgaGain) -> opamp_trait::Result { + let opaen_state: bool = self.csr.read().opaen().bit_is_set(); + match gain { + opamp_trait::PgaGain::PgaG1 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b11)}); + }, + opamp_trait::PgaGain::PgaG2 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b00)}); + }, + opamp_trait::PgaGain::PgaG4 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b01)}); + }, + opamp_trait::PgaGain::PgaG8 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b10)}); + }, + opamp_trait::PgaGain::PgaG16 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b11)}); + }, + _ => return Err(opamp_trait::Error::NotImplemented), + }; + if opaen_state == true { + // if it has been enabled before, enable it again + self.csr.modify(|_, w| w.opaen().set_bit()); + } + Ok(()) + } + + fn set_power_mode(&self, power_mode: opamp_trait::PowerMode) -> opamp_trait::Result { + match power_mode { + opamp_trait::PowerMode::Normal => { + // set normal mode + self.csr.modify(|_, w| w.opalpm().clear_bit()); + }, + opamp_trait::PowerMode::LowPower => { + // set normal mode + self.csr.modify(|_, w| w.opalpm().set_bit()); + }, + _ => return Err(opamp_trait::Error::NotImplemented), + }; + Ok(()) + } + + fn calibrate(&self) -> opamp_trait::Result { + // set opamp into callibration mode + self.csr.modify(|_, w| w.calon().set_bit()); + // select NMOS calibration first + self.csr.modify(|_, w| w.calsel().clear_bit()); + // read if in LowPower Mode or in normal mode + let low_poer_mode = self.csr.read().opalpm().bit_is_set(); + + // set N calibration registers to 0 + if low_poer_mode == true { + self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetn().bits(0b00000)}); + } else { + self.otr.modify(|_, w| unsafe {w.trimoffsetn().bits(0b00000)}); + } + + // increase calibration reg N till it toggles + while self.csr.read().calout().bit_is_set() == false { + let t_val: u8; + if low_poer_mode == true { + t_val = self.lpotr.read().trimlpoffsetn().bits(); + self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetn().bits(t_val + 1)}); + } else { + t_val = self.otr.read().trimoffsetn().bits(); + self.otr.modify(|_, w| unsafe {w.trimoffsetn().bits(t_val + 1)}); + } + if t_val > 32 { + return Err(opamp_trait::Error::CalibrationError); + } + // wait at least 1ms to new config to settle + // TODO + } + + // select NMOS calibration first + self.csr.modify(|_, w| w.calsel().set_bit()); + + // set P calibration registers to 0 + if low_poer_mode == true { + self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetp().bits(0b00000)}); + } else { + self.otr.modify(|_, w| unsafe {w.trimoffsetp().bits(0b00000)}); + } + // increase calibration reg P till it toggles + while self.csr.read().calout().bit_is_set() == false { + let t_val: u8; + if low_poer_mode == true { + t_val = self.lpotr.read().trimlpoffsetp().bits(); + self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetp().bits(t_val + 1)}); + } else { + t_val = self.otr.read().trimoffsetp().bits(); + self.otr.modify(|_, w| unsafe {w.trimoffsetp().bits(t_val + 1)}); + } + // wait at least 1ms to new config to settle + if t_val > 32 { + return Err(opamp_trait::Error::CalibrationError); + } + // wait for at least 1ms to settle of Configuration + // TODO + } + Ok(()) + } + + fn enable(&self, en: bool) { + if en { + self.csr.modify(|_, w| w.opaen().set_bit()); + } else { + self.csr.modify(|_, w| w.opaen().clear_bit()); + } + } +} diff --git a/src/traits/mod.rs b/src/traits/mod.rs index 2e50f82b..036ab33e 100644 --- a/src/traits/mod.rs +++ b/src/traits/mod.rs @@ -1 +1,2 @@ pub mod flash; +pub mod opamp; diff --git a/src/traits/opamp.rs b/src/traits/opamp.rs new file mode 100644 index 00000000..8f3db365 --- /dev/null +++ b/src/traits/opamp.rs @@ -0,0 +1,105 @@ + + +#[derive(Copy, Clone, Debug)] +pub enum OPAMPS { + OP1, + OP2, +} + +/// Opamp Operation Modes +#[derive(Copy, Clone, Debug)] +pub enum OperationMode { + // wrong values provided + External, + // PGA mode, (configurable gain) connected to an ADC + PgaADC1, + // pga mode with external filter connected + PgaADC1ExternalFiltering, + // PGA mode, (configurable gain) connected to an ADC + PgaADC2, + // pga mode with external filter connected + PgaADC2ExternalFiltering, + // // Calibration Modes + // CalibrationMode, +} + +/// Opamp Power Mode configuration +#[derive(Copy, Clone, Debug)] +pub enum PowerMode { + // Normal operational power (full bandwith) + Normal, + // low power mode with resticted bandwith + LowPower, +} + +#[derive(Copy, Clone, Debug)] +pub enum VINP { + // output conected to external pin + ExternalPin1, + // output conected to DAC1 + DAC1, + // output of opamp1 + OPAMP1 +} + +#[derive(Copy, Clone, Debug)] +pub enum VINM { + // input connected to Opamp output of other Opamp + LeakageInputPin, + // internally connected to PGA gain settings + PGA, + // input conected to external pin (also pga mode with filtering) + ExternalPin1, + // input conected to external pin (also pga mode with filtering) + ExternalPin2, +} + +#[derive(Copy, Clone, Debug)] +pub enum PgaGain { + PgaG1, + PgaG2, + PgaG4, + PgaG8, + PgaG16, +} + + + +/// Opamp configuration error +#[derive(Copy, Clone, Debug)] +pub enum Error { + // wrong values provided + ConfigFailure, + // operaation mode not supportet for this Opamp + UnsuportedMode, + // gain out of bound + PDAGainOutOfBound, + // not Implemented + NotImplemented, + // calibration Error + CalibrationError, +} + + + +/// A type alias for the result of opamp configruation error. +pub type Result = core::result::Result<(), Error>; + +// impl From<> for Error { +// fn from +// } + +pub trait ConfigOpamp { + + fn set_opamp_oper_mode(&self, opmode: OperationMode) -> Result; + + fn conect_inputs(&self, vinp: VINP, vinm: VINM) -> Result; + + fn set_pga_gain(&self, gain: PgaGain) -> Result; + + fn set_power_mode(&self, power_mode: PowerMode) -> Result; + + fn calibrate(&self) -> Result; + + fn enable(&self, en: bool); +} From c3f06638ed0e92e3a8e6c741ad5127d5c0f682a1 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Wed, 19 Jan 2022 22:16:00 +0100 Subject: [PATCH 17/35] delay added to calibration function --- examples/opamp_ext.rs | 7 ++++++- src/opamp.rs | 7 ++++--- src/traits/opamp.rs | 3 ++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/examples/opamp_ext.rs b/examples/opamp_ext.rs index aa0fa33b..cb5a2393 100644 --- a/examples/opamp_ext.rs +++ b/examples/opamp_ext.rs @@ -11,6 +11,8 @@ use cortex_m_rt::entry; use stm32l4xx_hal::{opamp::*, prelude::*, pac}; use stm32l4xx_hal::traits::opamp::*; +//use stm32l4xx_hal::delay::Delay; +use stm32l4xx_hal::delay::DelayCM; #[entry] fn main() -> ! { @@ -25,7 +27,9 @@ fn main() -> ! { let mut flash = dp.FLASH.constrain(); let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); - let _clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); + let clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); + + let mut delay = DelayCM::new(clocks); // set IOs to analgo mode, which are used by the Opamp let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); @@ -41,6 +45,7 @@ fn main() -> ! { let op1: OP1 = OP1::new(& ops.opamp1_csr, & ops.opamp1_otr, & ops.opamp1_lpotr, &rcc.apb1r1); // set operation models let _ret = op1.set_opamp_oper_mode(OperationMode::External); + op1.calibrate(&mut delay); op1.enable(true); loop { diff --git a/src/opamp.rs b/src/opamp.rs index c07fb9bb..30bd7452 100644 --- a/src/opamp.rs +++ b/src/opamp.rs @@ -9,6 +9,7 @@ use crate::stm32::{opamp::*}; use crate::traits::opamp as opamp_trait; use crate::rcc::APB1R1; //{Enable, Reset, APB1R1, CCIPR}; +use crate::hal::{blocking::delay::DelayUs,}; // OPAMP1_CSR::opaen // OPAMP1_OTR @@ -215,7 +216,7 @@ impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { Ok(()) } - fn calibrate(&self) -> opamp_trait::Result { + fn calibrate(&self, delay: &mut impl DelayUs) -> opamp_trait::Result { // set opamp into callibration mode self.csr.modify(|_, w| w.calon().set_bit()); // select NMOS calibration first @@ -244,7 +245,7 @@ impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { return Err(opamp_trait::Error::CalibrationError); } // wait at least 1ms to new config to settle - // TODO + delay.delay_us(1200); } // select NMOS calibration first @@ -271,7 +272,7 @@ impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { return Err(opamp_trait::Error::CalibrationError); } // wait for at least 1ms to settle of Configuration - // TODO + delay.delay_us(1200); } Ok(()) } diff --git a/src/traits/opamp.rs b/src/traits/opamp.rs index 8f3db365..420a8f38 100644 --- a/src/traits/opamp.rs +++ b/src/traits/opamp.rs @@ -1,4 +1,5 @@ +use crate::hal::{blocking::delay::DelayUs,}; #[derive(Copy, Clone, Debug)] pub enum OPAMPS { @@ -99,7 +100,7 @@ pub trait ConfigOpamp { fn set_power_mode(&self, power_mode: PowerMode) -> Result; - fn calibrate(&self) -> Result; + fn calibrate(&self, delay: &mut impl DelayUs) -> Result; fn enable(&self, en: bool); } From f170133fba18e6dbe2b8229802870557ba0c6faf Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Thu, 20 Jan 2022 21:17:36 +0100 Subject: [PATCH 18/35] added function to enable/disable user calibration (if disabled, factory calibration is applied) --- examples/opamp_ext.rs | 10 +++++++++- src/opamp.rs | 8 ++++++++ src/traits/opamp.rs | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/examples/opamp_ext.rs b/examples/opamp_ext.rs index cb5a2393..37e0cc15 100644 --- a/examples/opamp_ext.rs +++ b/examples/opamp_ext.rs @@ -42,10 +42,18 @@ fn main() -> ! { let ops = dp.OPAMP; //ops.opamp1_csr.opaen; - let op1: OP1 = OP1::new(& ops.opamp1_csr, & ops.opamp1_otr, & ops.opamp1_lpotr, &rcc.apb1r1); + let op1: OP1 = OP1::new(& ops.opamp1_csr, + & ops.opamp1_otr, + & ops.opamp1_lpotr, + &rcc.apb1r1,); // set operation models let _ret = op1.set_opamp_oper_mode(OperationMode::External); + + // calibrate the opamp in normal mode, since it has not been switched to low power mode op1.calibrate(&mut delay); + + // set user trim mode (as calibration for user has been perfomed above) + op1.set_calibration_mode(true); op1.enable(true); loop { diff --git a/src/opamp.rs b/src/opamp.rs index 30bd7452..8ecf3a52 100644 --- a/src/opamp.rs +++ b/src/opamp.rs @@ -277,6 +277,14 @@ impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { Ok(()) } + fn set_calibration_mode(&self, usertrim: bool){ + if usertrim { + self.csr.modify(|_, w| w.usertrim().set_bit()); + } else { + self.csr.modify(|_, w| w.usertrim().clear_bit()); + } + } + fn enable(&self, en: bool) { if en { self.csr.modify(|_, w| w.opaen().set_bit()); diff --git a/src/traits/opamp.rs b/src/traits/opamp.rs index 420a8f38..562bbb77 100644 --- a/src/traits/opamp.rs +++ b/src/traits/opamp.rs @@ -102,5 +102,7 @@ pub trait ConfigOpamp { fn calibrate(&self, delay: &mut impl DelayUs) -> Result; + fn set_calibration_mode(&self, usertrim: bool); + fn enable(&self, en: bool); } From 297198c048c4777bf26d0e934bc5bcc7302a24fa Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Fri, 21 Jan 2022 09:02:25 +0100 Subject: [PATCH 19/35] Added enum vars, to suppress unreachable warnings in match statememts --- src/traits/opamp.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/traits/opamp.rs b/src/traits/opamp.rs index 562bbb77..62d6f638 100644 --- a/src/traits/opamp.rs +++ b/src/traits/opamp.rs @@ -22,6 +22,8 @@ pub enum OperationMode { PgaADC2ExternalFiltering, // // Calibration Modes // CalibrationMode, + // added, that warnings for global match pattern are suppressed + SuppressMachtWarnings, } /// Opamp Power Mode configuration @@ -31,6 +33,8 @@ pub enum PowerMode { Normal, // low power mode with resticted bandwith LowPower, + // added, that warnings for global match pattern are suppressed + SuppressMachtWarnings, } #[derive(Copy, Clone, Debug)] @@ -40,7 +44,9 @@ pub enum VINP { // output conected to DAC1 DAC1, // output of opamp1 - OPAMP1 + OPAMP1, + // added, that warnings for global match pattern are suppressed + SuppressMachtWarnings, } #[derive(Copy, Clone, Debug)] @@ -53,6 +59,8 @@ pub enum VINM { ExternalPin1, // input conected to external pin (also pga mode with filtering) ExternalPin2, + // added, that warnings for global match pattern are suppressed + SuppressMachtWarnings, } #[derive(Copy, Clone, Debug)] @@ -62,6 +70,8 @@ pub enum PgaGain { PgaG4, PgaG8, PgaG16, + // added, that warnings for global match pattern are suppressed + SuppressMachtWarnings, } @@ -79,6 +89,10 @@ pub enum Error { NotImplemented, // calibration Error CalibrationError, + // wrong pin assignment for selected operation mode + WrongPinAssinment, + // added, that warnings for global match pattern are suppressed + SuppressMachtWarnings, } From b19af6e9b11caa749a77e1d1aaa787de78af1576 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Fri, 21 Jan 2022 10:04:33 +0100 Subject: [PATCH 20/35] added set_pga_gain with int argument, seems more general usful in a trait --- examples/opamp_ext.rs | 8 +- examples/opamp_pga.rs | 2 +- src/opamp.rs | 171 ++++++++++++++++++++++++++---------------- src/traits/opamp.rs | 13 +++- 4 files changed, 124 insertions(+), 70 deletions(-) diff --git a/examples/opamp_ext.rs b/examples/opamp_ext.rs index 37e0cc15..d369bebc 100644 --- a/examples/opamp_ext.rs +++ b/examples/opamp_ext.rs @@ -41,16 +41,18 @@ fn main() -> ! { let mut _pa3 = gpioa.pa3.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); let ops = dp.OPAMP; + //ops.opamp1_csr.opaen; let op1: OP1 = OP1::new(& ops.opamp1_csr, & ops.opamp1_otr, & ops.opamp1_lpotr, - &rcc.apb1r1,); + &rcc.apb1r1, + ); // set operation models - let _ret = op1.set_opamp_oper_mode(OperationMode::External); + let _ret = op1.set_opamp_oper_mode(OperationMode::External).unwrap(); // calibrate the opamp in normal mode, since it has not been switched to low power mode - op1.calibrate(&mut delay); + op1.calibrate(&mut delay).unwrap(); // set user trim mode (as calibration for user has been perfomed above) op1.set_calibration_mode(true); diff --git a/examples/opamp_pga.rs b/examples/opamp_pga.rs index f8376eb4..a8cc0375 100644 --- a/examples/opamp_pga.rs +++ b/examples/opamp_pga.rs @@ -38,7 +38,7 @@ fn main() -> ! { // set operation models op1.set_opamp_oper_mode(OperationMode::PgaADC1); // set pga gain to 8 - op1.set_pga_gain(PgaGain::PgaG8); + op1.set_pga_gain_enum(PgaGain::PgaG8); op1.enable(true); loop { } diff --git a/src/opamp.rs b/src/opamp.rs index 8ecf3a52..5b341d93 100644 --- a/src/opamp.rs +++ b/src/opamp.rs @@ -1,26 +1,11 @@ - -// use core::{ -// // convert::Infallible, -// ops::DerefMut, -// // sync::atomic::{self, Ordering}, -// }; - use crate::stm32::{opamp::*}; use crate::traits::opamp as opamp_trait; use crate::rcc::APB1R1; //{Enable, Reset, APB1R1, CCIPR}; use crate::hal::{blocking::delay::DelayUs,}; -// OPAMP1_CSR::opaen -// OPAMP1_OTR -// OPAMP1_LPOTR -// OPAMP2_CSR -// OPAMP2_OTR -// OPAMP2_LPOTR - -//opamp1_csr::opaen -#[derive(Clone, Copy)] +//#[derive(Clone, Copy)] pub struct OP1<'a> { csr: &'a OPAMP1_CSR, otr: &'a OPAMP1_OTR, @@ -45,6 +30,23 @@ impl<'a> OP1<'a> { } } + /// opa range specifice the VDDA voltage applied to the device. + /// it is by default set to >2.4V (high) + /// do not use this function, if you do not know, what you are decoding + /// you might damage the devices + /// since the setting applies to all opamps in the device and before + /// changeing this value, all opamps must be disabled; up to this pointe + /// only one opamp is supportd in this file, for that only that opamp is disable + /// before the value is set. + /// you need to enable the opamp after calling this function separately + pub fn set_opa_range(&self, high: bool) { + self.csr.modify(|_, w| w.opaen().clear_bit()); + if high { + self.csr.modify(|_, w| w.opa_range().set_bit()); + } else { + self.csr.modify(|_, w| w.opa_range().clear_bit()); + } + } } // s.common.ccr.modify(|_, w| w.vrefen().clear_bit()); @@ -65,57 +67,44 @@ impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { match opmode { opamp_trait::OperationMode::External => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPA_RANGE = 1 (VDDA > 2.4V) - self.csr.modify(|_, w| w.opa_range().set_bit()); - // set OPAMODE = 0 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b00)}); - // VP_SEL = 0 (GPIO) - self.csr.modify(|_, w| w.vp_sel().clear_bit()); - // VM_SEL = 0 (GPIO) - self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); - Ok(()) + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPA_RANGE = 1 (VDDA > 2.4V) + self.csr.modify(|_, w| w.opa_range().set_bit()); + // set OPAMODE = 0 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b00)}); + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + // VM_SEL = 0 (GPIO) + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); + Ok(()) }, opamp_trait::OperationMode::PgaADC1 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPA_RANGE = 1 (VDDA > 2.4V) - self.csr.modify(|_, w| w.opa_range().set_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b11)}); - // VP_SEL = 0 (GPIO) - self.csr.modify(|_, w| w.vp_sel().clear_bit()); - // VM_SEL = 0 (GPIO) - self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b10)}); - Ok(()) + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPA_RANGE = 1 (VDDA > 2.4V) + self.csr.modify(|_, w| w.opa_range().set_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b11)}); + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + // VM_SEL = 0 (GPIO) + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b10)}); + Ok(()) }, opamp_trait::OperationMode::PgaADC1ExternalFiltering => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPA_RANGE = 1 (VDDA > 2.4V) - self.csr.modify(|_, w| w.opa_range().set_bit()); - // set OPAMODE = 2 // pga mode = pga, gain = 2..16 (no filtering in follower mode) - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // VP_SEL = 0 (GPIO) - self.csr.modify(|_, w| w.vp_sel().clear_bit()); - // VM_SEL = 0 (GPIO) for external filtering - self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); - Ok(()) + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPA_RANGE = 1 (VDDA > 2.4V) + self.csr.modify(|_, w| w.opa_range().set_bit()); + // set OPAMODE = 2 // pga mode = pga, gain = 2..16 (no filtering in follower mode) + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + // VM_SEL = 0 (GPIO) for external filtering + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); + Ok(()) }, - // opamp_trait::OperationMode::CalibrationMode => { - // // disable OPEAN (before changeing anything else) - // self.csr.modify(|_, w| w.opaen().clear_bit()); - // // set OPA_RANGE = 1 (VDDA > 2.4V) - // self.csr.modify(|_, w| w.opa_range().set_bit()); - // // set OPAMODE = 3 // pga mode = pga gain = 2 (no filtering in follower mode) - // self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // // VP_SEL = 0 (GPIO) - // self.csr.modify(|_, w| w.vp_sel().clear_bit()); - // // VM_SEL = 0 (GPIO) for external filtering - // self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); - // () - // }, _ => Err(opamp_trait::Error::NotImplemented), } // Err(opamp_trait::Error::NotImplemented) @@ -124,7 +113,7 @@ impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { fn conect_inputs(&self, vinp: opamp_trait::VINP, vinm: opamp_trait::VINM) -> opamp_trait::Result { match vinp { opamp_trait::VINP::ExternalPin1 => { - // VP_SEL = 0 (GPIO) + // VP_SEL = 0 (GPIO), PA0 self.csr.modify(|_, w| w.vp_sel().clear_bit()); }, opamp_trait::VINP::DAC1 => { @@ -135,7 +124,7 @@ impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { }; match vinm { opamp_trait::VINM::ExternalPin1 => { - // VM_SEL = 0 (GPIO) for external filtering + // VM_SEL = 0 (GPIO), PA1 for external filtering self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); }, opamp_trait::VINM::LeakageInputPin => { @@ -151,7 +140,7 @@ impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { Ok(()) } - fn set_pga_gain(&self, gain: opamp_trait::PgaGain) -> opamp_trait::Result { + fn set_pga_gain_enum(&self, gain: opamp_trait::PgaGain) -> opamp_trait::Result { let opaen_state: bool = self.csr.read().opaen().bit_is_set(); match gain { opamp_trait::PgaGain::PgaG1 => { @@ -201,6 +190,58 @@ impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { Ok(()) } + fn set_pga_gain(&self, gain: u16) -> opamp_trait::Result { + let opaen_state: bool = self.csr.read().opaen().bit_is_set(); + + match gain { + 1 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b11)}); + }, + 2 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b00)}); + }, + 4 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b01)}); + }, + 8 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b10)}); + }, + 16 => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b11)}); + }, + _ => return Err(opamp_trait::Error::NotImplemented), + }; + + if opaen_state == true { + // if it has been enabled before, enable it again + self.csr.modify(|_, w| w.opaen().set_bit()); + } + Ok(()) + } + fn set_power_mode(&self, power_mode: opamp_trait::PowerMode) -> opamp_trait::Result { match power_mode { opamp_trait::PowerMode::Normal => { diff --git a/src/traits/opamp.rs b/src/traits/opamp.rs index 62d6f638..01eae15e 100644 --- a/src/traits/opamp.rs +++ b/src/traits/opamp.rs @@ -37,6 +37,8 @@ pub enum PowerMode { SuppressMachtWarnings, } +/// Opamp postive input configuration. External pins are numerated, to which they finaly match is +/// device specific #[derive(Copy, Clone, Debug)] pub enum VINP { // output conected to external pin @@ -49,6 +51,8 @@ pub enum VINP { SuppressMachtWarnings, } +/// Opamp negativ input configuration. External pins are numerated, to which they finaly match is +/// device specific #[derive(Copy, Clone, Debug)] pub enum VINM { // input connected to Opamp output of other Opamp @@ -63,6 +67,7 @@ pub enum VINM { SuppressMachtWarnings, } +/// Opamp gain configuration in PGA mode #[derive(Copy, Clone, Debug)] pub enum PgaGain { PgaG1, @@ -70,6 +75,10 @@ pub enum PgaGain { PgaG4, PgaG8, PgaG16, + PgaG32, // this values and below may be used for stm32g4 devices + PgaG64, + PgaG128, + PgaG256, // added, that warnings for global match pattern are suppressed SuppressMachtWarnings, } @@ -110,7 +119,9 @@ pub trait ConfigOpamp { fn conect_inputs(&self, vinp: VINP, vinm: VINM) -> Result; - fn set_pga_gain(&self, gain: PgaGain) -> Result; + fn set_pga_gain_enum(&self, gain: PgaGain) -> Result; + + fn set_pga_gain(&self, gain: u16) -> Result; fn set_power_mode(&self, power_mode: PowerMode) -> Result; From f8e33ad89428e62a0b8ea7c1cfafb8568ad02286 Mon Sep 17 00:00:00 2001 From: oldsheep68 <83419094+oldsheep68@users.noreply.github.com> Date: Sat, 22 Jan 2022 09:35:41 +0100 Subject: [PATCH 21/35] Create ci_opamp.yml workflow version for opamp branch --- .github/workflows/ci_opamp.yml | 84 ++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 .github/workflows/ci_opamp.yml diff --git a/.github/workflows/ci_opamp.yml b/.github/workflows/ci_opamp.yml new file mode 100644 index 00000000..81513d28 --- /dev/null +++ b/.github/workflows/ci_opamp.yml @@ -0,0 +1,84 @@ +on: + push: + branches: [opamp] + pull_request: + +name: Continuous integration + +jobs: + ci: + runs-on: ubuntu-latest + strategy: + matrix: # All permutations of {rust, mcu} + rust: + - stable + mcu: + - stm32l412 + - stm32l422 + - stm32l431 + - stm32l432 + - stm32l433 + - stm32l442 + - stm32l443 + - stm32l451 + - stm32l452 + - stm32l462 + - stm32l471 + - stm32l475 + - stm32l476 + - stm32l486 + - stm32l496 + - stm32l4a6 + #- stm32l4r9 + #- stm32l4s9 + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: thumbv7em-none-eabihf + override: true + - name: build + uses: actions-rs/cargo@v1 + with: + use-cross: true + command: build + args: --verbose --release --examples --target thumbv7em-none-eabihf --features rt,unproven,${{ matrix.mcu }} + - name: test + uses: actions-rs/cargo@v1 + with: + command: test + args: --lib --target x86_64-unknown-linux-gnu --features rt,unproven,${{ matrix.mcu }} + + ci-r9: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + mcu: + - stm32l4r9 + - stm32l4s9 + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: thumbv7em-none-eabihf + override: true + - name: build + uses: actions-rs/cargo@v1 + with: + use-cross: true + command: build + args: --verbose --release --target thumbv7em-none-eabihf --features rt,unproven,${{ matrix.mcu }} + # note that examples were not built + - name: test + uses: actions-rs/cargo@v1 + with: + command: test + args: --lib --target x86_64-unknown-linux-gnu --features rt,unproven,${{ matrix.mcu }} From 84029c0c72da0ec72013501d0ea34afbe8994d44 Mon Sep 17 00:00:00 2001 From: oldsheep68 <83419094+oldsheep68@users.noreply.github.com> Date: Sat, 22 Jan 2022 09:38:10 +0100 Subject: [PATCH 22/35] Create clippy_opamp.yml opamp action version --- .github/workflows/clippy_opamp.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/clippy_opamp.yml diff --git a/.github/workflows/clippy_opamp.yml b/.github/workflows/clippy_opamp.yml new file mode 100644 index 00000000..4a087de2 --- /dev/null +++ b/.github/workflows/clippy_opamp.yml @@ -0,0 +1,22 @@ +on: + push: + branches: [ opamp ] + pull_request: + +name: Clippy check +jobs: + clippy_check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + target: thumbv7em-none-eabihf + override: true + components: clippy + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --examples --target thumbv7em-none-eabihf --features=stm32l432,rt,unproven From 70eef4fc702ab4578e1773123ef43418c3e67308 Mon Sep 17 00:00:00 2001 From: oldsheep68 <83419094+oldsheep68@users.noreply.github.com> Date: Sat, 22 Jan 2022 09:39:03 +0100 Subject: [PATCH 23/35] Create rustfmt_opamp.yml opamp action for rustfmt --- .github/workflows/rustfmt_opamp.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/rustfmt_opamp.yml diff --git a/.github/workflows/rustfmt_opamp.yml b/.github/workflows/rustfmt_opamp.yml new file mode 100644 index 00000000..102f0e3d --- /dev/null +++ b/.github/workflows/rustfmt_opamp.yml @@ -0,0 +1,23 @@ +on: + push: + branches: [ master ] + pull_request: + +name: Code formatting check + +jobs: + fmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check From 6e39709cfa28cc3bc32a4213e7147737e8de5cc1 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 22 Jan 2022 11:37:48 +0100 Subject: [PATCH 24/35] Add ADC read out for simler testing --- examples/opamp_pga.rs | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/examples/opamp_pga.rs b/examples/opamp_pga.rs index a8cc0375..e4e926a5 100644 --- a/examples/opamp_pga.rs +++ b/examples/opamp_pga.rs @@ -7,25 +7,25 @@ extern crate panic_halt; // use cortex_m::asm; use cortex_m_rt::entry; -// use rtt_target::{rprint, rprintln}; -use stm32l4xx_hal::{opamp::*, prelude::*, pac}; +use rtt_target::{rprint, rprintln}; +use stm32l4xx_hal::{adc::ADC, delay::Delay, opamp::*, prelude::*, pac}; use stm32l4xx_hal::traits::opamp::*; #[entry] fn main() -> ! { - // rtt_target::rtt_init_print!(); - // rprint!("Initializing..."); + rtt_target::rtt_init_print!(); + rprint!("Initializing..."); - let _cp = pac::CorePeripherals::take().unwrap(); + let cp = pac::CorePeripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); let mut flash = dp.FLASH.constrain(); let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); - let _clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); + let clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); // set IOs to analgo mode, which are used by the Opamp let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); @@ -38,8 +38,26 @@ fn main() -> ! { // set operation models op1.set_opamp_oper_mode(OperationMode::PgaADC1); // set pga gain to 8 - op1.set_pga_gain_enum(PgaGain::PgaG8); + op1.set_pga_gain_enum(PgaGain::PgaG2); op1.enable(true); + + + let mut delay = Delay::new(cp.SYST, clocks); + let mut adc = ADC::new( + dp.ADC1, + dp.ADC_COMMON, + &mut rcc.ahb2, + &mut rcc.ccipr, + &mut delay, + ); + + // use ADC-in-8 to read from Opamp 1 in ADC1 (PA3) + let mut a3 = gpioa.pa3.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + + rprintln!(" done."); + loop { + let value = adc.read(&mut a3).unwrap(); + rprintln!("Value: {}", value); } } From 9b412292a357ba8f7f97f0b7ed83c6a684a11b7b Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 17:47:30 +0100 Subject: [PATCH 25/35] opamp updated after testing on devices --- examples/adc_opamp1.rs | 64 +++++ examples/opamp_ext.rs | 78 ++++-- examples/opamp_pga.rs | 63 +++-- src/adc.rs | 31 ++- src/opamp.rs | 619 +++++++++++++++++++++-------------------- src/traits/opamp.rs | 22 +- 6 files changed, 505 insertions(+), 372 deletions(-) create mode 100644 examples/adc_opamp1.rs diff --git a/examples/adc_opamp1.rs b/examples/adc_opamp1.rs new file mode 100644 index 00000000..fff10dab --- /dev/null +++ b/examples/adc_opamp1.rs @@ -0,0 +1,64 @@ +#![no_main] +#![no_std] + +use panic_rtt_target as _; + +use cortex_m_rt::entry; +use rtt_target::{rprint, rprintln}; +use stm32l4xx_hal::{adc::ADC, delay::Delay, opamp::*, pac, prelude::*}; + +use stm32l4xx_hal::traits::opamp::*; + +#[entry] +fn main() -> ! { + rtt_target::rtt_init_print!(); + rprint!("Initializing..."); + + let cp = pac::CorePeripherals::take().unwrap(); + let dp = pac::Peripherals::take().unwrap(); + + let mut rcc = dp.RCC.constrain(); + let mut flash = dp.FLASH.constrain(); + let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); + + let clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); + + // set IOs to analgo mode, which are used by the Opamp + let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); + // OPAMP1_VINP + let mut pa0 = gpioa.pa0.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + + let mut delay = Delay::new(cp.SYST, clocks); + let mut adc = ADC::new( + dp.ADC1, + dp.ADC_COMMON, + &mut rcc.ahb2, + &mut rcc.ccipr, + &mut delay, + ); + + let mut opamp1_out = adc.enable_opamp1_out(); + + let ops = dp.OPAMP; + let op1: OP1 = OP1::new( + &ops.opamp1_csr, + &ops.opamp1_otr, + &ops.opamp1_lpotr, + &ops.opamp1_csr, + &rcc.apb1r1, + ); + + op1.set_opamp_oper_mode(OperationMode::Pga); + // set pga gain + op1.set_pga_gain(16); + op1.enable(true); + + rprintln!(" done."); + + loop { + // let value = adc.read(&mut opamp2_out).unwrap(); + let value_opamp1 = adc.read(&mut opamp1_out).unwrap(); + let value_a0 = adc.read(&mut pa0).unwrap(); + rprintln!("Value: pa0 {} opam1 {}", value_a0, value_opamp1); + } +} diff --git a/examples/opamp_ext.rs b/examples/opamp_ext.rs index d369bebc..c5edd293 100644 --- a/examples/opamp_ext.rs +++ b/examples/opamp_ext.rs @@ -1,4 +1,4 @@ -#![deny(unsafe_code)] +// #![deny(unsafe_code)] // #![deny(warnings)] #![no_main] #![no_std] @@ -7,18 +7,20 @@ extern crate panic_halt; // use cortex_m::asm; use cortex_m_rt::entry; -// use rtt_target::{rprint, rprintln}; -use stm32l4xx_hal::{opamp::*, prelude::*, pac}; +use rtt_target::{rprint, rprintln}; +use stm32l4xx_hal; +use stm32l4xx_hal::{opamp::*, pac, prelude::*}; use stm32l4xx_hal::traits::opamp::*; -//use stm32l4xx_hal::delay::Delay; -use stm32l4xx_hal::delay::DelayCM; + +// use embedded_hal::*; +// use embedded_hal::blocking::delay::DelayUs; +use stm32l4xx_hal::*; #[entry] fn main() -> ! { - - // rtt_target::rtt_init_print!(); - // rprint!("Initializing..."); + rtt_target::rtt_init_print!(); + rprint!("Initializing..."); let _cp = pac::CorePeripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap(); @@ -29,9 +31,9 @@ fn main() -> ! { let clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); - let mut delay = DelayCM::new(clocks); + let mut _delay = delay::DelayCM::new(clocks); - // set IOs to analgo mode, which are used by the Opamp + // // set IOs to analgo mode, which are used by the Opamp let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); // OPAMP1_VINP let mut _pa0 = gpioa.pa0.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); @@ -40,24 +42,56 @@ fn main() -> ! { // OPAMP1_VOUT let mut _pa3 = gpioa.pa3.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + // // set IOs to analgo mode, which are used by the Opamp + // let mut gpiob = dp.GPIOB.split(&mut rcc.ahb2); + // // OPAMP1_VINP + // let mut _pa6 = gpioa.pa6.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + // // OPAMP1_VINM + // let mut _pa7 = gpioa.pa7.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); + // // OPAMP1_VOUT + // let mut _pb0 = gpiob.pb0.into_analog(&mut gpiob.moder, &mut gpiob.pupdr); + let ops = dp.OPAMP; //ops.opamp1_csr.opaen; - let op1: OP1 = OP1::new(& ops.opamp1_csr, - & ops.opamp1_otr, - & ops.opamp1_lpotr, - &rcc.apb1r1, - ); + let op1: OP1 = OP1::new( + &ops.opamp1_csr, + &ops.opamp1_otr, + &ops.opamp1_lpotr, + &ops.opamp1_csr, + &rcc.apb1r1, + ); + // let op2: OP2 = OP2::new( + // &ops.opamp2_csr, + // &ops.opamp2_otr, + // &ops.opamp2_lpotr, + // &ops.opamp1_csr, + // &rcc.apb1r1, + // ); + + rprintln!("op1 object created..."); // set operation models let _ret = op1.set_opamp_oper_mode(OperationMode::External).unwrap(); + rprintln!("op1 operation mode set..."); + + + op1.enable(true); - // calibrate the opamp in normal mode, since it has not been switched to low power mode - op1.calibrate(&mut delay).unwrap(); + // =================================================================================== + // Debug Info below - // set user trim mode (as calibration for user has been perfomed above) - op1.set_calibration_mode(true); - op1.enable(true); + rprintln!("opamode OP1: {}\n", ops.opamp1_csr.read().opamode().bits() as u8); + // rprintln!("opaen: {}\n", ops.opamp1_csr.read().opaen().bits() as u8); + // rprintln!("opa_range: {}\n", ops.opamp1_csr.read().opa_range().bits() as u8); + // rprintln!("vp_sel: {}\n", ops.opamp1_csr.read().vp_sel().bits() as u8); + // rprintln!("vm_sel: {}\n", ops.opamp1_csr.read().vm_sel().bits() as u8); + // rprintln!("opalpm: {}\n", ops.opamp1_csr.read().opalpm().bits() as u8); + // rprintln!("calout: {}\n", ops.opamp1_csr.read().calout().bits() as u8); + // rprintln!("calon: {}\n", ops.opamp1_csr.read().calon().bits() as u8); + // rprintln!("calsel: {}\n", ops.opamp1_csr.read().calsel().bits() as u8); + // rprintln!("usertrim: {}\n", ops.opamp1_csr.read().usertrim().bits() as u8); + // rprintln!("pga_gain: {}\n", ops.opamp1_csr.read().pga_gain().bits() as u8); - loop { - } + + loop {} } diff --git a/examples/opamp_pga.rs b/examples/opamp_pga.rs index e4e926a5..86251e92 100644 --- a/examples/opamp_pga.rs +++ b/examples/opamp_pga.rs @@ -8,24 +8,19 @@ extern crate panic_halt; // use cortex_m::asm; use cortex_m_rt::entry; use rtt_target::{rprint, rprintln}; -use stm32l4xx_hal::{adc::ADC, delay::Delay, opamp::*, prelude::*, pac}; +use stm32l4xx_hal::{opamp::*, pac, prelude::*}; use stm32l4xx_hal::traits::opamp::*; #[entry] fn main() -> ! { - rtt_target::rtt_init_print!(); rprint!("Initializing..."); - let cp = pac::CorePeripherals::take().unwrap(); + let _cp = pac::CorePeripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); - let mut flash = dp.FLASH.constrain(); - let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); - - let clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); // set IOs to analgo mode, which are used by the Opamp let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); @@ -34,30 +29,50 @@ fn main() -> ! { let ops = dp.OPAMP; //ops.opamp1_csr.opaen; - let op1: OP1 = OP1::new(& ops.opamp1_csr, & ops.opamp1_otr, & ops.opamp1_lpotr, &rcc.apb1r1); + let op1: OP1 = OP1::new( + &ops.opamp1_csr, + &ops.opamp1_otr, + &ops.opamp1_lpotr, + &ops.opamp1_csr, + &rcc.apb1r1, + ); + // set operation models - op1.set_opamp_oper_mode(OperationMode::PgaADC1); + op1.set_opamp_oper_mode(OperationMode::Pga).unwrap(); // set pga gain to 8 - op1.set_pga_gain_enum(PgaGain::PgaG2); + op1.set_pga_gain(2).unwrap(); op1.enable(true); + - let mut delay = Delay::new(cp.SYST, clocks); - let mut adc = ADC::new( - dp.ADC1, - dp.ADC_COMMON, - &mut rcc.ahb2, - &mut rcc.ccipr, - &mut delay, - ); - - // use ADC-in-8 to read from Opamp 1 in ADC1 (PA3) - let mut a3 = gpioa.pa3.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); - + // =================================================================================== + // Debug Info below rprintln!(" done."); + rprintln!( + "opamode: {}\n", + ops.opamp1_csr.read().opamode().bits() as u8 + ); + rprintln!("opaen: {}\n", ops.opamp1_csr.read().opaen().bits() as u8); + rprintln!( + "opa_range: {}\n", + ops.opamp1_csr.read().opa_range().bits() as u8 + ); + rprintln!("vp_sel: {}\n", ops.opamp1_csr.read().vp_sel().bits() as u8); + rprintln!("vm_sel: {}\n", ops.opamp1_csr.read().vm_sel().bits() as u8); + rprintln!("opalpm: {}\n", ops.opamp1_csr.read().opalpm().bits() as u8); + rprintln!("calout: {}\n", ops.opamp1_csr.read().calout().bits() as u8); + rprintln!("calon: {}\n", ops.opamp1_csr.read().calon().bits() as u8); + rprintln!("calsel: {}\n", ops.opamp1_csr.read().calsel().bits() as u8); + rprintln!( + "usertrim: {}\n", + ops.opamp1_csr.read().usertrim().bits() as u8 + ); + rprintln!( + "pga_gain: {}\n", + ops.opamp1_csr.read().pga_gain().bits() as u8 + ); + loop { - let value = adc.read(&mut a3).unwrap(); - rprintln!("Value: {}", value); } } diff --git a/src/adc.rs b/src/adc.rs index 2e7f3dba..d6a6bc6d 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -30,6 +30,12 @@ pub struct Vbat; /// Core temperature internal signal pub struct Temperature; +/// Opamp1 output connected to ADC1 +pub struct Opamp1Out; + +/// Opamp1 output connected to ADC1 +pub struct Opamp2Out; + /// Analog to Digital converter interface pub struct ADC { pub(crate) adc: ADC1, @@ -254,6 +260,16 @@ impl ADC { Vbat {} } + /// Get the `Opamp1Out` + pub fn enable_opamp1_out(&mut self) -> Opamp1Out { + Opamp1Out {} + } + + /// Get the `Opamp2Out` + pub fn enable_opamp2_out(&mut self) -> Opamp2Out { + Opamp2Out {} + } + /// Calculates the system VDDA by sampling the internal VREF channel and comparing /// the result with the value stored at the factory. If the chip's VDDA is not stable, run /// this before each ADC conversion. @@ -383,7 +399,7 @@ impl ADC { /// Configure the channel for a specific step in the sequence. /// /// Automatically sets the sequence length to the farthes sequence - /// index that has been used so far. Use [`ADC::reset_sequence`] to + /// index that has been used so far. Use [`ADC::reset_jsequence`] to /// reset the sequence length. pub fn configure_jsequence( &mut self, @@ -623,6 +639,14 @@ impl ADC { } } + /// Reset the jsequence length to 1 + /// + /// Does *not* erase previously configured sequence settings, only + /// changes the sequence length + pub fn reset_jsequence(&mut self) { + self.adc.jsqr.modify(|_, w| unsafe { w.jl().bits(0b00) }) + } + /// clear jeos interrupt flag pub fn set_jeos(&mut self) { self.adc.isr.modify(|_, w| w.jeos().set_bit()); @@ -931,6 +955,9 @@ macro_rules! adc_pins { }; } +// smprx : sample time main register +// smpx : smple tim channel value register + adc_pins!( 0, Vref, smpr1, smp0; 1, gpio::PC0, smpr1, smp1; @@ -951,4 +978,6 @@ adc_pins!( 16, gpio::PB1, smpr2, smp16; 17, Temperature, smpr2, smp17; 18, Vbat, smpr2, smp18; + 8, Opamp1Out, smpr1, smp8; + 15, Opamp2Out, smpr2, smp15; ); diff --git a/src/opamp.rs b/src/opamp.rs index 5b341d93..da239fb2 100644 --- a/src/opamp.rs +++ b/src/opamp.rs @@ -1,336 +1,339 @@ - -use crate::stm32::{opamp::*}; -use crate::traits::opamp as opamp_trait; +use crate::hal::blocking::delay::DelayUs; use crate::rcc::APB1R1; //{Enable, Reset, APB1R1, CCIPR}; -use crate::hal::{blocking::delay::DelayUs,}; +use crate::stm32::opamp::*; +use crate::traits::opamp as opamp_trait; +use core::sync::atomic::{compiler_fence, Ordering}; -//#[derive(Clone, Copy)] -pub struct OP1<'a> { - csr: &'a OPAMP1_CSR, - otr: &'a OPAMP1_OTR, - lpotr: &'a OPAMP1_LPOTR, -} +// // s.common.ccr.modify(|_, w| w.vrefen().clear_bit()); +// // self.csr.modify(|_, w| w.opaen().clear_bit()); +// // .clear_bit() +// // .set_bit() +// // .bit_is_set() +// // .bit_is_clear() +// // let en = self.csr.read().opaen().bit_is_set(); +// // let mode = self.csr.read().opamode().bits() as u8; -impl<'a> OP1<'a> { - pub fn new( - csr: &'a OPAMP1_CSR, - otr: &'a OPAMP1_OTR, - lpotr: &'a OPAMP1_LPOTR, - // rcc pointer and enable the clock for the configuration registers - // RCC_APB1ENR1 OPAMPEN - apb1r1: &'a APB1R1, - ) -> Self { - // enable clock for configuration registers of OPAMPS - apb1r1.enr().modify(|_, w| w.opampen().set_bit()); - OP1 { - csr: csr, - otr: otr, - lpotr: lpotr, - } +// // let en = self.csr.read().opaen().bit_is_set(); +// // self.csr.modify(|_, w| w.opaen().clear_bit()); +// // let mode = self.csr.read().opamode().bits() as u8; - } - /// opa range specifice the VDDA voltage applied to the device. - /// it is by default set to >2.4V (high) - /// do not use this function, if you do not know, what you are decoding - /// you might damage the devices - /// since the setting applies to all opamps in the device and before - /// changeing this value, all opamps must be disabled; up to this pointe - /// only one opamp is supportd in this file, for that only that opamp is disable - /// before the value is set. - /// you need to enable the opamp after calling this function separately - pub fn set_opa_range(&self, high: bool) { - self.csr.modify(|_, w| w.opaen().clear_bit()); - if high { - self.csr.modify(|_, w| w.opa_range().set_bit()); - } else { - self.csr.modify(|_, w| w.opa_range().clear_bit()); - } - } -} +macro_rules! opamps { + ( + $( + $op:ident, + $csr_ty:ty, + $otr_ty:ty, + $lpotr_ty:ty, + $range_ty:ty; + )* + ) => { + $( -// s.common.ccr.modify(|_, w| w.vrefen().clear_bit()); -// self.csr.modify(|_, w| w.opaen().clear_bit()); -// .clear_bit() -// .set_bit() -// .bit_is_set() -// .bit_is_cleared() -// let en = self.csr.read().opaen().bit_is_set(); -// let mode = self.csr.read().opamode().bits() as u8; + pub struct $op<'a> { + csr: &'a $csr_ty, + otr: &'a $otr_ty, + lpotr: &'a $lpotr_ty, + range: &'a $range_ty, + } -// let en = self.csr.read().opaen().bit_is_set(); -// self.csr.modify(|_, w| w.opaen().clear_bit()); -// let mode = self.csr.read().opamode().bits() as u8; + impl<'a> $op<'a> { -impl<'a> opamp_trait::ConfigOpamp for OP1<'a> { - fn set_opamp_oper_mode(&self, opmode: opamp_trait::OperationMode) -> opamp_trait::Result { + /// Create a new OPAMP instance. the default range is always set to >2.4V so that the device is + /// not damaged at first call on typical eval-boards from ST + pub fn new( + csr: &'a $csr_ty, + otr: &'a $otr_ty, + lpotr: &'a $lpotr_ty, + // to set default range to > 2.4V + range: &'a $range_ty, + // rcc pointer and enable the clock for the configuration registers + apb1r1: &'a APB1R1, + ) -> Self { + // enable clock for configuration registers of OPAMPS + apb1r1.enr().modify(|_, w| w.opampen().set_bit()); - match opmode { - opamp_trait::OperationMode::External => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPA_RANGE = 1 (VDDA > 2.4V) - self.csr.modify(|_, w| w.opa_range().set_bit()); - // set OPAMODE = 0 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b00)}); - // VP_SEL = 0 (GPIO) - self.csr.modify(|_, w| w.vp_sel().clear_bit()); - // VM_SEL = 0 (GPIO) - self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); - Ok(()) - }, - opamp_trait::OperationMode::PgaADC1 => { - // disable OPEAN (before changeing anything else) + // set OPA_RANGE = 1 (VDDA > 2.4V) by default, if ADC1 is not enabled + // if a lower voltage is applied, use an instance of ADC1 to clear the opa_range bit + if range.read().opaen().bit_is_clear() == true { + range.modify(|_, w| w.opa_range().set_bit()); // else expect bit is set correct + } + compiler_fence(Ordering::SeqCst); + $op { + csr: csr, + otr: otr, + lpotr: lpotr, + range: range, + } + + } + + /// opa range specifice the VDDA voltage applied to the device. + /// Is valied for both OP, if there are two in the device + /// it is by default set to >2.4V (high) + /// do not use this function, if you do not know, what you are decoding + /// you might damage the devices + /// since the setting applies to all opamps in the device and before + /// changeing this value, all opamps must be disabled; up to this pointe + /// only one opamp is supportd in this file, for that only that opamp is disable + /// before the value is set. + /// you need to enable the opamp after calling this function separately + pub fn set_opa_range(&self, high: bool) { self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPA_RANGE = 1 (VDDA > 2.4V) - self.csr.modify(|_, w| w.opa_range().set_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b11)}); - // VP_SEL = 0 (GPIO) - self.csr.modify(|_, w| w.vp_sel().clear_bit()); - // VM_SEL = 0 (GPIO) - self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b10)}); + if high { + self.range.modify(|_, w| w.opa_range().set_bit()); + } else { + self.range.modify(|_, w| w.opa_range().clear_bit()); + } + compiler_fence(Ordering::SeqCst); + } + } + + impl<'a> opamp_trait::ConfigOpamp for $op<'a> { + + /// Set operation mode, External is the defalult mode, where all signals are routed to pins + /// and must be configured connected to define the function of the opamp + fn set_opamp_oper_mode(&self, opmode: opamp_trait::OperationMode) -> opamp_trait::Result { + + match opmode { + opamp_trait::OperationMode::External => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 0 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b00)}); + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + // VM_SEL = 0 (GPIO) + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); + Ok(()) + }, + opamp_trait::OperationMode::Pga => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b11)}); + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + // VM_SEL = 0 (GPIO) + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b10)}); + Ok(()) + }, + opamp_trait::OperationMode::PgaExternalFiltering => { + // disable OPEAN (before changeing anything else) + self.csr.modify(|_, w| w.opaen().clear_bit()); + // set OPAMODE = 2 // pga mode = pga, gain = 2..16 (no filtering in follower mode) + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // VP_SEL = 0 (GPIO) + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + // VM_SEL = 0 (GPIO) for external filtering + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); + Ok(()) + }, + _ => Err(opamp_trait::Error::NotImplemented), + } + } + + /// Connect the input pins of the opamp to DAC or internnaly to follower or leakage-input + fn conect_inputs(&self, vinp: opamp_trait::VINP, vinm: opamp_trait::VINM) -> opamp_trait::Result { + match vinp { + opamp_trait::VINP::ExternalPin1 => { + // VP_SEL = 0 (GPIO), PA0 + self.csr.modify(|_, w| w.vp_sel().clear_bit()); + }, + opamp_trait::VINP::DAC1 => { + // VP_SEL = 1 (DAC1) + self.csr.modify(|_, w| w.vp_sel().set_bit()); + }, + _ => return Err(opamp_trait::Error::NotImplemented), + }; + match vinm { + opamp_trait::VINM::ExternalPin1 => { + // VM_SEL = 0 (GPIO), PA1 for external filtering + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); + }, + opamp_trait::VINM::LeakageInputPin => { + // VM_SEL = 01 + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b01)}); + }, + opamp_trait::VINM::PGA=> { + // VM_SEL = 10 + self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b10)}); + }, + _ => return Err(opamp_trait::Error::NotImplemented), + }; Ok(()) - }, - opamp_trait::OperationMode::PgaADC1ExternalFiltering => { + } + + /// Set the gain in pga mode, the device supports + /// the values 1, 2, 4, 8, 16 all other values are ignored + fn set_pga_gain(&self, gain: u16) -> opamp_trait::Result { + let opaen_state: bool = self.csr.read().opaen().bit_is_set(); // disable OPEAN (before changeing anything else) self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPA_RANGE = 1 (VDDA > 2.4V) - self.csr.modify(|_, w| w.opa_range().set_bit()); - // set OPAMODE = 2 // pga mode = pga, gain = 2..16 (no filtering in follower mode) - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // VP_SEL = 0 (GPIO) - self.csr.modify(|_, w| w.vp_sel().clear_bit()); - // VM_SEL = 0 (GPIO) for external filtering - self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); - Ok(()) - }, - _ => Err(opamp_trait::Error::NotImplemented), - } - // Err(opamp_trait::Error::NotImplemented) - } - fn conect_inputs(&self, vinp: opamp_trait::VINP, vinm: opamp_trait::VINM) -> opamp_trait::Result { - match vinp { - opamp_trait::VINP::ExternalPin1 => { - // VP_SEL = 0 (GPIO), PA0 - self.csr.modify(|_, w| w.vp_sel().clear_bit()); - }, - opamp_trait::VINP::DAC1 => { - // VP_SEL = 0 (GPIO) - self.csr.modify(|_, w| w.vp_sel().set_bit()); - }, - _ => return Err(opamp_trait::Error::NotImplemented), - }; - match vinm { - opamp_trait::VINM::ExternalPin1 => { - // VM_SEL = 0 (GPIO), PA1 for external filtering - self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b00)}); - }, - opamp_trait::VINM::LeakageInputPin => { - // VM_SEL = 0 (GPIO) for external filtering - self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b01)}); - }, - opamp_trait::VINM::PGA=> { - // VM_SEL = 0 (GPIO) for external filtering - self.csr.modify(|_, w| unsafe {w.vm_sel().bits(0b10)}); - }, - _ => return Err(opamp_trait::Error::NotImplemented), - }; - Ok(()) - } + match gain { + 1 => { + // set OPAMODE = 3 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b11)}); + }, + 2 => { + // set OPAMODE = 3 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b00)}); + }, + 4 => { + // set OPAMODE = 3 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b01)}); + }, + 8 => { + // set OPAMODE = 3 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b10)}); + }, + 16 => { + // set OPAMODE = 3 + self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); + // set PGA_GAIN = 2 // follower mode = pga gain = 1 + self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b11)}); + }, + _ => return Err(opamp_trait::Error::NotImplemented), + }; - fn set_pga_gain_enum(&self, gain: opamp_trait::PgaGain) -> opamp_trait::Result { - let opaen_state: bool = self.csr.read().opaen().bit_is_set(); - match gain { - opamp_trait::PgaGain::PgaG1 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b11)}); - }, - opamp_trait::PgaGain::PgaG2 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // set PGA_GAIN = 2 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b00)}); - }, - opamp_trait::PgaGain::PgaG4 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // set PGA_GAIN = 2 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b01)}); - }, - opamp_trait::PgaGain::PgaG8 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // set PGA_GAIN = 2 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b10)}); - }, - opamp_trait::PgaGain::PgaG16 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // set PGA_GAIN = 2 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b11)}); - }, - _ => return Err(opamp_trait::Error::NotImplemented), - }; - if opaen_state == true { - // if it has been enabled before, enable it again - self.csr.modify(|_, w| w.opaen().set_bit()); - } - Ok(()) - } + if opaen_state == true { + // if it has been enabled before, enable it again + self.csr.modify(|_, w| w.opaen().set_bit()); + } + Ok(()) + } - fn set_pga_gain(&self, gain: u16) -> opamp_trait::Result { - let opaen_state: bool = self.csr.read().opaen().bit_is_set(); + /// the function preserves the enable state + /// when the function is called and the opamp is enabled, it is disabled + /// and reenabled after switch the power mode. + /// short incontinous signals may occrue + fn set_power_mode(&self, power_mode: opamp_trait::PowerMode) -> opamp_trait::Result { + let ena_state = self.csr.read().opaen().bit_is_set(); + self.enable(false); + match power_mode { + opamp_trait::PowerMode::Normal => { + // set normal mode + self.csr.modify(|_, w| w.opalpm().clear_bit()); + }, + opamp_trait::PowerMode::LowPower => { + // set normal mode + self.csr.modify(|_, w| w.opalpm().set_bit()); + }, + _ => return Err(opamp_trait::Error::NotImplemented), + }; + if ena_state { + self.enable(true); + } - match gain { - 1 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b11)}); - }, - 2 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // set PGA_GAIN = 2 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b00)}); - }, - 4 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // set PGA_GAIN = 2 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b01)}); - }, - 8 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // set PGA_GAIN = 2 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b10)}); - }, - 16 => { - // disable OPEAN (before changeing anything else) - self.csr.modify(|_, w| w.opaen().clear_bit()); - // set OPAMODE = 3 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.opamode().bits(0b10)}); - // set PGA_GAIN = 2 // follower mode = pga gain = 1 - self.csr.modify(|_, w| unsafe {w.pga_gain().bits(0b11)}); - }, - _ => return Err(opamp_trait::Error::NotImplemented), - }; + Ok(()) + } - if opaen_state == true { - // if it has been enabled before, enable it again - self.csr.modify(|_, w| w.opaen().set_bit()); - } - Ok(()) - } + /// For the calibration to work, the opamp must be enabled and in + /// Calibration must be called for low power and normal mode separately if both + /// are needed + /// USERTRIM is preserved as it is before calling calibrate() + /// the driven load must be below 500uA during calibration + /// and must not be in external filtering mode and PGA-GAIN=1 + fn calibrate(&self, delay: &mut impl DelayUs) -> opamp_trait::Result { + // get USERTRIM bit value + let usertrim = self.csr.read().usertrim().bit(); + // set usertrim bit, so that calibration is possible + self.csr.modify(|_, w| w.usertrim().bit(true)); + // set opamp into callibration mode + self.csr.modify(|_, w| w.calon().set_bit()); + // select PMOS calibration first + self.csr.modify(|_, w| w.calsel().set_bit()); + // read if in LowPower Mode or in normal mode + let low_poer_mode = self.csr.read().opalpm().bit_is_set(); - fn set_power_mode(&self, power_mode: opamp_trait::PowerMode) -> opamp_trait::Result { - match power_mode { - opamp_trait::PowerMode::Normal => { - // set normal mode - self.csr.modify(|_, w| w.opalpm().clear_bit()); - }, - opamp_trait::PowerMode::LowPower => { - // set normal mode - self.csr.modify(|_, w| w.opalpm().set_bit()); - }, - _ => return Err(opamp_trait::Error::NotImplemented), - }; - Ok(()) - } + // set N and P calibration registers to 0 + if low_poer_mode == true { + self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetn().bits(0b00000)}); + self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetp().bits(0b00000)}); + } else { + self.otr.modify(|_, w| unsafe {w.trimoffsetn().bits(0b00000)}); + self.otr.modify(|_, w| unsafe {w.trimoffsetp().bits(0b00000)}); + } - fn calibrate(&self, delay: &mut impl DelayUs) -> opamp_trait::Result { - // set opamp into callibration mode - self.csr.modify(|_, w| w.calon().set_bit()); - // select NMOS calibration first - self.csr.modify(|_, w| w.calsel().clear_bit()); - // read if in LowPower Mode or in normal mode - let low_poer_mode = self.csr.read().opalpm().bit_is_set(); + // increase calibration reg P till it toggles + for i in 0..32 { + if low_poer_mode == true { + self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetp().bits(i)}); + } else { + self.otr.modify(|_, w| unsafe {w.trimoffsetp().bits(i)}); + } - // set N calibration registers to 0 - if low_poer_mode == true { - self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetn().bits(0b00000)}); - } else { - self.otr.modify(|_, w| unsafe {w.trimoffsetn().bits(0b00000)}); - } + compiler_fence(Ordering::SeqCst); + // wait at least 1ms to new config to settle + delay.delay_us(1200); + if self.csr.read().calout().bit_is_set() == false { + break; + } + } + // if this point is reached, an the flag didn't change over the whole range + if self.csr.read().calout().bit_is_set() == true { + return Err(opamp_trait::Error::CalibrationError); + } - // increase calibration reg N till it toggles - while self.csr.read().calout().bit_is_set() == false { - let t_val: u8; - if low_poer_mode == true { - t_val = self.lpotr.read().trimlpoffsetn().bits(); - self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetn().bits(t_val + 1)}); - } else { - t_val = self.otr.read().trimoffsetn().bits(); - self.otr.modify(|_, w| unsafe {w.trimoffsetn().bits(t_val + 1)}); - } - if t_val > 32 { - return Err(opamp_trait::Error::CalibrationError); - } - // wait at least 1ms to new config to settle - delay.delay_us(1200); - } + // select NMOS calibration first + self.csr.modify(|_, w| w.calsel().clear_bit()); + // increase calibration reg N till it toggles + for i in 0..32 { + if low_poer_mode == true { + self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetn().bits(i)}); + } else { + self.otr.modify(|_, w| unsafe {w.trimoffsetn().bits(i)}); + } + compiler_fence(Ordering::SeqCst); + // wait for at least 1ms to settle of Configuration + delay.delay_us(1200); + if self.csr.read().calout().bit_is_set() == true { + break + } + } + if self.csr.read().calout().bit_is_set() == false { + return Err(opamp_trait::Error::CalibrationError); + } + // set opamp into normal mode + self.csr.modify(|_, w| w.calon().clear_bit()); + // restore usertrim bit as it was before caling calibrate() + self.csr.modify(|_, w| w.usertrim().bit(usertrim)); - // select NMOS calibration first - self.csr.modify(|_, w| w.calsel().set_bit()); + Ok(()) + } + /// in calibration mode the calibrated values are used, which were set with calibrate() + /// default is using factory trimmed values which should be good for room temperatures + fn set_calibration_mode(&self, usertrim: bool){ + if usertrim { + self.csr.modify(|_, w| w.usertrim().set_bit()); + } else { + self.csr.modify(|_, w| w.usertrim().clear_bit()); + } + } - // set P calibration registers to 0 - if low_poer_mode == true { - self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetp().bits(0b00000)}); - } else { - self.otr.modify(|_, w| unsafe {w.trimoffsetp().bits(0b00000)}); - } - // increase calibration reg P till it toggles - while self.csr.read().calout().bit_is_set() == false { - let t_val: u8; - if low_poer_mode == true { - t_val = self.lpotr.read().trimlpoffsetp().bits(); - self.lpotr.modify(|_, w| unsafe {w.trimlpoffsetp().bits(t_val + 1)}); - } else { - t_val = self.otr.read().trimoffsetp().bits(); - self.otr.modify(|_, w| unsafe {w.trimoffsetp().bits(t_val + 1)}); - } - // wait at least 1ms to new config to settle - if t_val > 32 { - return Err(opamp_trait::Error::CalibrationError); + /// enable the opamp + fn enable(&self, en: bool) { + compiler_fence(Ordering::SeqCst); + if en { + self.csr.modify(|_, w| w.opaen().set_bit()); + } else { + self.csr.modify(|_, w| w.opaen().clear_bit()); + } + } } - // wait for at least 1ms to settle of Configuration - delay.delay_us(1200); - } - Ok(()) + )* } - fn set_calibration_mode(&self, usertrim: bool){ - if usertrim { - self.csr.modify(|_, w| w.usertrim().set_bit()); - } else { - self.csr.modify(|_, w| w.usertrim().clear_bit()); - } - } - - fn enable(&self, en: bool) { - if en { - self.csr.modify(|_, w| w.opaen().set_bit()); - } else { - self.csr.modify(|_, w| w.opaen().clear_bit()); - } - } } + +opamps!( + OP1, OPAMP1_CSR, OPAMP1_OTR, OPAMP1_LPOTR, OPAMP1_CSR; + OP2, OPAMP2_CSR, OPAMP2_OTR, OPAMP2_LPOTR, OPAMP1_CSR; +); diff --git a/src/traits/opamp.rs b/src/traits/opamp.rs index 01eae15e..46cc09d8 100644 --- a/src/traits/opamp.rs +++ b/src/traits/opamp.rs @@ -1,5 +1,4 @@ - -use crate::hal::{blocking::delay::DelayUs,}; +use crate::hal::blocking::delay::DelayUs; #[derive(Copy, Clone, Debug)] pub enum OPAMPS { @@ -13,15 +12,9 @@ pub enum OperationMode { // wrong values provided External, // PGA mode, (configurable gain) connected to an ADC - PgaADC1, - // pga mode with external filter connected - PgaADC1ExternalFiltering, - // PGA mode, (configurable gain) connected to an ADC - PgaADC2, + Pga, // pga mode with external filter connected - PgaADC2ExternalFiltering, - // // Calibration Modes - // CalibrationMode, + PgaExternalFiltering, // added, that warnings for global match pattern are suppressed SuppressMachtWarnings, } @@ -75,7 +68,7 @@ pub enum PgaGain { PgaG4, PgaG8, PgaG16, - PgaG32, // this values and below may be used for stm32g4 devices + PgaG32, // this values and below may be used for stm32g4 devices PgaG64, PgaG128, PgaG256, @@ -83,8 +76,6 @@ pub enum PgaGain { SuppressMachtWarnings, } - - /// Opamp configuration error #[derive(Copy, Clone, Debug)] pub enum Error { @@ -104,8 +95,6 @@ pub enum Error { SuppressMachtWarnings, } - - /// A type alias for the result of opamp configruation error. pub type Result = core::result::Result<(), Error>; @@ -114,12 +103,11 @@ pub type Result = core::result::Result<(), Error>; // } pub trait ConfigOpamp { - fn set_opamp_oper_mode(&self, opmode: OperationMode) -> Result; fn conect_inputs(&self, vinp: VINP, vinm: VINM) -> Result; - fn set_pga_gain_enum(&self, gain: PgaGain) -> Result; + // fn set_pga_gain_enum(&self, gain: PgaGain) -> Result; fn set_pga_gain(&self, gain: u16) -> Result; From a5337305fd335559e47cc8acca867b8d8fef6fad Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 17:53:01 +0100 Subject: [PATCH 26/35] fmt fixed --- examples/opamp_ext.rs | 9 +++++---- examples/opamp_pga.rs | 5 +---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/examples/opamp_ext.rs b/examples/opamp_ext.rs index c5edd293..7a6e7cd3 100644 --- a/examples/opamp_ext.rs +++ b/examples/opamp_ext.rs @@ -73,14 +73,16 @@ fn main() -> ! { // set operation models let _ret = op1.set_opamp_oper_mode(OperationMode::External).unwrap(); rprintln!("op1 operation mode set..."); - - + op1.enable(true); // =================================================================================== // Debug Info below - rprintln!("opamode OP1: {}\n", ops.opamp1_csr.read().opamode().bits() as u8); + rprintln!( + "opamode OP1: {}\n", + ops.opamp1_csr.read().opamode().bits() as u8 + ); // rprintln!("opaen: {}\n", ops.opamp1_csr.read().opaen().bits() as u8); // rprintln!("opa_range: {}\n", ops.opamp1_csr.read().opa_range().bits() as u8); // rprintln!("vp_sel: {}\n", ops.opamp1_csr.read().vp_sel().bits() as u8); @@ -92,6 +94,5 @@ fn main() -> ! { // rprintln!("usertrim: {}\n", ops.opamp1_csr.read().usertrim().bits() as u8); // rprintln!("pga_gain: {}\n", ops.opamp1_csr.read().pga_gain().bits() as u8); - loop {} } diff --git a/examples/opamp_pga.rs b/examples/opamp_pga.rs index 86251e92..0b157100 100644 --- a/examples/opamp_pga.rs +++ b/examples/opamp_pga.rs @@ -43,8 +43,6 @@ fn main() -> ! { op1.set_pga_gain(2).unwrap(); op1.enable(true); - - // =================================================================================== // Debug Info below rprintln!(" done."); @@ -73,6 +71,5 @@ fn main() -> ! { ops.opamp1_csr.read().pga_gain().bits() as u8 ); - loop { - } + loop {} } From 405f26ef28a0c06d1797ba728e8919176844045c Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 18:25:27 +0100 Subject: [PATCH 27/35] removed dac from this branch --- Cargo.toml | 3 - examples/dac.rs | 82 --------------- src/dac.rs | 267 ------------------------------------------------ src/lib.rs | 7 +- 4 files changed, 1 insertion(+), 358 deletions(-) delete mode 100644 examples/dac.rs delete mode 100644 src/dac.rs diff --git a/Cargo.toml b/Cargo.toml index e3dde1a0..6472f5b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -206,6 +206,3 @@ required-features = ["rt", "stm32l476"] name = "adc_injectedsequence" required-features = ["rt", "stm32l476"] -[[example]] -name = "dac" -required-features = ["rt", "stm32l476"] diff --git a/examples/dac.rs b/examples/dac.rs deleted file mode 100644 index 7ca9d21c..00000000 --- a/examples/dac.rs +++ /dev/null @@ -1,82 +0,0 @@ -// #![deny(warnings)] -#![deny(unsafe_code)] -#![no_main] -#![no_std] - -// use rtt_target::{rprintln, rtt_init_print}; - -// currently only works with these devices -// #[cfg(any(feature = "stm32l476", feature = "stm32l486", feature = "stm32l496", feature = "stm32l4a6"))] - -extern crate cortex_m; -extern crate cortex_m_rt as rt; -extern crate panic_halt; -extern crate stm32l4xx_hal as hal; - -// use hal::dac::GeneratorConfig; -use hal::delay::Delay; -use hal::hal::Direction; -use hal::prelude::*; -// use hal::rcc::Config; -use hal::stm32; -use rt::entry; - -use crate::hal::dac::DacExt; -use crate::hal::dac::DacOut; - -#[entry] -fn main() -> ! { - // rtt_init_print!(); - - let dp = stm32::Peripherals::take().expect("cannot take peripherals"); - let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals"); - - let mut rcc = dp.RCC.constrain(); - let mut flash = dp.FLASH.constrain(); - let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); - let clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr); - let mut delay = Delay::new(cp.SYST, clocks); - - let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); - let pa4 = gpioa.pa4.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); - let pa5 = gpioa.pa5.into_analog(&mut gpioa.moder, &mut gpioa.pupdr); - - #[cfg(any( - feature = "stm32l476", - feature = "stm32l486", - feature = "stm32l496", - feature = "stm32l4a6" - ))] - let (dac0, _dac1) = dp.DAC.constrain((pa4, pa5), &mut rcc.apb1r1); - - #[cfg(not(any( - // feature = "stm32l412", - feature = "stm32l476", - feature = "stm32l486", - feature = "stm32l496", - feature = "stm32l4a6" - )))] - let dac0 = dp.DAC1.constrain(pa4, &mut rcc.apb1r1); - - let mut dac = dac0.calibrate_buffer(&mut delay).enable(); - - // let mut generator = dac1.enable_generator(GeneratorConfig::noise(11)); - - let mut dir = Direction::Upcounting; - let mut val = 0; - - loop { - // generator.trigger(); - dac.set_value(val); - match val { - 0 => dir = Direction::Upcounting, - 4095 => dir = Direction::Downcounting, - _ => (), - }; - - match dir { - Direction::Upcounting => val += 1, - Direction::Downcounting => val -= 1, - } - } -} diff --git a/src/dac.rs b/src/dac.rs deleted file mode 100644 index b53a20c1..00000000 --- a/src/dac.rs +++ /dev/null @@ -1,267 +0,0 @@ -//! DAC - -use core::marker::PhantomData; -use core::mem::MaybeUninit; - -use crate::gpio::gpioa::{PA4, PA5}; -use crate::gpio::Analog; -use crate::hal::blocking::delay::DelayUs; -use crate::rcc::*; -use crate::stm32::DAC; - -pub trait DacOut { - fn set_value(&mut self, val: V); - fn get_value(&mut self) -> V; -} - -pub struct GeneratorConfig { - mode: u8, - amp: u8, -} - -impl GeneratorConfig { - pub fn triangle(amplitude: u8) -> Self { - Self { - mode: 0b10, - amp: amplitude, - } - } - - pub fn noise(seed: u8) -> Self { - Self { - mode: 0b01, - amp: seed, - } - } -} - -/// Enabled DAC (type state) -pub struct Enabled; -/// Enabled DAC without output buffer (type state) -pub struct EnabledUnbuffered; -/// Enabled DAC wave generator (type state) -pub struct WaveGenerator; -/// Disabled DAC (type state) -pub struct Disabled; - -pub trait ED {} -impl ED for Enabled {} -impl ED for EnabledUnbuffered {} -impl ED for WaveGenerator {} -impl ED for Disabled {} - -pub struct Channel1 { - _enabled: PhantomData, -} -pub struct Channel2 { - _enabled: PhantomData, -} - -/// Trait for GPIO pins that can be converted to DAC output pins -pub trait Pins { - type Output; -} - -impl Pins for PA4 { - type Output = Channel1; -} - -impl Pins for PA5 { - type Output = Channel2; -} - -impl Pins for (PA4, PA5) { - type Output = (Channel1, Channel2); -} - -// pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut Rcc::APB1R1) -> PINS::Output -pub fn dac(_dac: DAC, _pins: PINS, rcc: &mut APB1R1) -> PINS::Output -where - PINS: Pins, -{ - DAC::enable(rcc); - DAC::reset(rcc); - - #[allow(clippy::uninit_assumed_init)] - unsafe { - MaybeUninit::uninit().assume_init() - } -} - -macro_rules! dac { - ($($CX:ident: ( - $en:ident, - $cen:ident, - $cal_flag:ident, - $trim:ident, - $mode:ident, - $dhrx:ident, - $dac_dor:ident, - $daccxdhr:ident, - $wave:ident, - $mamp:ident, - $ten:ident, - $swtrig:ident - ),)+) => { - $( - impl $CX { - pub fn enable(self) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; - - dac.mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); - dac.cr.modify(|_, w| w.$en().set_bit()); - - $CX { - _enabled: PhantomData, - } - } - - pub fn enable_unbuffered(self) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; - - dac.mcr.modify(|_, w| unsafe { w.$mode().bits(2) }); - dac.cr.modify(|_, w| w.$en().set_bit()); - - $CX { - _enabled: PhantomData, - } - } - - pub fn enable_generator(self, config: GeneratorConfig) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; - - dac.mcr.modify(|_, w| unsafe { w.$mode().bits(1) }); - dac.cr.modify(|_, w| unsafe { - w.$wave().bits(config.mode); - w.$ten().set_bit(); - w.$mamp().bits(config.amp); - w.$en().set_bit() - }); - - $CX { - _enabled: PhantomData, - } - } - } - - impl $CX { - /// Calibrate the DAC output buffer by performing a "User - /// trimming" operation. It is useful when the VDDA/VREF+ - /// voltage or temperature differ from the factory trimming - /// conditions. - /// - /// The calibration is only valid when the DAC channel is - /// operating with the buffer enabled. If applied in other - /// modes it has no effect. - /// - /// After the calibration operation, the DAC channel is - /// disabled. - pub fn calibrate_buffer(self, delay: &mut T) -> $CX - where - T: DelayUs, - { - let dac = unsafe { &(*DAC::ptr()) }; - 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.ccr.modify(|_, w| unsafe { w.$trim().bits(trim) }); - delay.delay_us(64_u32); - if dac.sr.read().$cal_flag().bit() { - break; - } - trim += 1; - } - dac.cr.modify(|_, w| w.$cen().clear_bit()); - - $CX { - _enabled: PhantomData, - } - } - - /// Disable the DAC channel - pub fn disable(self) -> $CX { - let dac = unsafe { &(*DAC::ptr()) }; - dac.cr.modify(|_, w| unsafe { - w.$en().clear_bit().$wave().bits(0).$ten().clear_bit() - }); - - $CX { - _enabled: PhantomData, - } - } - } - - /// DacOut implementation available in any Enabled/Disabled - /// state - 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) }); - } - - fn get_value(&mut self) -> u16 { - let dac = unsafe { &(*DAC::ptr()) }; - dac.$dac_dor.read().bits() as u16 - } - } - - /// Wave generator state implementation - impl $CX { - pub fn trigger(&mut self) { - let dac = unsafe { &(*DAC::ptr()) }; - dac.swtrigr.write(|w| { w.$swtrig().set_bit() }); - } - } - )+ - }; -} - -pub trait DacExt { - fn constrain(self, pins: PINS, rcc: &mut APB1R1) -> PINS::Output - where - PINS: Pins; -} - -impl DacExt for DAC { - fn constrain(self, pins: PINS, rcc: &mut APB1R1) -> PINS::Output - where - PINS: Pins, - { - dac(self, pins, rcc) - } -} - -dac!( - Channel1: - ( - en1, - cen1, - cal_flag1, - otrim1, - mode1, - dhr12r1, - dor1, - dacc1dhr, - wave1, - mamp1, - ten1, - swtrig1 - ), - Channel2: - ( - en2, - cen2, - cal_flag2, - otrim2, - mode2, - dhr12r2, - dor2, - dacc2dhr, - wave2, - mamp2, - ten2, - swtrig2 - ), -); diff --git a/src/lib.rs b/src/lib.rs index efad7ba1..8ab87aeb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,12 +128,7 @@ pub mod adc; pub mod can; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod crc; -#[cfg(any( - feature = "stm32l476", - feature = "stm32l486", - feature = "stm32l496", - feature = "stm32l4a6" -))] + pub mod dac; pub mod datetime; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] From a245a8408217a932e9fc755bcaca9f627d827f29 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 18:52:07 +0100 Subject: [PATCH 28/35] fix lib error --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 8ab87aeb..c57b2057 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -129,7 +129,6 @@ pub mod can; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod crc; -pub mod dac; pub mod datetime; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod delay; From 1c72eed4422780060963e81edacff0e1ac83ba05 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 18:58:07 +0100 Subject: [PATCH 29/35] adc with minimal adaption for opamp use --- src/adc.rs | 282 ++--------------------------------------------------- 1 file changed, 9 insertions(+), 273 deletions(-) diff --git a/src/adc.rs b/src/adc.rs index d6a6bc6d..a69691a6 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -51,7 +51,6 @@ pub enum DmaMode { Oneshot = 1, // FIXME: Figure out how to get circular DMA to function properly (requires circbuffer?) // Circular = 2, - ExtTrigger = 3, } #[derive(PartialEq, PartialOrd, Clone, Copy)] @@ -121,37 +120,6 @@ impl Into for Sequence { } } -#[derive(PartialEq, PartialOrd, Clone, Copy)] -pub enum Jsequence { - One = 0, - Two = 1, - Three = 2, - Four = 3, -} - -impl From for Jsequence { - fn from(bits: u8) -> Self { - match bits { - 0 => Jsequence::One, - 1 => Jsequence::Two, - 2 => Jsequence::Three, - 3 => Jsequence::Four, - _ => unimplemented!(), - } - } -} - -impl Into for Jsequence { - fn into(self) -> u8 { - match self { - Jsequence::One => 0, - Jsequence::Two => 1, - Jsequence::Three => 2, - Jsequence::Four => 3, - } - } -} - #[derive(PartialEq, PartialOrd, Clone, Copy)] pub enum Event { EndOfRegularSequence, @@ -321,7 +289,7 @@ impl ADC { /// Convert a measurement to millivolts pub fn to_millivolts(&self, sample: u16) -> u16 { - ((u32::from(sample) * self.calibrated_vdda) / self.resolution.tomax_count()) as u16 + ((u32::from(sample) * self.calibrated_vdda) / self.resolution.to_max_count()) as u16 } /// Convert a raw sample from the `Temperature` to deg C @@ -396,52 +364,6 @@ impl ADC { } } - /// Configure the channel for a specific step in the sequence. - /// - /// Automatically sets the sequence length to the farthes sequence - /// index that has been used so far. Use [`ADC::reset_jsequence`] to - /// reset the sequence length. - pub fn configure_jsequence( - &mut self, - channel: &mut C, - sequence: Jsequence, - sample_time: SampleTime, - ) where - C: Channel, - { - let channel_bits = C::channel(); - channel.set_sample_time(&self.adc, sample_time); - - unsafe { - // This is sound as channel() always returns a valid channel number - match sequence { - Jsequence::One => self.adc.jsqr.modify(|_, w| w.jsq1().bits(channel_bits)), - Jsequence::Two => self.adc.jsqr.modify(|_, w| w.jsq2().bits(channel_bits)), - Jsequence::Three => self.adc.jsqr.modify(|_, w| w.jsq3().bits(channel_bits)), - Jsequence::Four => self.adc.jsqr.modify(|_, w| w.jsq4().bits(channel_bits)), - } - } - - // This will only ever extend the sequence, not shrink it. - let current_seql = self.get_jsequence_length(); - let next_seql: u8 = sequence.into(); - if next_seql >= current_seql { - // Note: sequence length of 0 = 1 conversion - self.set_jsequence_length(sequence.into()); - } - } - - /// Get the configured sequence length (= `actual sequence length - 1`) - pub(crate) fn get_jsequence_length(&self) -> u8 { - self.adc.jsqr.read().jl().bits() - } - - /// Private: length must be `actual sequence length - 1`, so not API-friendly. - /// Use [`ADC::reset_sequence`] and [`ADC::configure_sequence`] instead - fn set_jsequence_length(&mut self, length: u8) { - self.adc.jsqr.modify(|_, w| unsafe { w.jl().bits(length) }); - } - /// Get the configured sequence length (= `actual sequence length - 1`) pub(crate) fn get_sequence_length(&self) -> u8 { self.adc.sqr1.read().l().bits() @@ -526,171 +448,6 @@ impl ADC { pub fn disable(&mut self) { self.adc.cr.modify(|_, w| w.addis().set_bit()); } - - /// channels for external triggers - /// TIM1_CH1 0b0000 - /// TIM1_CH2 0b0001 - /// TIM1_CH3 0b0010 - /// TIM2_CH2 0b0011 - /// TIM3_TRGO 0b0100 (not on all chips available) - /// EXTI line 11 0b0110 - /// TIM8_TRGO 0b0111 - /// TIM8_TRGO2 0b1000 - /// TIM1_TRGO 0b1001 - /// TIM1_TRGO2 0b1010 - /// TIM2_TRGO 0b1011 - /// TIM4_TRGO 0b1100 - /// TIM6_TRGO 0b1101 - /// TIM15_TRGO 0b1110 - /// TIM3_CH4 0b1111 - /// these bits are only allowed to be set, when ADC is disabled - /// set edge of injected trigger by timers - /// None 0b00 - /// Positive edge 0b01 - /// Negative edge 0b10 - /// both edges 0b11 - pub fn set_external_trigger(&mut self, ch: u8, edge: u8) { - if self.adc.cr.read().adstart().bit_is_clear() { - self.adc.cfgr.modify(|_, w| unsafe { w.extsel().bits(ch) }); - - self.adc.cfgr.modify(|_, w| unsafe { w.exten().bits(edge) }); // 1 as u8 - } - } - - /// channels for injection Transmitter - /// TIM1_TRGO 0b0000 - /// TIM1_CH4 0b0001 - /// TIM2_TRGO 0b0010 - /// TIM2_CH1 0b0011 - /// TIM3_CH4 0b0100 (not on all chips available) - /// EXTI line 15 0b0110 - /// TIM1_TRGO2 0b1000 - /// TIM6_TRGO 0b1110 - /// TIM15_TRGO 0b1111 - /// set edge of injected trigger by timers - /// None 0b00 - /// Positive edge 0b01 - /// Negative edge 0b10 - /// both edges 0b11 - pub fn set_inject_channel(&mut self, ch: u8, edge: u8) { - self.adc.jsqr.modify(|_, w| unsafe { w.jextsel().bits(ch) }); - - self.adc - .jsqr - .modify(|_, w| unsafe { w.jexten().bits(edge) }); // 1 as u8 - } - - pub fn start_injected(&mut self) { - if !self.is_injected_mod_enabled() { - while self.adc.cr.read().addis().bit_is_set() {} - self.adc.ier.modify(|_, w| w.jeocie().set_bit()); // end of sequence interupt enable - self.adc.cr.modify(|_, w| w.aden().set_bit()); - self.adc.cr.modify(|_, w| w.jadstart().set_bit()); - // ADSTART bit is cleared to 0 bevor using this function - while self.adc.isr.read().adrdy().bit_is_clear() {} - } - } - - pub fn start_injected_sequence(&mut self) { - if !self.is_injected_mod_enabled() { - while self.adc.cr.read().addis().bit_is_set() {} - self.adc.ier.modify(|_, w| w.jeosie().set_bit()); // end of sequence interupt enable - - self.adc.cr.modify(|_, w| w.aden().set_bit()); - while self.adc.isr.read().adrdy().bit_is_clear() {} - self.adc.cr.modify(|_, w| w.jadstart().set_bit()); - // ADSTART bit is cleared to 0 bevor using this function - - // clear end of sequencd conversion interrupt flag - } - } - - pub fn is_injected_mod_enabled(&self) -> bool { - self.adc.cr.read().jadstart().bit_is_set() - } - - pub fn stop_injected(&mut self) { - // ?????? or is it reset after each conversion? - self.adc.cr.modify(|_, w| w.jadstp().set_bit()); - // self.adc.cr.modify(|_, w| w.jadstp().set_bit()); - // ADSTART bit is cleared to 0 bevor using this function - // disable EOS interrupt - // maybe self.rb.cr.adstp().set_bit() must be performed before interrupt is disabled + wait abortion - self.adc.ier.modify(|_, w| w.jeocie().clear_bit()); // end of sequence interupt disable - } - - pub fn stop_injected_sequence(&mut self) { - // ?????? or is it reset after each conversion? - self.adc.cr.modify(|_, w| w.jadstp().set_bit()); - // self.adc.cr.modify(|_, w| w.jadstp().set_bit()); - // ADSTART bit is cleared to 0 bevor using this function - // disable EOS interrupt - // maybe self.rb.cr.adstp().set_bit() must be performed before interrupt is disabled + wait abortion - self.adc.ier.modify(|_, w| w.jeosie().clear_bit()); // end of sequence interupt disable - } - - pub fn get_injected_jdr(&mut self, jdrx: u8) -> u16 { - match jdrx { - 1 => self.adc.jdr1.read().jdata1().bits() as u16, - 2 => self.adc.jdr2.read().jdata2().bits() as u16, - 3 => self.adc.jdr3.read().jdata3().bits() as u16, - 4 => self.adc.jdr4.read().jdata4().bits() as u16, - _ => 0xffff_u16, - } - } - - /// Reset the jsequence length to 1 - /// - /// Does *not* erase previously configured sequence settings, only - /// changes the sequence length - pub fn reset_jsequence(&mut self) { - self.adc.jsqr.modify(|_, w| unsafe { w.jl().bits(0b00) }) - } - - /// clear jeos interrupt flag - pub fn set_jeos(&mut self) { - self.adc.isr.modify(|_, w| w.jeos().set_bit()); - } - - /// Oversampling of adc according to datasheet of stm32g0, when oversampling is enabled - /// 000: 2x - /// 001: 4x - /// 010: 8x - /// 011: 16x - /// 100: 32x - /// 101: 64x - /// 110: 128x - /// 111: 256x - pub fn set_oversampling_ratio(&mut self, multyply: u8) { - self.adc - .cfgr2 - .modify(|_, w| unsafe { w.ovsr().bits(multyply) }); - } - - /// Oversampling shif configurations - /// 0000: No shift - /// 0001: Shift 1-bit - /// 0010: Shift 2-bits - /// 0011: Shift 3-bits - /// 0100: Shift 4-bits - /// 0101: Shift 5-bits - /// 0110: Shift 6-bits - /// 0111: Shift 7-bits - /// 1000: Shift 8-bits - /// Other codes reserved - pub fn set_oversampling_shift(&mut self, nrbits: u8) { - self.adc - .cfgr2 - .modify(|_, w| unsafe { w.ovss().bits(nrbits) }); - } - - pub fn oversampling_enable(&mut self) { - self.adc.cfgr2.modify(|_, w| w.rovse().set_bit()); - } - - pub fn inject_oversampling_enable(&mut self) { - self.adc.cfgr2.modify(|_, w| w.jovse().set_bit()); - } } impl OneShot for ADC @@ -769,10 +526,9 @@ where ) -> Self { assert!(dma_mode != DmaMode::Disabled); - let (enable, circular, exttrig) = match dma_mode { - DmaMode::Disabled => (false, false, false), - DmaMode::Oneshot => (true, false, false), - DmaMode::ExtTrigger => (true, false, true), + let (enable, circular) = match dma_mode { + DmaMode::Disabled => (false, false), + DmaMode::Oneshot => (true, false), }; adc.adc @@ -784,45 +540,29 @@ where // SAFETY: since the length of BUFFER is known to be `N`, we are allowed // to perform N transfers into said buffer channel.set_memory_address(buffer.as_ptr() as u32, true); - channel.set_transfer_length(N as u16); // N is buffer legnth + channel.set_transfer_length(N as u16); channel.cselr().modify(|_, w| w.c1s().bits(0b0000)); channel.ccr().modify(|_, w| unsafe { w.mem2mem() - // clear memory to memory mode .clear_bit() - // dma priority: 00: Low, 01: Medium, 10: High, 11: Very high + // 00: Low, 01: Medium, 10: High, 11: Very high .pl() .bits(0b01) - // dma transfer size: 00: 8-bits, 01: 16-bits, 10: 32-bits, 11: Reserved + // 00: 8-bits, 01: 16-bits, 10: 32-bits, 11: Reserved .msize() .bits(0b01) - // dma periferal transer size: 00: 8-bits, 01: 16-bits, 10: 32-bits, 11: Reserved + // 00: 8-bits, 01: 16-bits, 10: 32-bits, 11: Reserved .psize() .bits(0b01) // Peripheral -> Mem .dir() .clear_bit() - // memory increment mode - .minc() - .clear_bit() - // peripheral increment mode - .pinc() - .clear_bit() - // set circual mode as defined in DMAmode .circ() .bit(circular) }); - // read ADC sequence length - let sequence_length = adc.adc.sqr1.read().l().bits(); - // buffer increment bit in memory, if dma with several sequential reads are performed - if sequence_length > 0 && exttrig { - // memory increment mode - channel.ccr().modify(|_, w| w.minc().set_bit()); - } - if transfer_complete_interrupt { channel.listen(DMAEvent::TransferComplete); } @@ -830,7 +570,6 @@ where atomic::compiler_fence(Ordering::Release); channel.start(); - adc.start_conversion(); Transfer::w( @@ -868,7 +607,7 @@ impl Default for Resolution { } impl Resolution { - fn tomax_count(&self) -> u32 { + fn to_max_count(&self) -> u32 { match self { Resolution::Bits12 => (1 << 12) - 1, Resolution::Bits10 => (1 << 10) - 1, @@ -955,9 +694,6 @@ macro_rules! adc_pins { }; } -// smprx : sample time main register -// smpx : smple tim channel value register - adc_pins!( 0, Vref, smpr1, smp0; 1, gpio::PC0, smpr1, smp1; From 02ed97cf03f8723b3080c139a6a91fa4f8a6fbec Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 19:04:32 +0100 Subject: [PATCH 30/35] unwrap() added in adc_opamp1 --- examples/adc_opamp1.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/adc_opamp1.rs b/examples/adc_opamp1.rs index fff10dab..f493a43f 100644 --- a/examples/adc_opamp1.rs +++ b/examples/adc_opamp1.rs @@ -48,9 +48,9 @@ fn main() -> ! { &rcc.apb1r1, ); - op1.set_opamp_oper_mode(OperationMode::Pga); + op1.set_opamp_oper_mode(OperationMode::Pga).unwrap(); // set pga gain - op1.set_pga_gain(16); + op1.set_pga_gain(2).unwrap(); op1.enable(true); rprintln!(" done."); From 25cc29e47a0e0206036e2cdafa7cd91fadf91286 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 19:10:13 +0100 Subject: [PATCH 31/35] added deny in examples --- examples/adc_opamp1.rs | 2 ++ examples/opamp_ext.rs | 4 ++-- examples/opamp_pga.rs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/adc_opamp1.rs b/examples/adc_opamp1.rs index f493a43f..e456436b 100644 --- a/examples/adc_opamp1.rs +++ b/examples/adc_opamp1.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_code)] +#![deny(warnings)] #![no_main] #![no_std] diff --git a/examples/opamp_ext.rs b/examples/opamp_ext.rs index 7a6e7cd3..ccae329f 100644 --- a/examples/opamp_ext.rs +++ b/examples/opamp_ext.rs @@ -1,5 +1,5 @@ -// #![deny(unsafe_code)] -// #![deny(warnings)] +#![deny(unsafe_code)] +#![deny(warnings)] #![no_main] #![no_std] diff --git a/examples/opamp_pga.rs b/examples/opamp_pga.rs index 0b157100..e078ba8b 100644 --- a/examples/opamp_pga.rs +++ b/examples/opamp_pga.rs @@ -1,5 +1,5 @@ #![deny(unsafe_code)] -// #![deny(warnings)] +#![deny(warnings)] #![no_main] #![no_std] From c6ffb015cb963da3b2ebadd6418cfcfede48bfc5 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 19:14:43 +0100 Subject: [PATCH 32/35] remove adc examples, where no features are implemented --- Cargo.toml | 8 -- examples/adc_injectedsequence.rs | 123 ----------------------------- examples/adc_timer2_dma_seq.rs | 128 ------------------------------- 3 files changed, 259 deletions(-) delete mode 100644 examples/adc_injectedsequence.rs delete mode 100644 examples/adc_timer2_dma_seq.rs diff --git a/Cargo.toml b/Cargo.toml index 6472f5b1..6ae4c951 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -198,11 +198,3 @@ required-features = ["rt"] name = "adc_dma" required-features = ["rt"] -[[example]] -name = "adc_timer2_dma_seq" -required-features = ["rt", "stm32l476"] - -[[example]] -name = "adc_injectedsequence" -required-features = ["rt", "stm32l476"] - diff --git a/examples/adc_injectedsequence.rs b/examples/adc_injectedsequence.rs deleted file mode 100644 index 244167cb..00000000 --- a/examples/adc_injectedsequence.rs +++ /dev/null @@ -1,123 +0,0 @@ -#![no_main] -#![no_std] - -extern crate stm32l4; - -use panic_rtt_target as _; -use rtt_target::{rprintln, rtt_init_print}; -use stm32l4xx_hal::{ - adc::{Jsequence, SampleTime, ADC}, - delay::DelayCM, - pac::TIM2, - prelude::*, - time::Hertz, - timer::Timer, -}; - -use rtic::app; - -#[app(device = stm32l4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] -const APP: () = { - // RTIC app is written in here! - - struct Resources { - adc: stm32l4xx_hal::adc::ADC, - } - - #[init] - fn init(cx: init::Context) -> init::LateResources { - rtt_init_print!(); - - rprintln!("Hello from init!"); - - let cp = cx.core; - let mut dcb = cp.DCB; - let mut dwt = cp.DWT; - - dcb.enable_trace(); - dwt.enable_cycle_counter(); - - let pac = cx.device; - - let mut rcc = pac.RCC.constrain(); - let mut flash = pac.FLASH.constrain(); - let mut pwr = pac.PWR.constrain(&mut rcc.apb1r1); - - // - // Initialize the clocks - // - let clocks = rcc - .cfgr - .sysclk(Hertz(80_000_000)) - .freeze(&mut flash.acr, &mut pwr); - - let mut delay = DelayCM::new(clocks); - - let mut adc = ADC::new( - pac.ADC1, - pac.ADC_COMMON, - &mut rcc.ahb2, - &mut rcc.ccipr, - &mut delay, - ); - - let mut temp_pin = adc.enable_temperature(&mut delay); - - let mut gpioc = pac.GPIOC.split(&mut rcc.ahb2); - let mut pc0 = gpioc.pc0.into_analog(&mut gpioc.moder, &mut gpioc.pupdr); - - adc.configure_jsequence(&mut temp_pin, Jsequence::One, SampleTime::Cycles247_5); - adc.configure_jsequence(&mut pc0, Jsequence::Two, SampleTime::Cycles247_5); - adc.configure_jsequence(&mut temp_pin, Jsequence::Three, SampleTime::Cycles640_5); - adc.configure_jsequence(&mut temp_pin, Jsequence::Four, SampleTime::Cycles12_5); - - // optional oversampling settings (added, otherwise the first sampling is wrong due to adc errata in L4) - adc.set_oversampling_ratio(7); - adc.set_oversampling_shift(8); - adc.inject_oversampling_enable(); - - // set injection trigger source to timer2 TRGO and rising edge - adc.set_inject_channel(2_u8, 1_u8); - - adc.start_injected_sequence(); - - // start the timer - let mut _timer = Timer::tim2(pac.TIM2, 1.hz(), clocks, &mut rcc.apb1r1); - - // Set timer output to trigger signal to ADC for start of sampling sequence - unsafe { - // get pointer of timer 2 - let tim = &(*TIM2::ptr()); - // config master mode selection to TRGO to Compare Pulse of timer2 - tim.cr2.modify(|_, w| w.mms().bits(3_u8)); - tim.dier.write(|w| w.ude().set_bit()); - } - - init::LateResources { adc } - } - - #[idle] - fn idle(_cx: idle::Context) -> ! { - loop { - cortex_m::asm::nop(); - } - } - - // when sequence of adc has finished, the data can be fetched from the - // injected data registers - #[task(binds = ADC1_2, resources = [adc] )] - fn adc1_irg(cx: adc1_irg::Context) { - let adc1 = cx.resources.adc; - - let jdr1_val = adc1.get_injected_jdr(1_u8); - let jdr2_val = adc1.get_injected_jdr(2_u8); - let jdr3_val = adc1.get_injected_jdr(3_u8); - let jdr4_val = adc1.get_injected_jdr(4_u8); - rprintln!("jdr1: {}", jdr1_val); - rprintln!("jdr2: {}", jdr2_val); - rprintln!("jdr3: {}", jdr3_val); - rprintln!("jdr4: {}", jdr4_val); - - adc1.set_jeos(); - } -}; diff --git a/examples/adc_timer2_dma_seq.rs b/examples/adc_timer2_dma_seq.rs deleted file mode 100644 index 61dd46db..00000000 --- a/examples/adc_timer2_dma_seq.rs +++ /dev/null @@ -1,128 +0,0 @@ -#![no_main] -#![no_std] - -use panic_rtt_target as _; -use rtt_target::{rprintln, rtt_init_print}; -use stm32l4xx_hal::{ - adc::{DmaMode, SampleTime, Sequence, ADC}, - delay::DelayCM, - dma::{dma1, RxDma, Transfer, W}, - prelude::*, - time::Hertz, - timer::Timer, // Event, -}; - -use rtic::app; - -const SEQUENCE_LEN: usize = 4; - -#[app(device = stm32l4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] -const APP: () = { - // RTIC app is written in here! - - struct Resources { - transfer: Option>>, - } - - #[init] - fn init(cx: init::Context) -> init::LateResources { - let MEMORY = { - static mut MEMORY: [u16; SEQUENCE_LEN] = [0u16; SEQUENCE_LEN]; - unsafe { &mut MEMORY } - }; - - rtt_init_print!(); - - rprintln!("Hello from init!"); - - let cp = cx.core; - let mut dcb = cp.DCB; - let mut dwt = cp.DWT; - - dcb.enable_trace(); - dwt.enable_cycle_counter(); - - let pac = cx.device; - - let mut rcc = pac.RCC.constrain(); - let mut flash = pac.FLASH.constrain(); - let mut pwr = pac.PWR.constrain(&mut rcc.apb1r1); - let dma_channels = pac.DMA1.split(&mut rcc.ahb1); - - // - // Initialize the clocks - // - let clocks = rcc - .cfgr - .sysclk(Hertz(80_000_000)) - .freeze(&mut flash.acr, &mut pwr); - - let mut delay = DelayCM::new(clocks); - - let mut adc = ADC::new( - pac.ADC1, - pac.ADC_COMMON, - &mut rcc.ahb2, - &mut rcc.ccipr, - &mut delay, - ); - - let mut temp_pin = adc.enable_temperature(&mut delay); - - let dma1_channel = dma_channels.1; - // let adc_buffer1_addr = MEMORY.as_ptr(); - let mut gpioc = pac.GPIOC.split(&mut rcc.ahb2); - let mut pc0 = gpioc.pc0.into_analog(&mut gpioc.moder, &mut gpioc.pupdr); - - adc.configure_sequence(&mut temp_pin, Sequence::One, SampleTime::Cycles12_5); - adc.configure_sequence(&mut temp_pin, Sequence::Two, SampleTime::Cycles247_5); - adc.configure_sequence(&mut temp_pin, Sequence::Three, SampleTime::Cycles640_5); - adc.configure_sequence(&mut pc0, Sequence::Four, SampleTime::Cycles640_5); - - // optional oversampling settings - adc.set_oversampling_ratio(7); - adc.set_oversampling_shift(8); - adc.oversampling_enable(); - - adc.set_external_trigger(0b1011, 1_u8); // Timer2_TRGO - - // Heapless boxes also work very well as buffers for DMA transfers - let transfer = Transfer::from_adc(adc, dma1_channel, MEMORY, DmaMode::ExtTrigger, true); - - // unsafe { NVIC::unmask(stm32l4xx_hal::stm32::Interrupt::TIM2) }; - let _timer = Timer::tim2(pac.TIM2, 1.hz(), clocks, &mut rcc.apb1r1); - unsafe { - // get pointer of timer 2 - let tim = &(*stm32l4::stm32l4x6::TIM2::ptr()); - // config master mode selection to TRGO to Compare Pulse of timer2 - tim.cr2.modify(|_, w| w.mms().bits(3_u8)); - tim.dier.write(|w| w.ude().set_bit()); - } - - init::LateResources { - transfer: Some(transfer), - } - } - - #[idle] - fn idle(_cx: idle::Context) -> ! { - loop { - cortex_m::asm::nop(); - } - } - - #[task(binds = DMA1_CH1, resources = [transfer])] - fn dma1_interrupt(cx: dma1_interrupt::Context) { - let transfer = cx.resources.transfer; - if let Some(transfer_val) = transfer.take() { - let (buffer, rx_dma) = transfer_val.wait(); - rprintln!("DMA measurements: {:?}", buffer); - *transfer = Some(Transfer::from_adc_dma( - rx_dma, - buffer, - DmaMode::ExtTrigger, - true, - )); - } - } -}; From 0293cd2cf1a12873d8840962d7d08a76094d80e5 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 19:20:45 +0100 Subject: [PATCH 33/35] deny warnings removed, need empty loop{} statement --- examples/opamp_ext.rs | 2 +- examples/opamp_pga.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/opamp_ext.rs b/examples/opamp_ext.rs index ccae329f..f8123fbc 100644 --- a/examples/opamp_ext.rs +++ b/examples/opamp_ext.rs @@ -1,5 +1,5 @@ #![deny(unsafe_code)] -#![deny(warnings)] +// #![deny(warnings)] #![no_main] #![no_std] diff --git a/examples/opamp_pga.rs b/examples/opamp_pga.rs index e078ba8b..0b157100 100644 --- a/examples/opamp_pga.rs +++ b/examples/opamp_pga.rs @@ -1,5 +1,5 @@ #![deny(unsafe_code)] -#![deny(warnings)] +// #![deny(warnings)] #![no_main] #![no_std] From da0d4d61156fa27f38436cc72ad10cb626a9a507 Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 19:25:26 +0100 Subject: [PATCH 34/35] add opamp testing --- .github/workflows/rustfmt_opamp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rustfmt_opamp.yml b/.github/workflows/rustfmt_opamp.yml index 102f0e3d..7b035804 100644 --- a/.github/workflows/rustfmt_opamp.yml +++ b/.github/workflows/rustfmt_opamp.yml @@ -1,6 +1,6 @@ on: push: - branches: [ master ] + branches: [ opamp ] pull_request: name: Code formatting check From 902371464232febdac81ffdb7913ecbda9f1acaf Mon Sep 17 00:00:00 2001 From: oldsheep68 Date: Sat, 5 Feb 2022 19:30:09 +0100 Subject: [PATCH 35/35] formatting stuff --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c57b2057..92255019 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -142,6 +142,8 @@ pub mod gpio; pub mod i2c; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod lptimer; +#[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] +pub mod opamp; #[cfg(all( feature = "otg_fs", any( @@ -154,8 +156,6 @@ pub mod lptimer; ))] pub mod otg_fs; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] -pub mod opamp; -#[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod prelude; #[cfg(not(any(feature = "stm32l4r9", feature = "stm32l4s9",)))] pub mod pwm;