Refactor sx127x radio to use async SPI with DMA

This commit is contained in:
Ulf Lilleengen 2021-12-01 21:59:53 +01:00
parent b9693c0b91
commit 9a730ef692
4 changed files with 252 additions and 226 deletions

View File

@ -1,7 +1,6 @@
use core::future::Future; use core::future::Future;
use embassy::traits::gpio::WaitForRisingEdge; use embassy::traits::gpio::WaitForRisingEdge;
use embedded_hal::blocking::delay::DelayMs; use embassy::traits::spi::*;
use embedded_hal::blocking::spi::{Transfer, Write};
use embedded_hal::digital::v2::OutputPin; use embedded_hal::digital::v2::OutputPin;
use lorawan_device::async_device::{ use lorawan_device::async_device::{
radio::{Bandwidth, PhyRxTx, RfConfig, RxQuality, SpreadingFactor, TxConfig}, radio::{Bandwidth, PhyRxTx, RfConfig, RxQuality, SpreadingFactor, TxConfig},
@ -21,7 +20,7 @@ pub trait RadioSwitch {
/// Semtech Sx127x radio peripheral /// Semtech Sx127x radio peripheral
pub struct Sx127xRadio<SPI, CS, RESET, E, I, RFS> pub struct Sx127xRadio<SPI, CS, RESET, E, I, RFS>
where where
SPI: Transfer<u8, Error = E> + Write<u8, Error = E> + 'static, SPI: FullDuplex<u8, Error = E> + 'static,
E: 'static, E: 'static,
CS: OutputPin + 'static, CS: OutputPin + 'static,
RESET: OutputPin + 'static, RESET: OutputPin + 'static,
@ -43,29 +42,29 @@ pub enum State {
impl<SPI, CS, RESET, E, I, RFS> Sx127xRadio<SPI, CS, RESET, E, I, RFS> impl<SPI, CS, RESET, E, I, RFS> Sx127xRadio<SPI, CS, RESET, E, I, RFS>
where where
SPI: Transfer<u8, Error = E> + Write<u8, Error = E> + 'static, SPI: FullDuplex<u8, Error = E> + 'static,
CS: OutputPin + 'static, CS: OutputPin + 'static,
RESET: OutputPin + 'static, RESET: OutputPin + 'static,
I: WaitForRisingEdge + 'static, I: WaitForRisingEdge + 'static,
RFS: RadioSwitch + 'static, RFS: RadioSwitch + 'static,
E: 'static,
{ {
pub fn new<D: DelayMs<u32>>( pub async fn new(
spi: SPI, spi: SPI,
cs: CS, cs: CS,
reset: RESET, reset: RESET,
irq: I, irq: I,
rfs: RFS, rfs: RFS,
d: &mut D,
) -> Result<Self, RadioError<E, CS::Error, RESET::Error>> { ) -> Result<Self, RadioError<E, CS::Error, RESET::Error>> {
let mut radio = LoRa::new(spi, cs, reset); let mut radio = LoRa::new(spi, cs, reset);
radio.reset(d)?; radio.reset().await?;
Ok(Self { radio, irq, rfs }) Ok(Self { radio, irq, rfs })
} }
} }
impl<SPI, CS, RESET, E, I, RFS> Timings for Sx127xRadio<SPI, CS, RESET, E, I, RFS> impl<SPI, CS, RESET, E, I, RFS> Timings for Sx127xRadio<SPI, CS, RESET, E, I, RFS>
where where
SPI: Transfer<u8, Error = E> + Write<u8, Error = E> + 'static, SPI: FullDuplex<u8, Error = E> + 'static,
CS: OutputPin + 'static, CS: OutputPin + 'static,
RESET: OutputPin + 'static, RESET: OutputPin + 'static,
I: WaitForRisingEdge + 'static, I: WaitForRisingEdge + 'static,
@ -81,7 +80,7 @@ where
impl<SPI, CS, RESET, E, I, RFS> PhyRxTx for Sx127xRadio<SPI, CS, RESET, E, I, RFS> impl<SPI, CS, RESET, E, I, RFS> PhyRxTx for Sx127xRadio<SPI, CS, RESET, E, I, RFS>
where where
SPI: Transfer<u8, Error = E> + Write<u8, Error = E> + 'static, SPI: FullDuplex<u8, Error = E> + 'static,
CS: OutputPin + 'static, CS: OutputPin + 'static,
E: 'static, E: 'static,
RESET: OutputPin + 'static, RESET: OutputPin + 'static,
@ -96,29 +95,33 @@ where
fn tx<'m>(&'m mut self, config: TxConfig, buf: &'m [u8]) -> Self::TxFuture<'m> { fn tx<'m>(&'m mut self, config: TxConfig, buf: &'m [u8]) -> Self::TxFuture<'m> {
trace!("TX START"); trace!("TX START");
async move { async move {
self.radio.set_mode(RadioMode::Stdby).await.ok().unwrap();
self.rfs.set_tx(); self.rfs.set_tx();
self.radio.set_tx_power(14, 0)?; self.radio.set_tx_power(14, 0).await?;
self.radio.set_frequency(config.rf.frequency)?; self.radio.set_frequency(config.rf.frequency).await?;
// TODO: Modify radio to support other coding rates // 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 self.radio
.set_signal_bandwidth(bandwidth_to_i64(config.rf.bandwidth))?; .set_signal_bandwidth(bandwidth_to_i64(config.rf.bandwidth))
.await?;
self.radio 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_preamble_length(8).await?;
self.radio.set_lora_pa_ramp()?; self.radio.set_lora_pa_ramp().await?;
self.radio.set_lora_sync_word()?; self.radio.set_lora_sync_word().await?;
self.radio.set_invert_iq(false)?; self.radio.set_invert_iq(false).await?;
self.radio.set_crc(true)?; self.radio.set_crc(true).await?;
self.radio.set_dio0_tx_done()?; self.radio.set_dio0_tx_done().await?;
self.radio.transmit_payload(buf)?;
self.radio.transmit_start(buf).await?;
loop { loop {
self.irq.wait_for_rising_edge().await; self.irq.wait_for_rising_edge().await;
self.radio.set_mode(RadioMode::Stdby).ok().unwrap(); self.radio.set_mode(RadioMode::Stdby).await.ok().unwrap();
let irq = self.radio.clear_irq().ok().unwrap(); let irq = self.radio.clear_irq().await.ok().unwrap();
if (irq & IRQ::IrqTxDoneMask.addr()) != 0 { if (irq & IRQ::IrqTxDoneMask.addr()) != 0 {
trace!("TX DONE"); trace!("TX DONE");
return Ok(0); return Ok(0);
@ -134,32 +137,34 @@ where
trace!("RX START"); trace!("RX START");
async move { async move {
self.rfs.set_rx(); self.rfs.set_rx();
self.radio.reset_payload_length()?; self.radio.reset_payload_length().await?;
self.radio.set_frequency(config.frequency)?; self.radio.set_frequency(config.frequency).await?;
// TODO: Modify radio to support other coding rates // 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 self.radio
.set_signal_bandwidth(bandwidth_to_i64(config.bandwidth))?; .set_signal_bandwidth(bandwidth_to_i64(config.bandwidth))
.await?;
self.radio 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_preamble_length(8).await?;
self.radio.set_lora_sync_word()?; self.radio.set_lora_sync_word().await?;
self.radio.set_invert_iq(true)?; self.radio.set_invert_iq(true).await?;
self.radio.set_crc(true)?; self.radio.set_crc(true).await?;
self.radio.set_dio0_rx_done()?; self.radio.set_dio0_rx_done().await?;
self.radio.set_mode(RadioMode::RxContinuous)?; self.radio.set_mode(RadioMode::RxContinuous).await?;
loop { loop {
self.irq.wait_for_rising_edge().await; self.irq.wait_for_rising_edge().await;
self.radio.set_mode(RadioMode::Stdby).ok().unwrap(); self.radio.set_mode(RadioMode::Stdby).await.ok().unwrap();
let irq = self.radio.clear_irq().ok().unwrap(); let irq = self.radio.clear_irq().await.ok().unwrap();
if (irq & IRQ::IrqRxDoneMask.addr()) != 0 { if (irq & IRQ::IrqRxDoneMask.addr()) != 0 {
let rssi = self.radio.get_packet_rssi().unwrap_or(0) as i16; let rssi = self.radio.get_packet_rssi().await.unwrap_or(0) as i16;
let snr = self.radio.get_packet_snr().unwrap_or(0.0) as i8; 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() { let response = if let Ok(size) = self.radio.read_packet_size().await {
self.radio.read_packet(buf)?; self.radio.read_packet(buf).await?;
Ok((size, RxQuality::new(rssi, snr))) Ok((size, RxQuality::new(rssi, snr)))
} else { } else {
Ok((0, RxQuality::new(rssi, snr))) Ok((0, RxQuality::new(rssi, snr)))

View File

@ -6,24 +6,15 @@
#![allow(dead_code)] #![allow(dead_code)]
use bit_field::BitField; use bit_field::BitField;
use embedded_hal::blocking::{ use embassy::time::{Duration, Timer};
delay::DelayMs, use embassy::traits::spi::*;
spi::{Transfer, Write},
};
use embedded_hal::digital::v2::OutputPin; use embedded_hal::digital::v2::OutputPin;
use embedded_hal::spi::{Mode, Phase, Polarity};
mod register; mod register;
use self::register::PaConfig; use self::register::PaConfig;
use self::register::Register; use self::register::Register;
pub use self::register::IRQ; 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 /// Provides high-level access to Semtech SX1276/77/78/79 based boards connected to a Raspberry Pi
pub struct LoRa<SPI, CS, RESET> { pub struct LoRa<SPI, CS, RESET> {
spi: SPI, spi: SPI,
@ -56,7 +47,7 @@ const VERSION_CHECK: u8 = 0x09;
impl<SPI, CS, RESET, E> LoRa<SPI, CS, RESET> impl<SPI, CS, RESET, E> LoRa<SPI, CS, RESET>
where where
SPI: Transfer<u8, Error = E> + Write<u8, Error = E>, SPI: FullDuplex<u8, Error = E>,
CS: OutputPin, CS: OutputPin,
RESET: OutputPin, RESET: OutputPin,
{ {
@ -72,24 +63,25 @@ where
} }
} }
pub fn reset<D: DelayMs<u32>>( pub async fn reset(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
&mut self,
d: &mut D,
) -> Result<(), Error<E, CS::Error, RESET::Error>> {
self.reset.set_low().map_err(Reset)?; 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)?; self.reset.set_high().map_err(Reset)?;
d.delay_ms(10_u32); Timer::after(Duration::from_millis(10)).await;
let version = self.read_register(Register::RegVersion.addr())?; let version = self.read_register(Register::RegVersion.addr()).await?;
if version == VERSION_CHECK { if version == VERSION_CHECK {
self.set_mode(RadioMode::Sleep)?; self.set_mode(RadioMode::Sleep).await?;
self.write_register(Register::RegFifoTxBaseAddr.addr(), 0)?; self.write_register(Register::RegFifoTxBaseAddr.addr(), 0)
self.write_register(Register::RegFifoRxBaseAddr.addr(), 0)?; .await?;
let lna = self.read_register(Register::RegLna.addr())?; self.write_register(Register::RegFifoRxBaseAddr.addr(), 0)
self.write_register(Register::RegLna.addr(), lna | 0x03)?; .await?;
self.write_register(Register::RegModemConfig3.addr(), 0x04)?; let lna = self.read_register(Register::RegLna.addr()).await?;
self.set_tcxo(true)?; self.write_register(Register::RegLna.addr(), lna | 0x03)
self.set_mode(RadioMode::Stdby)?; .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)?; self.cs.set_high().map_err(CS)?;
Ok(()) Ok(())
} else { } 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 pub async fn set_dio0_tx_done(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
/// array and a payload size and returns the number of bytes sent if successful. self.write_register(Register::RegIrqFlagsMask.addr(), 0b1111_0111)
pub fn transmit_payload_busy( .await?;
&mut self, let mapping = self.read_register(Register::RegDioMapping1.addr()).await?;
buffer: [u8; 255],
payload_size: usize,
) -> Result<usize, Error<E, CS::Error, RESET::Error>> {
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<E, CS::Error, RESET::Error>> {
self.write_register(Register::RegIrqFlagsMask.addr(), 0b1111_0111)?;
let mapping = self.read_register(Register::RegDioMapping1.addr())?;
self.write_register(Register::RegDioMapping1.addr(), (mapping & 0x3F) | 0x40) self.write_register(Register::RegDioMapping1.addr(), (mapping & 0x3F) | 0x40)
.await
} }
pub fn set_dio0_rx_done(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> { pub async fn set_dio0_rx_done(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
self.write_register(Register::RegIrqFlagsMask.addr(), 0b0001_1111)?; self.write_register(Register::RegIrqFlagsMask.addr(), 0b0001_1111)
let mapping = self.read_register(Register::RegDioMapping1.addr())?; .await?;
let mapping = self.read_register(Register::RegDioMapping1.addr()).await?;
self.write_register(Register::RegDioMapping1.addr(), mapping & 0x3F) self.write_register(Register::RegDioMapping1.addr(), mapping & 0x3F)
.await
} }
pub fn transmit_payload( pub async fn transmit_start(
&mut self, &mut self,
buffer: &[u8], buffer: &[u8],
) -> Result<(), Error<E, CS::Error, RESET::Error>> { ) -> Result<(), Error<E, CS::Error, RESET::Error>> {
assert!(buffer.len() < 255); assert!(buffer.len() < 255);
if self.transmitting()? { if self.transmitting().await? {
//trace!("ALREADY TRANSMNITTING");
Err(Transmitting) Err(Transmitting)
} else { } else {
self.set_mode(RadioMode::Stdby)?; self.set_mode(RadioMode::Stdby).await?;
if self.explicit_header { if self.explicit_header {
self.set_explicit_header_mode()?; self.set_explicit_header_mode().await?;
} else { } else {
self.set_implicit_header_mode()?; self.set_implicit_header_mode().await?;
} }
self.write_register(Register::RegIrqFlags.addr(), 0)?; self.write_register(Register::RegIrqFlags.addr(), 0).await?;
self.write_register(Register::RegFifoAddrPtr.addr(), 0)?; self.write_register(Register::RegFifoAddrPtr.addr(), 0)
self.write_register(Register::RegPayloadLength.addr(), 0)?; .await?;
self.write_register(Register::RegPayloadLength.addr(), 0)
.await?;
for byte in buffer.iter() { 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.write_register(Register::RegPayloadLength.addr(), buffer.len() as u8)
self.set_mode(RadioMode::Tx)?; .await?;
self.set_mode(RadioMode::Tx).await?;
Ok(()) Ok(())
} }
} }
pub fn packet_ready(&mut self) -> Result<bool, Error<E, CS::Error, RESET::Error>> { pub async fn packet_ready(&mut self) -> Result<bool, Error<E, CS::Error, RESET::Error>> {
Ok(self.read_register(Register::RegIrqFlags.addr())?.get_bit(6)) Ok(self
.read_register(Register::RegIrqFlags.addr())
.await?
.get_bit(6))
} }
pub fn irq_flags_mask(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> { pub async fn irq_flags_mask(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> {
Ok(self.read_register(Register::RegIrqFlagsMask.addr())? as u8) Ok(self.read_register(Register::RegIrqFlagsMask.addr()).await? as u8)
} }
pub fn irq_flags(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> { pub async fn irq_flags(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> {
Ok(self.read_register(Register::RegIrqFlags.addr())? as u8) Ok(self.read_register(Register::RegIrqFlags.addr()).await? as u8)
} }
pub fn read_packet_size(&mut self) -> Result<usize, Error<E, CS::Error, RESET::Error>> { pub async fn read_packet_size(&mut self) -> Result<usize, Error<E, CS::Error, RESET::Error>> {
let size = self.read_register(Register::RegRxNbBytes.addr())?; let size = self.read_register(Register::RegRxNbBytes.addr()).await?;
Ok(size as usize) 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 /// 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. /// new packet ready to be read.
pub fn read_packet( pub async fn read_packet(
&mut self, &mut self,
buffer: &mut [u8], buffer: &mut [u8],
) -> Result<(), Error<E, CS::Error, RESET::Error>> { ) -> Result<(), Error<E, CS::Error, RESET::Error>> {
self.clear_irq()?; self.clear_irq().await?;
let size = self.read_register(Register::RegRxNbBytes.addr())?; let size = self.read_register(Register::RegRxNbBytes.addr()).await?;
assert!(size as usize <= buffer.len()); assert!(size as usize <= buffer.len());
let fifo_addr = self.read_register(Register::RegFifoRxCurrentAddr.addr())?; let fifo_addr = self
self.write_register(Register::RegFifoAddrPtr.addr(), fifo_addr)?; .read_register(Register::RegFifoRxCurrentAddr.addr())
.await?;
self.write_register(Register::RegFifoAddrPtr.addr(), fifo_addr)
.await?;
for i in 0..size { 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; buffer[i as usize] = byte;
} }
self.write_register(Register::RegFifoAddrPtr.addr(), 0)?; self.write_register(Register::RegFifoAddrPtr.addr(), 0)
.await?;
Ok(()) Ok(())
} }
/// Returns true if the radio is currently transmitting a packet. /// Returns true if the radio is currently transmitting a packet.
pub fn transmitting(&mut self) -> Result<bool, Error<E, CS::Error, RESET::Error>> { pub async fn transmitting(&mut self) -> Result<bool, Error<E, CS::Error, RESET::Error>> {
if (self.read_register(Register::RegOpMode.addr())? & RadioMode::Tx.addr()) if (self.read_register(Register::RegOpMode.addr()).await?) & RadioMode::Tx.addr()
== RadioMode::Tx.addr() == RadioMode::Tx.addr()
{ {
Ok(true) Ok(true)
} else { } 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) Ok(false)
} }
} }
/// Clears the radio's IRQ registers. /// Clears the radio's IRQ registers.
pub fn clear_irq(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> { pub async fn clear_irq(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> {
let irq_flags = self.read_register(Register::RegIrqFlags.addr())?; let irq_flags = self.read_register(Register::RegIrqFlags.addr()).await?;
self.write_register(Register::RegIrqFlags.addr(), 0xFF)?; self.write_register(Register::RegIrqFlags.addr(), 0xFF)
.await?;
Ok(irq_flags) Ok(irq_flags)
} }
/// Sets the transmit power and pin. Levels can range from 0-14 when the output /// 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. /// pin = 0(RFO), and form 0-20 when output pin = 1(PaBoost). Power is in dB.
/// Default value is `17`. /// Default value is `17`.
pub fn set_tx_power( pub async fn set_tx_power(
&mut self, &mut self,
mut level: i32, mut level: i32,
output_pin: u8, output_pin: u8,
@ -240,6 +220,7 @@ where
level = 14; level = 14;
} }
self.write_register(Register::RegPaConfig.addr(), (0x70 | level) as u8) self.write_register(Register::RegPaConfig.addr(), (0x70 | level) as u8)
.await
} else { } else {
// PA BOOST // PA BOOST
if level > 17 { if level > 17 {
@ -250,30 +231,31 @@ where
level -= 3; level -= 3;
// High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.)
self.write_register(Register::RegPaDac.addr(), 0x87)?; self.write_register(Register::RegPaDac.addr(), 0x87).await?;
self.set_ocp(140)?; self.set_ocp(140).await?;
} else { } else {
if level < 2 { if level < 2 {
level = 2; level = 2;
} }
//Default value PA_HF/LF or +17dBm //Default value PA_HF/LF or +17dBm
self.write_register(Register::RegPaDac.addr(), 0x84)?; self.write_register(Register::RegPaDac.addr(), 0x84).await?;
self.set_ocp(100)?; self.set_ocp(100).await?;
} }
level -= 2; level -= 2;
self.write_register( self.write_register(
Register::RegPaConfig.addr(), Register::RegPaConfig.addr(),
PaConfig::PaBoost.addr() | level as u8, PaConfig::PaBoost.addr() | level as u8,
) )
.await
} }
} }
pub fn get_modem_stat(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> { pub async fn get_modem_stat(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> {
Ok(self.read_register(Register::RegModemStat.addr())? as u8) Ok(self.read_register(Register::RegModemStat.addr()).await? as u8)
} }
/// Sets the over current protection on the radio(mA). /// Sets the over current protection on the radio(mA).
pub fn set_ocp(&mut self, ma: u8) -> Result<(), Error<E, CS::Error, RESET::Error>> { pub async fn set_ocp(&mut self, ma: u8) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let mut ocp_trim: u8 = 27; let mut ocp_trim: u8 = 27;
if ma <= 120 { if ma <= 120 {
@ -282,31 +264,40 @@ where
ocp_trim = (ma + 30) / 10; ocp_trim = (ma + 30) / 10;
} }
self.write_register(Register::RegOcp.addr(), 0x20 | (0x1F & ocp_trim)) self.write_register(Register::RegOcp.addr(), 0x20 | (0x1F & ocp_trim))
.await
} }
/// Sets the state of the radio. Default mode after initiation is `Standby`. /// Sets the state of the radio. Default mode after initiation is `Standby`.
pub fn set_mode(&mut self, mode: RadioMode) -> Result<(), Error<E, CS::Error, RESET::Error>> { pub async fn set_mode(
&mut self,
mode: RadioMode,
) -> Result<(), Error<E, CS::Error, RESET::Error>> {
if self.explicit_header { if self.explicit_header {
self.set_explicit_header_mode()?; self.set_explicit_header_mode().await?;
} else { } else {
self.set_implicit_header_mode()?; self.set_implicit_header_mode().await?;
} }
self.write_register( self.write_register(
Register::RegOpMode.addr(), Register::RegOpMode.addr(),
RadioMode::LongRangeMode.addr() | mode.addr(), RadioMode::LongRangeMode.addr() | mode.addr(),
)?; )
.await?;
self.mode = mode; self.mode = mode;
Ok(()) Ok(())
} }
pub fn reset_payload_length(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> { pub async fn reset_payload_length(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
self.write_register(Register::RegPayloadLength.addr(), 0xFF) self.write_register(Register::RegPayloadLength.addr(), 0xFF)
.await
} }
/// Sets the frequency of the radio. Values are in megahertz. /// 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. /// 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<E, CS::Error, RESET::Error>> { pub async fn set_frequency(
&mut self,
freq: u32,
) -> Result<(), Error<E, CS::Error, RESET::Error>> {
const FREQ_STEP: f64 = 61.03515625; const FREQ_STEP: f64 = 61.03515625;
// calculate register values // calculate register values
let frf = (freq as f64 / FREQ_STEP) as u32; let frf = (freq as f64 / FREQ_STEP) as u32;
@ -314,23 +305,28 @@ where
self.write_register( self.write_register(
Register::RegFrfMsb.addr(), Register::RegFrfMsb.addr(),
((frf & 0x00FF_0000) >> 16) as u8, ((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) self.write_register(Register::RegFrfLsb.addr(), (frf & 0x0000_00FF) as u8)
.await
} }
/// Sets the radio to use an explicit header. Default state is `ON`. /// Sets the radio to use an explicit header. Default state is `ON`.
fn set_explicit_header_mode(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> { async fn set_explicit_header_mode(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let reg_modem_config_1 = self.read_register(Register::RegModemConfig1.addr())?; let reg_modem_config_1 = self.read_register(Register::RegModemConfig1.addr()).await?;
self.write_register(Register::RegModemConfig1.addr(), reg_modem_config_1 & 0xfe)?; self.write_register(Register::RegModemConfig1.addr(), reg_modem_config_1 & 0xfe)
.await?;
self.explicit_header = true; self.explicit_header = true;
Ok(()) Ok(())
} }
/// Sets the radio to use an implicit header. Default state is `OFF`. /// Sets the radio to use an implicit header. Default state is `OFF`.
fn set_implicit_header_mode(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> { async fn set_implicit_header_mode(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let reg_modem_config_1 = self.read_register(Register::RegModemConfig1.addr())?; let reg_modem_config_1 = self.read_register(Register::RegModemConfig1.addr()).await?;
self.write_register(Register::RegModemConfig1.addr(), reg_modem_config_1 & 0x01)?; self.write_register(Register::RegModemConfig1.addr(), reg_modem_config_1 & 0x01)
.await?;
self.explicit_header = false; self.explicit_header = false;
Ok(()) Ok(())
} }
@ -338,7 +334,7 @@ where
/// Sets the spreading factor of the radio. Supported values are between 6 and 12. /// 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 /// If a spreading factor of 6 is set, implicit header mode must be used to transmit
/// and receive packets. Default value is `7`. /// and receive packets. Default value is `7`.
pub fn set_spreading_factor( pub async fn set_spreading_factor(
&mut self, &mut self,
mut sf: u8, mut sf: u8,
) -> Result<(), Error<E, CS::Error, RESET::Error>> { ) -> Result<(), Error<E, CS::Error, RESET::Error>> {
@ -349,36 +345,45 @@ where
} }
if sf == 6 { if sf == 6 {
self.write_register(Register::RegDetectionOptimize.addr(), 0xc5)?; self.write_register(Register::RegDetectionOptimize.addr(), 0xc5)
self.write_register(Register::RegDetectionThreshold.addr(), 0x0c)?; .await?;
self.write_register(Register::RegDetectionThreshold.addr(), 0x0c)
.await?;
} else { } else {
self.write_register(Register::RegDetectionOptimize.addr(), 0xc3)?; self.write_register(Register::RegDetectionOptimize.addr(), 0xc3)
self.write_register(Register::RegDetectionThreshold.addr(), 0x0a)?; .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( self.write_register(
Register::RegModemConfig2.addr(), Register::RegModemConfig2.addr(),
(modem_config_2 & 0x0f) | ((sf << 4) & 0xf0), (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(()) Ok(())
} }
pub fn set_tcxo(&mut self, external: bool) -> Result<(), Error<E, CS::Error, RESET::Error>> { pub async fn set_tcxo(
&mut self,
external: bool,
) -> Result<(), Error<E, CS::Error, RESET::Error>> {
if external { if external {
self.write_register(Register::RegTcxo.addr(), 0x10) self.write_register(Register::RegTcxo.addr(), 0x10).await
} else { } 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`, /// 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` /// `15600 Hz`, `20800 Hz`, `31250 Hz`,`41700 Hz` ,`62500 Hz`,`125000 Hz` and `250000 Hz`
/// Default value is `125000 Hz` /// Default value is `125000 Hz`
pub fn set_signal_bandwidth( pub async fn set_signal_bandwidth(
&mut self, &mut self,
sbw: i64, sbw: i64,
) -> Result<(), Error<E, CS::Error, RESET::Error>> { ) -> Result<(), Error<E, CS::Error, RESET::Error>> {
@ -394,19 +399,20 @@ where
250_000 => 8, 250_000 => 8,
_ => 9, _ => 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( self.write_register(
Register::RegModemConfig1.addr(), Register::RegModemConfig1.addr(),
(modem_config_1 & 0x0f) | ((bw << 4) as u8), (modem_config_1 & 0x0f) | ((bw << 4) as u8),
)?; )
self.set_ldo_flag()?; .await?;
self.set_ldo_flag().await?;
Ok(()) Ok(())
} }
/// Sets the coding rate of the radio with the numerator fixed at 4. Supported values /// 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`. /// are between `5` and `8`, these correspond to coding rates of `4/5` and `4/8`.
/// Default value is `5`. /// Default value is `5`.
pub fn set_coding_rate_4( pub async fn set_coding_rate_4(
&mut self, &mut self,
mut denominator: u8, mut denominator: u8,
) -> Result<(), Error<E, CS::Error, RESET::Error>> { ) -> Result<(), Error<E, CS::Error, RESET::Error>> {
@ -416,52 +422,64 @@ where
denominator = 8; denominator = 8;
} }
let cr = denominator - 4; 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( self.write_register(
Register::RegModemConfig1.addr(), Register::RegModemConfig1.addr(),
(modem_config_1 & 0xf1) | (cr << 1), (modem_config_1 & 0xf1) | (cr << 1),
) )
.await
} }
/// Sets the preamble length of the radio. Values are between 6 and 65535. /// Sets the preamble length of the radio. Values are between 6 and 65535.
/// Default value is `8`. /// Default value is `8`.
pub fn set_preamble_length( pub async fn set_preamble_length(
&mut self, &mut self,
length: i64, length: i64,
) -> Result<(), Error<E, CS::Error, RESET::Error>> { ) -> Result<(), Error<E, CS::Error, RESET::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) self.write_register(Register::RegPreambleLsb.addr(), length as u8)
.await
} }
/// Enables are disables the radio's CRC check. Default value is `false`. /// Enables are disables the radio's CRC check. Default value is `false`.
pub fn set_crc(&mut self, value: bool) -> Result<(), Error<E, CS::Error, RESET::Error>> { pub async fn set_crc(&mut self, value: bool) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let modem_config_2 = self.read_register(Register::RegModemConfig2.addr())?; let modem_config_2 = self.read_register(Register::RegModemConfig2.addr()).await?;
if value { if value {
self.write_register(Register::RegModemConfig2.addr(), modem_config_2 | 0x04) self.write_register(Register::RegModemConfig2.addr(), modem_config_2 | 0x04)
.await
} else { } else {
self.write_register(Register::RegModemConfig2.addr(), modem_config_2 & 0xfb) self.write_register(Register::RegModemConfig2.addr(), modem_config_2 & 0xfb)
.await
} }
} }
/// Inverts the radio's IQ signals. Default value is `false`. /// Inverts the radio's IQ signals. Default value is `false`.
pub fn set_invert_iq(&mut self, value: bool) -> Result<(), Error<E, CS::Error, RESET::Error>> { pub async fn set_invert_iq(
&mut self,
value: bool,
) -> Result<(), Error<E, CS::Error, RESET::Error>> {
if value { if value {
self.write_register(Register::RegInvertiq.addr(), 0x66)?; self.write_register(Register::RegInvertiq.addr(), 0x66)
.await?;
self.write_register(Register::RegInvertiq2.addr(), 0x19) self.write_register(Register::RegInvertiq2.addr(), 0x19)
.await
} else { } else {
self.write_register(Register::RegInvertiq.addr(), 0x27)?; self.write_register(Register::RegInvertiq.addr(), 0x27)
.await?;
self.write_register(Register::RegInvertiq2.addr(), 0x1d) self.write_register(Register::RegInvertiq2.addr(), 0x1d)
.await
} }
} }
/// Returns the spreading factor of the radio. /// Returns the spreading factor of the radio.
pub fn get_spreading_factor(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> { pub async fn get_spreading_factor(&mut self) -> Result<u8, Error<E, CS::Error, RESET::Error>> {
Ok(self.read_register(Register::RegModemConfig2.addr())? >> 4) Ok(self.read_register(Register::RegModemConfig2.addr()).await? >> 4)
} }
/// Returns the signal bandwidth of the radio. /// Returns the signal bandwidth of the radio.
pub fn get_signal_bandwidth(&mut self) -> Result<i64, Error<E, CS::Error, RESET::Error>> { pub async fn get_signal_bandwidth(&mut self) -> Result<i64, Error<E, CS::Error, RESET::Error>> {
let bw = self.read_register(Register::RegModemConfig1.addr())? >> 4; let bw = self.read_register(Register::RegModemConfig1.addr()).await? >> 4;
let bw = match bw { let bw = match bw {
0 => 7_800, 0 => 7_800,
1 => 10_400, 1 => 10_400,
@ -479,69 +497,77 @@ where
} }
/// Returns the RSSI of the last received packet. /// Returns the RSSI of the last received packet.
pub fn get_packet_rssi(&mut self) -> Result<i32, Error<E, CS::Error, RESET::Error>> { pub async fn get_packet_rssi(&mut self) -> Result<i32, Error<E, CS::Error, RESET::Error>> {
Ok(i32::from(self.read_register(Register::RegPktRssiValue.addr())?) - 157) Ok(i32::from(self.read_register(Register::RegPktRssiValue.addr()).await?) - 157)
} }
/// Returns the signal to noise radio of the the last received packet. /// Returns the signal to noise radio of the the last received packet.
pub fn get_packet_snr(&mut self) -> Result<f64, Error<E, CS::Error, RESET::Error>> { pub async fn get_packet_snr(&mut self) -> Result<f64, Error<E, CS::Error, RESET::Error>> {
Ok(f64::from( 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. /// Returns the frequency error of the last received packet in Hz.
pub fn get_packet_frequency_error(&mut self) -> Result<i64, Error<E, CS::Error, RESET::Error>> { pub async fn get_packet_frequency_error(
&mut self,
) -> Result<i64, Error<E, CS::Error, RESET::Error>> {
let mut freq_error: i32; 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 <<= 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 <<= 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_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)) 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) Ok(f_error as i64)
} }
fn set_ldo_flag(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> { async fn set_ldo_flag(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
let sw = self.get_signal_bandwidth()?; let sw = self.get_signal_bandwidth().await?;
// Section 4.1.1.5 // 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 // Section 4.1.1.6
let ldo_on = symbol_duration > 16; 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(3, ldo_on);
//config_3.set_bit(2, true); //config_3.set_bit(2, true);
self.write_register(Register::RegModemConfig3.addr(), config_3) self.write_register(Register::RegModemConfig3.addr(), config_3)
.await
} }
fn read_register(&mut self, reg: u8) -> Result<u8, Error<E, CS::Error, RESET::Error>> { async fn read_register(&mut self, reg: u8) -> Result<u8, Error<E, CS::Error, RESET::Error>> {
let mut buffer = [reg & 0x7f, 0];
self.cs.set_low().map_err(CS)?; self.cs.set_low().map_err(CS)?;
let mut buffer = [reg & 0x7f, 0]; let _ = self
let transfer = self.spi.transfer(&mut buffer).map_err(SPI)?; .spi
.read_write(&mut buffer, &[reg & 0x7f, 0])
.await
.map_err(SPI)?;
self.cs.set_high().map_err(CS)?; self.cs.set_high().map_err(CS)?;
Ok(transfer[1]) Ok(buffer[1])
} }
fn write_register( async fn write_register(
&mut self, &mut self,
reg: u8, reg: u8,
byte: u8, byte: u8,
) -> Result<(), Error<E, CS::Error, RESET::Error>> { ) -> Result<(), Error<E, CS::Error, RESET::Error>> {
self.cs.set_low().map_err(CS)?; self.cs.set_low().map_err(CS)?;
let mut rx = [0, 0];
let buffer = [reg | 0x80, byte]; 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)?; self.cs.set_high().map_err(CS)?;
Ok(()) Ok(())
} }
pub fn put_in_fsk_mode(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> { pub async fn put_in_fsk_mode(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
// Put in FSK mode // Put in FSK mode
let mut op_mode = 0; let mut op_mode = 0;
op_mode op_mode
@ -551,9 +577,10 @@ where
.set_bits(0..2, 0b011); // Mode .set_bits(0..2, 0b011); // Mode
self.write_register(Register::RegOpMode as u8, op_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, &mut self,
modulation_shaping: FskDataModulationShaping, modulation_shaping: FskDataModulationShaping,
ramp: FskRampUpRamDown, ramp: FskRampUpRamDown,
@ -564,14 +591,15 @@ where
.set_bits(0..3, ramp as u8); .set_bits(0..3, ramp as u8);
self.write_register(Register::RegPaRamp as u8, pa_ramp) self.write_register(Register::RegPaRamp as u8, pa_ramp)
.await
} }
pub fn set_lora_pa_ramp(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> { pub async fn set_lora_pa_ramp(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
self.write_register(Register::RegPaRamp as u8, 0b1000) self.write_register(Register::RegPaRamp as u8, 0b1000).await
} }
pub fn set_lora_sync_word(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> { pub async fn set_lora_sync_word(&mut self) -> Result<(), Error<E, CS::Error, RESET::Error>> {
self.write_register(Register::RegSyncWord as u8, 0x34) self.write_register(Register::RegSyncWord as u8, 0x34).await
} }
} }
/// Modes of the radio and their corresponding register values. /// Modes of the radio and their corresponding register values.

View File

@ -20,7 +20,7 @@ defmt-rtt = "0.3"
cortex-m = "0.7.3" cortex-m = "0.7.3"
cortex-m-rt = "0.7.0" cortex-m-rt = "0.7.0"
embedded-hal = "0.2.6"
panic-probe = { version = "0.3", features = ["print-defmt"] } panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.7.5", default-features = false } heapless = { version = "0.7.5", default-features = false }
embedded-hal = "0.2.6"

View File

@ -12,7 +12,6 @@ mod example_common;
use embassy_lora::{sx127x::*, LoraTimer}; use embassy_lora::{sx127x::*, LoraTimer};
use embassy_stm32::{ use embassy_stm32::{
dbgmcu::Dbgmcu, dbgmcu::Dbgmcu,
dma::NoDma,
exti::ExtiInput, exti::ExtiInput,
gpio::{Input, Level, Output, Pull, Speed}, gpio::{Input, Level, Output, Pull, Speed},
rcc, rcc,
@ -45,8 +44,8 @@ async fn main(_spawner: embassy::executor::Spawner, mut p: Peripherals) {
p.PB3, p.PB3,
p.PA7, p.PA7,
p.PA6, p.PA6,
NoDma, p.DMA1_CH3,
NoDma, p.DMA1_CH2,
200_000.hz(), 200_000.hz(),
spi::Config::default(), 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 = Input::new(p.PB4, Pull::Up);
let ready_pin = ExtiInput::new(ready, p.EXTI4); let ready_pin = ExtiInput::new(ready, p.EXTI4);
let radio = Sx127xRadio::new( let radio = Sx127xRadio::new(spi, cs, reset, ready_pin, DummySwitch)
spi, .await
cs, .unwrap();
reset,
ready_pin,
DummySwitch,
&mut embassy::time::Delay,
)
.unwrap();
let region = region::EU868::default().into(); let region = region::EU868::default().into();
let mut radio_buffer = [0; 256]; let mut radio_buffer = [0; 256];