2024-03-22 17:44:06 +08:00
|
|
|
use core::ptr::addr_of_mut;
|
2024-04-23 17:09:26 +08:00
|
|
|
|
2023-12-21 13:13:06 +08:00
|
|
|
use fugit::KilohertzU32;
|
2024-04-23 17:09:26 +08:00
|
|
|
use stm32f4xx_hal::{adc::{config::{self, AdcConfig},
|
|
|
|
Adc},
|
|
|
|
dma::{config::DmaConfig, PeripheralToMemory, Stream2, StreamsTuple, Transfer as DMA_Transfer},
|
|
|
|
gpio::{gpioa::*, gpiob::*, gpioc::*, Analog, Output, PushPull},
|
|
|
|
hal::{digital::OutputPin, spi::SpiBus},
|
|
|
|
interrupt,
|
|
|
|
pac::{Peripherals, ADC1, ADC2, DMA2, NVIC, SPI1, TIM4},
|
|
|
|
spi::Spi,
|
|
|
|
timer::pwm::PwmChannel};
|
|
|
|
use uom::si::{electric_potential::millivolt, f32::ElectricPotential, ratio::ratio};
|
|
|
|
|
2024-07-10 18:16:03 +08:00
|
|
|
use crate::{device::sys_timer::sleep, thermostat::ad5680};
|
2023-12-20 12:08:48 +08:00
|
|
|
|
2023-12-21 13:13:06 +08:00
|
|
|
pub const PWM_FREQ_KHZ: KilohertzU32 = KilohertzU32::from_raw(20);
|
|
|
|
|
|
|
|
pub trait ChannelPins {
|
2024-03-22 17:44:06 +08:00
|
|
|
type DacSpi: SpiBus<u8>;
|
2023-12-21 13:13:06 +08:00
|
|
|
type DacSync: OutputPin;
|
|
|
|
type ShdnPin: OutputPin;
|
|
|
|
type VRefPin;
|
|
|
|
type ItecPin;
|
|
|
|
type DacFeedbackPin;
|
|
|
|
type VTecPin;
|
|
|
|
type MaxVPin;
|
|
|
|
type MaxIPosPin;
|
|
|
|
type MAXINegPin;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Channel0;
|
|
|
|
|
|
|
|
impl ChannelPins for Channel0 {
|
|
|
|
type DacSpi = DacSpi;
|
|
|
|
type DacSync = DacSync;
|
|
|
|
type ShdnPin = PA5<Output<PushPull>>;
|
|
|
|
type VRefPin = PA6<Analog>;
|
|
|
|
type ItecPin = PB1<Analog>;
|
2024-01-24 11:21:34 +08:00
|
|
|
type DacFeedbackPin = PC0<Analog>;
|
2023-12-21 13:13:06 +08:00
|
|
|
type VTecPin = PB0<Analog>;
|
|
|
|
type MaxVPin = PwmChannel<TIM4, 1>;
|
|
|
|
type MaxIPosPin = PwmChannel<TIM4, 2>;
|
|
|
|
type MAXINegPin = PwmChannel<TIM4, 0>;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct MAX1968Phy<C: ChannelPins> {
|
|
|
|
pub dac: ad5680::Dac<C::DacSpi, C::DacSync>,
|
|
|
|
pub shdn: C::ShdnPin,
|
|
|
|
pub vref_pin: C::VRefPin,
|
|
|
|
pub itec_pin: C::ItecPin,
|
|
|
|
pub dac_feedback_pin: C::DacFeedbackPin,
|
|
|
|
pub vtec_pin: C::VTecPin,
|
|
|
|
pub max_v: C::MaxVPin,
|
|
|
|
pub max_i_pos: C::MaxIPosPin,
|
|
|
|
pub max_i_neg: C::MAXINegPin,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct MAX1968PinSet<C: ChannelPins> {
|
|
|
|
pub dac: ad5680::Dac<C::DacSpi, C::DacSync>,
|
|
|
|
pub shdn: C::ShdnPin,
|
|
|
|
pub vref_pin: C::VRefPin,
|
|
|
|
pub itec_pin: C::ItecPin,
|
|
|
|
pub dac_feedback_pin: C::DacFeedbackPin,
|
|
|
|
pub vtec_pin: C::VTecPin,
|
|
|
|
pub max_v: C::MaxVPin,
|
|
|
|
pub max_i_pos: C::MaxIPosPin,
|
|
|
|
pub max_i_neg: C::MAXINegPin,
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
|
|
|
|
2024-03-22 17:44:06 +08:00
|
|
|
type DacSpi = Spi<SPI1>;
|
2023-12-20 12:08:48 +08:00
|
|
|
type DacSync = PB4<Output<PushPull>>;
|
|
|
|
|
2024-03-15 14:45:19 +08:00
|
|
|
static mut DMA_TRANSFER_COMPLETE: bool = true;
|
|
|
|
|
2023-12-20 12:08:48 +08:00
|
|
|
pub struct MAX1968 {
|
2023-12-21 13:13:06 +08:00
|
|
|
pub phy: MAX1968Phy<Channel0>,
|
|
|
|
pub pins_adc: Adc<ADC1>,
|
2024-02-29 16:47:03 +08:00
|
|
|
pub dma_adc: DMA_Transfer<Stream2<DMA2>, 1, Adc<ADC2>, PeripheralToMemory, &'static mut [u16; 16]>,
|
2024-07-10 18:16:03 +08:00
|
|
|
pub dac_out_range: ElectricPotential,
|
2024-03-15 14:45:19 +08:00
|
|
|
prev_vtec_volt: ElectricPotential,
|
|
|
|
prev_itec_volt: ElectricPotential,
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
2023-12-21 13:13:06 +08:00
|
|
|
|
2024-01-04 17:13:46 +08:00
|
|
|
pub enum PwmPinsEnum {
|
2023-12-20 12:08:48 +08:00
|
|
|
MaxV,
|
|
|
|
MaxPosI,
|
|
|
|
MaxNegI,
|
|
|
|
}
|
|
|
|
|
2024-02-29 16:47:03 +08:00
|
|
|
#[allow(unused)]
|
2023-12-20 12:08:48 +08:00
|
|
|
pub enum AdcReadTarget {
|
|
|
|
VREF,
|
|
|
|
DacVfb,
|
|
|
|
ITec,
|
|
|
|
VTec,
|
|
|
|
}
|
|
|
|
|
2023-12-21 13:13:06 +08:00
|
|
|
impl<C: ChannelPins> MAX1968Phy<C> {
|
|
|
|
pub fn new(pins: MAX1968PinSet<C>) -> Self {
|
|
|
|
MAX1968Phy {
|
|
|
|
dac: pins.dac,
|
|
|
|
shdn: pins.shdn,
|
|
|
|
vref_pin: pins.vref_pin,
|
|
|
|
itec_pin: pins.itec_pin,
|
|
|
|
dac_feedback_pin: pins.dac_feedback_pin,
|
|
|
|
vtec_pin: pins.vtec_pin,
|
|
|
|
max_v: pins.max_v,
|
|
|
|
max_i_pos: pins.max_i_pos,
|
|
|
|
max_i_neg: pins.max_i_neg,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-12-20 12:08:48 +08:00
|
|
|
|
2024-04-23 17:09:26 +08:00
|
|
|
static mut ADC2_FIRST_BUFFER: [u16; 16] = [0; 16];
|
|
|
|
static mut ADC2_LOCAL_BUFFER: [u16; 16] = [0; 16];
|
2024-02-29 16:47:03 +08:00
|
|
|
|
2023-12-21 13:13:06 +08:00
|
|
|
impl MAX1968 {
|
2024-07-10 18:16:03 +08:00
|
|
|
pub fn new(mut phy_ch0: MAX1968Phy<Channel0>, adc1: ADC1, adc2: ADC2, dma2: DMA2) -> Self {
|
2024-02-29 16:47:03 +08:00
|
|
|
let adc_config = AdcConfig::default()
|
2024-01-22 12:24:19 +08:00
|
|
|
.clock(config::Clock::Pclk2_div_8)
|
2023-12-20 12:08:48 +08:00
|
|
|
.default_sample_time(config::SampleTime::Cycles_480);
|
2024-01-24 17:03:06 +08:00
|
|
|
// Do not set reset RCCs as it causes other ADCs' clock to be disabled
|
2024-02-29 16:47:03 +08:00
|
|
|
let mut pins_adc1 = Adc::adc1(adc1, false, adc_config);
|
2024-04-23 17:09:26 +08:00
|
|
|
|
2024-04-23 15:35:23 +08:00
|
|
|
// adc1.calibrate() fn only read REFINT once to assign the calibration value.
|
|
|
|
// It does not take the STM32F4's ADC Precision Limitation into account.
|
|
|
|
// AN4073: ADC Reading Dispersion can be reduced through Averaging
|
|
|
|
let mut vdda_mv: u32 = 0;
|
|
|
|
for _ in (0..512).rev() {
|
|
|
|
pins_adc1.calibrate();
|
|
|
|
vdda_mv += pins_adc1.reference_voltage();
|
|
|
|
}
|
|
|
|
vdda_mv = vdda_mv / 512 as u32;
|
|
|
|
pins_adc1.apply_config(adc_config.reference_voltage(vdda_mv));
|
2024-02-29 16:47:03 +08:00
|
|
|
|
2024-04-23 17:09:26 +08:00
|
|
|
let adc_config = AdcConfig::default()
|
2024-02-29 16:47:03 +08:00
|
|
|
.clock(config::Clock::Pclk2_div_8)
|
|
|
|
.default_sample_time(config::SampleTime::Cycles_480)
|
|
|
|
.dma(config::Dma::Continuous)
|
|
|
|
.scan(config::Scan::Enabled)
|
|
|
|
.reference_voltage(pins_adc1.reference_voltage());
|
|
|
|
let dma_config = DmaConfig::default()
|
|
|
|
.transfer_complete_interrupt(true)
|
|
|
|
.memory_increment(true)
|
|
|
|
.double_buffer(false);
|
|
|
|
let mut pins_adc2 = Adc::adc2(adc2, false, adc_config);
|
|
|
|
pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::One, config::SampleTime::Cycles_480);
|
|
|
|
pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Two, config::SampleTime::Cycles_480);
|
2024-04-23 17:09:26 +08:00
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.itec_pin,
|
|
|
|
config::Sequence::Three,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.vtec_pin,
|
|
|
|
config::Sequence::Four,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.itec_pin,
|
|
|
|
config::Sequence::Five,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
2024-02-29 16:47:03 +08:00
|
|
|
pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Six, config::SampleTime::Cycles_480);
|
2024-04-23 17:09:26 +08:00
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.itec_pin,
|
|
|
|
config::Sequence::Seven,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.vtec_pin,
|
|
|
|
config::Sequence::Eight,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.itec_pin,
|
|
|
|
config::Sequence::Nine,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
2024-02-29 16:47:03 +08:00
|
|
|
pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Ten, config::SampleTime::Cycles_480);
|
2024-04-23 17:09:26 +08:00
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.itec_pin,
|
|
|
|
config::Sequence::Eleven,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.vtec_pin,
|
|
|
|
config::Sequence::Twelve,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.itec_pin,
|
|
|
|
config::Sequence::Thirteen,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.vtec_pin,
|
|
|
|
config::Sequence::Fourteen,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.itec_pin,
|
|
|
|
config::Sequence::Fifteen,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
|
|
|
pins_adc2.configure_channel(
|
|
|
|
&phy_ch0.vtec_pin,
|
|
|
|
config::Sequence::Sixteen,
|
|
|
|
config::SampleTime::Cycles_480,
|
|
|
|
);
|
2024-02-29 16:47:03 +08:00
|
|
|
|
|
|
|
let dma = StreamsTuple::new(dma2);
|
2024-04-23 17:09:26 +08:00
|
|
|
let dma_adc: DMA_Transfer<Stream2<DMA2>, 1, Adc<ADC2>, PeripheralToMemory, &'static mut [u16; 16]>;
|
2024-02-29 16:47:03 +08:00
|
|
|
unsafe {
|
2024-04-23 17:09:26 +08:00
|
|
|
dma_adc = DMA_Transfer::init_peripheral_to_memory(
|
|
|
|
dma.2,
|
|
|
|
pins_adc2,
|
|
|
|
addr_of_mut!(ADC2_FIRST_BUFFER).as_mut().unwrap(),
|
|
|
|
None,
|
|
|
|
dma_config,
|
|
|
|
);
|
2024-03-15 14:45:19 +08:00
|
|
|
NVIC::unmask(interrupt::DMA2_STREAM2);
|
2024-02-29 16:47:03 +08:00
|
|
|
}
|
2024-07-10 18:16:03 +08:00
|
|
|
|
|
|
|
phy_ch0.dac.set(ad5680::MAX_VALUE).unwrap();
|
|
|
|
sleep(500);
|
|
|
|
let mut sample = 0;
|
|
|
|
for _ in 0..512 {
|
|
|
|
sample += pins_adc1.convert(
|
|
|
|
&phy_ch0.dac_feedback_pin,
|
|
|
|
stm32f4xx_hal::adc::config::SampleTime::Cycles_480,
|
|
|
|
) as u32;
|
|
|
|
}
|
|
|
|
let sample = sample / 512 as u32;
|
|
|
|
let mv = pins_adc1.sample_to_millivolts(sample as u16);
|
|
|
|
let dac_out_range = ElectricPotential::new::<millivolt>(mv as f32);
|
|
|
|
phy_ch0.dac.set(0).unwrap();
|
|
|
|
|
2023-12-20 12:08:48 +08:00
|
|
|
|
|
|
|
MAX1968 {
|
2023-12-21 13:13:06 +08:00
|
|
|
phy: phy_ch0,
|
2024-02-29 16:47:03 +08:00
|
|
|
pins_adc: pins_adc1,
|
|
|
|
dma_adc: dma_adc,
|
2024-07-10 18:16:03 +08:00
|
|
|
dac_out_range: dac_out_range,
|
2024-04-23 17:09:26 +08:00
|
|
|
prev_vtec_volt: ElectricPotential::new::<millivolt>(0.0),
|
|
|
|
prev_itec_volt: ElectricPotential::new::<millivolt>(0.0),
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-23 17:09:26 +08:00
|
|
|
pub fn dma_adc_start_conversion(&mut self) {
|
|
|
|
if unsafe { DMA_TRANSFER_COMPLETE } {
|
|
|
|
unsafe {
|
|
|
|
DMA_TRANSFER_COMPLETE = false;
|
|
|
|
}
|
|
|
|
self.dma_adc.start(|adc| {
|
2024-03-15 14:45:19 +08:00
|
|
|
adc.clear_end_of_conversion_flag();
|
|
|
|
adc.start_conversion();
|
|
|
|
});
|
2024-04-23 17:09:26 +08:00
|
|
|
}
|
2024-02-29 16:47:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_tec_readings(&mut self) -> (ElectricPotential, ElectricPotential) {
|
2024-03-15 14:45:19 +08:00
|
|
|
if unsafe { DMA_TRANSFER_COMPLETE } {
|
|
|
|
let buffer: &[u16; 16];
|
|
|
|
unsafe {
|
2024-04-23 17:09:26 +08:00
|
|
|
(buffer, _) = self
|
|
|
|
.dma_adc
|
2024-03-22 17:44:06 +08:00
|
|
|
.next_transfer(addr_of_mut!(ADC2_LOCAL_BUFFER).as_mut().unwrap())
|
2024-03-15 14:45:19 +08:00
|
|
|
.unwrap();
|
|
|
|
}
|
2024-04-23 17:09:26 +08:00
|
|
|
|
2024-03-15 14:45:19 +08:00
|
|
|
let sample_to_millivolts = self.dma_adc.peripheral().make_sample_to_millivolts();
|
|
|
|
let mut itec: u16 = 0;
|
|
|
|
for data in buffer.into_iter().step_by(2) {
|
|
|
|
itec += *data;
|
|
|
|
}
|
|
|
|
itec = itec >> 3;
|
2024-02-29 16:47:03 +08:00
|
|
|
|
2024-03-15 14:45:19 +08:00
|
|
|
let mut vtec: u16 = 0;
|
|
|
|
for data in buffer.into_iter().skip(1).step_by(2) {
|
|
|
|
vtec += *data;
|
|
|
|
}
|
|
|
|
vtec = vtec >> 3;
|
2024-02-29 16:47:03 +08:00
|
|
|
|
2024-03-15 14:45:19 +08:00
|
|
|
unsafe {
|
|
|
|
ADC2_LOCAL_BUFFER = *buffer;
|
|
|
|
}
|
|
|
|
self.prev_vtec_volt = ElectricPotential::new::<millivolt>(sample_to_millivolts(vtec) as f32);
|
|
|
|
self.prev_itec_volt = ElectricPotential::new::<millivolt>(sample_to_millivolts(itec) as f32);
|
2024-02-29 16:47:03 +08:00
|
|
|
}
|
2024-03-15 14:45:19 +08:00
|
|
|
(self.prev_vtec_volt, self.prev_itec_volt)
|
2024-02-29 16:47:03 +08:00
|
|
|
}
|
|
|
|
|
2024-01-22 12:24:19 +08:00
|
|
|
// Return the calibrated VDDA Voltage
|
|
|
|
// Can be used to set reference voltage for other ADC
|
|
|
|
pub fn get_calibrated_vdda(&mut self) -> u32 {
|
|
|
|
self.pins_adc.reference_voltage()
|
|
|
|
}
|
|
|
|
|
2024-03-04 15:48:19 +08:00
|
|
|
pub fn is_powered_on(&mut self) -> bool {
|
2024-03-18 17:23:45 +08:00
|
|
|
self.phy.shdn.is_set_high()
|
2024-03-04 15:48:19 +08:00
|
|
|
}
|
|
|
|
|
2023-12-20 12:08:48 +08:00
|
|
|
pub fn power_down(&mut self) {
|
2024-01-05 15:00:50 +08:00
|
|
|
self.phy.shdn.set_low();
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn power_up(&mut self) {
|
2024-01-05 15:00:50 +08:00
|
|
|
self.phy.shdn.set_high();
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
|
|
|
|
2024-01-05 15:00:50 +08:00
|
|
|
pub fn set_dac(&mut self, voltage: ElectricPotential, dac_out_v_max: ElectricPotential) -> ElectricPotential {
|
2024-04-23 17:09:26 +08:00
|
|
|
let value = ((voltage / dac_out_v_max).get::<ratio>() * (ad5680::MAX_VALUE as f32)) as u32;
|
2023-12-21 13:13:06 +08:00
|
|
|
self.phy.dac.set(value).unwrap();
|
2023-12-20 12:08:48 +08:00
|
|
|
voltage
|
|
|
|
}
|
|
|
|
|
|
|
|
// AN4073: ADC Reading Dispersion can be reduced through Averaging
|
|
|
|
// Upon test, 16 Point Averaging = +-3 LSB Dispersion
|
2023-12-22 17:09:45 +08:00
|
|
|
pub fn adc_read(&mut self, adc_read_target: AdcReadTarget, avg_pt: u16) -> ElectricPotential {
|
2023-12-20 12:08:48 +08:00
|
|
|
let mut sample: u32 = 0;
|
|
|
|
sample = match adc_read_target {
|
|
|
|
AdcReadTarget::VREF => {
|
|
|
|
for _ in (0..avg_pt).rev() {
|
2024-04-23 17:09:26 +08:00
|
|
|
sample += self
|
|
|
|
.pins_adc
|
|
|
|
.convert(&self.phy.vref_pin, stm32f4xx_hal::adc::config::SampleTime::Cycles_480)
|
|
|
|
as u32;
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
|
|
|
sample / avg_pt as u32
|
|
|
|
}
|
|
|
|
AdcReadTarget::DacVfb => {
|
|
|
|
for _ in (0..avg_pt).rev() {
|
2023-12-21 13:13:06 +08:00
|
|
|
sample += self.pins_adc.convert(
|
|
|
|
&self.phy.dac_feedback_pin,
|
2023-12-20 12:08:48 +08:00
|
|
|
stm32f4xx_hal::adc::config::SampleTime::Cycles_480,
|
|
|
|
) as u32;
|
|
|
|
}
|
|
|
|
sample / avg_pt as u32
|
|
|
|
}
|
|
|
|
AdcReadTarget::ITec => {
|
|
|
|
for _ in (0..avg_pt).rev() {
|
2024-04-23 17:09:26 +08:00
|
|
|
sample += self
|
|
|
|
.pins_adc
|
|
|
|
.convert(&self.phy.itec_pin, stm32f4xx_hal::adc::config::SampleTime::Cycles_480)
|
|
|
|
as u32;
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
|
|
|
sample / avg_pt as u32
|
|
|
|
}
|
|
|
|
AdcReadTarget::VTec => {
|
|
|
|
for _ in (0..avg_pt).rev() {
|
2024-04-23 17:09:26 +08:00
|
|
|
sample += self
|
|
|
|
.pins_adc
|
|
|
|
.convert(&self.phy.vtec_pin, stm32f4xx_hal::adc::config::SampleTime::Cycles_480)
|
|
|
|
as u32;
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
|
|
|
sample / avg_pt as u32
|
|
|
|
}
|
|
|
|
};
|
2023-12-21 13:13:06 +08:00
|
|
|
let mv = self.pins_adc.sample_to_millivolts(sample as u16);
|
2024-02-27 16:26:05 +08:00
|
|
|
ElectricPotential::new::<millivolt>(mv as f32)
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
|
|
|
|
2024-01-04 17:13:46 +08:00
|
|
|
pub fn set_pwm(&mut self, pwm_pin: PwmPinsEnum, duty: f64, max_duty: f64) -> f64 {
|
2024-03-22 17:44:06 +08:00
|
|
|
fn duty_cycle_value(duty_cycle: f64, duty_cycle_limit: f64, max_value: u16) -> u16 {
|
|
|
|
((duty_cycle.min(duty_cycle_limit) * (max_value as f64)) as u16).min(max_value)
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
|
|
|
|
2024-03-22 17:44:06 +08:00
|
|
|
let value: u16;
|
|
|
|
let max_value: u16;
|
2023-12-20 12:08:48 +08:00
|
|
|
match pwm_pin {
|
2024-03-22 17:44:06 +08:00
|
|
|
PwmPinsEnum::MaxV => {
|
|
|
|
self.phy.max_v.enable();
|
|
|
|
max_value = self.phy.max_v.get_max_duty();
|
|
|
|
value = duty_cycle_value(duty, max_duty, max_value);
|
|
|
|
self.phy.max_v.set_duty(value);
|
|
|
|
}
|
|
|
|
PwmPinsEnum::MaxPosI => {
|
|
|
|
self.phy.max_i_pos.enable();
|
|
|
|
max_value = self.phy.max_i_pos.get_max_duty();
|
|
|
|
value = duty_cycle_value(duty, max_duty, max_value);
|
|
|
|
self.phy.max_i_pos.set_duty(value);
|
|
|
|
}
|
|
|
|
PwmPinsEnum::MaxNegI => {
|
|
|
|
self.phy.max_i_neg.enable();
|
|
|
|
max_value = self.phy.max_i_neg.get_max_duty();
|
|
|
|
value = duty_cycle_value(duty, max_duty, max_value);
|
|
|
|
self.phy.max_i_neg.set_duty(value);
|
|
|
|
}
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
2024-03-22 17:44:06 +08:00
|
|
|
return (value as f64) / (max_value as f64);
|
2023-12-20 12:08:48 +08:00
|
|
|
}
|
|
|
|
}
|
2024-03-15 14:45:19 +08:00
|
|
|
|
|
|
|
#[interrupt]
|
2024-04-23 17:09:26 +08:00
|
|
|
fn DMA2_STREAM2() {
|
2024-03-15 14:45:19 +08:00
|
|
|
cortex_m::interrupt::free(|_| {
|
2024-04-23 17:09:26 +08:00
|
|
|
unsafe {
|
|
|
|
// Clear all DMA2_STREAM2 interrupt flags
|
|
|
|
Peripherals::steal().DMA2.lifcr.write(|w| {
|
|
|
|
w.ctcif2()
|
|
|
|
.set_bit()
|
|
|
|
.cdmeif2()
|
|
|
|
.set_bit()
|
|
|
|
.chtif2()
|
|
|
|
.set_bit()
|
|
|
|
.cteif2()
|
|
|
|
.set_bit()
|
|
|
|
});
|
|
|
|
DMA_TRANSFER_COMPLETE = true;
|
2024-03-15 14:45:19 +08:00
|
|
|
}
|
2024-04-23 17:09:26 +08:00
|
|
|
})
|
2024-03-15 14:45:19 +08:00
|
|
|
}
|