{"id":6429,"date":"2017-08-21T17:59:43","date_gmt":"2017-08-21T09:59:43","guid":{"rendered":"http:\/\/www.rocketscream.com\/blog\/?p=6429"},"modified":"2019-04-13T13:44:41","modified_gmt":"2019-04-13T05:44:41","slug":"the-sx1276-modules-shootout-hoperfs-rfm95w-vs-nicerfs-lora1276-c1-vs-hpdteks-hpd13","status":"publish","type":"post","link":"https:\/\/www.rocketscream.com\/blog\/2017\/08\/21\/the-sx1276-modules-shootout-hoperfs-rfm95w-vs-nicerfs-lora1276-c1-vs-hpdteks-hpd13\/","title":{"rendered":"The SX1276 Modules Shootout &#8211; HopeRF&#8217;s RFM95W vs NiceRF&#8217;s LORA1276-C1 vs HPDTEK&#8217;s HPD13"},"content":{"rendered":"<p>Few months back, a customer of ours asked whether we could get a shielded version of the HopeRF&#8217;s RFM95W on our Mini Ultra Pro boards. And sure we asked HopeRF whether they are willing to provide a custom version with a metal shield. They gave us a quotation and a minimum order quantity (MOQ) to fulfilled. Unfortunately, the MOQ were too high for either of us. So, we went on to search high and low for a LoRa SX1276 based module with a shield. At first we stumbled upon <a href=\"http:\/\/www.nicerf.com\/product_146_136.html\">NiceRF&#8217;s LORA1276-100mW<\/a> but it doesn&#8217;t have the same form factor as the RFM95W. But, we went on and made a prototype board with it. On paper it looks great but as soon as we assembled the very first few units using our reflow oven, we notice that one side of the module would be slightly lifted due to the imbalance of the module pinout (it has 12 pads on 1 side and another 2 pads on the opposite side corner of the module). The solder tension on the side with 12 pads are stronger compare to the other side of the module. We believe that this will somehow create some potential issues in manufacturing. So, we dropped the plan.<!--more--><\/p>\n<p>Disappointing find but we didn&#8217;t throw the towel just yet, we went and asked NiceRF whether they have plans to make a shielded version that has similar footprint as the RFM95W in the near future. Unfortunately they replied with a not so convincing answer stating that &#8220;maybe they would&#8221;. But, about 2 months ago, NiceRF gave a big surprise by releasing the <a href=\"http:\/\/www.nicerf.com\/product_146_198.html\">LORA1276-C1<\/a> module that has the same form factor and pinout as the HopeRF&#8217;s RFM95W, except that it comes with a shield! Having the exact form factor and pinout would be great as we can swap them in on our Mini Ultra Pro board if anyone needs a shielded version. We went on and ordered a few pieces to try them out.<\/p>\n<p>By luck, we also stumbled upon <a href=\"http:\/\/www.hpdtek.cn\/content\/?188.html\">HPDTEK&#8217;s HPD13<\/a> module that has the exact some form factor, pinout and <strong>even PCB layout<\/strong> of HopeRF&#8217;s RFM95W. We believe they are exact copies of the RFM95W although HopeRF&#8217;s SX1276 chip has their own marking of &#8220;RF96&#8221; with the &#8220;H logo&#8221; while HPDTEK uses the off-the-shelf SX1276 like NiceRF. Here&#8217;s how the 3 module looks like (RFM95W, HPD13, LORA1276-C1) side by side.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-6441\" src=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/SX1276BasedModules.jpg\" alt=\"\" width=\"600\" height=\"600\" srcset=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/SX1276BasedModules.jpg 600w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/SX1276BasedModules-100x100.jpg 100w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/SX1276BasedModules-80x80.jpg 80w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/SX1276BasedModules-300x300.jpg 300w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/SX1276BasedModules-36x36.jpg 36w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/SX1276BasedModules-180x180.jpg 180w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>We have yet to desolder the metal shield off the NiceRF&#8217;s LORA1276-C1 module but they have provided an image of their LORA1278-C1 (SX1278 based for 433MHz band) module without the metal shield. Here&#8217;s how it looks like and as you can see the PCB layout is totally different from the HopeRF&#8217;s RFM95W.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-6440\" src=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/LORA1278-C1.jpg\" alt=\"\" width=\"600\" height=\"600\" srcset=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/LORA1278-C1.jpg 600w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/LORA1278-C1-100x100.jpg 100w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/LORA1278-C1-80x80.jpg 80w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/LORA1278-C1-300x300.jpg 300w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/LORA1278-C1-36x36.jpg 36w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/LORA1278-C1-180x180.jpg 180w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>We are curious how these modules perform especially in the range test. We believe crucial factors like PCB layout, component values tolerance and PCB material (just to name a few) will affects how they perform. We wanted to perform a range test that would be able to provide some statistical data and most importantly run in the condition close to a real world deployment.<\/p>\n<p><strong>Setup<\/strong><\/p>\n<p>Our plan was to perform a range test using a pair of Mini Ultra Pro assembled with the same type of module and compare them. Each pair will consist of a stagnant base station and mobile node. The base station unit is mounted on the roof top of a 2 storey high building. We recently bought a 58 cm long 5 dBi antenna that has a very good S11 and VSWR performance. We plan to use it on a <a href=\"https:\/\/www.thethingsnetwork.org\/\">TTN<\/a> gateway. Here&#8217;s how it looks like in the lab while being measured it&#8217;s S11 and VSWR characteristic using a <a href=\"http:\/\/pocketvna.com\/\">pocketVNA<\/a>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-gallery wp-image-6432\" src=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/BigAntennaVNAMeasurementSetup-845x563.jpg\" alt=\"\" width=\"845\" height=\"563\" \/><\/p>\n<p>The resulting S11 and VSWR measurement were spot on especially on the 868 MHz band.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-gallery wp-image-6433\" src=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/S11VSWRBigAntenna58cm-845x684.png\" alt=\"\" width=\"845\" height=\"684\" srcset=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/S11VSWRBigAntenna58cm-845x684.png 845w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/S11VSWRBigAntenna58cm-495x400.png 495w\" sizes=\"auto, (max-width: 845px) 100vw, 845px\" \/> <img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-gallery wp-image-6434\" src=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/SmithChartBigAntenna58cm-845x684.png\" alt=\"\" width=\"845\" height=\"684\" srcset=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/SmithChartBigAntenna58cm-845x684.png 845w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/SmithChartBigAntenna58cm-495x400.png 495w\" sizes=\"auto, (max-width: 845px) 100vw, 845px\" \/><\/p>\n<p>Armed with a driller and hammer, we assembled the antenna bracket mount on the highest possible wall on the rooftop.<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-6435\" src=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/Driller.jpg\" alt=\"\" width=\"600\" height=\"600\" srcset=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/Driller.jpg 600w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/Driller-100x100.jpg 100w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/Driller-80x80.jpg 80w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/Driller-300x300.jpg 300w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/Driller-36x36.jpg 36w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/Driller-180x180.jpg 180w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>Here&#8217;s how the antenna looks like once the assembly is completed.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-6436\" src=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/BigAntennaAssembled.jpg\" alt=\"\" width=\"600\" height=\"600\" srcset=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/BigAntennaAssembled.jpg 600w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/BigAntennaAssembled-100x100.jpg 100w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/BigAntennaAssembled-80x80.jpg 80w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/BigAntennaAssembled-300x300.jpg 300w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/BigAntennaAssembled-36x36.jpg 36w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/BigAntennaAssembled-180x180.jpg 180w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>On the mobile node, the Mini Ultra Pro will be equipped with a GPS shield powered by\u00a0<a href=\"http:\/\/quectel.com\/product\/l80.htm\">Quectel&#8217;s L80 GPS module<\/a> (we&#8217;ll be releasing this soon!) to keep track of the location where transmission and reception is successful. This location information (latitude, longitude and host of other information) is then log onto (using <a href=\"https:\/\/github.com\/PaulStoffregen\/SerialFlash\">SerialFlash library<\/a>) the Mini Ultra Pro on-board 2MB serial flash in CSV format which can be retrieved later for further analysis.The mobile node will periodically send a data package to the base station and expects an acknowledgement from the base station. If a valid acknowledgement packet is received, the current GPS information (using <a href=\"http:\/\/arduiniana.org\/libraries\/tinygps\/\">TinyGPS library<\/a>) \u00a0is retrieved from L80 GPS module and stored. Some of you might have argue why not use the full LoRaWAN stack (using Arduino-LMIC library) and run it using the The Things Network backend? As LoRaWAN network such as the TTN has <a href=\"https:\/\/www.thethingsnetwork.org\/wiki\/LoRaWAN\/Duty-Cycle\">duty cycle limitation<\/a> and <a href=\"https:\/\/www.thethingsnetwork.org\/wiki\/LoRaWAN\/Limitations\">maximum airtime<\/a> that can be used in a day (30 s), it does not go well with our test that requires frequent data transmission.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-6442\" src=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MiniUltraProGPSShield.jpg\" alt=\"\" width=\"600\" height=\"600\" srcset=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MiniUltraProGPSShield.jpg 600w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MiniUltraProGPSShield-100x100.jpg 100w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MiniUltraProGPSShield-80x80.jpg 80w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MiniUltraProGPSShield-300x300.jpg 300w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MiniUltraProGPSShield-36x36.jpg 36w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MiniUltraProGPSShield-180x180.jpg 180w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>Both the base station and the mobile node are powered by Li-Polymer batteries. The mobile node is also attached to an external buzzer circuitry to indicate when a data packet is successfully transmitted and GPS information is logged onto the on-board serial flash. We use our <a href=\"http:\/\/www.rocketscream.com\/blog\/product\/ism-band-3-dbi-dipole-antenna-straight\/\">3 dBi 868 MHz antenna<\/a> through a <a href=\"http:\/\/www.rocketscream.com\/blog\/product\/rp-sma-jack-to-sma-adapter-rg316-rf-cable\/\">RP-SMA jack to SMA adapter cable<\/a>. The mobile node setup is placed at the back of a car&#8217;s windscreen with the antenna position vertically.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-6443\" src=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MobileNodeSetup.jpg\" alt=\"\" width=\"600\" height=\"600\" srcset=\"https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MobileNodeSetup.jpg 600w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MobileNodeSetup-100x100.jpg 100w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MobileNodeSetup-80x80.jpg 80w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MobileNodeSetup-300x300.jpg 300w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MobileNodeSetup-36x36.jpg 36w, https:\/\/www.rocketscream.com\/blog\/wp-content\/uploads\/2017\/08\/MobileNodeSetup-180x180.jpg 180w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p><strong>Code<\/strong><br \/>\nOn the firmware side, the base station has a rather simple structure that acknowledges a data packet send by the mobile node. The RadioHead library handles the acknowledgement process of a data packet automatically. Here&#8217;s how the base station code looks like (code are mostly derived from the examples on RadioHead library). Do note that we used a custom setting on the radio of\u00a0Bw125Cr45Sf4096 to mimic one of the physical layer settings (SF=12, BW=125 kHz, CR=4\/5) used in LoRaWAN network which can be added in the RH_RF95.h and RH_RF95.cpp files of the RadioHead library.<\/p>\n<pre>#include &lt;RHReliableDatagram.h&gt;\r\n#include &lt;RH_RF95.h&gt;\r\n#include &lt;SPI.h&gt;\r\n\r\n#define NODE_ADDRESS 1\r\n#define BASE_STATION_ADDRESS 2\r\n\r\n\/\/ Singleton instance of the radio driver\r\nRH_RF95 driver(5, 2);\r\n\r\n\/\/ Class to manage message delivery and receipt, using the driver declared above\r\nRHReliableDatagram radio(driver, BASE_STATION_ADDRESS);\r\n\r\nvoid setup()\r\n{\r\n  \/\/ Initialize LED pin\r\n  pinMode(13, OUTPUT);\r\n  digitalWrite(13, LOW);\r\n  \/\/ Initialize serial flash CS pin\r\n  pinMode(4, OUTPUT);\r\n  digitalWrite(4, HIGH);\r\n\r\n  \/\/ Enable debugging serial port\r\n  SerialUSB.begin(115200);\r\n\r\n  \/\/ Initialize radio\r\n  if (!radio.init()) SerialUSB.println(\"init failed\");\r\n  \/\/ Maximum transmit power at 23 dBm\r\n  driver.setTxPower(23, false);\r\n  \/\/ 868 MHz frequency\r\n  driver.setFrequency(868.00);\r\n  \/\/ CR=4\/5, SF=12, BW=125 kHz\r\n  driver.setModemConfig(RH_RF95::Bw125Cr45Sf4096);\r\n}\r\n\r\nvoid loop()\r\n{\r\n  unsigned char buf[RH_RF95_MAX_MESSAGE_LEN];\r\n  \r\n  if (radio.available())\r\n  {\r\n    \/\/ Wait for a message addressed to us from the client\r\n    uint8_t len = sizeof(buf);\r\n    uint8_t from;\r\n    if (radio.recvfromAck(buf, &amp;len, &amp;from))\r\n    {\r\n\r\n    }\r\n  }\r\n}\r\n<\/pre>\n<p>The mobile node sends a 1 byte (see below for the explanation) and expects an acknowledgement packet from the base station. And in the case where it does receive a valid acknowledgement, it will retrieve the current GPS information and log them onto the on-board serial flash. To retrieve these logged information, simply connect the USB port to a serial terminal and send any character to the board. All the current logged GPS information will be retrieved and the serial flash will be erased after that.\u00a0Here&#8217;s how the mobile node code looks like (the <a href=\"http:\/\/forum.arduino.cc\/index.php?topic=368720.0\" target=\"_blank\" rel=\"noopener noreferrer\">dtostrf function on SAMD21 are provided by jsmith<\/a> as currently it is not implemented on the SAMD21 Arduino core):<\/p>\n<pre>#include &lt;RHReliableDatagram.h&gt;\r\n#include &lt;RH_RF95.h&gt;\r\n#include &lt;TinyGPS.h&gt;\r\n#include &lt;SerialFlash.h&gt;\r\n#include &lt;SPI.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n\r\n#define NODE_ADDRESS 1\r\n#define BASE_STATION_ADDRESS 2\r\n\r\n\/\/ Singleton instance of the radio driver\r\nRH_RF95 driver(5, 2);\r\n\/\/ GPS driver\r\nTinyGPS gps;\r\nSerialFlashFile flashFile;\r\n\r\n\/\/ Class to manage message delivery and receipt, using the driver declared above\r\nRHReliableDatagram radio(driver, NODE_ADDRESS);\r\n\r\nunsigned int counter;\r\n\r\nvoid setup()\r\n{\r\n  \/\/ Initialize LED pin\r\n  pinMode(13, OUTPUT);\r\n  digitalWrite(13, LOW);\r\n  \/\/ Initialize serial flash CS pin\r\n  pinMode(4, OUTPUT);\r\n  digitalWrite(4, HIGH);\r\n  \/\/ Initialize serial flash CS pin\r\n  pinMode(5, OUTPUT);\r\n  digitalWrite(5, HIGH);\r\n\r\n  \/\/ Enable GPS serial port\r\n  Serial.begin(9600);\r\n  \/\/ Enable debugging serial port\r\n  SerialUSB.begin(115200);\r\n  \/\/while (!SerialUSB) {};\r\n\r\n  SerialFlash.begin(4);\r\n\r\n  if (!SerialFlash.exists(\"SX1276.CSV\"))\r\n  {\r\n    SerialUSB.println(\"SX1276.CSV does not exist\");\r\n    if (SerialFlash.create(\"SX1276.CSV\", 1000000))\r\n    {\r\n      SerialUSB.println(\"SX1276.CSV is created\");\r\n    }\r\n    else\r\n    {\r\n      SerialUSB.println(\"Unable to create file\");\r\n    }\r\n  }\r\n  else\r\n  {\r\n    SerialUSB.println(\"SX1276.CSV is already created\");\r\n  }\r\n\r\n  flashFile = SerialFlash.open(\"SX1276.CSV\");\r\n  if (!flashFile)\r\n  {\r\n    while (1)\r\n    {\r\n      digitalWrite(13, HIGH);\r\n      delay(100);\r\n      digitalWrite(13, LOW);\r\n      delay(100);\r\n    }\r\n  }\r\n  else\r\n  {\r\n    SerialUSB.println(\"SX1276.CSV is open\");\r\n  }\r\n\r\n  \/\/ Initialize radio\r\n  if (!radio.init()) SerialUSB.println(\"Radio failed\");\r\n\r\n  \/\/ Maximum transmit power at 23 dBm\r\n  driver.setTxPower(23, false);\r\n  \/\/ 868 MHz frequency\r\n  driver.setFrequency(868.00);\r\n  \/\/ CR=4\/5, SF=12, BW=125 kHz\r\n  driver.setModemConfig(RH_RF95::Bw125Cr45Sf4096);\r\n  radio.setTimeout(1000);\r\n  SerialUSB.println(\"Counter,Latitude,Longitude,Satellite,HDOP,SNR\");\r\n}\r\n\r\nvoid loop()\r\n{\r\n  char gpsData[12];\r\n  char logData[50];\r\n  char *logDataPtr;\r\n  unsigned char data[] = \"1\";\r\n  unsigned long readCounter;\r\n  int snr;\r\n  bool newData = false;\r\n\r\n  \/\/ Send a message to base station\r\n  if (radio.sendtoWait(data, sizeof(data), BASE_STATION_ADDRESS))\r\n  {\r\n    snr = driver.lastSNR();\r\n    digitalWrite(13, HIGH);\r\n    counter++;\r\n    \/\/ Parse GPS data for 1 s\r\n    for (unsigned long start = millis(); millis() - start &lt; 1000;)\r\n    {\r\n      while (Serial.available())\r\n      {\r\n        char c = Serial.read();\r\n        \/\/ SerialUSB.write(c);\r\n        if (gps.encode(c))\r\n        newData = true;\r\n      }\r\n    }\r\n    if (newData)\r\n    {\r\n      float flat, flon;\r\n      unsigned long age;\r\n      gps.f_get_position(&amp;flat, &amp;flon, &amp;age);\r\n\r\n      sprintf (gpsData, \"%u\", counter);\r\n      strcpy(logData, gpsData);\r\n      strcat(logData, \",\");\r\n      dtostrf(flat, 3, 6, gpsData);\r\n      strcat(logData, gpsData);\r\n      strcat(logData, \",\");\r\n      dtostrf(flon, 3, 6, gpsData);\r\n      strcat(logData, gpsData);\r\n      strcat(logData, \",\");\r\n      sprintf (gpsData, \"%u\", gps.satellites());\r\n      strcat(logData, gpsData);\r\n      strcat(logData, \",\");\r\n      sprintf (gpsData, \"%u\", gps.hdop());\r\n      strcat(logData, gpsData);\r\n      strcat(logData, \",\");\r\n      sprintf (gpsData, \"%d\", snr);\r\n      strcat(logData, gpsData);\r\n      strcat(logData, \"\\r\\n\");\r\n      \/\/ Terminate the log data\r\n      strcat(logData, \"\\0\");\r\n      \/\/ Push location data to indicate successful transmission &amp; reception at current location\r\n      SerialUSB.print(logData);\r\n      \/\/ Log location data onto serial flash\r\n      flashFile.write(logData, strlen(logData));\r\n    }\r\n\r\n    digitalWrite(13, LOW);\r\n  }\r\n  else\r\n  {\r\n  \/\/SerialUSB.println(\"TX failed\");\r\n  }\r\n  if (SerialUSB.available())\r\n  {\r\n    while (SerialUSB.available()) SerialUSB.read();\r\n    flashFile.close();\r\n    flashFile = SerialFlash.open(\"SX1276.CSV\");\r\n    if (flashFile)\r\n    {\r\n      digitalWrite(13, HIGH);\r\n      readCounter = flashFile.size();\r\n      SerialUSB.println(\"File will be deleted after reading!\");\r\n      SerialUSB.println(\"Counter,Latitude,Longitude,Satellite,HDOP,SNR\");\r\n\r\n      while (readCounter &gt; 0)\r\n      {\r\n        \/\/ Read 1 byte at a time\r\n        flashFile.read(gpsData, 1);\r\n        if ((gpsData[0] &gt;= '0') &amp;&amp; (gpsData[0] &lt;= '9') ||\r\n            (gpsData[0] == '.') || (gpsData[0] == ',') ||\r\n            (gpsData[0] == '\\r') || (gpsData[0] == '\\n'))\r\n        {\r\n          readCounter -= 1;\r\n          SerialUSB.print(gpsData);\r\n        }\r\n        \/\/ End of file\r\n        else break;\r\n      }\r\n      digitalWrite(13, LOW);\r\n    }\r\n    else\r\n    {\r\n      SerialUSB.println(\"Unable to open file\");\r\n    }\r\n    flashFile.close();\r\n    SerialFlash.eraseAll();\r\n    while (!SerialFlash.ready())\r\n    {\r\n      delay(500);\r\n      digitalWrite(13, HIGH);\r\n      delay(500);\r\n      digitalWrite(13, LOW);\r\n    }\r\n    SerialFlash.create(\"SX1276.CSV\", 1000000);\r\n    flashFile = SerialFlash.open(\"SX1276.CSV\");\r\n  }\r\n  \/\/ Provide gaps in between transmission\r\n  delay(500);\r\n}\r\n\r\n\/\/ dtostrf function on SAMD21 are provided by jsmith:\r\n\/\/ http:\/\/forum.arduino.cc\/index.php?topic=368720.0\r\nchar *dtostrf(double value, int width, unsigned int precision, char *result)\r\n{\r\n  int decpt, sign, reqd, pad;\r\n  const char *s, *e;\r\n  char *p;\r\n  s = fcvt(value, precision, &amp;decpt, &amp;sign);\r\n  if (precision == 0 &amp;&amp; decpt == 0) {\r\n    s = (*s &lt; '5') ? \"0\" : \"1\"; reqd = 1; } else { reqd = strlen(s); if (reqd &gt; decpt) reqd++;\r\n    if (decpt == 0) reqd++;\r\n  }\r\n  if (sign) reqd++;\r\n  p = result;\r\n  e = p + reqd;\r\n  pad = width - reqd;\r\n  if (pad &gt; 0) {\r\n    e += pad;\r\n    while (pad-- &gt; 0) *p++ = ' ';\r\n  }\r\n  if (sign) *p++ = '-';\r\n  if (decpt &lt;= 0 &amp;&amp; precision &gt; 0) {\r\n    *p++ = '0';\r\n    *p++ = '.';\r\n    e++;\r\n    while ( decpt &lt; 0 ) {\r\n      decpt++;\r\n      *p++ = '0';\r\n    }\r\n  }\r\n  while (p &lt; e) {\r\n    *p++ = *s++;\r\n    if (p == e) break;\r\n    if (--decpt == 0) *p++ = '.';\r\n  }\r\n  if (width &lt; 0) { pad = (reqd + width) * -1; while (pad-- &gt; 0) *p++ = ' ';\r\n  }\r\n  *p = 0;\r\n  return result;\r\n}\r\n<\/pre>\n<p><strong>Outcome<\/strong><\/p>\n<p>After running the test for a different pairs of the modules, here&#8217;s how the range test plot turns out!<br \/>\n<iframe loading=\"lazy\" src=\"https:\/\/www.google.com\/maps\/d\/embed?mid=1bAQcAE5o24LUWCvQuUVphVgwFdY&amp;hl=en\" width=\"640\" height=\"480\"><\/iframe><\/p>\n<p>From the plot, all the modules performs fairly well within the 3 km range but beyond that it becomes patchy depending on the location and module. The furthest point achieve is around 6.4 km. Under any circumstances, there were no line of sight link between the base station and the mobile node. This scenario provides a better real world usage assessment of the LoRa module rather than using a clear line of sight test condition. Take a look at the plot for yourself and use the measurement tool to see far these module could go! 2 years ago, we could achieve up to 10 km of range but as the city grows with more tall buildings and denser vegetation these results in shorter range in the present.<\/p>\n<p><strong>Further Work<\/strong><\/p>\n<p>We have been working on the SX1276 based modules for more than 2 years now. We found out that with long range settings such as using Spreading Factor (SF) of 12 and 125 kHz of bandwidth does not work reliably with the crystal based modules. This is more apparent when long data is being sent over the channel. This is due to the tolerance of the crystal used on these modules rated at 10 ppm (advertised as such). Across wider temperature range, it will further deviate. This is the reason we used a single byte data in the test code (RadioHead library will add a few more bytes in the header of the data packet). We were lucky enough to get our hands on a TCXO based (replaces the less accurate crystal with a better 2 ppm tolerance) module (RFM95TW) made by HopeRF. Even though these TCXO based module solves the issues at high SF and small and bandwidth setting, they are not low power as it continues to run even though the radio transceiver chip is in sleep mode. This result in a huge <strong>600 uA<\/strong> (vs 0.1 uA)of sleep current!<\/p>\n<p>We have yet to measure to output power of these modules and we hope to do so in the near future (provided we have the correct tools). Mike McCauley (author of RadioHeadlibrary) <a href=\"http:\/\/www.airspayce.com\/mikem\/arduino\/RadioHead\/classRH__RF95.html\">did some output power measurement<\/a> on the RFM95W but it would be great to be able to compare them.<\/p>\n<p><strong>Conclusion<\/strong><\/p>\n<p>We have yet to decide on whether to swap out the RFM95W module from our Mini Ultra Pro V2 with any of the other 2 modules. But, the having a shielded radio module is a very interesting point to ponder. We are not allowed to discuss the pricing point of view of these modules but they do vary from one and another. Do let us know what you guys think!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Few months back, a customer of ours asked whether we could get a shielded version of the HopeRF&#8217;s RFM95W on our Mini Ultra Pro boards. And sure we asked HopeRF whether they are willing to provide a custom version with a metal shield. They gave us a quotation and a minimum order quantity (MOQ) to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":6441,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"footnotes":""},"categories":[4],"tags":[],"class_list":["post-6429","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news"],"_links":{"self":[{"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/posts\/6429","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/comments?post=6429"}],"version-history":[{"count":15,"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/posts\/6429\/revisions"}],"predecessor-version":[{"id":6450,"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/posts\/6429\/revisions\/6450"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/media\/6441"}],"wp:attachment":[{"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/media?parent=6429"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/categories?post=6429"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rocketscream.com\/blog\/wp-json\/wp\/v2\/tags?post=6429"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}