Odd behaviour when on battery only

I am having some interesting behaviour when I only have the battery connected. My code below describes a simple rfid tag system where I have an nfc reader (http://www.electrodragon.com/product/pn532-nfc-rfid-easy-module-r2/) that will grab the ID of the tag, store the number locally through the sparkfun micro sd breakout (https://www.sparkfun.com/products/13743) and then also send the tag up to the cloud while giving feedback locally with a small strip of ws2812s.

I have been testing potential pitfalls when the electron drops connection and I have come across some strange behaviour. If the device is connected via a USB cable, this behaviour does not present itself. When the electron is running off of the battery, and it connects to the cloud, there are no problems. When the device cannot connect (disconnecting the antenna), the indicator light is flashing green and it becomes difficult to read a tag. I have noticed that the code is still responsive as I have a button connected to give feedback about the battery however, I need to leave the tag on top of the reader for about 10 seconds and then it will eventually get picked up. I’m curious if the antenna is sucking up all the power and has a timeout set to roughly 10 seconds before it retries which allows my reader to get enough power for a second and read out a tag? But that’s just a random guess currently.

// This #include statement was automatically added by the Particle IDE.
#include <SdFat.h>
#include "Particle.h"
#include "neopixel.h"

//------------------------------------------------------------------------------
// Setup SPI configuration.
// Primary SPI with DMA
// SCK => A3, MISO => A4, MOSI => A5, SS => A2 (default)
SdFat sd;
const uint8_t chipSelect = SS;

#define DEBUG_MODE 0
FuelGauge fuel;

SYSTEM_MODE(SEMI_AUTOMATIC);
SYSTEM_THREAD(ENABLED);

// IMPORTANT: Set pixel COUNT, PIN and TYPE
#define PIXEL_PIN D2
#define PIXEL_COUNT 8
#define PIXEL_TYPE WS2812B

int counting = 0;

Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);

const unsigned char wake[24]={
  0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xfd, 0xd4, 0x14, 0x01, 0x17, 0x00};//wake up NFC module
const unsigned char firmware[9]={
  0x00, 0x00, 0xFF, 0x02, 0xFE, 0xD4, 0x02, 0x2A, 0x00};//
const unsigned char tag[11]={
  0x00, 0x00, 0xFF, 0x04, 0xFC, 0xD4, 0x4A, 0x01, 0x00, 0xE1, 0x00};//detecting tag command
const unsigned char std_nfc[25] = {
  0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x0C, \
0xF4, 0xD5, 0x4B, 0x01, 0x01, 0x00, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00};

unsigned char old_id[5];
unsigned char receive_nfc[25];//Command receiving buffer
unsigned char tag_id[8];//Command receiving buffer

int local_status = 0;

//button variables
int button_val = 0;
int button_val_last = 0;
bool debounce_state = false;
int debounce_count = 0;
int debounce_threshold = 200;

String tag_str = "";
void setup()
{
    pinMode(D0, INPUT_PULLUP);
    
    if (DEBUG_MODE == 1) Serial.begin(9600);

    while (!Serial) {
        SysCall::yield();
    
    }
    
    // Initialize SdFat or print a detailed error message and halt
    // Use half speed like the native library.
    // Change to SPI_FULL_SPEED for more performance.
    if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
        sd.initErrorHalt();
    }
    
    fuel.quickStart();
    strip.begin();
    strip.show(); // Initialize all pixels to 'off'
    strip.setBrightness(10);
    
    flash(100,100,100, 5); //initial white flash to let the user know we are online

    //to initially turn on the leds for checking the diffusion on the white acrylic
    //setAllPixels(8,0,100,0);

    Serial1.begin(115200);
    
    wake_nfc();
    delay(100);
    
    read_nfc(15);
    delay(100);
    
    display(15);
}

void loop() 
{

    Particle.connect();
    
    setAllPixels(strip.numPixels(), 0, 0, 0);

    int bat_level = random(0, 100);//fuel.getSoC();
    int button_val = checkButton();
    if (button_val == 0){
        
        checkBatLevel(bat_level);
    }
    
    File myFile;

    send_tag(); 
    read_nfc(25);
    delay(100);

    if (!cmp_id()){
        if(test_nfc()){
            display(25);
           if (DEBUG_MODE == 1) Serial.println(fuel.getSoC());

            if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
                sd.errorHalt("opening test.txt for write failed");
            }
            
            // if the file opened okay, write to it:
            myFile.println(tag_str);
            // close the file:
            myFile.close();
            if (Particle.connected()){
                Particle.publish("Button Pressed", String(fuel.getSoC()),1,PRIVATE);
                flash(0,100,0,5);                
            } //publishing nfc data to cloud
            else{
                flash(100,0,0,5);    
            }
            
            delay(100);
        }
    }
    copy_id();
}

void wake_nfc(void)
{
    unsigned char i;
    for(i=0; i<24; i++){
        Serial1.write(wake[i]);
        Serial1.flush();
    }
}

void read_nfc(unsigned int size)
{
    unsigned int i, j;
    tag_str = "";
    for(i=0;i<size;i++){
        receive_nfc[i] = Serial1.read();
    }
}

void display(unsigned int size)
{
    unsigned int i;
    tag_str = "";
    // for(i=0;i<size;i++){
    //     Serial.print(receive_nfc[i], HEX);
    //     Serial.print(" ");
    // }
    Serial.println();
    for(i=19;i<size-2;i++){
        tag_str += String(receive_nfc[i],HEX) + ":";
    }
    
    if (DEBUG_MODE == 1) Serial.println(tag_str);
}

void send_tag(void)
{
    unsigned char i;
    for(i=0;i<11;i++){
        Serial1.write(tag[i]);
        Serial1.flush();
    }
}

char cmp_id (void)
{
    int ai, oi;
    for(oi=0,ai=19; oi<5; oi++,ai++){
        if(old_id[oi] != receive_nfc[ai]){
            return 0;
        }
    }
    return 1;
}

int test_nfc(void)
{
    int i;
    for(i=0; i<19; i++){
        if(receive_nfc[i] != std_nfc[i]){
            return 0;
        }
    }
    
    return 1;
}

void copy_id(void)
{
    int ai, oi;
    for (oi=0,ai=19; oi<5; oi++,ai++){
        old_id[oi] = receive_nfc[ai];
    }
}


void flash(int r, int g, int b, int flashes){
    for(int j = 0; j < flashes; j++){
        setAllPixels(8,r,g,b);
        delay(100);
        setAllPixels(8,0,0,0);
        delay(100);
    }
}


void holdLights(int pixels, int r, int g, int b, int seconds){
    setAllPixelsChase(pixels, r, g, b);
    delay(seconds);
    setAllPixels(pixels, 0, 0, 0);
}


void setAllPixelsChase(int pixels, int r, int g, int b){
    for(int i=0; i< pixels; i++) {
        strip.setPixelColor(i, r, g, b);
        strip.show();
        delay(50);
    }
}

void setAllPixels(int pixels, int r, int g, int b){
    for(int i=0; i< pixels; i++) {
        strip.setPixelColor(i, r, g, b);
        strip.show();
    }
}

void checkBatLevel(int bat_level){
    int bat_delay = 1000;
    if (bat_level > 0 and bat_level < 20){
        holdLights(2, 100,0,0,bat_delay);
    }
    else if (bat_level > 20 and bat_level < 50){
        holdLights(4, 255,165,0, bat_delay);
    }
    else if (bat_level > 50 and bat_level < 80){
        holdLights(6, 100,100,0,bat_delay);
    }
    else if (bat_level > 80){
        holdLights(8, 0,100,0,bat_delay);
    }
    
}

int checkButton(){
    button_val = digitalRead(D0);
        
        return button_val;

}

The first thing I’d do is take the call to Particle.connect out of the top of loop(). You should only call it once from setup() in SEMI_AUTOMATIC mode. If you call it every time through loop, it will keep interrupting the connection attempt. It may or may not solve your problem, but it very well may cause problems, especially when having trouble connecting.

1 Like

Whoops. That was an artifact of trying random things to see if the manual connect() was doing anything in different areas. I now have it in the setup and it is behaving the same.

I would like to clarify the behaviour as rereading my initial post doesn’t encapsulate the whole picture. The odd behaviour is that the code is continuously running and not being blocked at any moment regardless of the connectivity status. The odd behaviour comes when the device is disconnected from the network, the portion of the code that reads in a tag, never gets executed even when a tag is present. So it is like the nfc reader dies when the electron is trying to reconnect.

This is to be expected due to your use of SYSTEM_THREAD(ENABLED) - so it's not that odd at all.

That would call for some more debugging steps and more in-depth symptom report from your side as we can't really tell without your exact setup.
To pin down such issues, you should put together a test-project that only does the what's absolutely necessary to reproduce the problem.

BTW, how have you wired the RFID reader?
Vin does not source 5V (actually none whatsoever) when the Electron is only powered from the LiPo.

Ok I took away everything that doesn’t have anything to do with the odd behaviour. So below is the code that I am currently running with the bare necessities to reproduce the problem. I have also included a diagram with the wiring set up.

Here are the results I am noticing during the different states of connection

USB connected, bat disconnected, antenna connected:
breathing cyan - scans no problem

USB connected, bat disconnected, antenna disconnected:
flashing green - scans no problem

USB disconnected, bat connected, antenna connected:
breathing cyan - scans no problem

USB disconnected, bat connected, antenna disconnected
flashing green - reliably scans after 13-14 seconds of holding the tag on the reader


SYSTEM_MODE(SEMI_AUTOMATIC);
SYSTEM_THREAD(ENABLED);


const unsigned char wake[24]={
  0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xfd, 0xd4, 0x14, 0x01, 0x17, 0x00};//wake up NFC module
const unsigned char firmware[9]={
  0x00, 0x00, 0xFF, 0x02, 0xFE, 0xD4, 0x02, 0x2A, 0x00};//
const unsigned char tag[11]={
  0x00, 0x00, 0xFF, 0x04, 0xFC, 0xD4, 0x4A, 0x01, 0x00, 0xE1, 0x00};//detecting tag command
const unsigned char std_nfc[25] = {
  0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x0C, \
0xF4, 0xD5, 0x4B, 0x01, 0x01, 0x00, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00};

unsigned char old_id[5];
unsigned char receive_nfc[25];//Command receiving buffer
unsigned char tag_id[8];//Command receiving buffer

String tag_str = "";
void setup()
{
    pinMode(D7, OUTPUT);
    Particle.connect();
    
    Serial.begin(9600);  

    Serial1.begin(115200);
    
    wake_nfc();
    delay(100);

}

void loop() 
{
    
    detect_tag();  //sends detect card command
    read_nfc(25); //reads in the tag returned
    delay(100);
    
    if (!cmp_id()){ //check if tag being read is the same as the last one, otherwise ignore
        if(test_nfc()){ //checks if the first 19 bytes of data matches our standard nfc tag, otherwise ignore
            display(25);
            for(int j = 0; j<5;j++){
                digitalWrite(D7, HIGH);
                delay(20);
                digitalWrite(D7, LOW);
                delay(20);
            }
        }
    }
    copy_id();
    Serial.println("here");
}

void wake_nfc(void)
{
    unsigned char i;
    for(i=0; i<24; i++){
        Serial1.write(wake[i]);
        Serial1.flush();
    }
}

void read_nfc(unsigned int size)
{
    unsigned int i, j;
    tag_str = "";
    for(i=0;i<size;i++){
        receive_nfc[i] = Serial1.read();
    }
}

void display(unsigned int size)
{
    unsigned int i;
    tag_str = "";
    for(i=19;i<size-2;i++){
        tag_str += String(receive_nfc[i],HEX) + ":";
    }
    
    Serial.println(tag_str);
}

void detect_tag(void)
{
    unsigned char i;
    for(i=0;i<11;i++){
        Serial1.write(tag[i]);
        Serial1.flush();
    }
}

char cmp_id (void)
{
    int ai, oi;
    for(oi=0,ai=19; oi<5; oi++,ai++){
        if(old_id[oi] != receive_nfc[ai]){
            return 0;
        }
    }
    return 1;
}

int test_nfc(void)  
{
    int i;
    for(i=0; i<19; i++){
        if(receive_nfc[i] != std_nfc[i]){
            return 0;
        }
    }
    
    return 1;
}

void copy_id(void)
{
    int ai, oi;
    for (oi=0,ai=19; oi<5; oi++,ai++){
        old_id[oi] = receive_nfc[ai];
    }
}

Does the D7 LED keep blinking at the normal rate?

But most importantly the schamtics don’t seem to match the code.
Why are you using Serial1 to communicate when your NFC reader is supposed to be connected to SPI?

the nfc module is running in UART mode. The pins have multiple functions based on the selected mode. Sorry I should have stated that initially. D7 is my signal if the card was read properly, and it will blink like expected except for when only the battery is connected and the electron is trying to connect showing a blinking green status light.

I do know about UART mode, but your schematic is just now reflecting that at all.

I’m very sorry and embarrassed, I have too many things going on today and completely goofed. please reference this updated image.

That makes a lot more sense now :wink:

With that sorted, I’d try to get a feeling about the actual flow of the code when you experience the issue.
One simple way would be by means of D7 LED checking whether it keeps blinking in regular intervals even while a reconnect is ongoing.
For that change your loop() somewhat like this

void loop() 
{
    digitalWrite(D7, !digitalRead(D7)); // toggle LED whenever loop is run again

    detect_tag();  //sends detect card command
    read_nfc(25); //reads in the tag returned
    delay(100);
    
    if (!cmp_id()){ //check if tag being read is the same as the last one, otherwise ignore
        if(test_nfc()){ //checks if the first 19 bytes of data matches our standard nfc tag, otherwise ignore
            display(25);
            for(int j = 0; j<5;j++){
                //digitalWrite(D7, HIGH);
                delay(20);
                //digitalWrite(D7, LOW);
                delay(20);
            }
        }
    }
    copy_id();
    Serial.println("here");
}

With this alteration the D7 LED should be blinking in a regular manner, irrespective of connection state. If it doesn’t the cause of you issue is probably connected to the communication with the cellular module while connecting.

Other possible causes might be due to power constraints.
Is your Electron using 2G or 3G? 2G has a considerable higher current draw during connection than 3G.

How far from the uFL connector have you got the NFC reader positioned?
Can you try further away.

And numerous other possible influences might be at play.

I tried with your modified code and it blinks consistently when only on battery power and a disconnected antennae until I hold a card on the reader for the 13-14 seconds where there will be a small delay because of the 2 ‘delay(20)’ left in there. The reader and the electron are currently connected with jumper wires as i removed the bread board out of the equation to be sure. So the distance between the two is about 6 inches. It is a 2g model and I do have a 3g model so I will try that next and report back.

Unfortunately I get the exact same behaviour on the 3g model as well

I ended up creating some connection handling code to kick it out of connecting mode if it’s trying for too long so I can continue to read tags but this is obviously not ideal. I guess my searching skills were lacking but I was able to find this library from adafruit Adafruit_PN532 which allows me to use i2c and funny enough the problem I described above doesn’t show itself when using it. Does anyone have any thoughts why this would be the case?

The issue might be rooted in the fact that the cellular module is connected to Serial3 and maybe the two UART interfaces interfere with eachother, hence the SPI version your original schema had shown may have been the better one, but I2C is fine too.

Ya, that’s a little disappointing, but I guess I have some options now. Thanks for your input. Do you think this is an issue that should be looked into?