Event driven loop/sleep question

I’ve looked around for the answer in the forums a bit and couldn’t find it - should be fairly straightforward though :smile:

Regarding power consumption - I am assuming that if I run a tight loop (e.g. an empty loop() function) this will draw a lot of power? Is that correct?

I would like the only code that is web-driven (e.g. Spark.function() type deals) to run on the core and have it idle as much as possible at that time. What is the correct thing to put in the loop() function? A delay(500000)? Nothing? Would putting nothing not just make it draw a ton of power?

Any thoughts? :smile:

@TheNirEast,

I think that even if you run an empty loop() it’s probably the same as running some non-wifi related commands :smile:

The main bulk of power consumption comes from using Wifi (transmission) and driving stuff using the pins.

So you can probably put…nothing :smiley:

Is it possible to keep the core sleeping until a function or variable request is made?
That would be ideal.

TheNirEast, sleep modes on the Core are not designed to wake on a user-specified event. You call Spark.sleep() with a time (seconds) to stay asleep after which it wakes and and your code runs. Regular sleep does not turn off the CC33000 whereas deep sleep does. So the idea is that you sleep or deep sleep for N seconds after which the Core RTC wakes it and your code runs again. At that point, your code checks for activity, responds accordingly and then goes back to sleep mode for another N seconds. Effectively, this brings down the overall power consumption.

However, there are still outstanding issues with sleep modes a discussed in the topic Finding Sleep Modes. Any outstanding problems are being addressed by the Spark Team and will eventually get resolved. :smile:

Makes sense. Thanks.

So for battery powered applications the strategy would be to use sleep in combination with publish to monitor data.

For wall powered solutions, I would just let it run without sleeping and poll from cloud. This way I can keep most monitoring logic in the cloud and keep core “dumb”.

@Peekay123 - I’m still not sure I understand 100% - I understand that deep sleep is not what I’m looking for: but what happens in a tight loop on a spark core? Is the core smart enough to do a NOP or does it literally go through the loop thousands of times per seconds crunching CPU time?

Am I better off sticking a delay() in there?

TheNirEast, think of loop() like a function instead of a true loop like Arduino. The loop “function” is called by the core firmware’s main() program which also handles all the background tasks including WiFi stuff. So main() calls loop(), which does its thing (obviously as quickly as possible) and the loop() ends and returns to main(), ad infinitum. So if loop() is empty, then the call is very short and uses next to no CPU time. The rest of the CPU time is spent in background tasks run by main().

The thing that takes power is primarily the CC3000 and the Core managing the CC3000 in the background. If you turn off WiFi and Cloud connectivity (WiFi.off() and Spark.disconnect()) then power consumption drops though I don’t believe anyone has profiled this yet. The only way to get the lowest power is to deep sleep for N seconds though it is not clear if coming out of this mode works correctly yet. This mode turns the CC3000 off and puts the Core in its deeplest sleep mode.

@TheNirEast Note that the delay() function on the Core periodically checks the Spark cloud for updates, so you definitely don’t want to use that function if you’re trying to minimize power usage.

bkize, as long as WiFi is enabled and Spark cloud is connected, it will connect to the cloud whether you call delay() or not. The delay() “hook” to the background task was added so that long delay() calls (eg. delay(10000)) would not hang the background task and lose the cloud connection. Arduino does not have this issue because there is no “background task”.

Not sure if related but, my code seems to work fine for 30 mins then I need to hit the reset button to get my core going again. I am thinking it requires a memory clear; how can I reset the memory in the loop? The led is flashing cyan .
thanks!

Dup, if the led is flashing cyan then it is not a memory issue. I would need to see your code to make recommendations.

@peekay123
Thanks!

#include "application.h"
#include "LSM303.h"
#define FEED_ID "xxxxxxxxxxxx" //note: fake id here.. 
#define XIVELY_API_KEY "Cxxxxxxxxxxxxxxxxxxxxxxx" //note: fake key here

TCPClient client;

LSM303 compass;

char report[100];
char doortemp[100];
char resultstr[120];
bool error;
int LEDpin = D7;
int doorstate = 0;
int laststate = 0;
int doorcount = 0;
int trigger = 0;
unsigned long LastUpTime = 0;
int xx;
void xivelycount(int count);
void ledStatus(int x, int t);
void xivelytemp(int temp);
void xivelymagx(int magx);
void xivelymagy(int magy);
void xivelymagz(int magz);

void setup()
{
	Serial.begin(9600);
	Wire.begin();
	error = compass.init();		// Returns "true" if device found
	compass.enableDefault();
	compass.writeReg(LSM303::CTRL5, 0xE4);  //to enable temperature sensor
	compass.writeReg(LSM303::CTRL2, 0x00);  //to use 2g Acc scale
	pinMode(LEDpin, OUTPUT);
	Spark.variable("doorcount" , &doorcount, INT);
    Spark.variable("doorstate" , &doorstate, INT);
    Spark.variable("laststate" , &laststate, INT);
    Spark.variable("report", &report, STRING);
    Spark.variable("doortemp", &doortemp, STRING);
    Spark.variable("result", &resultstr, STRING);
}

void loop()
{
    compass.read();
	byte tl = compass.readReg(LSM303::TEMP_OUT_L);
    byte th = compass.readReg(LSM303::TEMP_OUT_H);
    int temperature_raw = (int16_t)(th << 8 | tl);
    int temperature = ((float)temperature_raw / 8) + 20;
	
	int Mx = compass.m.x;
	Serial.print("Mx: ");
	Serial.print(Mx, 1);
	
	int My = compass.m.y;
	Serial.print("My: ");
	Serial.print(My, 1);
	
	int Mz = compass.m.z;
	Serial.print("Mz: ");
	Serial.print(Mz, 1);
	

xx = 2000;

if (Mx > xx) {
    trigger = HIGH;
    digitalWrite(LEDpin, HIGH); //LED turns "on" when magnet is near
}
if (Mx <= xx) {
    trigger = LOW;
    digitalWrite(LEDpin, LOW); //LED turns "off" when magnet is mot near
}
// read the door input pin:
  doorstate = trigger;


  // compare the buttonState to its previous state
  if (doorstate != laststate) {
    // if the state has changed, increment the counter
    if (doorstate == HIGH) {
      // if the current state is HIGH then the button
      // went from off to on:
      doorcount++;
      Serial.println("open");
      Serial.print("number of door opens:  ");
      Serial.println(doorcount);
    } 
    else {
      // if the current state is LOW then the button
      // went from on to off:
      Serial.println("closed"); 
    }
  }
  // save the current state as the last state, 
  //for next time through the loop
  laststate = doorstate;

if (millis()-LastUpTime>2000){
//    digitalWrite(LEDpin, HIGH);
//    Spark.publish("AccMag", String(report));
//    Spark.publish("Mx", String(Mx));
    xivelycount(doorcount);
    xivelytemp(temperature);
    xivelymagx(Mx);
    xivelymagy(My);
    xivelymagz(Mz);
    LastUpTime = millis();
    }
}

void xivelycount(int count) {

   //Serial.println("Connecting to server...");
    if (client.connect("api.xively.com", 8081)) 
    {

        // Connection succesful, update datastreams
        client.print("{");
        client.print("  \"method\" : \"put\",");
        client.print("  \"resource\" : \"/feeds/");
        client.print(FEED_ID);
        client.print("\",");
        client.print("  \"params\" : {},");
        client.print("  \"headers\" : {\"X-ApiKey\":\"");
        client.print(XIVELY_API_KEY);
        client.print("\"},");
        client.print("  \"body\" :");
        client.print("    {");
        client.print("      \"version\" : \"1.0.0\",");
        client.print("      \"datastreams\" : [");
        client.print("        {");
        client.print("          \"id\" : \"countingsheep\",");
        client.print("          \"current_value\" : \"");
        client.print(count);
        client.print("\"");
        client.print("        }");
        client.print("      ]");
        client.print("    },");
        client.print("  \"token\" : \"0x123abc\"");
        client.print("}");
        client.println();

        ledStatus(1, 50); 
        
    } 
    else 
    {
        // Connection failed
        Serial.println("connection failed");
   //    ledStatus(3, 2000);// 
    }


    if (client.available()) 
    {
        // Read response
        //char c = client.read();
        //Serial.print(c);
    }

    if (!client.connected()) 
    {
        //Serial.println();
        //Serial.println("disconnecting.");
        client.stop();
    }

    client.flush();
    client.stop();
}
        
        
void xivelytemp(int temp) {

   //Serial.println("Connecting to server...");
    if (client.connect("api.xively.com", 8081)) 
    {
        client.print("{");
        client.print("  \"method\" : \"put\",");
        client.print("  \"resource\" : \"/feeds/");
        client.print(FEED_ID);
        client.print("\",");
        client.print("  \"params\" : {},");
        client.print("  \"headers\" : {\"X-ApiKey\":\"");
        client.print(XIVELY_API_KEY);
        client.print("\"},");
        client.print("  \"body\" :");
        client.print("    {");
        client.print("      \"version\" : \"1.0.0\",");
        client.print("      \"datastreams\" : [");
        client.print("        {");
        client.print("          \"id\" : \"roomtemp2\",");
        client.print("          \"current_value\" : \"");
        client.print(temp);
        client.print("\"");
        client.print("        }");
        client.print("      ]");
        client.print("    },");
        client.print("  \"token\" : \"0x123abc\"");
        client.print("}");
        client.println();
        
        ledStatus(2, 50); 
    } 
    else 
    {
        // Connection failed
        Serial.println("connection failed");
   //    ledStatus(3, 2000);// 
    }


    if (client.available()) 
    {
        // Read response
        //char c = client.read();
        //Serial.print(c);
    }

    if (!client.connected()) 
    {
        //Serial.println();
        //Serial.println("disconnecting.");
        client.stop();
    }

    client.flush();
    client.stop();
}

void xivelymagx(int magx) {

   //Serial.println("Connecting to server...");
    if (client.connect("api.xively.com", 8081)) 
    {
        client.print("{");
        client.print("  \"method\" : \"put\",");
        client.print("  \"resource\" : \"/feeds/");
        client.print(FEED_ID);
        client.print("\",");
        client.print("  \"params\" : {},");
        client.print("  \"headers\" : {\"X-ApiKey\":\"");
        client.print(XIVELY_API_KEY);
        client.print("\"},");
        client.print("  \"body\" :");
        client.print("    {");
        client.print("      \"version\" : \"1.0.0\",");
        client.print("      \"datastreams\" : [");
        client.print("        {");
        client.print("          \"id\" : \"magx\",");
        client.print("          \"current_value\" : \"");
        client.print(magx);
        client.print("\"");
        client.print("        }");
        client.print("      ]");
        client.print("    },");
        client.print("  \"token\" : \"0x123abc\"");
        client.print("}");
        client.println();
        
        ledStatus(3, 50); 
    } 
    else 
    {
        // Connection failed
        Serial.println("connection failed");
   //    ledStatus(3, 2000);// 
    }


    if (client.available()) 
    {
        // Read response
        //char c = client.read();
        //Serial.print(c);
    }

    if (!client.connected()) 
    {
        //Serial.println();
        //Serial.println("disconnecting.");
        client.stop();
    }

    client.flush();
    client.stop();
}

void xivelymagy(int magy) {

   //Serial.println("Connecting to server...");
    if (client.connect("api.xively.com", 8081)) 
    {
        client.print("{");
        client.print("  \"method\" : \"put\",");
        client.print("  \"resource\" : \"/feeds/");
        client.print(FEED_ID);
        client.print("\",");
        client.print("  \"params\" : {},");
        client.print("  \"headers\" : {\"X-ApiKey\":\"");
        client.print(XIVELY_API_KEY);
        client.print("\"},");
        client.print("  \"body\" :");
        client.print("    {");
        client.print("      \"version\" : \"1.0.0\",");
        client.print("      \"datastreams\" : [");
        client.print("        {");
        client.print("          \"id\" : \"magy\",");
        client.print("          \"current_value\" : \"");
        client.print(magy);
        client.print("\"");
        client.print("        }");
        client.print("      ]");
        client.print("    },");
        client.print("  \"token\" : \"0x123abc\"");
        client.print("}");
        client.println();
        
        ledStatus(4, 50); 
    } 
    else 
    {
        // Connection failed
        Serial.println("connection failed");
   //    ledStatus(3, 2000);// 
    }


    if (client.available()) 
    {
        // Read response
        //char c = client.read();
        //Serial.print(c);
    }

    if (!client.connected()) 
    {
        //Serial.println();
        //Serial.println("disconnecting.");
        client.stop();
    }

    client.flush();
    client.stop();
}

void xivelymagz(int magz) {

   //Serial.println("Connecting to server...");
    if (client.connect("api.xively.com", 8081)) 
    {
        client.print("{");
        client.print("  \"method\" : \"put\",");
        client.print("  \"resource\" : \"/feeds/");
        client.print(FEED_ID);
        client.print("\",");
        client.print("  \"params\" : {},");
        client.print("  \"headers\" : {\"X-ApiKey\":\"");
        client.print(XIVELY_API_KEY);
        client.print("\"},");
        client.print("  \"body\" :");
        client.print("    {");
        client.print("      \"version\" : \"1.0.0\",");
        client.print("      \"datastreams\" : [");
        client.print("        {");
        client.print("          \"id\" : \"magz\",");
        client.print("          \"current_value\" : \"");
        client.print(magz);
        client.print("\"");
        client.print("        }");
        client.print("      ]");
        client.print("    },");
        client.print("  \"token\" : \"0x123abc\"");
        client.print("}");
        client.println();
        
        ledStatus(5, 50); 
    } 
    else 
    {
        // Connection failed
        Serial.println("connection failed");
   //    ledStatus(3, 2000);// 
    }


    if (client.available()) 
    {
        // Read response
        //char c = client.read();
        //Serial.print(c);
    }

    if (!client.connected()) 
    {
        //Serial.println();
        //Serial.println("disconnecting.");
        client.stop();
    }

    client.flush();
    client.stop();
}
void ledStatus(int x, int t)
{
    for (int j = 0; j <= x-1; j++)
    {
        digitalWrite(LEDpin, HIGH);
        delay(t);
        digitalWrite(LEDpin, LOW);
        delay(t); 
  }
}

Dup, first I would change the timer statement a bit to include bracket around the subtraction like this:

if ((millis()-LastUpTime) > 2000) {

The existing statement may not work as expected and your xlively calls will be too fast.

Then, uncomment the Serial.print statements in the xlively functions so you can see where the code is hanging. The other thing is that there is not delay between compass.read() calls so it is executed as fast as the loop() goes. Is this correct? My hunch is that you need to slow down the compass sampling to a known period the same way you do the timing for the xilively stuff.

You need to put a serial terminal on the Spark and see where the code “hangs” by looking at the messages put out by your code. This will give us a better idea of where the problem may lie. Let me know what you get.

BTW, you have five different xlively functions that could be cleaned up into one. I will work on that later and post it for you. :smile:

@peekay123
Thanks! I am now gonna look at this stuff!!
I will let you know my findings!
Dup

Dup, I cleaned up your code a bit since each xively call was almost identical. Here is the updated LSM303.cpp file:

I have not compiled it yet so let me know if you have any problems.

1 Like

@peekay123
my core stayed up all night by doing the millis change and as well, applying the same logic to the compass.read :smile:
I will try the cleaned up version later today
thanks again!

1 Like

If that needed doing then a lot more of my code may be flaky than already is. I assumed the normal C arithmetic precedence rules applied. And I need to know if not because then I need to carefully re-examine all my Spark code.

psb777, I hate taking chances with precedence assumptions and I like clarity. I have yet to go wrong putting in an extra set of parantheses! :smile:

2 Likes

@peekay123
hi!
I tried the simplified version and I get this LSM303.cpp: In function ‘void xively(xvar, int)’:
LSM303.cpp:140:18: error: ‘count’ was not declared in this scope
LSM303.cpp:146:18: error: ‘temp’ was not declared in this scope
LSM303.cpp:152:18: error: ‘magx’ was not declared in this scope
LSM303.cpp:158:18: error: ‘magy’ was not declared in this scope
LSM303.cpp:163:18: error: ‘magz’ was not declared in this scope
make: *** [LSM303.o] Error 1

I attempted to declare count, etc… before setup but then i get other errors
any idea?

Also, I have been racking my brain on this one. I would like i.e to turn on an LED (do something) and leave it on when magx changes by lets say +/- 50%, however since magx is constantly changing, my LED will flicker “on”, “off”. How would I leave the LED “on” until magx comes back into the its set window?
Thanks!

Dup, my bad! Besides, I thought of an even better way last night. I will make sure the new code compiles first :open_mouth: