Author Topic: Moteino shortest wakeup time  (Read 6608 times)

incognico

  • Newbie
  • *
  • Posts: 15
  • Country: au
Moteino shortest wakeup time
« on: March 22, 2016, 12:26:25 AM »
FYI - this topic was split from this one after it went off topic.

At the risk of going off topic slightly, I was curious about your comment about wake-up times, so did a [very] little investigation.

From powerDown(SLEEP_FOREVER), the delay between an external interrupt and doing something useful (toggling a pin in this case) appears to be just under 150uS.

Excuse the MSPaint masterpiece  ;)



EDIT: This is using the RocketScream library
« Last Edit: March 29, 2016, 12:01:05 PM by Felix »

joelucid

  • Hero Member
  • *****
  • Posts: 869
Re: Moteino shortest wakeup time
« Reply #1 on: March 22, 2016, 02:24:01 AM »
Quote
From powerDown(SLEEP_FOREVER), the delay between an external interrupt and doing something useful (toggling a pin in this case) appears to be just under 150uS.

That is pretty long. With Moteino's fuse settings you'd expect 1000 clock cycles or 62.5uS. I've never been sure whether the BOD startup time of 60uS (section 10.2) is added to that - your measurement indicates it is.

Fastest wake-up times should be available with the internal 8Mhz oscillator and BOD turned off by fuse. That should result in pretty immediate wake-up (around 1uS).


WhiteHare

  • Hero Member
  • *****
  • Posts: 1298
  • Country: us
Re: Moteino shortest wakeup time
« Reply #2 on: March 22, 2016, 04:18:09 AM »
Quote
From powerDown(SLEEP_FOREVER), the delay between an external interrupt and doing something useful (toggling a pin in this case) appears to be just under 150uS.

That is pretty long. With Moteino's fuse settings you'd expect 1000 clock cycles or 62.5uS. I've never been sure whether the BOD startup time of 60uS (section 10.2) is added to that - your measurement indicates it is.

Fastest wake-up times should be available with the internal 8Mhz oscillator and BOD turned off by fuse. That should result in pretty immediate wake-up (around 1uS).

@Joe So, in addition to those two fuse settings, which sleep library (or code) are you using to enter powerdown sleep mode?  Or does it not matter?  I've been using Nick Gammon's Sketch J.

This is quite exciting.  I hadn't known that anyone was getting a wake-up time of only  1uSec.
« Last Edit: March 22, 2016, 04:22:14 AM by WhiteHare »

incognico

  • Newbie
  • *
  • Posts: 15
  • Country: au
Re: Moteino shortest wakeup time
« Reply #3 on: March 22, 2016, 05:19:40 AM »
Cool, I'm happy to try and test some of this out  8)

Setup:
  • using UNO R3 for this test - easier for me to flash fuses etc than the Moetino
  • Moteino default fuses flashed to UNO before starting
  • Measurement functions in the oscilloscope were used to determine the "wake-up" times I've quoted
  • Wake-up time is defined as per the above test; Time from external interrupt to asserting a port pin

Start settings, Ext Osc, 8MHz-, 258 CK PowerDown start delay.
Wakeup time of 156.0uS. Good - pretty close to what I saw with the Moteino hardware.

BOD disabled in fuses: 156.0uS. No change!  :o

Internal Osc 8MHz: 208.0uS. Increased!  :o

I tried quite a few different fuse combinations, but did not find anything that gave a faster time than the default Moteino fuse settings. The longer PWRDWN Start Delay options in the clock fuses had a big negative impact of course - 1.160mS with the Ext Crystal Osc 8.0- MHz; 16K CK option. Actually I think this may be the default setting on some of my clones.
Int RC Osc 128kHz;   9.920 mS

I have not looked inside the LowPower library yet. And now my UNO is non-responsive after an unfortunate clock source fuse setting  ::) I will attempt to recover it tomorrow.

Any comments/suggestions or tests you'd like to see performed are more than welcome.

Is it better to abandon the abstractions of the LowPower library and the Arduino IDE for better investigation of PWRDWN -> WAKE timings?  :-\

joelucid

  • Hero Member
  • *****
  • Posts: 869
Re: Moteino shortest wakeup time
« Reply #4 on: March 22, 2016, 06:44:31 AM »
Quote
@Joe So, in addition to those two fuse settings, which sleep library (or code) are you using to enter powerdown sleep mode?  Or does it not matter?  I've been using Nick Gammon's Sketch J.

Due to my listen mode with timer implementation I did my own. I started from LowPower and worked from there.

Interestingly for the new bootloader I threw all of this out and I'm now just setting the CPU prescaler to 256 to enter a low power mode. That's comparable in terms of power consumption to the WDT, but has the advantage of not using any interrupts. So you can get rid of the interrupt table and save a whopping 128 bytes, yay! Unfortunately that doesn't work for the case at hand since entering the irq handler will take 256 times as long as usual - which is worse than using the original fuse settings.

joelucid

  • Hero Member
  • *****
  • Posts: 869
Re: Moteino shortest wakeup time
« Reply #5 on: March 22, 2016, 06:51:59 AM »
Quote
Internal Osc 8MHz: 208.0uS. Increased!  :o

Hmm. If you check 9.6) in the data sheet startup from power down should be 6 cycles with the internal oscillator vs 1000 cycles for the resonator. If wakeup time increased that seems to imply that enough code got executed before your handler got called for the CPU frequency to matter.

Yeah - maybe code directly to AVR to get rid of any artifacts introduced by abstractions.


WhiteHare

  • Hero Member
  • *****
  • Posts: 1298
  • Country: us
Re: Moteino shortest wakeup time
« Reply #6 on: March 22, 2016, 11:30:02 AM »

BOD disabled in fuses: 156.0uS. No change!  :o


This may be a longshot, but I wonder if maybe this is arising because the library you're using is still going through the motions of software disabling the BOD (even though the BOD is now already hardware disabled because of your change in the fuse settings)?  i.e. maybe the mere act of doing the software disabling sets some hidden flag inside the atmega to increase the awaken time, even though doing so is now somewhat incongruous with the hardware fuse setting.
« Last Edit: March 22, 2016, 04:37:27 PM by WhiteHare »

WhiteHare

  • Hero Member
  • *****
  • Posts: 1298
  • Country: us
Re: Moteino shortest wakeup time
« Reply #7 on: March 22, 2016, 05:16:40 PM »
Apparently the wakeup time I was remembering was for a generic pro mini, not a Moteino.  Sorry for the confusion.  I just now tested the wakeup time on a stock Monteino R4 (it still has its original fuse settings) using Nick Gammon's Sketch J, and the wakeup time looks like it's about 112 microseconds (see first of attached scope shots below).  That's interesting, if only because it is less than what incognico is getting using the Rocketscream sleep library.

By the way, I'm using interrupt 1 rather than interrupt 0 to trigger the wakeup in the test above, just to avoid any possible interference by the RFM69.

Running the same Sketch J, but this time leaving BOD enabled (still no changes to the original fuse settings) yields a wakeup time of something like 66 microseconds (see second screen shot below).

Presumably, disabling BOD at the hardware fuse level and rerunning the second sketch will produce the same wakeup time, but I haven't run that test yet.  Once I'm setup to change hardware fuse settings, I'll run that test and post the result if anyone is interested.

I'm kicking myself now because I should have run the above two tests on an RFM95 not an RFM69.  Force of habit,  but also more datapoints for comparison.  That probably explains the difference in wake-up time between what I measured and what incognico measured.  I'll re-run the test shortly using an RFM95 and then post the more on-point results. 


WhiteHare

  • Hero Member
  • *****
  • Posts: 1298
  • Country: us
Re: Moteino shortest wakeup time
« Reply #8 on: March 22, 2016, 05:49:09 PM »
Attached are the results of the same two tests on the RF95.  Looks like the wakeup times shrunk slightly to about 107uS with the BOD disabled by software and still about 66uS if the BOD isn't disabled by software.  As before, the hardware fuse settings have never been changed, and so they are whatever they are on a stock Moteino LoRa.

So, though I can't be sure, I presume the difference in wakeup time between what I just measured and what incognico measured may have to do with the differences in the sleep libraries/sketches.  In case it's of any use, here is the slightly modified version of the Sketch J code that I ran to produce the first capture below:
Code: [Select]
// Sketch J
#include <avr/sleep.h>

const byte LED = 9;
const byte YELLOW_LED = 7;
 
void blink(byte PIN, int DELAY_MS, long loops)
{
  pinMode(PIN, OUTPUT);
  pinMode(YELLOW_LED, OUTPUT);  //mirror PIN
  while (loops--)
  {
    digitalWrite(PIN,HIGH);
    digitalWrite(YELLOW_LED, HIGH);
    delay(DELAY_MS);
    digitalWrite(PIN,LOW);
    digitalWrite(YELLOW_LED, LOW);
    delay(DELAY_MS); 
  }
}
 
 
void wake ()
{
  // cancel sleep as a precaution
  sleep_disable();
  // precautionary while we do other stuff
  detachInterrupt (1);
}  // end of wake

void setup ()
  {
  digitalWrite (2, HIGH);  // enable pull-up
  }  // end of setup

void loop ()
{
  blink(LED,50,10);
  //pinMode (LED, OUTPUT);
  //digitalWrite (LED, HIGH);
  //delay (2000);
  //digitalWrite (LED, LOW);
  //delay (50);
  pinMode (LED, INPUT);
 
  // disable ADC
  ADCSRA = 0; 
 
  set_sleep_mode (SLEEP_MODE_PWR_DOWN); 
  sleep_enable();

  // Do not interrupt before we go to sleep, or the
  // ISR will detach interrupts and we won't wake.
  noInterrupts ();
 
  // will be called when pin D2 goes low 
  attachInterrupt (1, wake, FALLING);
  EIFR = bit (INTF1);  // clear flag for interrupt 1
 
  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
  MCUCR = bit (BODS) | bit (BODSE);
  // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS);
 
  // We are guaranteed that the sleep_cpu call will be done
  // as the processor executes the next instruction after
  // interrupts are turned on.
  interrupts ();  // one cycle
  sleep_cpu ();   // one cycle

  } // end of loop

I use the output of a pro mini to drive "interrupt 1" (pin D3) low on the Moteino LoRa (so, the yellow line on the scope plot is that), and soon after, I blink the yellow LED (the blue line on the scope plot goes high at the start of the blinking).

[Edit: the second capture below is simply the result of commenting out the two BOD related lines of code in the sketch above.]
« Last Edit: March 22, 2016, 06:50:48 PM by WhiteHare »

joelucid

  • Hero Member
  • *****
  • Posts: 869
Re: Moteino shortest wakeup time
« Reply #9 on: March 22, 2016, 07:21:44 PM »
These data points are very close to the spec. You should get out your dragon, program the fuses for internal 8mhz oscillator and see what happens. Life's much more fun once you start playing with fuses ;)

incognico

  • Newbie
  • *
  • Posts: 15
  • Country: au
Re: Moteino shortest wakeup time
« Reply #10 on: March 22, 2016, 11:41:33 PM »
Nice!  :)

I copy'n'pasted your code and got the same results (108.0uS) on my R3 UNO.

I swapped out the sleep code for the LowPower library and it gave the identical result (108.0uS).

I compared my original testing code to yours and they looked pretty similar. I rejigged some parts and I ended up getting the same results. I had not saved the original code so I can't even comment on what was taking the additional time - perhaps an Arduino feature ;) I optimized the pin switching code a little too, see the results below.

Results:
  • WhiteHare's posted "Sketch J": 108.0uS
  • "Sketch J" with LowPower library: 108.0uS
  • Optimized pin switching: 86.4uS
  • BOD_ON option: 36.0uS
  • Changing to Int Osc, 8.0MHz: 9.8uS

Disabling BOD in the fuses did not change the last result. Next steps must be to try and optimize the code, getting rid of any Arduino IDE & library overhead.



The code I was using for this test is this -
Code: [Select]
#include "LowPower.h"

// using pin D7 for output
#define pinOn (PORTD) |= (1<<7)
#define pinOff (PORTD) &= ~(1<<7)

void setup() {
 
  pinMode(7, OUTPUT);
  pinMode(3, INPUT);
 
  digitalWrite(7, HIGH); // Interrupt will pull this output LOW - easier for my 'scope to measure if the int and the output are changing in the same direction
  digitalWrite(3, HIGH); // weak pullup
 
 
}

void wakeUp() {
    pinOff;
}

void loop() {

  attachInterrupt(1, wakeUp, FALLING); 
 
  while(1) {

    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_ON);
   
    delay(50);
    pinOn;
   
  }
 
}

WhiteHare

  • Hero Member
  • *****
  • Posts: 1298
  • Country: us
Re: Moteino shortest wakeup time
« Reply #11 on: March 23, 2016, 01:01:24 AM »
That's awesome: for only a little extra work you got an order of magnitude reduction in wakeup time.  I see you also caught and fixed an error in my code that I only just now noticed, which is that
Code: [Select]
  digitalWrite(2,HIGH);
should have been
Code: [Select]
  digitalWrite(3,HIGH);

I'd be very happy with 9.8uS, because that small amount is clearly overshadowed by the radio's CAD current consumption.  Still, just knowing that 1uS is actually possible makes me curious how it's done.  If there are additional easy wins to be had, then I'd be inclined to incorporate them as well.

@Joe:  Regarding the AVR Dragon: it does looks very promising (especially for debugging), but setting it up looks a bit more involved than I have time for tonight.  Hopefully soon though!
« Last Edit: March 23, 2016, 01:15:45 AM by WhiteHare »

incognico

  • Newbie
  • *
  • Posts: 15
  • Country: au
Re: Moteino shortest wakeup time
« Reply #12 on: March 23, 2016, 02:31:51 AM »
I rewrote the test code in an AVR-GCC project in AVR Studio 4, removing any Arduino overhead.

Results:

  • Ext Osc, disabling BOD in software: was 86.4uS, now 84.0uS
  • Ext Osc, leaving BOD alone: was 36.0uS, now 32.8uS
  • Int Osc, leaving BOD alone: was 9.8uS, now 5.2uS  :)

Code as tested -

Code: [Select]
#include <avr/io.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include <avr/interrupt.h>

// using pin D7 for output
#define pinOn (PORTD) |= (1<<7)
#define pinOff (PORTD) &= ~(1<<7)

ISR(INT1_vect)
{
   // ISR code to execute here
   pinOff;
}

int main(void)
{
  // note to self: 1 = output, 0 = input
  DDRD |= (1<<7); // output pin
  DDRD &= ~(1<<3); // input for INT1

  // pullups
  PORTD |= (1<<7);
  PORTD |= (1<<3);

  EICRA &= ~(0x0C); // clear existing flags
  EICRA |= 0x08;    // set falling level interrupt
  EIMSK |= 0x02;    // enable it

  set_sleep_mode (SLEEP_MODE_PWR_DOWN);

  while(1) {

    cli();
    sleep_enable();
    //sleep_bod_disable();
    sei();
    sleep_cpu();
    sleep_disable();

    _delay_ms(50);
    pinOn;

  }

  return 1;
}


Edit - fixed some tabs/spaces in the pasted code that came out weird
« Last Edit: March 23, 2016, 02:35:51 AM by incognico »

joelucid

  • Hero Member
  • *****
  • Posts: 869
Re: Moteino shortest wakeup time
« Reply #13 on: March 23, 2016, 02:48:38 AM »
Nice! You could also tune the internal oscillator to a higher frequency which should directly translate into a proportional improvement. See page 512 in the spec. it can run at ~13 MHz.

incognico

  • Newbie
  • *
  • Posts: 15
  • Country: au
Re: Moteino shortest wakeup time
« Reply #14 on: March 23, 2016, 03:13:00 AM »
OSCCAL=0xFF, result: 4.0uS  ;D

Although.. the datasheet does give vague warnings about EEPROM writes possibly failing, so not sure if this will be suitable for all applications  ???

Edit - Actually, because OSCCAL is set in code, we could just set it before powerdown, and put it back to something more sensible at wake-up... or will it be ok as long as we do not write to flash/EEPROM?
« Last Edit: March 23, 2016, 04:56:40 AM by incognico »