use stm32f4xx_hal::{ adc::Adc, gpio::{ AF5, Alternate, AlternateOD, Analog, Floating, Input, gpioa::*, gpiob::*, gpioc::*, gpioe::*, gpiof::*, gpiog::*, GpioExt, Output, PushPull, }, hal::{self, blocking::spi::Transfer, digital::v2::OutputPin}, i2c::I2c, otg_fs::USB, rcc::Clocks, pwm::{self, PwmChannels}, spi::{Spi, NoMiso, TransferModeNormal}, pac::{ ADC1, GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, I2C1, OTG_FS_GLOBAL, OTG_FS_DEVICE, OTG_FS_PWRCLK, SPI2, SPI4, SPI5, TIM1, TIM3, TIM8 }, timer::Timer, time::U32Ext, }; use eeprom24x::{self, Eeprom24x}; use stm32_eth::EthPins; use crate::{ channel::{Channel0, Channel1}, leds::Leds, fan_ctrl::FanPin, hw_rev::{HWRev, HWSettings}, }; pub type Eeprom = Eeprom24x< I2c>, PB9> )>, eeprom24x::page_size::B8, eeprom24x::addr_size::OneByte >; pub type EthernetPins = EthPins< PA1>, PA7>, PB11>, PG13>, PB13>, PC4>, PC5>, >; pub trait ChannelPins { type DacSpi: Transfer; type DacSync: OutputPin; type Shdn: OutputPin; type VRefPin; type ItecPin; type DacFeedbackPin; type TecUMeasPin; } pub enum Channel0VRef { Analog(PA0), Disabled(PA0>), } impl ChannelPins for Channel0 { type DacSpi = Dac0Spi; type DacSync = PE4>; type Shdn = PE10>; type VRefPin = Channel0VRef; type ItecPin = PA6; type DacFeedbackPin = PA4; type TecUMeasPin = PC2; } pub enum Channel1VRef { Analog(PA3), Disabled(PA3>), } impl ChannelPins for Channel1 { type DacSpi = Dac1Spi; type DacSync = PF6>; type Shdn = PE15>; type VRefPin = Channel1VRef; type ItecPin = PB0; type DacFeedbackPin = PA5; type TecUMeasPin = PC3; } /// SPI peripheral used for communication with the ADC pub type AdcSpi = Spi>, PB14>, PB15>), TransferModeNormal>; pub type AdcNss = PB12>; type Dac0Spi = Spi>, NoMiso, PE6>), TransferModeNormal>; type Dac1Spi = Spi>, NoMiso, PF9>), TransferModeNormal>; pub type PinsAdc = Adc; pub struct ChannelPinSet { pub dac_spi: C::DacSpi, pub dac_sync: C::DacSync, pub shdn: C::Shdn, pub vref_pin: C::VRefPin, pub itec_pin: C::ItecPin, pub dac_feedback_pin: C::DacFeedbackPin, pub tec_u_meas_pin: C::TecUMeasPin, } pub struct HWRevPins { pub hwrev0: stm32f4xx_hal::gpio::gpiod::PD0>, pub hwrev1: stm32f4xx_hal::gpio::gpiod::PD1>, pub hwrev2: stm32f4xx_hal::gpio::gpiod::PD2>, pub hwrev3: stm32f4xx_hal::gpio::gpiod::PD3>, } pub struct Pins { pub adc_spi: AdcSpi, pub adc_nss: AdcNss, pub pins_adc: PinsAdc, pub pwm: PwmPins, pub channel0: ChannelPinSet, pub channel1: ChannelPinSet, } impl Pins { /// Setup GPIO pins and configure MCU peripherals pub fn setup( clocks: Clocks, tim1: TIM1, tim3: TIM3, tim8: TIM8, gpioa: GPIOA, gpiob: GPIOB, gpioc: GPIOC, gpiod: GPIOD, gpioe: GPIOE, gpiof: GPIOF, gpiog: GPIOG, i2c1: I2C1, spi2: SPI2, spi4: SPI4, spi5: SPI5, adc1: ADC1, otg_fs_global: OTG_FS_GLOBAL, otg_fs_device: OTG_FS_DEVICE, otg_fs_pwrclk: OTG_FS_PWRCLK, ) -> (Self, Leds, Eeprom, EthernetPins, USB, Option, HWRev, HWSettings) { let gpioa = gpioa.split(); let gpiob = gpiob.split(); let gpioc = gpioc.split(); let gpiod = gpiod.split(); let gpioe = gpioe.split(); let gpiof = gpiof.split(); let gpiog = gpiog.split(); let adc_spi = Self::setup_spi_adc(clocks, spi2, gpiob.pb10, gpiob.pb14, gpiob.pb15); let adc_nss = gpiob.pb12.into_push_pull_output(); let pins_adc = Adc::adc1(adc1, true, Default::default()); let pwm = PwmPins::setup( clocks, tim1, tim3, gpioc.pc6, gpioc.pc7, gpioe.pe9, gpioe.pe11, gpioe.pe13, gpioe.pe14 ); let hwrev = HWRev::detect_hw_rev(&HWRevPins {hwrev0: gpiod.pd0, hwrev1: gpiod.pd1, hwrev2: gpiod.pd2, hwrev3: gpiod.pd3}); let hw_settings = hwrev.settings(); let (dac0_spi, dac0_sync) = Self::setup_dac0( clocks, spi4, gpioe.pe2, gpioe.pe4, gpioe.pe6 ); let mut shdn0 = gpioe.pe10.into_push_pull_output(); let _ = shdn0.set_low(); let vref0_pin = if hwrev.major > 2 {Channel0VRef::Analog(gpioa.pa0.into_analog())} else {Channel0VRef::Disabled(gpioa.pa0)}; let itec0_pin = gpioa.pa6.into_analog(); let dac_feedback0_pin = gpioa.pa4.into_analog(); let tec_u_meas0_pin = gpioc.pc2.into_analog(); let channel0 = ChannelPinSet { dac_spi: dac0_spi, dac_sync: dac0_sync, shdn: shdn0, vref_pin: vref0_pin, itec_pin: itec0_pin, dac_feedback_pin: dac_feedback0_pin, tec_u_meas_pin: tec_u_meas0_pin, }; let (dac1_spi, dac1_sync) = Self::setup_dac1( clocks, spi5, gpiof.pf7, gpiof.pf6, gpiof.pf9 ); let mut shdn1 = gpioe.pe15.into_push_pull_output(); let _ = shdn1.set_low(); let vref1_pin = if hwrev.major > 2 {Channel1VRef::Analog(gpioa.pa3.into_analog())} else {Channel1VRef::Disabled(gpioa.pa3)}; let itec1_pin = gpiob.pb0.into_analog(); let dac_feedback1_pin = gpioa.pa5.into_analog(); let tec_u_meas1_pin = gpioc.pc3.into_analog(); let channel1 = ChannelPinSet { dac_spi: dac1_spi, dac_sync: dac1_sync, shdn: shdn1, vref_pin: vref1_pin, itec_pin: itec1_pin, dac_feedback_pin: dac_feedback1_pin, tec_u_meas_pin: tec_u_meas1_pin, }; let pins = Pins { adc_spi, adc_nss, pins_adc, pwm, channel0, channel1, }; let leds = Leds::new(gpiod.pd9, gpiod.pd10.into_push_pull_output(), gpiod.pd11.into_push_pull_output()); let eeprom_scl = gpiob.pb8.into_alternate().set_open_drain(); let eeprom_sda = gpiob.pb9.into_alternate().set_open_drain(); let eeprom_i2c = I2c::new(i2c1, (eeprom_scl, eeprom_sda), 400.khz(), clocks); let eeprom = Eeprom24x::new_24x02(eeprom_i2c, eeprom24x::SlaveAddr::default()); let eth_pins = EthPins { ref_clk: gpioa.pa1, crs: gpioa.pa7, tx_en: gpiob.pb11, tx_d0: gpiog.pg13, tx_d1: gpiob.pb13, rx_d0: gpioc.pc4, rx_d1: gpioc.pc5, }; let usb = USB { usb_global: otg_fs_global, usb_device: otg_fs_device, usb_pwrclk: otg_fs_pwrclk, pin_dm: gpioa.pa11.into_alternate(), pin_dp: gpioa.pa12.into_alternate(), hclk: clocks.hclk(), }; let fan = if hw_settings.fan_available { Some(Timer::new(tim8, &clocks).pwm(gpioc.pc9.into_alternate(), hw_settings.fan_pwm_freq_hz.hz())) } else { None }; (pins, leds, eeprom, eth_pins, usb, fan, hwrev, hw_settings) } /// Configure the GPIO pins for SPI operation, and initialize SPI fn setup_spi_adc( clocks: Clocks, spi2: SPI2, sck: PB10, miso: PB14, mosi: PB15, ) -> AdcSpi { let sck = sck.into_alternate(); let miso = miso.into_alternate(); let mosi = mosi.into_alternate(); Spi::new( spi2, (sck, miso, mosi), crate::ad7172::SPI_MODE, crate::ad7172::SPI_CLOCK, clocks ) } fn setup_dac0( clocks: Clocks, spi4: SPI4, sclk: PE2, sync: PE4, sdin: PE6 ) -> (Dac0Spi, ::DacSync) { let sclk = sclk.into_alternate(); let sdin = sdin.into_alternate(); let spi = Spi::new( spi4, (sclk, NoMiso {}, sdin), crate::ad5680::SPI_MODE, crate::ad5680::SPI_CLOCK, clocks ); let sync = sync.into_push_pull_output(); (spi, sync) } fn setup_dac1( clocks: Clocks, spi5: SPI5, sclk: PF7, sync: PF6, sdin: PF9 ) -> (Dac1Spi, ::DacSync) { let sclk = sclk.into_alternate(); let sdin = sdin.into_alternate(); let spi = Spi::new( spi5, (sclk, NoMiso {}, sdin), crate::ad5680::SPI_MODE, crate::ad5680::SPI_CLOCK, clocks ); let sync = sync.into_push_pull_output(); (spi, sync) } } pub struct PwmPins { pub max_v0: PwmChannels, pub max_v1: PwmChannels, pub max_i_pos0: PwmChannels, pub max_i_pos1: PwmChannels, pub max_i_neg0: PwmChannels, pub max_i_neg1: PwmChannels, } impl PwmPins { fn setup( clocks: Clocks, tim1: TIM1, tim3: TIM3, max_v0: PC6, max_v1: PC7, max_i_pos0: PE9, max_i_pos1: PE11, max_i_neg0: PE13, max_i_neg1: PE14, ) -> PwmPins { let freq = 20u32.khz(); fn init_pwm_pin>(pin: &mut P) { pin.set_duty(0); pin.enable(); } let channels = ( max_v0.into_alternate(), max_v1.into_alternate(), ); //let (mut max_v0, mut max_v1) = pwm::tim3(tim3, channels, clocks, freq); let (mut max_v0, mut max_v1) = Timer::new(tim3, &clocks).pwm(channels, freq); init_pwm_pin(&mut max_v0); init_pwm_pin(&mut max_v1); let channels = ( max_i_pos0.into_alternate(), max_i_pos1.into_alternate(), max_i_neg0.into_alternate(), max_i_neg1.into_alternate(), ); let (mut max_i_pos0, mut max_i_pos1, mut max_i_neg0, mut max_i_neg1) = Timer::new(tim1, &clocks).pwm(channels, freq); init_pwm_pin(&mut max_i_pos0); init_pwm_pin(&mut max_i_neg0); init_pwm_pin(&mut max_i_pos1); init_pwm_pin(&mut max_i_neg1); PwmPins { max_v0, max_v1, max_i_pos0, max_i_pos1, max_i_neg0, max_i_neg1, } } }