diff options
| author | Timo Kröger <[email protected]> | 2022-06-25 11:59:07 +0200 |
|---|---|---|
| committer | Timo Kröger <[email protected]> | 2022-08-26 15:44:58 +0200 |
| commit | f31116cafaeea7746aec19903fb1c73adaea9ea6 (patch) | |
| tree | 8f735abceb824e60f757290062ff99428407b530 /embassy-lora | |
| parent | 69d80c086d2f22f66aa25fafb55918cb1c5e3bdd (diff) | |
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.
Diffstat (limited to 'embassy-lora')
| -rw-r--r-- | embassy-lora/src/stm32wl/mod.rs | 75 |
1 files changed, 37 insertions, 38 deletions
diff --git a/embassy-lora/src/stm32wl/mod.rs b/embassy-lora/src/stm32wl/mod.rs index 7502dc379..5170b261a 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}; | |||
| 6 | use embassy_stm32::dma::NoDma; | 6 | use embassy_stm32::dma::NoDma; |
| 7 | use embassy_stm32::interrupt::{Interrupt, InterruptExt, SUBGHZ_RADIO}; | 7 | use embassy_stm32::interrupt::{Interrupt, InterruptExt, SUBGHZ_RADIO}; |
| 8 | use embassy_stm32::subghz::{ | 8 | use embassy_stm32::subghz::{ |
| 9 | CalibrateImage, CfgIrq, CodingRate, Error, HeaderType, Irq, LoRaBandwidth, LoRaModParams, LoRaPacketParams, | 9 | CalibrateImage, CfgIrq, CodingRate, Error, HeaderType, HseTrim, Irq, LoRaBandwidth, LoRaModParams, |
| 10 | LoRaSyncWord, Ocp, PaConfig, PaSel, PacketType, RampTime, RegMode, RfFreq, SpreadingFactor as SF, StandbyClk, | 10 | LoRaPacketParams, LoRaSyncWord, Ocp, PaConfig, PacketType, RampTime, RegMode, RfFreq, SpreadingFactor as SF, |
| 11 | Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams, | 11 | StandbyClk, Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams, |
| 12 | }; | 12 | }; |
| 13 | use embassy_sync::waitqueue::AtomicWaker; | 13 | use embassy_sync::waitqueue::AtomicWaker; |
| 14 | use futures::future::poll_fn; | 14 | use futures::future::poll_fn; |
| @@ -61,46 +61,17 @@ impl<'d, RS: RadioSwitch> SubGhzRadio<'d, RS> { | |||
| 61 | unsafe { SUBGHZ_RADIO::steal().disable() }; | 61 | unsafe { SUBGHZ_RADIO::steal().disable() }; |
| 62 | }); | 62 | }); |
| 63 | 63 | ||
| 64 | Self { radio, switch, irq } | 64 | configure_radio(&mut radio, config)?; |
| 65 | } | ||
| 66 | |||
| 67 | /// Configure radio settings in preparation for TX or RX | ||
| 68 | pub(crate) fn configure(&mut self) -> Result<(), RadioError> { | ||
| 69 | trace!("Configuring STM32WL SUBGHZ radio"); | ||
| 70 | self.radio.set_standby(StandbyClk::Rc)?; | ||
| 71 | let tcxo_mode = TcxoMode::new() | ||
| 72 | .set_txco_trim(TcxoTrim::Volts1pt7) | ||
| 73 | .set_timeout(Timeout::from_duration_sat(core::time::Duration::from_millis(40))); | ||
| 74 | |||
| 75 | self.radio.set_tcxo_mode(&tcxo_mode)?; | ||
| 76 | self.radio.set_regulator_mode(RegMode::Ldo)?; | ||
| 77 | |||
| 78 | self.radio.calibrate_image(CalibrateImage::ISM_863_870)?; | ||
| 79 | |||
| 80 | self.radio.set_buffer_base_address(0, 0)?; | ||
| 81 | |||
| 82 | self.radio | ||
| 83 | .set_pa_config(&PaConfig::new().set_pa_duty_cycle(0x1).set_hp_max(0x0).set_pa(PaSel::Lp))?; | ||
| 84 | 65 | ||
| 85 | self.radio.set_pa_ocp(Ocp::Max140m)?; | 66 | Ok(Self { radio, switch, irq }) |
| 86 | |||
| 87 | // let tx_params = TxParams::LP_14.set_ramp_time(RampTime::Micros40); | ||
| 88 | self.radio | ||
| 89 | .set_tx_params(&TxParams::new().set_ramp_time(RampTime::Micros40).set_power(0x0A))?; | ||
| 90 | |||
| 91 | self.radio.set_packet_type(PacketType::LoRa)?; | ||
| 92 | self.radio.set_lora_sync_word(LoRaSyncWord::Public)?; | ||
| 93 | trace!("Done initializing STM32WL SUBGHZ radio"); | ||
| 94 | Ok(()) | ||
| 95 | } | 67 | } |
| 96 | 68 | ||
| 97 | /// Perform a transmission with the given parameters and payload. Returns any time adjustements needed form | 69 | /// Perform a transmission with the given parameters and payload. Returns any time adjustements needed form |
| 98 | /// the upcoming RX window start. | 70 | /// the upcoming RX window start. |
| 99 | async fn do_tx(&mut self, config: TxConfig, buf: &[u8]) -> Result<u32, RadioError> { | 71 | async fn do_tx(&mut self, config: TxConfig, buf: &[u8]) -> Result<u32, RadioError> { |
| 100 | //trace!("TX Request: {}", config); | 72 | trace!("TX Request: {}", config); |
| 101 | trace!("TX START"); | 73 | //trace!("TX START"); |
| 102 | self.switch.set_tx(); | 74 | self.switch.set_tx(); |
| 103 | self.configure()?; | ||
| 104 | 75 | ||
| 105 | self.radio | 76 | self.radio |
| 106 | .set_rf_frequency(&RfFreq::from_frequency(config.rf.frequency))?; | 77 | .set_rf_frequency(&RfFreq::from_frequency(config.rf.frequency))?; |
| @@ -164,7 +135,6 @@ impl<'d, RS: RadioSwitch> SubGhzRadio<'d, RS> { | |||
| 164 | trace!("RX START"); | 135 | trace!("RX START"); |
| 165 | // trace!("Starting RX: {}", config); | 136 | // trace!("Starting RX: {}", config); |
| 166 | self.switch.set_rx(); | 137 | self.switch.set_rx(); |
| 167 | self.configure()?; | ||
| 168 | 138 | ||
| 169 | self.radio.set_rf_frequency(&RfFreq::from_frequency(config.frequency))?; | 139 | self.radio.set_rf_frequency(&RfFreq::from_frequency(config.frequency))?; |
| 170 | 140 | ||
| @@ -180,7 +150,7 @@ impl<'d, RS: RadioSwitch> SubGhzRadio<'d, RS> { | |||
| 180 | 150 | ||
| 181 | let irq_cfg = CfgIrq::new() | 151 | let irq_cfg = CfgIrq::new() |
| 182 | .irq_enable_all(Irq::RxDone) | 152 | .irq_enable_all(Irq::RxDone) |
| 183 | .irq_enable_all(Irq::PreambleDetected) | 153 | //.irq_enable_all(Irq::PreambleDetected) |
| 184 | .irq_enable_all(Irq::HeaderErr) | 154 | .irq_enable_all(Irq::HeaderErr) |
| 185 | .irq_enable_all(Irq::Timeout) | 155 | .irq_enable_all(Irq::Timeout) |
| 186 | .irq_enable_all(Irq::Err); | 156 | .irq_enable_all(Irq::Err); |
| @@ -235,6 +205,35 @@ impl<'d, RS: RadioSwitch> SubGhzRadio<'d, RS> { | |||
| 235 | } | 205 | } |
| 236 | } | 206 | } |
| 237 | 207 | ||
| 208 | fn configure_radio(radio: &mut SubGhz<'_, NoDma, NoDma>, config: SubGhzRadioConfig) -> Result<(), RadioError> { | ||
| 209 | trace!("Configuring STM32WL SUBGHZ radio"); | ||
| 210 | |||
| 211 | radio.set_regulator_mode(config.reg_mode)?; | ||
| 212 | radio.set_standby(StandbyClk::Rc)?; | ||
| 213 | |||
| 214 | let tcxo_mode = TcxoMode::new() | ||
| 215 | .set_txco_trim(TcxoTrim::Volts1pt7) | ||
| 216 | .set_timeout(Timeout::from_duration_sat(core::time::Duration::from_millis(100))); | ||
| 217 | radio.set_tcxo_mode(&tcxo_mode)?; | ||
| 218 | // Reduce input capacitance as shown in Reference Manual "Figure 23. HSE32 TCXO control". | ||
| 219 | // The STM32CUBE C driver also does this. | ||
| 220 | radio.set_hse_in_trim(HseTrim::MIN)?; | ||
| 221 | |||
| 222 | // Re-calibrate everything after setting the TXCO config. | ||
| 223 | radio.calibrate(0x7F)?; | ||
| 224 | radio.calibrate_image(config.calibrate_image)?; | ||
| 225 | |||
| 226 | radio.set_pa_config(&PaConfig::HP_14)?; | ||
| 227 | radio.set_tx_params(&TxParams::HP.set_ramp_time(RampTime::Micros40))?; | ||
| 228 | radio.set_pa_ocp(Ocp::Max140m)?; | ||
| 229 | |||
| 230 | radio.set_packet_type(PacketType::LoRa)?; | ||
| 231 | radio.set_lora_sync_word(LoRaSyncWord::Public)?; | ||
| 232 | |||
| 233 | trace!("Done initializing STM32WL SUBGHZ radio"); | ||
| 234 | Ok(()) | ||
| 235 | } | ||
| 236 | |||
| 238 | impl<RS: RadioSwitch> PhyRxTx for SubGhzRadio<'static, RS> { | 237 | impl<RS: RadioSwitch> PhyRxTx for SubGhzRadio<'static, RS> { |
| 239 | type PhyError = RadioError; | 238 | type PhyError = RadioError; |
| 240 | 239 | ||
