Dragino LoRa shield can be used with Arduino Due.
http://wiki.dragino.com/index.php?title=Lora_Shield
Semtech SX1278 chip (https://cdn-shop.adafruit.com/product-files/3179/sx1276_77_78_79.pdf) can do packet and continuos (raw) data modes in FSK, ASK, GFSK and MSK. Arduino Due provides more processing power than Uno and is more suitable for raw mode.
I wrote short code for Arduino to handle packet/continuous modes which works in both Due and Uno. #define CONT_MODE 1 sets raw mode and 0 sets packet mode. Raw mode uses shiftIn function and it could be optimized with direct port manipulation instead of shiftIn function. Arduino Due also provides flash memory which could be used to store raw data (DueFlashStorage).
Direct port shiftIn for Uno: https://teknokoodiradio.vuodatus.net/lue/2017/08/semtech-sx1278-continuous-mode-arduino-shiftin
// http://wiki.dragino.com/index.php?title=Lora_Shield
#include <SPI.h>
#define SERIAL_SPEED 9600
#define BPS 9600
#define FREQ 869.525
#define STATE_SLEEP 0
#define STATE_STANDBY 1
#define STATE_FSRX 4
#define STATE_RX 5
#define S_DELAY 10
#define L_DELAY 100
#define RX_BUFFER_LEN 255
#define SX_BITRATE "BPS "
#define SX_FREQ "Frequency "
#define SX_IRQ1_TXT "RegIrqFlags1_value "
#define SX_IRQ2_TXT "RegIrqFlags2_value "
#define SX_VERSION "Version code of the chip "
#define RSSI_THRESHOLD 180 // -rssi/2
#define CH_FILTER_BW B00001100 // 25 kHz 00100 31.3 kHz 10100 20.8 kHz 00101 15.6 kHz
#define SYNC_VALUE 0x01
#define PRINT_IRQ_CHG 0
#define CONT_MODE 0
#define DATA_PIN 7
#define DCLK_PIN 6
#define RegFifo 0x00
#define RegOpMode 0x01
#define RegBitrateMsb 0x02
#define RegBitrateLsb 0x03
#define RegFrfMsb 0x06
#define RegFrfMid 0x07
#define RegFrfLsb 0x08
#define RegPaRamp 0x0a
#define RegRssiConfig 0x0e
#define RegRssiThresh 0x10
#define RegRxBw 0x12
#define RegOokPeak 0x14
#define RegPreambleDetect 0x1f
#define RegSyncConfig 0x27
#define RegSyncValue1 0x28
#define RegSyncValue2 0x29
#define RegSyncValue3 0x2a
#define RegPacketConfig1 0x30
#define RegPacketConfig2 0x31
#define RegPayloadLength 0x32
#define RegIrqFlags1 0x3e
#define RegIrqFlags2 0x3f
#define RegDioMapping1 0x40
#define RegVersion 0x42
#define SX_OSC_FREQ 32000000
#define SX_RESET 5
#define SX_RESET_DELAY_H 1
#define SX_RESET_DELAY_L 25
#define SPI_SS 10
#define SPI_RW_DELAY 50
uint8_t RegIrqFlags1_value;
uint8_t RegIrqFlags2_value;
uint8_t rxBuffer[RX_BUFFER_LEN];
void setup() {
Serial.begin(SERIAL_SPEED);
if (initSX()) {
#if (CONT_MODE == 1)
pinMode(DATA_PIN, INPUT);
pinMode(DCLK_PIN, INPUT);
#endif
Serial.print(F(SX_VERSION));
Serial.print(readSPI(RegVersion));
Serial.println();
delay(S_DELAY);
startFSK();
uint8_t b = readSPI(RegOpMode);
bitClear(b, 6);
bitClear(b, 5);
writeSPI(RegOpMode, b);
// Channel filter bandwidth control
writeSPI(RegRxBw, CH_FILTER_BW);
setFreq(FREQ);
Serial.print(F(SX_FREQ));
Serial.println(FREQ, DEC);
setBps(BPS);
Serial.print(F(SX_BITRATE));
Serial.println(BPS);
// 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 = readSPI(RegSyncConfig);
bitClear(b, 7);
bitSet(b, 6);
bitSet(b, 4);
bitClear(b, 5);
bitClear(b, 2);
bitSet(b, 1);
bitClear(b, 0);
writeSPI(RegSyncConfig, b);
writeSPI(RegSyncValue1, SYNC_VALUE);
writeSPI(RegSyncValue2, SYNC_VALUE);
writeSPI(RegSyncValue3, SYNC_VALUE);
// 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;
bitSet(b, 7);
writeSPI(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 = readSPI(RegPaRamp);
bitClear(b, 6);
bitClear(b, 5);
bitSet(b, 3);
bitClear(b, 2);
bitClear(b, 1);
bitSet(b, 0);
writeSPI(RegPaRamp, b);
writeSPI(RegPayloadLength, RX_BUFFER_LEN);
// Data processing mode: 0 => Continuous mode, 1 => Packet mode
b = readSPI(RegPacketConfig2);
#if (CONT_MODE == 1)
bitClear(b, 6);
#else
bitSet(b, 6);
#endif
writeSPI(RegPacketConfig2, b);
#if (CONT_MODE == 1)
// Set DIO mapping
b = readSPI(RegDioMapping1);
bitClear(b, 5);
bitClear(b, 4);
bitClear(b, 3);
bitClear(b, 2);
writeSPI(RegDioMapping1, b);
#endif
// RSSI smoothing.
// Defines the number of samples taken to average the RSSI result. 010 -> 8 samples
b = readSPI(RegRssiConfig);
bitClear(b, 2);
bitSet(b, 1);
bitClear(b, 0);
writeSPI(RegRssiConfig, b);
writeSPI(RegRssiThresh, RSSI_THRESHOLD);
// Bit 5: enables the Bit Synchronizer:
// 0 -> bit sync disabled (not possible in packet mode), 1 -> bit sync enabled
b = readSPI(RegOokPeak);
bitSet(b, 5);
writeSPI(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 = readSPI(RegPreambleDetect);
bitClear(b, 7);
bitClear(b, 6);
bitClear(b, 5);
writeSPI(RegPreambleDetect, b);
clearFifoAndFlags();
#if (CONT_MODE == 1)
digitalWrite(DCLK_PIN, LOW);
#endif
setState(STATE_FSRX);
delay(L_DELAY);
setState(STATE_RX);
delay(S_DELAY);
#if (PRINT_IRQ_CHG == 1)
RegIrqFlags1_value = readSPI(RegIrqFlags1);
RegIrqFlags2_value = readSPI(RegIrqFlags2);
Serial.print(F(SX_IRQ1_TXT));
Serial.println(RegIrqFlags1_value, BIN);
Serial.print(F(SX_IRQ2_TXT));
Serial.println(RegIrqFlags2_value, BIN);
#endif
}
}
void loop() {
uint8_t r2;
#if (CONT_MODE == 1)
r2 = shiftIn(DATA_PIN, DCLK_PIN, MSBFIRST);
Serial.println(r2);
#else
r2 = readSPI(RegIrqFlags2);
#if (PRINT_IRQ_CHG == 1)
uint8_t r1 = readSPI(RegIrqFlags1);
if (r1 != RegIrqFlags1_value) {
RegIrqFlags1_value = r1;
Serial.print(F(SX_IRQ1_TXT));
Serial.println(RegIrqFlags1_value, BIN);
}
if (r2 != RegIrqFlags2_value) {
RegIrqFlags2_value = r2;
Serial.print(F(SX_IRQ2_TXT));
Serial.println(RegIrqFlags2_value, BIN);
}
#endif
if (bitRead(r2, 2) == 1) {
uint8_t b = readSPI(RegPayloadLength);
if (b > 0) {
b = fetchData(rxBuffer, b);
if (b > 0) {
uint8_t n;
for (n = 0; n < b; n++) {
Serial.print(rxBuffer[n]);
Serial.print(";");
}
Serial.print(b);
Serial.println();
}
}
}
#endif
}
void clearFifoAndFlags() {
// Flag(s) and FIFO are cleared when this bit is set
uint8_t b = readSPI(RegIrqFlags2);
bitSet(b, 4);
writeSPI(RegIrqFlags2, b);
delay(S_DELAY);
}
void setBps(uint16_t bps) {
uint16_t baudRate = SX_OSC_FREQ / bps;
writeSPI(RegBitrateMsb, baudRate >> 8);
writeSPI(RegBitrateLsb, baudRate & 0xff);
}
void setFreq(float f)
{
uint32_t lf = (f * 1000000) / 61.035;
writeSPI(RegFrfMsb, (lf >> 16) & 0xff);
writeSPI(RegFrfMid, (lf >> 8) & 0xff);
writeSPI(RegFrfLsb, lf & 0xff);
}
void setState(uint8_t s) {
uint8_t b = readSPI(RegOpMode);
b = b | s;
writeSPI(RegOpMode, b);
}
void startFSK()
{
setState(STATE_SLEEP);
delay(S_DELAY);
uint8_t b = readSPI(RegOpMode);
bitClear(b, 7);
writeSPI(RegOpMode, b);
}
uint8_t fetchData(uint8_t data[], uint8_t len)
{
for (uint8_t n = 0; n < len; n++) {
data[n] = readSPI(RegFifo);
if (bitRead(readSPI(RegIrqFlags2), 6) == 1) {
return n;
}
}
return 0;
}
bool initSX() {
pinMode(SX_RESET, OUTPUT);
digitalWrite(SX_RESET, LOW);
initSPI();
resetSX();
if (readSPI(RegVersion) == 0) {
return false;
}
setState(STATE_STANDBY);
return true;
}
void resetSX() {
digitalWrite(SX_RESET, HIGH);
delay(SX_RESET_DELAY_H);
digitalWrite(SX_RESET, LOW);
delay(SX_RESET_DELAY_L);
}
uint8_t readSPI(uint8_t addr) {
digitalWrite(SPI_SS, LOW);
SPI.transfer(addr);
delayMicroseconds(SPI_RW_DELAY);
uint8_t v = SPI.transfer(0x00);
digitalWrite(SPI_SS, HIGH);
return v;
}
void writeSPI(uint8_t addr, uint8_t v) {
digitalWrite(SPI_SS, LOW);
SPI.transfer(addr | 0x80);
delayMicroseconds(SPI_RW_DELAY);
SPI.transfer(v);
digitalWrite(SPI_SS, HIGH);
}
void initSPI()
{
digitalWrite(SPI_SS, HIGH);
pinMode(SPI_SS, OUTPUT);
SPI.begin();
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
}
Kommentit
Tämän blogin kommentit tarkistetaan ennen julkaisua.