From cd0df701a93b46ad2f06c938dee6036912bac595 Mon Sep 17 00:00:00 2001 From: Anthony Elder Date: Sat, 5 May 2018 21:12:22 +0100 Subject: [PATCH 01/12] Issue 85 setting ldo flag (#121) * Add getting the frequency error of a packet * Update for review comments * Add functions to set low data rate optimization flag * Typo * Fixes * Add packetFrequencyError to API.md * WIP * Simplify * Make getSpreadingFactor private * Correct LDO bit calculation * Update LDO determination * Correct calculation * Correct calculation * Revert back to old LDO calculation --- src/LoRa.cpp | 38 +++++++++++++++++++++++++++++--------- src/LoRa.h | 3 +++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 78eb172..c026d5f 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -373,6 +373,11 @@ void LoRaClass::setFrequency(long frequency) writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0)); } +int LoRaClass::getSpreadingFactor() +{ + return readRegister(REG_MODEM_CONFIG_2) >> 4; +} + void LoRaClass::setSpreadingFactor(int sf) { if (sf < 6) { @@ -390,6 +395,7 @@ void LoRaClass::setSpreadingFactor(int sf) } writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)); + setLdoFlag(); } long LoRaClass::getSignalBandwidth() @@ -397,15 +403,15 @@ long LoRaClass::getSignalBandwidth() byte bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); switch (bw) { case 0: return 7.8E3; - case 1: return 10.4E3; - case 2: return 15.6E3; - case 3: return 20.8E3; - case 4: return 31.25E3; - case 5: return 41.7E3; - case 6: return 62.5E3; - case 7: return 125E3; - case 8: return 250E3; - case 9: return 500E3; + case 1: return 10.4E3; + case 2: return 15.6E3; + case 3: return 20.8E3; + case 4: return 31.25E3; + case 5: return 41.7E3; + case 6: return 62.5E3; + case 7: return 125E3; + case 8: return 250E3; + case 9: return 500E3; } } @@ -436,6 +442,20 @@ void LoRaClass::setSignalBandwidth(long sbw) } writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)); + setLdoFlag(); +} + +void LoRaClass::setLdoFlag() +{ + // Section 4.1.1.5 + long symbolDuration = 1000 / ( getSignalBandwidth() / (1L << getSpreadingFactor()) ) ; + + // Section 4.1.1.6 + boolean ldoOn = symbolDuration > 16; + + uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); + bitWrite(config3, 3, ldoOn); + writeRegister(REG_MODEM_CONFIG_3, config3); } void LoRaClass::setCodingRate4(int denominator) diff --git a/src/LoRa.h b/src/LoRa.h index a7ec8ff..46c2880 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -72,8 +72,11 @@ private: void handleDio0Rise(); + int getSpreadingFactor(); long getSignalBandwidth(); + void setLdoFlag(); + uint8_t readRegister(uint8_t address); void writeRegister(uint8_t address, uint8_t value); uint8_t singleTransfer(uint8_t address, uint8_t value); From a2636d10a9f12d65ca6cea7f6280943aeae36ef0 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Sat, 5 May 2018 16:14:33 -0400 Subject: [PATCH 02/12] Version 0.4.0 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index e96af7a..741ff52 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=LoRa -version=0.3.0 +version=0.4.0 author=Sandeep Mistry maintainer=Sandeep Mistry sentence=An Arduino library for sending and receiving data using LoRa radios. From 039b138d8006ecf66953deafb8fe9478a0a66b35 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Mon, 7 May 2018 13:02:06 -0400 Subject: [PATCH 03/12] Add support for Arduino MKR WAN 1300 boards (#105) * Add support for Arduino MKR WAN 1300 board * Add new LoRa.setSPI(...) API to use radio with a different SPI interface * Disable LoRa.onReceive(...) and LoRa.receive() on Arduino MKR WAN 1300 * Add errors on sketches not compatible with the Arduino MKR WAN 1300 --- .travis.yml | 9 ++++- API.md | 13 +++++++ README.md | 3 ++ .../LoRaDuplexCallback/LoRaDuplexCallback.ino | 4 ++ .../LoRaReceiverCallback.ino | 4 ++ src/LoRa.cpp | 39 +++++++++++++++---- src/LoRa.h | 24 +++++++++--- 7 files changed, 82 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2dcac81..8a9cb12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ env: - BOARD="arduino:samd:arduino_zero_edbg" - BOARD="arduino:samd:mkr1000" - BOARD="arduino:samd:mkrzero" + - BOARD="arduino:samd:mkrwan1300" before_install: - wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz - tar xf arduino-$IDE_VERSION-linux64.tar.xz @@ -24,9 +25,13 @@ install: script: - buildExampleSketch LoRaDumpRegisters - buildExampleSketch LoRaDuplex - - buildExampleSketch LoRaDuplexCallback + - if [[ "$BOARD" != "arduino:samd:mkrwan1300" ]]; then + buildExampleSketch LoRaDuplexCallback; + fi - buildExampleSketch LoRaReceiver - - buildExampleSketch LoRaReceiverCallback + - if [[ "$BOARD" != "arduino:samd:mkrwan1300" ]]; then + buildExampleSketch LoRaReceiverCallback; + fi - buildExampleSketch LoRaSender - buildExampleSketch LoRaSetSpread - buildExampleSketch LoRaSetSyncWord diff --git a/API.md b/API.md index 0e4a8e9..a9a89b5 100644 --- a/API.md +++ b/API.md @@ -38,6 +38,17 @@ To save further pins one could connect the reset pin of the MCU with reset pin o * `reset` - set to `-1` to omit this pin +### Set SPI interface + +Override the default SPI interface used by the library. **Must** be called before `LoRa.begin()`. + +```arduino +LoRa.setSPI(spi); +``` + * `spi` - new SPI interface to use, defaults to `SPI` + +This call is optional and only needs to be used if you need to change the default SPI interface used, in the case your Arduino (or compatible) board has more than one SPI interface present. + ### Set SPI Frequency Override the default SPI frequency of 10 MHz used by the library. **Must** be called before `LoRa.begin()`. @@ -122,6 +133,8 @@ Returns the packet size in bytes or `0` if no packet was received. ### Continuous receive mode +**WARNING**: Not supported on the Arduino MKR WAN 1300 board! + #### Register callback Register a callback function for when a packet is received. diff --git a/README.md b/README.md index da9446e..f527971 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,9 @@ An [Arduino](https://arduino.cc/) library for sending and receiving data using [ * [Dragino Lora Shield](http://www.dragino.com/products/module/item/102-lora-shield.html) * [HopeRF](http://www.hoperf.com/rf_transceiver/lora/) [RFM95W](http://www.hoperf.com/rf_transceiver/lora/RFM95W.html), [RFM96W](http://www.hoperf.com/rf_transceiver/lora/RFM96W.html), and [RFM98W](http://www.hoperf.com/rf_transceiver/lora/RFM98W.html) * [Modtronix](http://modtronix.com/) [inAir4](http://modtronix.com/inair4.html), [inAir9](http://modtronix.com/inair9.html), and [inAir9B](http://modtronix.com/inair9b.html) + * [Arduino MKR WAN 1300](https://store.arduino.cc/usa/mkr-wan-1300) + * **NOTE:** Requires firmware v1.1.6 or later on the on-board Murata module + * **WARNING**: [LoRa.onReceive(...)](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#register-callback) and [LoRa.recieve()](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#receive-mode) is not compatible with this board! ### Semtech SX1276/77/78/79 wiring diff --git a/examples/LoRaDuplexCallback/LoRaDuplexCallback.ino b/examples/LoRaDuplexCallback/LoRaDuplexCallback.ino index 2385188..0511f3e 100644 --- a/examples/LoRaDuplexCallback/LoRaDuplexCallback.ino +++ b/examples/LoRaDuplexCallback/LoRaDuplexCallback.ino @@ -15,6 +15,10 @@ #include // include libraries #include +#ifdef ARDUINO_SAMD_MKRWAN1300 +#error "This example is not compatible with the Arduino MKR WAN 1300 board!" +#endif + const int csPin = 7; // LoRa radio chip select const int resetPin = 6; // LoRa radio reset const int irqPin = 1; // change for your board; must be a hardware interrupt pin diff --git a/examples/LoRaReceiverCallback/LoRaReceiverCallback.ino b/examples/LoRaReceiverCallback/LoRaReceiverCallback.ino index 1920c5d..e227e23 100644 --- a/examples/LoRaReceiverCallback/LoRaReceiverCallback.ino +++ b/examples/LoRaReceiverCallback/LoRaReceiverCallback.ino @@ -1,6 +1,10 @@ #include #include +#ifdef ARDUINO_SAMD_MKRWAN1300 +#error "This example is not compatible with the Arduino MKR WAN 1300 board!" +#endif + void setup() { Serial.begin(9600); while (!Serial); diff --git a/src/LoRa.cpp b/src/LoRa.cpp index c026d5f..4296e76 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -54,7 +54,8 @@ #define MAX_PKT_LENGTH 255 LoRaClass::LoRaClass() : - _spiSettings(8E6, MSBFIRST, SPI_MODE0), + _spiSettings(LORA_DEFAULT_SPI_FREQUENCY, MSBFIRST, SPI_MODE0), + _spi(&LORA_DEFAULT_SPI), _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _frequency(0), _packetIndex(0), @@ -67,6 +68,23 @@ LoRaClass::LoRaClass() : int LoRaClass::begin(long frequency) { +#ifdef ARDUINO_SAMD_MKRWAN1300 + pinMode(LORA_IRQ_DUMB, OUTPUT); + digitalWrite(LORA_IRQ_DUMB, LOW); + + // Hardware reset + pinMode(LORA_BOOT0, OUTPUT); + digitalWrite(LORA_BOOT0, LOW); + + pinMode(LORA_RESET, OUTPUT); + digitalWrite(LORA_RESET, HIGH); + delay(200); + digitalWrite(LORA_RESET, LOW); + delay(200); + digitalWrite(LORA_RESET, HIGH); + delay(50); +#endif + // setup pins pinMode(_ss, OUTPUT); // set SS high @@ -83,7 +101,7 @@ int LoRaClass::begin(long frequency) } // start SPI - SPI.begin(); + _spi->begin(); // check version uint8_t version = readRegister(REG_VERSION); @@ -122,7 +140,7 @@ void LoRaClass::end() sleep(); // stop SPI - SPI.end(); + _spi->end(); } int LoRaClass::beginPacket(int implicitHeader) @@ -296,6 +314,7 @@ void LoRaClass::flush() { } +#ifndef ARDUINO_SAMD_MKRWAN1300 void LoRaClass::onReceive(void(*callback)(int)) { _onReceive = callback; @@ -328,6 +347,7 @@ void LoRaClass::receive(int size) writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); } +#endif void LoRaClass::idle() { @@ -504,6 +524,11 @@ void LoRaClass::setPins(int ss, int reset, int dio0) _dio0 = dio0; } +void LoRaClass::setSPI(SPIClass& spi) +{ + _spi = &spi; +} + void LoRaClass::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); @@ -575,10 +600,10 @@ uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value) digitalWrite(_ss, LOW); - SPI.beginTransaction(_spiSettings); - SPI.transfer(address); - response = SPI.transfer(value); - SPI.endTransaction(); + _spi->beginTransaction(_spiSettings); + _spi->transfer(address); + response = _spi->transfer(value); + _spi->endTransaction(); digitalWrite(_ss, HIGH); diff --git a/src/LoRa.h b/src/LoRa.h index 46c2880..248a988 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -7,12 +7,22 @@ #include #include -#define LORA_DEFAULT_SS_PIN 10 -#define LORA_DEFAULT_RESET_PIN 9 -#define LORA_DEFAULT_DIO0_PIN 2 +#ifdef ARDUINO_SAMD_MKRWAN1300 +#define LORA_DEFAULT_SPI SPI1 +#define LORA_DEFAULT_SPI_FREQUENCY 250000 +#define LORA_DEFAULT_SS_PIN LORA_IRQ_DUMB +#define LORA_DEFAULT_RESET_PIN -1 +#define LORA_DEFAULT_DIO0_PIN -1 +#else +#define LORA_DEFAULT_SPI SPI +#define LORA_DEFAULT_SPI_FREQUENCY 8E6 +#define LORA_DEFAULT_SS_PIN 10 +#define LORA_DEFAULT_RESET_PIN 9 +#define LORA_DEFAULT_DIO0_PIN 2 +#endif -#define PA_OUTPUT_RFO_PIN 0 -#define PA_OUTPUT_PA_BOOST_PIN 1 +#define PA_OUTPUT_RFO_PIN 0 +#define PA_OUTPUT_PA_BOOST_PIN 1 class LoRaClass : public Stream { public: @@ -39,9 +49,11 @@ public: virtual int peek(); virtual void flush(); +#ifndef ARDUINO_SAMD_MKRWAN1300 void onReceive(void(*callback)(int)); void receive(int size = 0); +#endif void idle(); void sleep(); @@ -62,6 +74,7 @@ public: byte random(); void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN); + void setSPI(SPIClass& spi); void setSPIFrequency(uint32_t frequency); void dumpRegisters(Stream& out); @@ -85,6 +98,7 @@ private: private: SPISettings _spiSettings; + SPIClass* _spi; int _ss; int _reset; int _dio0; From 5f62ed2ce9d1623bfc12f468b8152ba1878b5b16 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Mon, 7 May 2018 13:03:15 -0400 Subject: [PATCH 04/12] Version 0.5.0 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 741ff52..af09c7a 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=LoRa -version=0.4.0 +version=0.5.0 author=Sandeep Mistry maintainer=Sandeep Mistry sentence=An Arduino library for sending and receiving data using LoRa radios. From 4db4095f92ad66636726805fdce2ffb6d979927f Mon Sep 17 00:00:00 2001 From: Morgan Allen Date: Mon, 30 Jul 2018 09:27:22 -0700 Subject: [PATCH 05/12] Fix incorrect sync word in API.md API currently states the default sync word is 0x34 when in fact it\'s 0x12. 0x34 is the sync word when using LoRaWAN --- API.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API.md b/API.md index a9a89b5..9dd8867 100644 --- a/API.md +++ b/API.md @@ -317,7 +317,7 @@ Change the sync word of the radio. LoRa.setSyncWord(syncWord); ``` - * `syncWord` - byte value to use as the sync word, defaults to `0x34` + * `syncWord` - byte value to use as the sync word, defaults to `0x12` ### CRC From 884769e20686238742d833e9517679acf0080eee Mon Sep 17 00:00:00 2001 From: Evgeny Dontsov Date: Tue, 7 Aug 2018 02:23:53 +0300 Subject: [PATCH 06/12] sx127x 20dBm support (#153) --- API.md | 2 +- src/LoRa.cpp | 37 +++++++++++++++++++++++++++++++++---- src/LoRa.h | 1 + 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/API.md b/API.md index 9dd8867..01c1526 100644 --- a/API.md +++ b/API.md @@ -249,7 +249,7 @@ LoRa.setTxPower(txPower, outputPin); * `txPower` - TX power in dB, defaults to `17` * `outputPin` - (optional) PA output pin, supported values are `PA_OUTPUT_RFO_PIN` and `PA_OUTPUT_PA_BOOST_PIN`, defaults to `PA_OUTPUT_PA_BOOST_PIN`. -Supported values are between `2` and `17` for `PA_OUTPUT_PA_BOOST_PIN`, `0` and `14` for `PA_OUTPUT_RFO_PIN`. +Supported values are `2` to `20` for `PA_OUTPUT_PA_BOOST_PIN`, and `0` to `14` for `PA_OUTPUT_RFO_PIN`. Most modules have the PA output pin connected to PA BOOST, diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 4296e76..855f6bf 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -10,6 +10,7 @@ #define REG_FRF_MID 0x07 #define REG_FRF_LSB 0x08 #define REG_PA_CONFIG 0x09 +#define REG_OCP 0x0b #define REG_LNA 0x0c #define REG_FIFO_ADDR_PTR 0x0d #define REG_FIFO_TX_BASE_ADDR 0x0e @@ -34,6 +35,7 @@ #define REG_SYNC_WORD 0x39 #define REG_DIO_MAPPING_1 0x40 #define REG_VERSION 0x42 +#define REG_PA_DAC 0x4d // modes #define MODE_LONG_RANGE_MODE 0x80 @@ -372,10 +374,24 @@ void LoRaClass::setTxPower(int level, int outputPin) writeRegister(REG_PA_CONFIG, 0x70 | level); } else { // PA BOOST - if (level < 2) { - level = 2; - } else if (level > 17) { - level = 17; + if (level > 17) { + if (level > 20) { + level = 20; + } + + // subtract 3 from level, so 18 - 20 maps to 15 - 17 + level -= 3; + + // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) + writeRegister(REG_PA_DAC, 0x87); + setOCP(140); + } else { + if (level < 2) { + level = 2; + } + //Default value PA_HF/LF or +17dBm + writeRegister(REG_PA_DAC, 0x84); + setOCP(100); } writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2)); @@ -512,6 +528,19 @@ void LoRaClass::disableCrc() writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); } +void LoRaClass::setOCP(uint8_t mA) +{ + uint8_t ocpTrim = 27; + + if (mA <= 120) { + ocpTrim = (mA - 45) / 5; + } else if (mA <=240) { + ocpTrim = (mA + 30) / 10; + } + + writeRegister(REG_OCP, 0x20 | (0x1F & ocpTrim)); +} + byte LoRaClass::random() { return readRegister(REG_RSSI_WIDEBAND); diff --git a/src/LoRa.h b/src/LoRa.h index 248a988..a5cc2de 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -66,6 +66,7 @@ public: void setSyncWord(int sw); void enableCrc(); void disableCrc(); + void setOCP(uint8_t mA); // Over Current Protection control // deprecated void crc() { enableCrc(); } From 6a6e9c39d0ad74de7f14fa3bc0474e9af9f4d4ea Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Mon, 6 Aug 2018 19:25:34 -0400 Subject: [PATCH 07/12] Remove trailing white space --- src/LoRa.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 855f6bf..cecf277 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -390,7 +390,7 @@ void LoRaClass::setTxPower(int level, int outputPin) level = 2; } //Default value PA_HF/LF or +17dBm - writeRegister(REG_PA_DAC, 0x84); + writeRegister(REG_PA_DAC, 0x84); setOCP(100); } @@ -485,10 +485,10 @@ void LoRaClass::setLdoFlag() { // Section 4.1.1.5 long symbolDuration = 1000 / ( getSignalBandwidth() / (1L << getSpreadingFactor()) ) ; - + // Section 4.1.1.6 boolean ldoOn = symbolDuration > 16; - + uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); bitWrite(config3, 3, ldoOn); writeRegister(REG_MODEM_CONFIG_3, config3); @@ -538,7 +538,7 @@ void LoRaClass::setOCP(uint8_t mA) ocpTrim = (mA + 30) / 10; } - writeRegister(REG_OCP, 0x20 | (0x1F & ocpTrim)); + writeRegister(REG_OCP, 0x20 | (0x1F & ocpTrim)); } byte LoRaClass::random() From 403738660b333b7f4febf75623dbc8f358943947 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Mon, 6 Aug 2018 19:26:01 -0400 Subject: [PATCH 08/12] Fix warning --- src/LoRa.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index cecf277..7f829ca 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -437,6 +437,7 @@ void LoRaClass::setSpreadingFactor(int sf) long LoRaClass::getSignalBandwidth() { byte bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); + switch (bw) { case 0: return 7.8E3; case 1: return 10.4E3; @@ -449,6 +450,8 @@ long LoRaClass::getSignalBandwidth() case 8: return 250E3; case 9: return 500E3; } + + return -1; } void LoRaClass::setSignalBandwidth(long sbw) From 07bfead143cf617b76e19d40a291dffb5c7e3685 Mon Sep 17 00:00:00 2001 From: Luiz Date: Sun, 19 Aug 2018 10:53:52 -0300 Subject: [PATCH 09/12] Add function to invert IQ signal register (#179) Add function to change register (REG_INVERTIQ) to support communication node and gateway The register does not exist in datasheet but use on but used in Semtech code. Reference : https://github.com/intel-iot-devkit/upm/blob/master/src/sx1276/sx1276.cxx * Add LoRa Simple Gateway/Node Exemple Example how to use InvertIQ function to create a simple Gateway/Node logic. --- API.md | 10 ++ .../LoRaSimpleGateway/LoRaSimpleGateway.ino | 113 ++++++++++++++++++ examples/LoRaSimpleNode/LoRaSimpleNode.ino | 113 ++++++++++++++++++ keywords.txt | 2 + src/LoRa.cpp | 14 +++ src/LoRa.h | 3 + 6 files changed, 255 insertions(+) create mode 100644 examples/LoRaSimpleGateway/LoRaSimpleGateway.ino create mode 100644 examples/LoRaSimpleNode/LoRaSimpleNode.ino diff --git a/API.md b/API.md index 01c1526..4b7d46e 100644 --- a/API.md +++ b/API.md @@ -329,6 +329,16 @@ LoRa.enableCrc(); LoRa.disableCrc(); ``` +### Invert IQ Signals + +Enable or disable Invert the LoRa I and Q signals, by default a invertIQ is not used. + +```arduino +LoRa.enableInvertIQ(); + +LoRa.disableInvertIQ(); +``` + ## Other functions ### Random diff --git a/examples/LoRaSimpleGateway/LoRaSimpleGateway.ino b/examples/LoRaSimpleGateway/LoRaSimpleGateway.ino new file mode 100644 index 0000000..745bf1f --- /dev/null +++ b/examples/LoRaSimpleGateway/LoRaSimpleGateway.ino @@ -0,0 +1,113 @@ +/* + LoRa Simple Gateway/Node Exemple + + This code uses InvertIQ function to create a simple Gateway/Node logic. + + Gateway - Sends messages with enableInvertIQ() + - Receives messages with disableInvertIQ() + + Node - Sends messages with disableInvertIQ() + - Receives messages with enableInvertIQ() + + With this arrangement a Gateway never receive messages from another Gateway + and a Node never receive message from another Node. + Only Gateway to Node and vice versa. + + This code receives messages and sends a message every second. + + InvertIQ function basically invert the LoRa I and Q signals. + + See the Semtech datasheet, http://www.semtech.com/images/datasheet/sx1276.pdf + for more on InvertIQ register 0x33. + + created 05 August 2018 + by Luiz H. Cassettari +*/ + +#include // include libraries +#include + +const long frequency = 915E6; // LoRa Frequency + +const int csPin = 10; // LoRa radio chip select +const int resetPin = 9; // LoRa radio reset +const int irqPin = 2; // change for your board; must be a hardware interrupt pin + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + LoRa.setPins(csPin, resetPin, irqPin); + + if (!LoRa.begin(frequency)) { + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + Serial.println("LoRa init succeeded."); + Serial.println(); + Serial.println("LoRa Simple Gateway"); + Serial.println("Only receive messages from nodes"); + Serial.println("Tx: invertIQ enable"); + Serial.println("Rx: invertIQ disable"); + Serial.println(); + + LoRa.onReceive(onReceive); + LoRa_rxMode(); +} + +void loop() { + if (runEvery(5000)) { // repeat every 5000 millis + + String message = "HeLoRa World! "; + message += "I'm a Gateway! "; + message += millis(); + + LoRa_sendMessage(message); // send a message + + Serial.println("Send Message!"); + } +} + +void LoRa_rxMode(){ + LoRa.disableInvertIQ(); // normal mode + LoRa.receive(); // set receive mode +} + +void LoRa_txMode(){ + LoRa.idle(); // set standby mode + LoRa.enableInvertIQ(); // active invert I and Q signals +} + +void LoRa_sendMessage(String message) { + LoRa_txMode(); // set tx mode + LoRa.beginPacket(); // start packet + LoRa.print(message); // add payload + LoRa.endPacket(); // finish packet and send it + LoRa_rxMode(); // set rx mode +} + +void onReceive(int packetSize) { + String message = ""; + + while (LoRa.available()) { + message += (char)LoRa.read(); + } + + Serial.print("Gateway Receive: "); + Serial.println(message); + +} + +boolean runEvery(unsigned long interval) +{ + static unsigned long previousMillis = 0; + unsigned long currentMillis = millis(); + if (currentMillis - previousMillis >= interval) + { + previousMillis = currentMillis; + return true; + } + return false; +} + diff --git a/examples/LoRaSimpleNode/LoRaSimpleNode.ino b/examples/LoRaSimpleNode/LoRaSimpleNode.ino new file mode 100644 index 0000000..a6cb0c0 --- /dev/null +++ b/examples/LoRaSimpleNode/LoRaSimpleNode.ino @@ -0,0 +1,113 @@ +/* + LoRa Simple Gateway/Node Exemple + + This code uses InvertIQ function to create a simple Gateway/Node logic. + + Gateway - Sends messages with enableInvertIQ() + - Receives messages with disableInvertIQ() + + Node - Sends messages with disableInvertIQ() + - Receives messages with enableInvertIQ() + + With this arrangement a Gateway never receive messages from another Gateway + and a Node never receive message from another Node. + Only Gateway to Node and vice versa. + + This code receives messages and sends a message every second. + + InvertIQ function basically invert the LoRa I and Q signals. + + See the Semtech datasheet, http://www.semtech.com/images/datasheet/sx1276.pdf + for more on InvertIQ register 0x33. + + created 05 August 2018 + by Luiz H. Cassettari +*/ + +#include // include libraries +#include + +const long frequency = 915E6; // LoRa Frequency + +const int csPin = 10; // LoRa radio chip select +const int resetPin = 9; // LoRa radio reset +const int irqPin = 2; // change for your board; must be a hardware interrupt pin + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + LoRa.setPins(csPin, resetPin, irqPin); + + if (!LoRa.begin(frequency)) { + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + Serial.println("LoRa init succeeded."); + Serial.println(); + Serial.println("LoRa Simple Node"); + Serial.println("Only receive messages from gateways"); + Serial.println("Tx: invertIQ disable"); + Serial.println("Rx: invertIQ enable"); + Serial.println(); + + LoRa.onReceive(onReceive); + LoRa_rxMode(); +} + +void loop() { + if (runEvery(1000)) { // repeat every 1000 millis + + String message = "HeLoRa World! "; + message += "I'm a Node! "; + message += millis(); + + LoRa_sendMessage(message); // send a message + + Serial.println("Send Message!"); + } +} + +void LoRa_rxMode(){ + LoRa.enableInvertIQ(); // active invert I and Q signals + LoRa.receive(); // set receive mode +} + +void LoRa_txMode(){ + LoRa.idle(); // set standby mode + LoRa.disableInvertIQ(); // normal mode +} + +void LoRa_sendMessage(String message) { + LoRa_txMode(); // set tx mode + LoRa.beginPacket(); // start packet + LoRa.print(message); // add payload + LoRa.endPacket(); // finish packet and send it + LoRa_rxMode(); // set rx mode +} + +void onReceive(int packetSize) { + String message = ""; + + while (LoRa.available()) { + message += (char)LoRa.read(); + } + + Serial.print("Node Receive: "); + Serial.println(message); + +} + +boolean runEvery(unsigned long interval) +{ + static unsigned long previousMillis = 0; + unsigned long currentMillis = millis(); + if (currentMillis - previousMillis >= interval) + { + previousMillis = currentMillis; + return true; + } + return false; +} + diff --git a/keywords.txt b/keywords.txt index 759bb0a..854ed8c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -44,6 +44,8 @@ setPreambleLength KEYWORD2 setSyncWord KEYWORD2 enableCrc KEYWORD2 disableCrc KEYWORD2 +enableInvertIQ KEYWORD2 +disableInvertIQ KEYWORD2 random KEYWORD2 setPins KEYWORD2 diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 7f829ca..065c5e3 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -31,8 +31,10 @@ #define REG_FREQ_ERROR_LSB 0x2a #define REG_RSSI_WIDEBAND 0x2c #define REG_DETECTION_OPTIMIZE 0x31 +#define REG_INVERTIQ 0x33 #define REG_DETECTION_THRESHOLD 0x37 #define REG_SYNC_WORD 0x39 +#define REG_INVERTIQ2 0x3b #define REG_DIO_MAPPING_1 0x40 #define REG_VERSION 0x42 #define REG_PA_DAC 0x4d @@ -531,6 +533,18 @@ void LoRaClass::disableCrc() writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); } +void LoRaClass::enableInvertIQ() +{ + writeRegister(REG_INVERTIQ, 0x66); + writeRegister(REG_INVERTIQ2, 0x19); +} + +void LoRaClass::disableInvertIQ() +{ + writeRegister(REG_INVERTIQ, 0x27); + writeRegister(REG_INVERTIQ2, 0x1d); +} + void LoRaClass::setOCP(uint8_t mA) { uint8_t ocpTrim = 27; diff --git a/src/LoRa.h b/src/LoRa.h index a5cc2de..a58007d 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -66,6 +66,9 @@ public: void setSyncWord(int sw); void enableCrc(); void disableCrc(); + void enableInvertIQ(); + void disableInvertIQ(); + void setOCP(uint8_t mA); // Over Current Protection control // deprecated From 9d2a8c9c824af07f1e59dd42c6af453e56eef0b4 Mon Sep 17 00:00:00 2001 From: Samuel Lang Date: Sun, 19 Aug 2018 16:34:32 +0200 Subject: [PATCH 10/12] non blocking functions added (#62) --- .travis.yml | 1 + API.md | 7 ++-- .../LoRaSenderNonBlocking.ino | 35 ++++++++++++++++++ src/LoRa.cpp | 36 +++++++++++++++---- src/LoRa.h | 3 +- 5 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino diff --git a/.travis.yml b/.travis.yml index 8a9cb12..ae7a782 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,5 +33,6 @@ script: buildExampleSketch LoRaReceiverCallback; fi - buildExampleSketch LoRaSender + - buildExampleSketch LoRaSenderNonBlocking - buildExampleSketch LoRaSetSpread - buildExampleSketch LoRaSetSyncWord diff --git a/API.md b/API.md index 4b7d46e..ded3b9c 100644 --- a/API.md +++ b/API.md @@ -82,7 +82,7 @@ LoRa.beginPacket(implicitHeader); * `implicitHeader` - (optional) `true` enables implicit header mode, `false` enables explicit header mode (default) -Returns `1` on success, `0` on failure. +Returns `1` if radio is ready to transmit, `0` if busy or on failure. ### Writing @@ -109,8 +109,11 @@ Returns the number of bytes written. End the sequence of sending a packet. ```arduino -LoRa.endPacket() +LoRa.endPacket(); + +LoRa.endPacket(async); ``` + * `async` - (optional) `true` enables non-blocking mode, `false` waits for transmission to be completed (default) Returns `1` on success, `0` on failure. diff --git a/examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino b/examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino new file mode 100644 index 0000000..0f39077 --- /dev/null +++ b/examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino @@ -0,0 +1,35 @@ +#include +#include + +int counter = 0; + +void setup() { + Serial.begin(9600); + while (!Serial); + + Serial.println("LoRa Sender non-blocking"); + + if (!LoRa.begin(915E6)) { + Serial.println("Starting LoRa failed!"); + while (1); + } +} + +void loop() { + // wait until the radio is ready to send a packet + while (LoRa.beginPacket() == 0) { + Serial.print("waiting for radio ... "); + delay(100); + } + + Serial.print("Sending packet non-blocking: "); + Serial.println(counter); + + // send in async / non-blocking mode + LoRa.beginPacket(); + LoRa.print("hello "); + LoRa.print(counter); + LoRa.endPacket(true); // true = async / non-blocking mode + + counter++; +} diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 065c5e3..94841b2 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -149,6 +149,10 @@ void LoRaClass::end() int LoRaClass::beginPacket(int implicitHeader) { + if (isTransmitting()) { + return 0; + } + // put in standby mode idle(); @@ -165,22 +169,40 @@ int LoRaClass::beginPacket(int implicitHeader) return 1; } -int LoRaClass::endPacket() +int LoRaClass::endPacket(bool async) { // put in TX mode writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); - // wait for TX done - while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { - yield(); + if (async) { + // grace time is required for the radio + delayMicroseconds(150); + } else { + // wait for TX done + while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { + yield(); + } + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); } - // clear IRQ's - writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); - return 1; } +bool LoRaClass::isTransmitting() +{ + if ((readRegister(REG_OP_MODE) & MODE_TX) == MODE_TX) { + return true; + } + + if (readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) { + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); + } + + return false; +} + int LoRaClass::parsePacket(int size) { int packetLength = 0; diff --git a/src/LoRa.h b/src/LoRa.h index a58007d..c5d239e 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -32,7 +32,7 @@ public: void end(); int beginPacket(int implicitHeader = false); - int endPacket(); + int endPacket(bool async = false); int parsePacket(int size = 0); int packetRssi(); @@ -88,6 +88,7 @@ private: void implicitHeaderMode(); void handleDio0Rise(); + bool isTransmitting(); int getSpreadingFactor(); long getSignalBandwidth(); From baf0d73849e226343633d96a78da2ce2a6cf184d Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Sun, 19 Aug 2018 10:38:43 -0400 Subject: [PATCH 11/12] Update README.md Add more info. about the MKR WAN 1300 firmware. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f527971..c89956a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ An [Arduino](https://arduino.cc/) library for sending and receiving data using [ * [HopeRF](http://www.hoperf.com/rf_transceiver/lora/) [RFM95W](http://www.hoperf.com/rf_transceiver/lora/RFM95W.html), [RFM96W](http://www.hoperf.com/rf_transceiver/lora/RFM96W.html), and [RFM98W](http://www.hoperf.com/rf_transceiver/lora/RFM98W.html) * [Modtronix](http://modtronix.com/) [inAir4](http://modtronix.com/inair4.html), [inAir9](http://modtronix.com/inair9.html), and [inAir9B](http://modtronix.com/inair9b.html) * [Arduino MKR WAN 1300](https://store.arduino.cc/usa/mkr-wan-1300) - * **NOTE:** Requires firmware v1.1.6 or later on the on-board Murata module + * **NOTE:** Requires firmware v1.1.6 or later on the on-board Murata module. Please use the [MKRWANFWUpdate_standalone example](https://github.com/arduino-libraries/MKRWAN/blob/master/examples/MKRWANFWUpdate_standalone/MKRWANFWUpdate_standalone.ino) from latest [MKRWAN library](https://github.com/arduino-libraries/MKRWAN) release to update the firmware. * **WARNING**: [LoRa.onReceive(...)](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#register-callback) and [LoRa.recieve()](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#receive-mode) is not compatible with this board! ### Semtech SX1276/77/78/79 wiring From 510cc003e2432cda41dd13d946259e7cebc3c62e Mon Sep 17 00:00:00 2001 From: per1234 Date: Mon, 27 Aug 2018 05:35:16 -0700 Subject: [PATCH 12/12] Use correct field separator in keywords.txt The Arduino IDE requires the use of a single true tab separator between the keyword name and identifier. When spaces are used rather than a true tab the keyword is not highlighted. Reference: https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification#keywords --- keywords.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keywords.txt b/keywords.txt index 854ed8c..2cf0351 100644 --- a/keywords.txt +++ b/keywords.txt @@ -44,8 +44,8 @@ setPreambleLength KEYWORD2 setSyncWord KEYWORD2 enableCrc KEYWORD2 disableCrc KEYWORD2 -enableInvertIQ KEYWORD2 -disableInvertIQ KEYWORD2 +enableInvertIQ KEYWORD2 +disableInvertIQ KEYWORD2 random KEYWORD2 setPins KEYWORD2