Hi!
I am working on a project where I interface a RFM95W (915MHz) transceiver to an Arduino Pro Mini 3.3V. I have removed the in-built voltage regulator on it and replaced it with MCP1702 (which has a 250mA max supply current). The regulator is powering the arduino, RFM95W and INA219. I am powering the setup with a 9V battery and using an INA219 to measure the battery voltage.
This node communicates to a single channel gateway Dragino LG01-N (I am not using LoRaWAN. Just updating the data to a cloud via https). The gateway on receiving a packet from the node sends some data back to the node.
The node waits for the gateway and if the packet is received it goes to sleep for ‘x’ minutes (as set from the cloud) after which it again wakes up and re-transmits the data. If it does not receive any data from the gateway then it waits for 20secs and then goes to sleep for 1min.
For the node, I am using this antenna:
wideband GSM antenna
The problem:
Now, this setup is running great at first (the RSSI of the received packet is a bit weak, -50 to -70 @ 1m distance from the gateway). However, the problem occurs after I leave the node to run for more than 15-16hrs continuously. The node suddenly stops receiving data from the gateway. It transmits just fine though (the gateway is able to receive). But it will not receive any data.
After I checked the "dio0 pin of the RFM95W module, I found out that it is always HIGH and when I check it with a multimeter (on continuity test mode), it shows a short to Vcc of the same module.
Does this mean that the module gets damaged somehow while running? Is there a way to fix this? This has happened twice with the same circuit. The last reported battery voltage seems to be 8.7V before the node stops receiving, so the battery does not seem to be the issue here.
The antenna could be the problem here but I’m not sure.
Here is the code for the arduino pro mini 3.3V:
#include <LowPower.h>
#include <SPI.h>
#include <LoRa.h>
#include <Adafruit_INA219.h>
/* CONSTANTS (DO NOT MODIFY THESE) */
#define ON true
#define OFF false
#define RCV_BUFFER_SIZE_MAX 100
/* CONSTANTS */
/* USER CONFIGURABLE PARAMETERS */
#define USB_DEBUGGING ON //Set as ON to use serial monitor debugging. Set as OFF during standalone operation
#define USB_DEBUGGING_BAUD_RATE 115200 //Set the baud rate for USB debugging
#define DEVICE_ID 1 //Identity of the node. Same ID should be present in the cloud database for it to work
#define DEFAULT_CALL_HOME_FREQUENCY 1 //Set the default call home frequency for this node. This frequency will be used until data from cloud is synced after power-up
#define FAILSAFE_CALL_HOME_FREQUENCY 1 //Call Home Frequency if anything goes wrong during communication
#define DEFAULT_STATE OFF //Default state of remote device on first power-up or after reset
#define SPREADING_FACTOR 10 //Set spreading factor for radio. Should be the same as Gateway
#define PREAMBLE_LENGTH 8 //Set the preamble length for radio. Should be the same as Gateway
#define SYNC_WORD 0x34 //Set sync word for radio. Should be the same as Gateway (in decimal)
#define RADIO_FREQUENCY 915E6 //Set the radio frequency. Should be same as Gateway. Keep this at 915MHz (915E6) for best results
#define RADIO_TX_POWER 20 //2(min) - 20(max). HIgher number for greater range (!!!more power consumption)
#define RCV_TIMEOUT 20000 //Set the time for which this node will wait for Gateway in receive mode in milli-seconds
#define ON_WIRE_PIN 8 //Set the pin corresponding to ON-WIRE of remote device. !!!Need to change HW connection to change this!!!
#define OFF_WIRE_PIN 7 //Set the pin corresponding to OFF-WIRE of remote device. !!!Need to change HW connection to change this!!!
#define ON_OFF_SIG_DURATION 3000 //Duration for which ON or OFF wire is shorted to GND in milli-seconds
/* USER CONFIGURABLE PARAMETERS */
/* INIT VALUES */
#define INIT_VOLTAGE 0.0 //in Volts
#define INIT_CURRENT 0.0 //in mA (milli-amperes)
/* INIT VALUES */
/*Global Variables */
const int device_id = DEVICE_ID; // ID of this End node
const float cutoff_volt = 3.5; //Device goes to sleep until next power-up at or below this voltage
float volt = INIT_VOLTAGE; // Default voltage.
float amp = INIT_CURRENT; // Default current.
bool device_state = DEFAULT_STATE; //Default Device State
int call_home_freq = DEFAULT_CALL_HOME_FREQUENCY; //Default Call Home Frequency
int sleep_flag = 0;
int count = 0;
int buff_size = RCV_BUFFER_SIZE_MAX;
char rcv_buffer[RCV_BUFFER_SIZE_MAX];
bool data_changed_flag = false;
/*Global Variables */
/*INA219 voltage/current sensor object */
Adafruit_INA219 ina219;
/*INA219 voltage/current sensor object */
/* Function : LoRa_rxMode()
* Return Val : None
* Parameters : None
* Description : Changes LoRa transceiver to receive mode and activates invert I,Q signals
*/
void LoRa_rxMode() {
LoRa.enableInvertIQ(); // active invert I and Q signals
LoRa.receive(); // set receive mode
}
/* Function : LoRa_txMode()
* Return Val : None
* Parameters : None
* Description : Changes LoRa transceiver to transmit mode and deactivates invert I,Q signals
*/
void LoRa_txMode() {
LoRa.idle(); // set standby mode
LoRa.disableInvertIQ(); // normal mode
}
/* Function : LoRa_sendData()
* Return Val : Type: bool
* 'true' - when transmission succeeds
* 'false' - when transmission fails
* Parameters : id (int) - device id of the LoRa node
* call_home_freq (int) - call home frequency of the LoRa node in minutes
* state (bool) - current state of the device, 'true' means ON and 'false' means OFF
* volt (float) - last read voltage of the battery upto 2 decimal places
* Description : Transmits data to gateway
*/
bool LoRa_sendData(int id, int call_home_freq, bool state, float volt)
{
// compose and send packet
LoRa.beginPacket();
LoRa.print("<");
LoRa.print(id);
LoRa.print(">CHF=");
LoRa.print(call_home_freq);
LoRa.print("&State=");
LoRa.print(state);
#if USB_DEBUGGING == ON
Serial.println(state);
#endif
LoRa.print("&Voltage=");
LoRa.print(volt);
if (LoRa.endPacket())
{
#if USB_DEBUGGING == ON
Serial.println("Sent Data");
#endif
return true;
}
else
{
#if USB_DEBUGGING == ON
Serial.println("Could not send data");
#endif
return false;
}
}
/* Function : LoRa_sendData()
* Return Val : Type: char *
* returns the extracted value as character array corresponding to the key
* Parameters : key (char *) - the field whose value is to be extracted
* Description : extracts the value from received packet corresponding to a key (for e.g. "CHF=" or "state=").
*/
char * extract_param(char *key)
{
int index_start = 0, index_end = 0, i, j;
char param[5];
#if USB_DEBUGGING == ON
Serial.print("Key =");
Serial.println(key);
#endif
index_start = strstr(rcv_buffer, key) + strlen(key);
#if USB_DEBUGGING == ON
Serial.print("Start Index =");
Serial.println(index_start);
#endif
index_end = strstr(rcv_buffer, '&');
#if USB_DEBUGGING == ON
Serial.print("End Index =");
Serial.println(index_end);
#endif
for (i = index_start, j = 0; i < index_end; i++, j++)
{
param[j] = rcv_buffer[i];
}
param[j] = '\0';
#if USB_DEBUGGING == ON
Serial.print("Parameter =");
Serial.println(param);
#endif
return param;
}
/* Function : onReceive()
* Return Val : None
* Parameters : packetSize (int) - Size of the received packet
* Description : Receiver callback function. Processed whenever a packet is received by the node.
*/
void onReceive(int packetSize) {
//int packetSize = LoRa.parsePacket();
// received a packet
char *temp;
#if USB_DEBUGGING == ON
Serial.print("Packet Size = ");
Serial.println(packetSize);
#endif
if (packetSize) {
buff_size = packetSize <= RCV_BUFFER_SIZE_MAX ? packetSize : RCV_BUFFER_SIZE_MAX;
#if USB_DEBUGGING == ON
Serial.println(buff_size);
Serial.print("Received packet '");
#endif
// read packet
for (int i = 0; i < buff_size; i++) {
rcv_buffer[i] = (char)LoRa.read();
#if USB_DEBUGGING == ON
Serial.print(rcv_buffer[i]);
#endif
}
#if USB_DEBUGGING == ON
// print RSSI of packet
Serial.print("' with RSSI ");
Serial.println(LoRa.packetRssi());
#endif
//call_home_freq=atoi(extract_param("CHF="));
//Extracting Device ID
temp = strtok(rcv_buffer, "=");
#if USB_DEBUGGING == ON
Serial.print("First token=");
Serial.println(temp);
#endif
if (!strcmp(temp, "DevID")) //If received packet does not contain DevID as header then ignore it.
{
#if USB_DEBUGGING == ON
Serial.print("Value=");
#endif
temp = strtok(NULL, "&");
#if USB_DEBUGGING == ON
Serial.println(temp);
#endif
if (atoi(temp) == DEVICE_ID)
{
//Extracting Call Home Frequency
temp = strtok(NULL, "=");
#if USB_DEBUGGING == ON
Serial.print("Second token=");
Serial.println(temp);
#endif
if (!strcmp(temp, "CHF")) //If Acknowledgement is NOT received and gateway sends fresh data from cloud
{
#if USB_DEBUGGING == ON
Serial.print("Value=");
#endif
temp = strtok(NULL, "&");
#if USB_DEBUGGING == ON
Serial.println(temp);
#endif
call_home_freq = atoi(temp);
call_home_freq = call_home_freq > 0 ? call_home_freq : FAILSAFE_CALL_HOME_FREQUENCY;
#if USB_DEBUGGING == ON
Serial.print("Call Home Freq = ");
Serial.println(call_home_freq);
//Serial.println(sleep_flag);
#endif
}
//Extracting Device State
temp = strtok(NULL, "=");
#if USB_DEBUGGING == ON
Serial.print("Third token=");
Serial.println(temp);
#endif
if (!strcmp(temp, "State")) //If Acknowledgement is NOT received and gateway sends fresh data from cloud
{
#if USB_DEBUGGING == ON
Serial.print("Value=");
#endif
temp = strtok(NULL, "\0");
#if USB_DEBUGGING == ON
Serial.println(temp);
#endif
if(device_state != atoi(temp))
{
device_state = atoi(temp);
data_changed_flag = true;
}
else
{
data_changed_flag = false;
}
#if USB_DEBUGGING == ON
Serial.print("Device State = ");
Serial.println(device_state);
#endif
}
if (!strcmp(temp, "ACK"))
{
data_changed_flag = false;
}
else
{
//Do nothing
}
sleep_flag = 1;
}
} // Header Verification end
else
{
//Do nothing as data received is not meant for this node.
}
}// Packet size check end
else
{
//Do nothing
}
} //onReceive() end
/* Function : setup()
* Return Val : None
* Parameters : None
* Description : First function executed after power-up. All modules are initialised here.
*/
void setup() {
pinMode(ON_WIRE_PIN, OUTPUT);
pinMode(OFF_WIRE_PIN, OUTPUT);
digitalWrite(ON_WIRE_PIN, LOW);
digitalWrite(OFF_WIRE_PIN, LOW);
#if USB_DEBUGGING == ON
Serial.begin(USB_DEBUGGING_BAUD_RATE);
while (!Serial);
#endif
#if USB_DEBUGGING == ON
Serial.println("Initialised serial...");
delay(100);
#endif
LoRa.setPins(10, 9, 2);
//Initialize the INA219. Will fail if jumpers are not connected on the board
if (!ina219.begin()) {
#if USB_DEBUGGING == ON
Serial.println("Failed to find INA219 chip");
#endif
{
delay(10);
}
}
//use a lower 16V, 400mA range (higher precision on volts and amps)
ina219.setCalibration_16V_400mA();
#if USB_DEBUGGING == ON
Serial.println("Measuring voltage and current with INA219 ...");
//Initialise LoRa module
Serial.println("LoRa Sender");
#endif
if (!LoRa.begin(RADIO_FREQUENCY)) {
#if USB_DEBUGGING == ON
Serial.println("Starting LoRa failed!");
#endif
while (1);
}
//Congifure LoRa module
LoRa.setSyncWord(SYNC_WORD);
LoRa.setSpreadingFactor(SPREADING_FACTOR);
#if USB_DEBUGGING != ON
LoRa.setTxPower(RADIO_TX_POWER);
#else
LoRa.setTxPower(2);
#endif
// Uncomment the next line to disable the default AGC and set LNA gain, values between 1 - 6 are supported
// LoRa.setGain(6);
// register the receive callback
LoRa.onReceive(onReceive);
}
/* Function : loop()
* Return Val : None
* Parameters : None
* Description : Main function executing all routines.
*/
void loop() {
float busvoltage = 0; //Store the battery voltage
unsigned long startedWaiting; //Store the time at which receive window is opened
#if USB_DEBUGGING == ON
Serial.print("Sending packet: ");
Serial.println(count);
#endif
/* Measuring battery voltage */
ina219.powerSave(false);
delay(10);
busvoltage = ina219.getBusVoltage_V();
ina219.powerSave(true);
/* Measuring battery voltage */
#if USB_DEBUGGING != ON
if (busvoltage >= cutoff_volt)
{
#endif
/* If voltage is greater than cutoff then begin normal operation */
LoRa_txMode();
while (!LoRa_sendData(device_id, call_home_freq, device_state, busvoltage)) {
#if USB_DEBUGGING == ON
Serial.println("Sending failed!");
#endif
delay(10);
}
count++;
LoRa_rxMode();
startedWaiting = millis();
#if USB_DEBUGGING == ON
Serial.println("Waiting for Gateway");
#endif
while (!sleep_flag && (millis() - startedWaiting <= RCV_TIMEOUT)) //sleep_flag is set inside receiver callback function onReceive()
{
/*Loop will exit if either data is received from gateway or configured timeout is acheived */
}
if (!sleep_flag)
{
#if USB_DEBUGGING == ON
Serial.println("Did not receive data!");
#endif
call_home_freq = FAILSAFE_CALL_HOME_FREQUENCY; //If no data received from gateway then change callback frequency to failsafe value
}
else
{
LoRa.sleep(); //Put LoRa module to sleep
if (data_changed_flag) //data_changed_flag is set whenever device state received from cloud is different from current device state
{
if (device_state) //is device state ON
{
//Set On wire of remote device to GND for 3 secs
digitalWrite(ON_WIRE_PIN, HIGH);
delay(ON_OFF_SIG_DURATION);
digitalWrite(ON_WIRE_PIN, LOW);
}
else
{
//Set Off wire of remote device to GND for3 secs
digitalWrite(OFF_WIRE_PIN, HIGH);
delay(ON_OFF_SIG_DURATION);
digitalWrite(OFF_WIRE_PIN, LOW);
}
data_changed_flag = false; //Reset Flag after changing state
}
}
#if USB_DEBUGGING == ON
Serial.println("Going to Sleep");
#endif
delay(10);
sleep_flag = 0;
/* Sleep count is calculated using a 4 second interval
* 1 minute has 15 sleep cycles (60s/4s)
* For a call home freqeuncy of 5 minutes, the node should sleep for 5*15 cycles
* The additional "(2 * call_home_freq)" is for compensating the Arduino's clock error
*/
int sleep_count = (call_home_freq * 15) - (2 * call_home_freq);
while (sleep_count)
{
LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
sleep_count--;
}
#if USB_DEBUGGING == ON
Serial.println("Waking up from Sleep");
#endif
delay(100); //Giving time to the CPU to settle down after waking
//LoRa.receive();
#if USB_DEBUGGING != ON
}//If battery is not dead
else
{
/* If voltage is less than cutoff then sleep until next forced power up or battery change*/
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
}
#endif
}
I want to get any ideas as to what things may lead to such an issue? And has anyone ever encountered this before with a RFM95W module?