SX1278 fast frequency hopping
lauantai, 8. heinäkuu 2017
SX1278 fast frequency hopping
Arduino Dragino Lora shield (Semtech SX1278 chip) can tune into frequency quite fast. Fasthop feature works at best in OOK continuous mode.
RegPllHop (0x44) bit 7:
Bypasses the main state machine for a quick frequency hop. Writing RegFrfLsb will trigger the frequency change.
1 -> Frf is validated triggered when RegFrfLsb is written.
1. set FastHopOn=1
2. set new Frf (*)
3. wait for TS_HOP
TS_HOP = Frequency synthesizer hop time at most 10 kHz away from the target frequency.
(*) RegFrfLsb must be written to trigger a frequency change.
SX1278 library: https://github.com/open-electronics/LoRa/releases
SX1278 datasheet: http://www.semtech.com/apps/filedown/down.php?file=sx1276_77_78_79.pdf
#include <SX1278.h>
#define SERIAL_SPEED 9600
#define F_START 433 // start freq
#define F_STEP 0.025 // 25 kHz step
#define F_CH 50 // channels to rx hop
#define BPS 1200
#define STATE_STANDBY 1
#define STATE_FSRX 4
#define STATE_RX 5
#define H_DELAY 2
#define M_DELAY 10
#define L_DELAY 100
#define SX_BEGIN "SX.begin"
#define SX_BITRATE "SX.readBPS "
#define SX_FREQ "SX.readFreq "
#define RSSI_THRESHOLD -80 // dBm
#define CH_FILTER_BW B00001100 // 25 kHz
#define RegRssiConfig 0x0e
#define RegRxBw 0x12
#define RegPacketConfig1 0x30
#define RegOpMode 0x01
#define RegPaRamp 0x0a
#define RegRssiThresh 0x10
#define RegOokPeak 0x14
#define RegPreambleDetect 0x1f
#define RegSyncConfig 0x27
#define RegPacketConfig2 0x31
#define RegIrqFlags1 0x3e
#define RegIrqFlags2 0x3f
#define RegPllHop 0x44
bool rx = false;
void setup() {
Serial.begin(SERIAL_SPEED);
if (SX.begin()) {
Serial.println(F(SX_BEGIN));
delay(M_DELAY);
SX.startModeFSKOOK();
// OOK
byte b = SX.SPIread(RegOpMode);
bitClear(b, 6);
bitSet(b, 5);
SX.SPIwrite(RegOpMode, b);
fastHop(0);
SX.setFreq(F_START);
Serial.print(F(SX_FREQ));
Serial.println(SX.readFreq(), DEC);
SX.setBPS(BPS);
Serial.print(F(SX_BITRATE));
Serial.println(SX.readBPS(), DEC);
// Channel filter bandwidth control
SX.SPIwrite(RegRxBw, CH_FILTER_BW);
// Bits 7-6: AutoRestartRxMode, 01 -> On, without waiting for the PLL to re-lock
// Bit 4: Enables the Sync word generation and detection: 0 -> Off, 1 -> On
// Bit 5: Sets the polarity of the Preamble. 0 -> 0xAA, 1 -> 0x55
// Bits 2-0: Size of the Sync word (SyncSize + 1)
b = SX.SPIread(RegSyncConfig);
bitClear(b, 7);
bitSet(b, 6);
bitClear(b, 4);
bitClear(b, 5);
bitClear(b, 2);
bitClear(b, 1);
bitClear(b, 0);
SX.SPIwrite(RegSyncConfig, b);
// Bits 6-5: Defines DC-free encoding/decoding performed:
// 00 -> none, 01 -> manchester, 10 -> whitening
// Bit 7: packet format, 0 -> fixed length, 1 -> variable length
// Bit 4: crc calc/check, 0 -> off, 1 -> on
// Bits 2-1: Defines address based filtering in Rx: 00 ->Â None (Off)
// Bit 3: Defines the behavior of the packet handler when CRC check fails:
// 0 -> Clear FIFO and restart new packet reception. No PayloadReady interrupt issued.
// 1 -> Do not clear FIFO. PayloadReady interrupt issued.
// Bit 0: Selects the CRC and whitening algorithms:
// 0 -> CCITT CRC implementation with standard whitening
// 1 -> IBM CRC implementation with alternate whitening
b = 0;
SX.SPIwrite(RegPacketConfig1, b);
// Bits 6-5: FSK data shaping:
// 00 -> no shaping, 01 -> Gaussian filter BT = 1.0
// 10 -> Gaussian filter BT = 0.5, 11 -> Gaussian filter BT = 0.3
// Bits 3-0: Rise/Fall time of ramp up/down in FSK:
// 1001 -> 40 us
b = SX.SPIread(RegPaRamp);
bitClear(b, 6);
bitClear(b, 5);
bitSet(b, 3);
bitClear(b, 2);
bitSet(b, 0);
SX.SPIwrite(RegPaRamp, b);
// Data processing mode: 0 ->Â Continuous mode, 1 -> Packet mode
b = SX.SPIread(RegPacketConfig2);
bitClear(b, 6);
SX.SPIwrite(RegPacketConfig2, b);
// RSSI smoothing.
// Defines the number of samples taken to average the RSSI result. 001 -> 4 samples
b = SX.SPIread(RegRssiConfig);
bitClear(b, 2);
bitClear(b, 1);
bitSet(b, 0);
SX.SPIwrite(RegRssiConfig, b);
SX.SPIwrite(RegRssiThresh, RSSI_THRESHOLD);
// Bit 5: enables the Bit Synchronizer:
// 0 -> bit sync disabled (not possible in packet mode), 1 -> bit sync enabled
b = SX.SPIread(RegOokPeak);
bitClear(b, 5);
SX.SPIwrite(RegOokPeak, b);
// RegPreambleDetect (0x1f). Enables Preamble detector when set to 1.
// The AGC settings supersede this bit during the startup / AGC phase.
// Bit 7: 0 -> turned off, 1 -> turned on
// Bits 6-5: Number of Preamble bytes to detect to trigger an interrupt.
// 00 -> 1 byte, 10 -> 3 bytes, 01 -> 2 bytes
b = SX.SPIread(RegPreambleDetect);
bitClear(b, 7);
bitClear(b, 6);
bitClear(b, 5);
SX.SPIwrite(RegPreambleDetect, b);
clearFifoAndFlags();
SX.setState(STATE_FSRX);
delay(L_DELAY);
SX.setState(STATE_RX);
delay(M_DELAY);
rx = true;
}
}
void loop() {
if (rx) {
float f = F_START;
for (int c = 0; c < F_CH; c++) {
fastHop(1);
SX.setFreq(f);
delay(H_DELAY);
float rssi = SX.readRSSIval();
if (rssi > RSSI_THRESHOLD) {
Serial.print(f, DEC);
Serial.print("\t");
Serial.println(rssi, DEC);
}
f = f + F_STEP;
}
}
}
void clearFifoAndFlags() {
// Flag(s) and FIFO are cleared when this bit is set
byte b = SX.SPIread(RegIrqFlags2);
bitSet(b, 4);
SX.SPIwrite(RegIrqFlags2, b);
delay(M_DELAY);
}
void fastHop(int val) {
byte b = SX.SPIread(RegPllHop);
bitWrite(b, 7, val);
SX.SPIwrite(RegPllHop, b);
}
Comments
Post a Comment