From 9a730ef692d2b5c529f5e1aac58e80c6d04c2458 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 1 Dec 2021 21:59:53 +0100 Subject: [PATCH] Refactor sx127x radio to use async SPI with DMA --- embassy-lora/src/sx127x/mod.rs | 85 ++--- embassy-lora/src/sx127x/sx127x_lora/mod.rs | 374 +++++++++++---------- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l0/src/bin/lorawan.rs | 17 +- 4 files changed, 252 insertions(+), 226 deletions(-) diff --git a/embassy-lora/src/sx127x/mod.rs b/embassy-lora/src/sx127x/mod.rs index a9736b85f..7d3280e05 100644 --- a/embassy-lora/src/sx127x/mod.rs +++ b/embassy-lora/src/sx127x/mod.rs @@ -1,7 +1,6 @@ use core::future::Future; use embassy::traits::gpio::WaitForRisingEdge; -use embedded_hal::blocking::delay::DelayMs; -use embedded_hal::blocking::spi::{Transfer, Write}; +use embassy::traits::spi::*; use embedded_hal::digital::v2::OutputPin; use lorawan_device::async_device::{ radio::{Bandwidth, PhyRxTx, RfConfig, RxQuality, SpreadingFactor, TxConfig}, @@ -21,7 +20,7 @@ pub trait RadioSwitch { /// Semtech Sx127x radio peripheral pub struct Sx127xRadio where - SPI: Transfer + Write + 'static, + SPI: FullDuplex + 'static, E: 'static, CS: OutputPin + 'static, RESET: OutputPin + 'static, @@ -43,29 +42,29 @@ pub enum State { impl Sx127xRadio where - SPI: Transfer + Write + 'static, + SPI: FullDuplex + 'static, CS: OutputPin + 'static, RESET: OutputPin + 'static, I: WaitForRisingEdge + 'static, RFS: RadioSwitch + 'static, + E: 'static, { - pub fn new>( + pub async fn new( spi: SPI, cs: CS, reset: RESET, irq: I, rfs: RFS, - d: &mut D, ) -> Result> { let mut radio = LoRa::new(spi, cs, reset); - radio.reset(d)?; + radio.reset().await?; Ok(Self { radio, irq, rfs }) } } impl Timings for Sx127xRadio where - SPI: Transfer + Write + 'static, + SPI: FullDuplex + 'static, CS: OutputPin + 'static, RESET: OutputPin + 'static, I: WaitForRisingEdge + 'static, @@ -81,7 +80,7 @@ where impl PhyRxTx for Sx127xRadio where - SPI: Transfer + Write + 'static, + SPI: FullDuplex + 'static, CS: OutputPin + 'static, E: 'static, RESET: OutputPin + 'static, @@ -96,29 +95,33 @@ where fn tx<'m>(&'m mut self, config: TxConfig, buf: &'m [u8]) -> Self::TxFuture<'m> { trace!("TX START"); async move { + self.radio.set_mode(RadioMode::Stdby).await.ok().unwrap(); self.rfs.set_tx(); - self.radio.set_tx_power(14, 0)?; - self.radio.set_frequency(config.rf.frequency)?; + self.radio.set_tx_power(14, 0).await?; + self.radio.set_frequency(config.rf.frequency).await?; // TODO: Modify radio to support other coding rates - self.radio.set_coding_rate_4(5)?; + self.radio.set_coding_rate_4(5).await?; self.radio - .set_signal_bandwidth(bandwidth_to_i64(config.rf.bandwidth))?; + .set_signal_bandwidth(bandwidth_to_i64(config.rf.bandwidth)) + .await?; self.radio - .set_spreading_factor(spreading_factor_to_u8(config.rf.spreading_factor))?; + .set_spreading_factor(spreading_factor_to_u8(config.rf.spreading_factor)) + .await?; - self.radio.set_preamble_length(8)?; - self.radio.set_lora_pa_ramp()?; - self.radio.set_lora_sync_word()?; - self.radio.set_invert_iq(false)?; - self.radio.set_crc(true)?; + self.radio.set_preamble_length(8).await?; + self.radio.set_lora_pa_ramp().await?; + self.radio.set_lora_sync_word().await?; + self.radio.set_invert_iq(false).await?; + self.radio.set_crc(true).await?; - self.radio.set_dio0_tx_done()?; - self.radio.transmit_payload(buf)?; + self.radio.set_dio0_tx_done().await?; + + self.radio.transmit_start(buf).await?; loop { self.irq.wait_for_rising_edge().await; - self.radio.set_mode(RadioMode::Stdby).ok().unwrap(); - let irq = self.radio.clear_irq().ok().unwrap(); + self.radio.set_mode(RadioMode::Stdby).await.ok().unwrap(); + let irq = self.radio.clear_irq().await.ok().unwrap(); if (irq & IRQ::IrqTxDoneMask.addr()) != 0 { trace!("TX DONE"); return Ok(0); @@ -134,32 +137,34 @@ where trace!("RX START"); async move { self.rfs.set_rx(); - self.radio.reset_payload_length()?; - self.radio.set_frequency(config.frequency)?; + self.radio.reset_payload_length().await?; + self.radio.set_frequency(config.frequency).await?; // TODO: Modify radio to support other coding rates - self.radio.set_coding_rate_4(5)?; + self.radio.set_coding_rate_4(5).await?; self.radio - .set_signal_bandwidth(bandwidth_to_i64(config.bandwidth))?; + .set_signal_bandwidth(bandwidth_to_i64(config.bandwidth)) + .await?; self.radio - .set_spreading_factor(spreading_factor_to_u8(config.spreading_factor))?; + .set_spreading_factor(spreading_factor_to_u8(config.spreading_factor)) + .await?; - self.radio.set_preamble_length(8)?; - self.radio.set_lora_sync_word()?; - self.radio.set_invert_iq(true)?; - self.radio.set_crc(true)?; + self.radio.set_preamble_length(8).await?; + self.radio.set_lora_sync_word().await?; + self.radio.set_invert_iq(true).await?; + self.radio.set_crc(true).await?; - self.radio.set_dio0_rx_done()?; - self.radio.set_mode(RadioMode::RxContinuous)?; + self.radio.set_dio0_rx_done().await?; + self.radio.set_mode(RadioMode::RxContinuous).await?; loop { self.irq.wait_for_rising_edge().await; - self.radio.set_mode(RadioMode::Stdby).ok().unwrap(); - let irq = self.radio.clear_irq().ok().unwrap(); + self.radio.set_mode(RadioMode::Stdby).await.ok().unwrap(); + let irq = self.radio.clear_irq().await.ok().unwrap(); if (irq & IRQ::IrqRxDoneMask.addr()) != 0 { - let rssi = self.radio.get_packet_rssi().unwrap_or(0) as i16; - let snr = self.radio.get_packet_snr().unwrap_or(0.0) as i8; - let response = if let Ok(size) = self.radio.read_packet_size() { - self.radio.read_packet(buf)?; + let rssi = self.radio.get_packet_rssi().await.unwrap_or(0) as i16; + let snr = self.radio.get_packet_snr().await.unwrap_or(0.0) as i8; + let response = if let Ok(size) = self.radio.read_packet_size().await { + self.radio.read_packet(buf).await?; Ok((size, RxQuality::new(rssi, snr))) } else { Ok((0, RxQuality::new(rssi, snr))) diff --git a/embassy-lora/src/sx127x/sx127x_lora/mod.rs b/embassy-lora/src/sx127x/sx127x_lora/mod.rs index c541815fe..77d16b184 100644 --- a/embassy-lora/src/sx127x/sx127x_lora/mod.rs +++ b/embassy-lora/src/sx127x/sx127x_lora/mod.rs @@ -6,24 +6,15 @@ #![allow(dead_code)] use bit_field::BitField; -use embedded_hal::blocking::{ - delay::DelayMs, - spi::{Transfer, Write}, -}; +use embassy::time::{Duration, Timer}; +use embassy::traits::spi::*; use embedded_hal::digital::v2::OutputPin; -use embedded_hal::spi::{Mode, Phase, Polarity}; mod register; use self::register::PaConfig; use self::register::Register; pub use self::register::IRQ; -/// Provides the necessary SPI mode configuration for the radio -pub const MODE: Mode = Mode { - phase: Phase::CaptureOnSecondTransition, - polarity: Polarity::IdleHigh, -}; - /// Provides high-level access to Semtech SX1276/77/78/79 based boards connected to a Raspberry Pi pub struct LoRa { spi: SPI, @@ -56,7 +47,7 @@ const VERSION_CHECK: u8 = 0x09; impl LoRa where - SPI: Transfer + Write, + SPI: FullDuplex, CS: OutputPin, RESET: OutputPin, { @@ -72,24 +63,25 @@ where } } - pub fn reset>( - &mut self, - d: &mut D, - ) -> Result<(), Error> { + pub async fn reset(&mut self) -> Result<(), Error> { self.reset.set_low().map_err(Reset)?; - d.delay_ms(10_u32); + Timer::after(Duration::from_millis(10)).await; self.reset.set_high().map_err(Reset)?; - d.delay_ms(10_u32); - let version = self.read_register(Register::RegVersion.addr())?; + Timer::after(Duration::from_millis(10)).await; + let version = self.read_register(Register::RegVersion.addr()).await?; if version == VERSION_CHECK { - self.set_mode(RadioMode::Sleep)?; - self.write_register(Register::RegFifoTxBaseAddr.addr(), 0)?; - self.write_register(Register::RegFifoRxBaseAddr.addr(), 0)?; - let lna = self.read_register(Register::RegLna.addr())?; - self.write_register(Register::RegLna.addr(), lna | 0x03)?; - self.write_register(Register::RegModemConfig3.addr(), 0x04)?; - self.set_tcxo(true)?; - self.set_mode(RadioMode::Stdby)?; + self.set_mode(RadioMode::Sleep).await?; + self.write_register(Register::RegFifoTxBaseAddr.addr(), 0) + .await?; + self.write_register(Register::RegFifoRxBaseAddr.addr(), 0) + .await?; + let lna = self.read_register(Register::RegLna.addr()).await?; + self.write_register(Register::RegLna.addr(), lna | 0x03) + .await?; + self.write_register(Register::RegModemConfig3.addr(), 0x04) + .await?; + self.set_tcxo(true).await?; + self.set_mode(RadioMode::Stdby).await?; self.cs.set_high().map_err(CS)?; Ok(()) } else { @@ -97,137 +89,125 @@ where } } - /// Transmits up to 255 bytes of data. To avoid the use of an allocator, this takes a fixed 255 u8 - /// array and a payload size and returns the number of bytes sent if successful. - pub fn transmit_payload_busy( - &mut self, - buffer: [u8; 255], - payload_size: usize, - ) -> Result> { - if self.transmitting()? { - Err(Transmitting) - } else { - self.set_mode(RadioMode::Stdby)?; - if self.explicit_header { - self.set_explicit_header_mode()?; - } else { - self.set_implicit_header_mode()?; - } - - self.write_register(Register::RegIrqFlags.addr(), 0)?; - self.write_register(Register::RegFifoAddrPtr.addr(), 0)?; - self.write_register(Register::RegPayloadLength.addr(), 0)?; - for byte in buffer.iter().take(payload_size) { - self.write_register(Register::RegFifo.addr(), *byte)?; - } - self.write_register(Register::RegPayloadLength.addr(), payload_size as u8)?; - self.set_mode(RadioMode::Tx)?; - while self.transmitting()? {} - Ok(payload_size) - } - } - - pub fn set_dio0_tx_done(&mut self) -> Result<(), Error> { - self.write_register(Register::RegIrqFlagsMask.addr(), 0b1111_0111)?; - let mapping = self.read_register(Register::RegDioMapping1.addr())?; + pub async fn set_dio0_tx_done(&mut self) -> Result<(), Error> { + self.write_register(Register::RegIrqFlagsMask.addr(), 0b1111_0111) + .await?; + let mapping = self.read_register(Register::RegDioMapping1.addr()).await?; self.write_register(Register::RegDioMapping1.addr(), (mapping & 0x3F) | 0x40) + .await } - pub fn set_dio0_rx_done(&mut self) -> Result<(), Error> { - self.write_register(Register::RegIrqFlagsMask.addr(), 0b0001_1111)?; - let mapping = self.read_register(Register::RegDioMapping1.addr())?; + pub async fn set_dio0_rx_done(&mut self) -> Result<(), Error> { + self.write_register(Register::RegIrqFlagsMask.addr(), 0b0001_1111) + .await?; + let mapping = self.read_register(Register::RegDioMapping1.addr()).await?; self.write_register(Register::RegDioMapping1.addr(), mapping & 0x3F) + .await } - pub fn transmit_payload( + pub async fn transmit_start( &mut self, buffer: &[u8], ) -> Result<(), Error> { assert!(buffer.len() < 255); - if self.transmitting()? { + if self.transmitting().await? { + //trace!("ALREADY TRANSMNITTING"); Err(Transmitting) } else { - self.set_mode(RadioMode::Stdby)?; + self.set_mode(RadioMode::Stdby).await?; if self.explicit_header { - self.set_explicit_header_mode()?; + self.set_explicit_header_mode().await?; } else { - self.set_implicit_header_mode()?; + self.set_implicit_header_mode().await?; } - self.write_register(Register::RegIrqFlags.addr(), 0)?; - self.write_register(Register::RegFifoAddrPtr.addr(), 0)?; - self.write_register(Register::RegPayloadLength.addr(), 0)?; + self.write_register(Register::RegIrqFlags.addr(), 0).await?; + self.write_register(Register::RegFifoAddrPtr.addr(), 0) + .await?; + self.write_register(Register::RegPayloadLength.addr(), 0) + .await?; for byte in buffer.iter() { - self.write_register(Register::RegFifo.addr(), *byte)?; + self.write_register(Register::RegFifo.addr(), *byte).await?; } - self.write_register(Register::RegPayloadLength.addr(), buffer.len() as u8)?; - self.set_mode(RadioMode::Tx)?; + self.write_register(Register::RegPayloadLength.addr(), buffer.len() as u8) + .await?; + self.set_mode(RadioMode::Tx).await?; Ok(()) } } - pub fn packet_ready(&mut self) -> Result> { - Ok(self.read_register(Register::RegIrqFlags.addr())?.get_bit(6)) + pub async fn packet_ready(&mut self) -> Result> { + Ok(self + .read_register(Register::RegIrqFlags.addr()) + .await? + .get_bit(6)) } - pub fn irq_flags_mask(&mut self) -> Result> { - Ok(self.read_register(Register::RegIrqFlagsMask.addr())? as u8) + pub async fn irq_flags_mask(&mut self) -> Result> { + Ok(self.read_register(Register::RegIrqFlagsMask.addr()).await? as u8) } - pub fn irq_flags(&mut self) -> Result> { - Ok(self.read_register(Register::RegIrqFlags.addr())? as u8) + pub async fn irq_flags(&mut self) -> Result> { + Ok(self.read_register(Register::RegIrqFlags.addr()).await? as u8) } - pub fn read_packet_size(&mut self) -> Result> { - let size = self.read_register(Register::RegRxNbBytes.addr())?; + pub async fn read_packet_size(&mut self) -> Result> { + let size = self.read_register(Register::RegRxNbBytes.addr()).await?; Ok(size as usize) } /// Returns the contents of the fifo as a fixed 255 u8 array. This should only be called is there is a /// new packet ready to be read. - pub fn read_packet( + pub async fn read_packet( &mut self, buffer: &mut [u8], ) -> Result<(), Error> { - self.clear_irq()?; - let size = self.read_register(Register::RegRxNbBytes.addr())?; + self.clear_irq().await?; + let size = self.read_register(Register::RegRxNbBytes.addr()).await?; assert!(size as usize <= buffer.len()); - let fifo_addr = self.read_register(Register::RegFifoRxCurrentAddr.addr())?; - self.write_register(Register::RegFifoAddrPtr.addr(), fifo_addr)?; + let fifo_addr = self + .read_register(Register::RegFifoRxCurrentAddr.addr()) + .await?; + self.write_register(Register::RegFifoAddrPtr.addr(), fifo_addr) + .await?; for i in 0..size { - let byte = self.read_register(Register::RegFifo.addr())?; + let byte = self.read_register(Register::RegFifo.addr()).await?; buffer[i as usize] = byte; } - self.write_register(Register::RegFifoAddrPtr.addr(), 0)?; + self.write_register(Register::RegFifoAddrPtr.addr(), 0) + .await?; Ok(()) } /// Returns true if the radio is currently transmitting a packet. - pub fn transmitting(&mut self) -> Result> { - if (self.read_register(Register::RegOpMode.addr())? & RadioMode::Tx.addr()) + pub async fn transmitting(&mut self) -> Result> { + if (self.read_register(Register::RegOpMode.addr()).await?) & RadioMode::Tx.addr() == RadioMode::Tx.addr() { Ok(true) } else { - if (self.read_register(Register::RegIrqFlags.addr())? & IRQ::IrqTxDoneMask.addr()) == 1 + if (self.read_register(Register::RegIrqFlags.addr()).await? & IRQ::IrqTxDoneMask.addr()) + == 1 { - self.write_register(Register::RegIrqFlags.addr(), IRQ::IrqTxDoneMask.addr())?; + self.write_register(Register::RegIrqFlags.addr(), IRQ::IrqTxDoneMask.addr()) + .await?; } Ok(false) } } /// Clears the radio's IRQ registers. - pub fn clear_irq(&mut self) -> Result> { - let irq_flags = self.read_register(Register::RegIrqFlags.addr())?; - self.write_register(Register::RegIrqFlags.addr(), 0xFF)?; + pub async fn clear_irq(&mut self) -> Result> { + let irq_flags = self.read_register(Register::RegIrqFlags.addr()).await?; + self.write_register(Register::RegIrqFlags.addr(), 0xFF) + .await?; Ok(irq_flags) } /// Sets the transmit power and pin. Levels can range from 0-14 when the output /// pin = 0(RFO), and form 0-20 when output pin = 1(PaBoost). Power is in dB. /// Default value is `17`. - pub fn set_tx_power( + pub async fn set_tx_power( &mut self, mut level: i32, output_pin: u8, @@ -240,6 +220,7 @@ where level = 14; } self.write_register(Register::RegPaConfig.addr(), (0x70 | level) as u8) + .await } else { // PA BOOST if level > 17 { @@ -250,30 +231,31 @@ where level -= 3; // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) - self.write_register(Register::RegPaDac.addr(), 0x87)?; - self.set_ocp(140)?; + self.write_register(Register::RegPaDac.addr(), 0x87).await?; + self.set_ocp(140).await?; } else { if level < 2 { level = 2; } //Default value PA_HF/LF or +17dBm - self.write_register(Register::RegPaDac.addr(), 0x84)?; - self.set_ocp(100)?; + self.write_register(Register::RegPaDac.addr(), 0x84).await?; + self.set_ocp(100).await?; } level -= 2; self.write_register( Register::RegPaConfig.addr(), PaConfig::PaBoost.addr() | level as u8, ) + .await } } - pub fn get_modem_stat(&mut self) -> Result> { - Ok(self.read_register(Register::RegModemStat.addr())? as u8) + pub async fn get_modem_stat(&mut self) -> Result> { + Ok(self.read_register(Register::RegModemStat.addr()).await? as u8) } /// Sets the over current protection on the radio(mA). - pub fn set_ocp(&mut self, ma: u8) -> Result<(), Error> { + pub async fn set_ocp(&mut self, ma: u8) -> Result<(), Error> { let mut ocp_trim: u8 = 27; if ma <= 120 { @@ -282,31 +264,40 @@ where ocp_trim = (ma + 30) / 10; } self.write_register(Register::RegOcp.addr(), 0x20 | (0x1F & ocp_trim)) + .await } /// Sets the state of the radio. Default mode after initiation is `Standby`. - pub fn set_mode(&mut self, mode: RadioMode) -> Result<(), Error> { + pub async fn set_mode( + &mut self, + mode: RadioMode, + ) -> Result<(), Error> { if self.explicit_header { - self.set_explicit_header_mode()?; + self.set_explicit_header_mode().await?; } else { - self.set_implicit_header_mode()?; + self.set_implicit_header_mode().await?; } self.write_register( Register::RegOpMode.addr(), RadioMode::LongRangeMode.addr() | mode.addr(), - )?; + ) + .await?; self.mode = mode; Ok(()) } - pub fn reset_payload_length(&mut self) -> Result<(), Error> { + pub async fn reset_payload_length(&mut self) -> Result<(), Error> { self.write_register(Register::RegPayloadLength.addr(), 0xFF) + .await } /// Sets the frequency of the radio. Values are in megahertz. /// I.E. 915 MHz must be used for North America. Check regulation for your area. - pub fn set_frequency(&mut self, freq: u32) -> Result<(), Error> { + pub async fn set_frequency( + &mut self, + freq: u32, + ) -> Result<(), Error> { const FREQ_STEP: f64 = 61.03515625; // calculate register values let frf = (freq as f64 / FREQ_STEP) as u32; @@ -314,23 +305,28 @@ where self.write_register( Register::RegFrfMsb.addr(), ((frf & 0x00FF_0000) >> 16) as u8, - )?; - self.write_register(Register::RegFrfMid.addr(), ((frf & 0x0000_FF00) >> 8) as u8)?; + ) + .await?; + self.write_register(Register::RegFrfMid.addr(), ((frf & 0x0000_FF00) >> 8) as u8) + .await?; self.write_register(Register::RegFrfLsb.addr(), (frf & 0x0000_00FF) as u8) + .await } /// Sets the radio to use an explicit header. Default state is `ON`. - fn set_explicit_header_mode(&mut self) -> Result<(), Error> { - let reg_modem_config_1 = self.read_register(Register::RegModemConfig1.addr())?; - self.write_register(Register::RegModemConfig1.addr(), reg_modem_config_1 & 0xfe)?; + async fn set_explicit_header_mode(&mut self) -> Result<(), Error> { + let reg_modem_config_1 = self.read_register(Register::RegModemConfig1.addr()).await?; + self.write_register(Register::RegModemConfig1.addr(), reg_modem_config_1 & 0xfe) + .await?; self.explicit_header = true; Ok(()) } /// Sets the radio to use an implicit header. Default state is `OFF`. - fn set_implicit_header_mode(&mut self) -> Result<(), Error> { - let reg_modem_config_1 = self.read_register(Register::RegModemConfig1.addr())?; - self.write_register(Register::RegModemConfig1.addr(), reg_modem_config_1 & 0x01)?; + async fn set_implicit_header_mode(&mut self) -> Result<(), Error> { + let reg_modem_config_1 = self.read_register(Register::RegModemConfig1.addr()).await?; + self.write_register(Register::RegModemConfig1.addr(), reg_modem_config_1 & 0x01) + .await?; self.explicit_header = false; Ok(()) } @@ -338,7 +334,7 @@ where /// Sets the spreading factor of the radio. Supported values are between 6 and 12. /// If a spreading factor of 6 is set, implicit header mode must be used to transmit /// and receive packets. Default value is `7`. - pub fn set_spreading_factor( + pub async fn set_spreading_factor( &mut self, mut sf: u8, ) -> Result<(), Error> { @@ -349,36 +345,45 @@ where } if sf == 6 { - self.write_register(Register::RegDetectionOptimize.addr(), 0xc5)?; - self.write_register(Register::RegDetectionThreshold.addr(), 0x0c)?; + self.write_register(Register::RegDetectionOptimize.addr(), 0xc5) + .await?; + self.write_register(Register::RegDetectionThreshold.addr(), 0x0c) + .await?; } else { - self.write_register(Register::RegDetectionOptimize.addr(), 0xc3)?; - self.write_register(Register::RegDetectionThreshold.addr(), 0x0a)?; + self.write_register(Register::RegDetectionOptimize.addr(), 0xc3) + .await?; + self.write_register(Register::RegDetectionThreshold.addr(), 0x0a) + .await?; } - let modem_config_2 = self.read_register(Register::RegModemConfig2.addr())?; + let modem_config_2 = self.read_register(Register::RegModemConfig2.addr()).await?; self.write_register( Register::RegModemConfig2.addr(), (modem_config_2 & 0x0f) | ((sf << 4) & 0xf0), - )?; - self.set_ldo_flag()?; + ) + .await?; + self.set_ldo_flag().await?; - self.write_register(Register::RegSymbTimeoutLsb.addr(), 0x05)?; + self.write_register(Register::RegSymbTimeoutLsb.addr(), 0x05) + .await?; Ok(()) } - pub fn set_tcxo(&mut self, external: bool) -> Result<(), Error> { + pub async fn set_tcxo( + &mut self, + external: bool, + ) -> Result<(), Error> { if external { - self.write_register(Register::RegTcxo.addr(), 0x10) + self.write_register(Register::RegTcxo.addr(), 0x10).await } else { - self.write_register(Register::RegTcxo.addr(), 0x00) + self.write_register(Register::RegTcxo.addr(), 0x00).await } } /// Sets the signal bandwidth of the radio. Supported values are: `7800 Hz`, `10400 Hz`, /// `15600 Hz`, `20800 Hz`, `31250 Hz`,`41700 Hz` ,`62500 Hz`,`125000 Hz` and `250000 Hz` /// Default value is `125000 Hz` - pub fn set_signal_bandwidth( + pub async fn set_signal_bandwidth( &mut self, sbw: i64, ) -> Result<(), Error> { @@ -394,19 +399,20 @@ where 250_000 => 8, _ => 9, }; - let modem_config_1 = self.read_register(Register::RegModemConfig1.addr())?; + let modem_config_1 = self.read_register(Register::RegModemConfig1.addr()).await?; self.write_register( Register::RegModemConfig1.addr(), (modem_config_1 & 0x0f) | ((bw << 4) as u8), - )?; - self.set_ldo_flag()?; + ) + .await?; + self.set_ldo_flag().await?; Ok(()) } /// Sets the coding rate of the radio with the numerator fixed at 4. Supported values /// are between `5` and `8`, these correspond to coding rates of `4/5` and `4/8`. /// Default value is `5`. - pub fn set_coding_rate_4( + pub async fn set_coding_rate_4( &mut self, mut denominator: u8, ) -> Result<(), Error> { @@ -416,52 +422,64 @@ where denominator = 8; } let cr = denominator - 4; - let modem_config_1 = self.read_register(Register::RegModemConfig1.addr())?; + let modem_config_1 = self.read_register(Register::RegModemConfig1.addr()).await?; self.write_register( Register::RegModemConfig1.addr(), (modem_config_1 & 0xf1) | (cr << 1), ) + .await } /// Sets the preamble length of the radio. Values are between 6 and 65535. /// Default value is `8`. - pub fn set_preamble_length( + pub async fn set_preamble_length( &mut self, length: i64, ) -> Result<(), Error> { - self.write_register(Register::RegPreambleMsb.addr(), (length >> 8) as u8)?; + self.write_register(Register::RegPreambleMsb.addr(), (length >> 8) as u8) + .await?; self.write_register(Register::RegPreambleLsb.addr(), length as u8) + .await } /// Enables are disables the radio's CRC check. Default value is `false`. - pub fn set_crc(&mut self, value: bool) -> Result<(), Error> { - let modem_config_2 = self.read_register(Register::RegModemConfig2.addr())?; + pub async fn set_crc(&mut self, value: bool) -> Result<(), Error> { + let modem_config_2 = self.read_register(Register::RegModemConfig2.addr()).await?; if value { self.write_register(Register::RegModemConfig2.addr(), modem_config_2 | 0x04) + .await } else { self.write_register(Register::RegModemConfig2.addr(), modem_config_2 & 0xfb) + .await } } /// Inverts the radio's IQ signals. Default value is `false`. - pub fn set_invert_iq(&mut self, value: bool) -> Result<(), Error> { + pub async fn set_invert_iq( + &mut self, + value: bool, + ) -> Result<(), Error> { if value { - self.write_register(Register::RegInvertiq.addr(), 0x66)?; + self.write_register(Register::RegInvertiq.addr(), 0x66) + .await?; self.write_register(Register::RegInvertiq2.addr(), 0x19) + .await } else { - self.write_register(Register::RegInvertiq.addr(), 0x27)?; + self.write_register(Register::RegInvertiq.addr(), 0x27) + .await?; self.write_register(Register::RegInvertiq2.addr(), 0x1d) + .await } } /// Returns the spreading factor of the radio. - pub fn get_spreading_factor(&mut self) -> Result> { - Ok(self.read_register(Register::RegModemConfig2.addr())? >> 4) + pub async fn get_spreading_factor(&mut self) -> Result> { + Ok(self.read_register(Register::RegModemConfig2.addr()).await? >> 4) } /// Returns the signal bandwidth of the radio. - pub fn get_signal_bandwidth(&mut self) -> Result> { - let bw = self.read_register(Register::RegModemConfig1.addr())? >> 4; + pub async fn get_signal_bandwidth(&mut self) -> Result> { + let bw = self.read_register(Register::RegModemConfig1.addr()).await? >> 4; let bw = match bw { 0 => 7_800, 1 => 10_400, @@ -479,69 +497,77 @@ where } /// Returns the RSSI of the last received packet. - pub fn get_packet_rssi(&mut self) -> Result> { - Ok(i32::from(self.read_register(Register::RegPktRssiValue.addr())?) - 157) + pub async fn get_packet_rssi(&mut self) -> Result> { + Ok(i32::from(self.read_register(Register::RegPktRssiValue.addr()).await?) - 157) } /// Returns the signal to noise radio of the the last received packet. - pub fn get_packet_snr(&mut self) -> Result> { + pub async fn get_packet_snr(&mut self) -> Result> { Ok(f64::from( - self.read_register(Register::RegPktSnrValue.addr())?, + self.read_register(Register::RegPktSnrValue.addr()).await?, )) } /// Returns the frequency error of the last received packet in Hz. - pub fn get_packet_frequency_error(&mut self) -> Result> { + pub async fn get_packet_frequency_error( + &mut self, + ) -> Result> { let mut freq_error: i32; - freq_error = i32::from(self.read_register(Register::RegFreqErrorMsb.addr())? & 0x7); + freq_error = i32::from(self.read_register(Register::RegFreqErrorMsb.addr()).await? & 0x7); freq_error <<= 8i64; - freq_error += i32::from(self.read_register(Register::RegFreqErrorMid.addr())?); + freq_error += i32::from(self.read_register(Register::RegFreqErrorMid.addr()).await?); freq_error <<= 8i64; - freq_error += i32::from(self.read_register(Register::RegFreqErrorLsb.addr())?); + freq_error += i32::from(self.read_register(Register::RegFreqErrorLsb.addr()).await?); let f_xtal = 32_000_000; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14) let f_error = ((f64::from(freq_error) * (1i64 << 24) as f64) / f64::from(f_xtal)) - * (self.get_signal_bandwidth()? as f64 / 500_000.0f64); // p. 37 + * (self.get_signal_bandwidth().await? as f64 / 500_000.0f64); // p. 37 Ok(f_error as i64) } - fn set_ldo_flag(&mut self) -> Result<(), Error> { - let sw = self.get_signal_bandwidth()?; + async fn set_ldo_flag(&mut self) -> Result<(), Error> { + let sw = self.get_signal_bandwidth().await?; // Section 4.1.1.5 - let symbol_duration = 1000 / (sw / ((1_i64) << self.get_spreading_factor()?)); + let symbol_duration = 1000 / (sw / ((1_i64) << self.get_spreading_factor().await?)); // Section 4.1.1.6 let ldo_on = symbol_duration > 16; - let mut config_3 = self.read_register(Register::RegModemConfig3.addr())?; + let mut config_3 = self.read_register(Register::RegModemConfig3.addr()).await?; config_3.set_bit(3, ldo_on); //config_3.set_bit(2, true); self.write_register(Register::RegModemConfig3.addr(), config_3) + .await } - fn read_register(&mut self, reg: u8) -> Result> { + async fn read_register(&mut self, reg: u8) -> Result> { + let mut buffer = [reg & 0x7f, 0]; self.cs.set_low().map_err(CS)?; - let mut buffer = [reg & 0x7f, 0]; - let transfer = self.spi.transfer(&mut buffer).map_err(SPI)?; + let _ = self + .spi + .read_write(&mut buffer, &[reg & 0x7f, 0]) + .await + .map_err(SPI)?; + self.cs.set_high().map_err(CS)?; - Ok(transfer[1]) + Ok(buffer[1]) } - fn write_register( + async fn write_register( &mut self, reg: u8, byte: u8, ) -> Result<(), Error> { self.cs.set_low().map_err(CS)?; - + let mut rx = [0, 0]; let buffer = [reg | 0x80, byte]; - self.spi.write(&buffer).map_err(SPI)?; + self.spi.read_write(&mut rx, &buffer).await.map_err(SPI)?; self.cs.set_high().map_err(CS)?; Ok(()) } - pub fn put_in_fsk_mode(&mut self) -> Result<(), Error> { + pub async fn put_in_fsk_mode(&mut self) -> Result<(), Error> { // Put in FSK mode let mut op_mode = 0; op_mode @@ -551,9 +577,10 @@ where .set_bits(0..2, 0b011); // Mode self.write_register(Register::RegOpMode as u8, op_mode) + .await } - pub fn set_fsk_pa_ramp( + pub async fn set_fsk_pa_ramp( &mut self, modulation_shaping: FskDataModulationShaping, ramp: FskRampUpRamDown, @@ -564,14 +591,15 @@ where .set_bits(0..3, ramp as u8); self.write_register(Register::RegPaRamp as u8, pa_ramp) + .await } - pub fn set_lora_pa_ramp(&mut self) -> Result<(), Error> { - self.write_register(Register::RegPaRamp as u8, 0b1000) + pub async fn set_lora_pa_ramp(&mut self) -> Result<(), Error> { + self.write_register(Register::RegPaRamp as u8, 0b1000).await } - pub fn set_lora_sync_word(&mut self) -> Result<(), Error> { - self.write_register(Register::RegSyncWord as u8, 0x34) + pub async fn set_lora_sync_word(&mut self) -> Result<(), Error> { + self.write_register(Register::RegSyncWord as u8, 0x34).await } } /// Modes of the radio and their corresponding register values. diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 6d840d503..53ba6ba39 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -20,7 +20,7 @@ defmt-rtt = "0.3" cortex-m = "0.7.3" cortex-m-rt = "0.7.0" -embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } +embedded-hal = "0.2.6" diff --git a/examples/stm32l0/src/bin/lorawan.rs b/examples/stm32l0/src/bin/lorawan.rs index 5ca69f9a7..cbae88356 100644 --- a/examples/stm32l0/src/bin/lorawan.rs +++ b/examples/stm32l0/src/bin/lorawan.rs @@ -12,7 +12,6 @@ mod example_common; use embassy_lora::{sx127x::*, LoraTimer}; use embassy_stm32::{ dbgmcu::Dbgmcu, - dma::NoDma, exti::ExtiInput, gpio::{Input, Level, Output, Pull, Speed}, rcc, @@ -45,8 +44,8 @@ async fn main(_spawner: embassy::executor::Spawner, mut p: Peripherals) { p.PB3, p.PA7, p.PA6, - NoDma, - NoDma, + p.DMA1_CH3, + p.DMA1_CH2, 200_000.hz(), spi::Config::default(), ); @@ -58,15 +57,9 @@ async fn main(_spawner: embassy::executor::Spawner, mut p: Peripherals) { let ready = Input::new(p.PB4, Pull::Up); let ready_pin = ExtiInput::new(ready, p.EXTI4); - let radio = Sx127xRadio::new( - spi, - cs, - reset, - ready_pin, - DummySwitch, - &mut embassy::time::Delay, - ) - .unwrap(); + let radio = Sx127xRadio::new(spi, cs, reset, ready_pin, DummySwitch) + .await + .unwrap(); let region = region::EU868::default().into(); let mut radio_buffer = [0; 256];