From f31116cafaeea7746aec19903fb1c73adaea9ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Sat, 25 Jun 2022 11:59:07 +0200 Subject: [PATCH] lora: Make some options configurable Call `config()` only once at construction not with every RX and TX operation. The Lora-E5 only supports HP mode, use that instead. The nucleo board supports both HP and LP and should continue to work. --- embassy-lora/src/stm32wl/mod.rs | 75 ++++++++++++++--------------- examples/stm32wl/src/bin/lorawan.rs | 4 +- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/embassy-lora/src/stm32wl/mod.rs b/embassy-lora/src/stm32wl/mod.rs index 7502dc37..5170b261 100644 --- a/embassy-lora/src/stm32wl/mod.rs +++ b/embassy-lora/src/stm32wl/mod.rs @@ -6,9 +6,9 @@ use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; use embassy_stm32::dma::NoDma; use embassy_stm32::interrupt::{Interrupt, InterruptExt, SUBGHZ_RADIO}; use embassy_stm32::subghz::{ - CalibrateImage, CfgIrq, CodingRate, Error, HeaderType, Irq, LoRaBandwidth, LoRaModParams, LoRaPacketParams, - LoRaSyncWord, Ocp, PaConfig, PaSel, PacketType, RampTime, RegMode, RfFreq, SpreadingFactor as SF, StandbyClk, - Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams, + CalibrateImage, CfgIrq, CodingRate, Error, HeaderType, HseTrim, Irq, LoRaBandwidth, LoRaModParams, + LoRaPacketParams, LoRaSyncWord, Ocp, PaConfig, PacketType, RampTime, RegMode, RfFreq, SpreadingFactor as SF, + StandbyClk, Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams, }; use embassy_sync::waitqueue::AtomicWaker; use futures::future::poll_fn; @@ -61,46 +61,17 @@ impl<'d, RS: RadioSwitch> SubGhzRadio<'d, RS> { unsafe { SUBGHZ_RADIO::steal().disable() }; }); - Self { radio, switch, irq } - } + configure_radio(&mut radio, config)?; - /// Configure radio settings in preparation for TX or RX - pub(crate) fn configure(&mut self) -> Result<(), RadioError> { - trace!("Configuring STM32WL SUBGHZ radio"); - self.radio.set_standby(StandbyClk::Rc)?; - let tcxo_mode = TcxoMode::new() - .set_txco_trim(TcxoTrim::Volts1pt7) - .set_timeout(Timeout::from_duration_sat(core::time::Duration::from_millis(40))); - - self.radio.set_tcxo_mode(&tcxo_mode)?; - self.radio.set_regulator_mode(RegMode::Ldo)?; - - self.radio.calibrate_image(CalibrateImage::ISM_863_870)?; - - self.radio.set_buffer_base_address(0, 0)?; - - self.radio - .set_pa_config(&PaConfig::new().set_pa_duty_cycle(0x1).set_hp_max(0x0).set_pa(PaSel::Lp))?; - - self.radio.set_pa_ocp(Ocp::Max140m)?; - - // let tx_params = TxParams::LP_14.set_ramp_time(RampTime::Micros40); - self.radio - .set_tx_params(&TxParams::new().set_ramp_time(RampTime::Micros40).set_power(0x0A))?; - - self.radio.set_packet_type(PacketType::LoRa)?; - self.radio.set_lora_sync_word(LoRaSyncWord::Public)?; - trace!("Done initializing STM32WL SUBGHZ radio"); - Ok(()) + Ok(Self { radio, switch, irq }) } /// Perform a transmission with the given parameters and payload. Returns any time adjustements needed form /// the upcoming RX window start. async fn do_tx(&mut self, config: TxConfig, buf: &[u8]) -> Result { - //trace!("TX Request: {}", config); - trace!("TX START"); + trace!("TX Request: {}", config); + //trace!("TX START"); self.switch.set_tx(); - self.configure()?; self.radio .set_rf_frequency(&RfFreq::from_frequency(config.rf.frequency))?; @@ -164,7 +135,6 @@ impl<'d, RS: RadioSwitch> SubGhzRadio<'d, RS> { trace!("RX START"); // trace!("Starting RX: {}", config); self.switch.set_rx(); - self.configure()?; self.radio.set_rf_frequency(&RfFreq::from_frequency(config.frequency))?; @@ -180,7 +150,7 @@ impl<'d, RS: RadioSwitch> SubGhzRadio<'d, RS> { let irq_cfg = CfgIrq::new() .irq_enable_all(Irq::RxDone) - .irq_enable_all(Irq::PreambleDetected) + //.irq_enable_all(Irq::PreambleDetected) .irq_enable_all(Irq::HeaderErr) .irq_enable_all(Irq::Timeout) .irq_enable_all(Irq::Err); @@ -235,6 +205,35 @@ impl<'d, RS: RadioSwitch> SubGhzRadio<'d, RS> { } } +fn configure_radio(radio: &mut SubGhz<'_, NoDma, NoDma>, config: SubGhzRadioConfig) -> Result<(), RadioError> { + trace!("Configuring STM32WL SUBGHZ radio"); + + radio.set_regulator_mode(config.reg_mode)?; + radio.set_standby(StandbyClk::Rc)?; + + let tcxo_mode = TcxoMode::new() + .set_txco_trim(TcxoTrim::Volts1pt7) + .set_timeout(Timeout::from_duration_sat(core::time::Duration::from_millis(100))); + radio.set_tcxo_mode(&tcxo_mode)?; + // Reduce input capacitance as shown in Reference Manual "Figure 23. HSE32 TCXO control". + // The STM32CUBE C driver also does this. + radio.set_hse_in_trim(HseTrim::MIN)?; + + // Re-calibrate everything after setting the TXCO config. + radio.calibrate(0x7F)?; + radio.calibrate_image(config.calibrate_image)?; + + radio.set_pa_config(&PaConfig::HP_14)?; + radio.set_tx_params(&TxParams::HP.set_ramp_time(RampTime::Micros40))?; + radio.set_pa_ocp(Ocp::Max140m)?; + + radio.set_packet_type(PacketType::LoRa)?; + radio.set_lora_sync_word(LoRaSyncWord::Public)?; + + trace!("Done initializing STM32WL SUBGHZ radio"); + Ok(()) +} + impl PhyRxTx for SubGhzRadio<'static, RS> { type PhyError = RadioError; diff --git a/examples/stm32wl/src/bin/lorawan.rs b/examples/stm32wl/src/bin/lorawan.rs index 0ef13354..83df0188 100644 --- a/examples/stm32wl/src/bin/lorawan.rs +++ b/examples/stm32wl/src/bin/lorawan.rs @@ -60,7 +60,9 @@ async fn main(_spawner: Spawner) { let radio = SubGhz::new(p.SUBGHZSPI, NoDma, NoDma); let irq = interrupt::take!(SUBGHZ_RADIO); - let radio = SubGhzRadio::new(radio, rfs, irq); + let mut radio_config = SubGhzRadioConfig::default(); + radio_config.calibrate_image = CalibrateImage::ISM_863_870; + let radio = SubGhzRadio::new(radio, rfs, irq, radio_config).unwrap(); let mut region: region::Configuration = region::EU868::default().into();