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.
This commit is contained in:
Timo Kröger 2022-06-25 11:59:07 +02:00
parent 69d80c086d
commit f31116cafa
2 changed files with 40 additions and 39 deletions

View File

@ -6,9 +6,9 @@ use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_stm32::dma::NoDma; use embassy_stm32::dma::NoDma;
use embassy_stm32::interrupt::{Interrupt, InterruptExt, SUBGHZ_RADIO}; use embassy_stm32::interrupt::{Interrupt, InterruptExt, SUBGHZ_RADIO};
use embassy_stm32::subghz::{ use embassy_stm32::subghz::{
CalibrateImage, CfgIrq, CodingRate, Error, HeaderType, Irq, LoRaBandwidth, LoRaModParams, LoRaPacketParams, CalibrateImage, CfgIrq, CodingRate, Error, HeaderType, HseTrim, Irq, LoRaBandwidth, LoRaModParams,
LoRaSyncWord, Ocp, PaConfig, PaSel, PacketType, RampTime, RegMode, RfFreq, SpreadingFactor as SF, StandbyClk, LoRaPacketParams, LoRaSyncWord, Ocp, PaConfig, PacketType, RampTime, RegMode, RfFreq, SpreadingFactor as SF,
Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams, StandbyClk, Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams,
}; };
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use futures::future::poll_fn; use futures::future::poll_fn;
@ -61,46 +61,17 @@ impl<'d, RS: RadioSwitch> SubGhzRadio<'d, RS> {
unsafe { SUBGHZ_RADIO::steal().disable() }; unsafe { SUBGHZ_RADIO::steal().disable() };
}); });
Self { radio, switch, irq } configure_radio(&mut radio, config)?;
}
/// Configure radio settings in preparation for TX or RX Ok(Self { radio, switch, irq })
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(())
} }
/// Perform a transmission with the given parameters and payload. Returns any time adjustements needed form /// Perform a transmission with the given parameters and payload. Returns any time adjustements needed form
/// the upcoming RX window start. /// the upcoming RX window start.
async fn do_tx(&mut self, config: TxConfig, buf: &[u8]) -> Result<u32, RadioError> { async fn do_tx(&mut self, config: TxConfig, buf: &[u8]) -> Result<u32, RadioError> {
//trace!("TX Request: {}", config); trace!("TX Request: {}", config);
trace!("TX START"); //trace!("TX START");
self.switch.set_tx(); self.switch.set_tx();
self.configure()?;
self.radio self.radio
.set_rf_frequency(&RfFreq::from_frequency(config.rf.frequency))?; .set_rf_frequency(&RfFreq::from_frequency(config.rf.frequency))?;
@ -164,7 +135,6 @@ impl<'d, RS: RadioSwitch> SubGhzRadio<'d, RS> {
trace!("RX START"); trace!("RX START");
// trace!("Starting RX: {}", config); // trace!("Starting RX: {}", config);
self.switch.set_rx(); self.switch.set_rx();
self.configure()?;
self.radio.set_rf_frequency(&RfFreq::from_frequency(config.frequency))?; 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() let irq_cfg = CfgIrq::new()
.irq_enable_all(Irq::RxDone) .irq_enable_all(Irq::RxDone)
.irq_enable_all(Irq::PreambleDetected) //.irq_enable_all(Irq::PreambleDetected)
.irq_enable_all(Irq::HeaderErr) .irq_enable_all(Irq::HeaderErr)
.irq_enable_all(Irq::Timeout) .irq_enable_all(Irq::Timeout)
.irq_enable_all(Irq::Err); .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<RS: RadioSwitch> PhyRxTx for SubGhzRadio<'static, RS> { impl<RS: RadioSwitch> PhyRxTx for SubGhzRadio<'static, RS> {
type PhyError = RadioError; type PhyError = RadioError;

View File

@ -60,7 +60,9 @@ async fn main(_spawner: Spawner) {
let radio = SubGhz::new(p.SUBGHZSPI, NoDma, NoDma); let radio = SubGhz::new(p.SUBGHZSPI, NoDma, NoDma);
let irq = interrupt::take!(SUBGHZ_RADIO); 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(); let mut region: region::Configuration = region::EU868::default().into();