Low frequency in a low power use

Hello friends,

I'm trying to understand the use of timer1. My scope is to measure a Hertz fraction in a loop of one second.
The reason is to sleep for about one second and collect the informations from what timer1 has read. So the MCU may be putted to sleep, except for timer one.
The sleep is governed by a ds3231, which pulse an interrupt every second. So I look at the Atmega328 data-sheet to find some fiddling on the registers to get timer1 counting.
My intent is to inject 32 KHz into timer1 on T1 and gate the counting by ICP1, which is connected to the sensor. I mean that every time the sensor is inactive, will inject a burst of 32 KHz pulses.

Doing that I should get a fraction of Hertz. But I'm not sure is possible. Anyways the achievement is to use the system with battery pack and to last for several months.

Is it possible and perhaps without external hardware ?

I'm having a hard time following the explanation. Are you trying to measure the frequency on the T1 pin (the 32 kHz signal) by using the Input Capture peripheral?

Thank you so much, for your kindness!!
I'm bit late to answer, since I lost all hopes to get answered.

I and my friends, we attempt to measure RPM and then save the data periodically on SD card. The system should have a lifespan for 6 months, at least. With the hope that a battery of 10 Ah will suffice.

An attempt was to inject 32KHz into the timer1 (T1/PD5) and gate by ICP (ICP/PB0). The pulses on ICP may vary from 0.16 to 5 Hertz.
I thought that doing so I'll have the count frozen to the number counted between two pulses, theoretically the period in 1/32768 seconds counts. So during that the MCU stay asleep.

This is one test. Part of this sketch I found on the web.

#include <RTClib.h>
#include "LowPower.h"
#include <SPI.h>
#include <SD.h>

#define filename datalog.txt ;
#define chipSelect 4

#define CADENCE 30

RTC_DS3231 RTC;
float RPM = 1;
volatile uint16_t T1capture;
volatile uint16_t lastT1capture;
volatile uint32_t period;
uint8_t numperiod;
char buffer[10];
bool captured;

ISR (TIMER1_CAPT_vect){
    T1capture = ICR1 ;
    captured = 1;
}

void setup() {
   Serial.begin(57600);
    while (!Serial) {;}
    Serial.println(F("Sistema Pronto"));
    RTC.begin();
    pinMode(5, INPUT_PULLUP);
    if (RTC.lostPower()) {
    RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  else {
        RTC.writeSqwPinMode(DS3231_SquareWave4kHz);
        DateTime now = RTC.now();
  }

  noInterrupts();
  TCNT1 = 0;
  TCCR1B = B01000111;
  TIMSK1 = (1<<ICIE1);
  TCCR1A = 0;
  interrupts();
}
void loop () {
    if (captured) {
        captured = 0;
        period +=  (T1capture - lastT1capture);
        lastT1capture = T1capture;
        numperiod++;
    }
    DateTime now = RTC.now();
    if (!(now.second() % CADENCE)) {
        pinMode(2, OUTPUT);
        digitalWrite(2, HIGH);
        delay(10);
        RPM = (float)4096 * 60 * numperiod / period;
        sprintf(buffer,  "[%02d/%02d-", now.day(), now.month());
        Serial.print(buffer);
        sprintf(buffer,  "%02d:%02d:%02d] ", now.hour(),
                now.minute(), now.second());
        Serial.print(buffer);
        Serial.println(RPM);
        pinMode(2, INPUT);
        LowPower.idle(SLEEP_FOREVER, ADC_OFF, TIMER2_OFF, TIMER1_ON,
            TIMER0_OFF,  SPI_OFF,  USART0_OFF, TWI_ON);
    }
}

I'd like to get the pulses number without calculations. ICR1 sholud hold last count and I won't need to calculate any further.
Then it seems that is not going down to power saving. Well I should find the informations to program the MCU for stand-alone.

Our achievement is to go for 1 mAh consumption. Perhaps, the system must be a stand-alone with SD powered down as long as possible and perhaps the RTC also should go power-down with the lowest consumption.

Sorry, I'm still having a hard time following your explanation. Is English not your first language?

I don't see anything that jumps out at me as wrong in your sketch. IDLE is the correct sleep mode to use, and you're even turning off Timer0 which would otherwise be waking you up every millisecond. The only interrupt that I see active is Input Capture, which is exactly how you want it.

Then it seems that is not going down to power saving. Well I should find the informations to program the MCU for stand-alone.

If you are using any of the development boards (like an Uno or Nano) you will not be able to notice significant power savings no matter what you put in your code. The extra chips of the board (primarily the USB-Serial converter) will draw dozens of mA of current and you can't turn them off. Standalone or a Pro Mini board are the only options if you want to use low power.

What board are you using? An Uno, Nano, Pro Mini, or breadboard?

My other concern is your battery. What voltage and chemistry are you planning to use, and how are you planning to regulate the power from it? The voltage you supply to the chip limits the maximum speed you are able to use. 16MHz requires a minimum of about 4.3V, whereas with 8MHz the chip can use down to about 2.4V, I believe. There is a graph in the Speed Grades section of the datasheet showing this information.

If you are using a relatively high voltage battery and regulating it down to 5V, you're wasting a lot of power.

Jiggy-Ninja:
Sorry, I'm still having a hard time following your explanation. Is English not your first language?

It won't take much to discover it, isn't it ?
Definitely not my mother language, sorry to puzzling.

Jiggy-Ninja:
My other concern is your battery.

The design is to achieve 6 months life, within a small size assembly. So basically the ATmega328 alone with its internal clock should be the core. There should be a RTC to grab the time and the SD to log the data.

So with this perspective, the power should be taken directly with no voltage regulators and the devices are expected to work in the range of 3.2~4,7 Volts. Li-ion or li-po would do the trick. Power budget would be around 10 Ah.

The problem is to get Timer1 give a number that is the frequency figure. I thought to inject the RTC output and get the count after one second. But the sensor should gate the 32KHz from RTC.
But lately I thought it's not possible, I must measure the period and calculate the resulting frequency.
Is there a way that I get the counting off by IPC and reset the Timer1 counter ?
Should I write 0 into TCNT1, as soon as the IPC interrupt comes up ?

If you need exact time you should use a temperature compensated RTC (DS3231). If you need a time that is "close to real time" +/- a few minutes you can use 32kHz crystal connected to the ATMega directly. In both cases I would use Timer/Counter2 (in asynchronous mode?) in ATMega to count the pulses. This way you can go to Power-save insted of Idle sleep mode, getting minimal power consumption.

Good idea to use Timer2 as RTC, less components. Anyways I need some MCU part running in order to get the count.
Beside that, If I set ASSR.AS2, Am I able to get the counts from PB6 ?
How is the setting to go power-save mode ?

I've read Gammon's reports. I still confuse about the way the MCU wakes up and where it resumes the work.
It seems to me that everything restarts as it was a reset. Particularly because I use LowPower library.

You say you have maximum frequency 5Hz. I think the best way in such low frequency is to use TC2 for counting time and use external interrupt to wake up the processor when a pulse comes. It logs time elapsed since last pulse and go to sleep again. With all unused peripherals turned off the ATMega will have very low average power consumption. My guess is less than 100uA. You need to add some power for logging data (SD card or large EEPROM/Flash) - less than another 100uA average I guess. Try to keep voltage as low as possible (look at power consumption vs Vcc in ATMega Datasheet).
If your sensor you are measuring has low power consumption and can work at low voltage I would use 2 rechargable 2000mAh AAs with low self-discharge (Eneloop) as power source without any regulation. You need use memory that works at 2-3V (no SD card). Running from internal 8MHz oscillator would probably be safe but you can divide it by 2 to 4MHz to stay well within specs.

I don't know how to use LowPower library - I read the Datasheet and manipulate the registers directly, it is less confusing for me.

ExperimentUno:
I've read Gammon's reports. I still confuse about the way the MCU wakes up and where it resumes the work.
It seems to me that everything restarts as it was a reset. Particularly because I use LowPower library.

It picks up where you left off. SLEEP is basically like a pause button on a video. The microcontroller stops where it's at and retains all the information in its memory. When you wake up, it's like hitting play. The microcontroller continues from just after the sleep instruction as if nothing had happened.

Thanks a lot for your details.
I think a solution like to set Timer2 counting at a millisecond rate. Attaching the interrupt on PD2/INT0. so when the pulse arrive then it record the period, the go down to sleep some more.
Timer2 would work also as time keeping, because millis() won't be there while the MCU is asleep.

So I may arrange to keep the informations in memory. Doing so I'll write to SD few times in a hour. I realize that record every seconds is non feasible, nor interesting. The SD module

is good also at 3,3 Volts and it has 8 Kbytes memory. Perhaps I should remove the LED, to spare some power.
The module seems not having any power regulator that will drain power.

I'll try some simulation. I'll be right back with my sketch.


EDIT
I wrote this

#include <avr/sleep.h>
#include <RTClib.h>
#include <Wire.h>
#define ON 1
#define OFF 0
// This below is used when we want to track some output
#define DEBUG
// This line define which RTC model will be used. Uncommenting will compile
// for DS3231 chip on the RTC
//#define RTC_DS3231

// selection on the RTC model
#ifdef RTC_DS3231
RTC_DS3231 RTC;
#else
RTC_DS1307 RTC;
#endif

bool started;
volatile uint32_t mymillis;
volatile uint32_t last_msec;
float RPMs;
char buffer[10];

ISR(TIMER2_COMPA_vect){         // milliseconds counter while asleep
    ++mymillis;
}

void pwrDownPort() {
    /* We set alla ports for the lowest power consumption */
    DDRB = 0;
    DDRC = 0;
    DDRD = 0;
    PORTB = 0;
    PORTC = 0;
    PORTD = 0;
    // one input is left ready for the sensor
    pinMode(2, INPUT_PULLUP);
}

void action() {
    started = ON;
}

void setup(){
    Serial.begin(57600);
    while (!Serial) {;}
    Serial.println("Ready");
    pinMode(2, INPUT_PULLUP);
    RTC.begin();

    #ifdef RTC_DS3231
    if (RTC.lostPower()) {
    #else
    if (! RTC.isrunning()) {
    #endif
        Serial.println("RTC is NOT running!");
        // following line sets the RTC to the date & time this sketch was compiled
        RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }
    attachInterrupt(0, action, RISING);
    noInterrupts();
    // disable ADC
    ADCSRA = 0;
    // turn off brown-out enable in software
    MCUCR = bit (BODS) | bit (BODSE);
    MCUCR = bit (BODS);
    //set timer2 interrupt at 1kHz
    TCCR2A = 0;// set entire TCCR2A register to 0
    TCCR2B = 0;// same for TCCR2B
    TCNT2  = 0;//initialize counter value to 0
    // set compare match register for 1khz increments
    OCR2A = 249;// = (16*10^6) / (8000*64) - 1 (must be <256)
    // turn on CTC mode
    TCCR2A |= (1 << WGM21);
    // Set CS21 bit for 8 prescaler
    TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20);
    // enable timer compare interrupt
    TIMSK2 |= (1 << OCIE2A);
    interrupts();
}

void loop () {
    if (started) {
        started = OFF;
        RPMs = (float)60000 / (mymillis - last_msec);
        last_msec = mymillis;
        Wire.begin();
        DateTime now = RTC.now();
        sprintf(buffer,  "%02d/%02d/%d-", now.day(), now.month(), now.year());
        Serial.print( buffer );
        sprintf(buffer,  "%02d:%02d:%02d ", now.hour(), now.minute(),
                now.second());
        Serial.print( buffer );
        Serial.println(RPMs);
    }
    pwrDownPort();

    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    sleep_cpu ();
    sleep_disable();
}

Tomorrow I'll try with the hardware, for real. But actually if I comment sleep_cpu () it works, else will not wake up.

PWR_DOWN requires level interrupts to wake up, meaning you need to use HIGH or LOW not RISING or FALLING.

At the Gammon's site (herein mentioned), the sketch J is using FALLING option.
I can't tell for sure that's working, but I believe it has been tested.
I found a very interesting blog, which brings some hope for my intent.

ExperimentUno:
At the Gammon's site (herein mentioned), the sketch J is using FALLING option.
I can't tell for sure that's working, but I believe it has been tested.

It looks like you (and Gammon) are right. The ATMega328p datasheet states:

Low level interrupts and the edge interrupt on INT2:0 are detected asynchronously. This implies that these interrupts can be used for waking the part also from sleep modes other than Idle mode. The I/O clock is halted in all sleep modes except Idle mode.

Beware it is not rule in AVR. For example ATTiny13a doesn't work this way. From its datasheet:

Note that recognition of falling or rising edge interrupts on INT0 requires the presence of an I/O clock (...) A low level interrupt on INT0 is detected asynchronously. This implies that this interrupt can be used for waking the part also from sleep modes other than Idle mode. The I/O clock is halted in all sleep modes except Idle mode

I found it the hard way ATTiny13a CANNOT be waken up by edge interrupt from power down.


Do you NEED so precise time you need to use the RTC DS3231 you linked on the picture? If I were you I would try to use 32kHz crystal instead. If you decide to use the RTC this way you should measure it's current consumption. The 32kHz signal is generated by an open drain and so there is a pull-up resistor on the board. It may drain lot of current. Possibly better way is to use the RTC to care about time - just ask it what time is it each time a pulse comes.


I was looking into your code. I am not sure why it doesn't wake up. But power-down will stop even the TC2 so you will loose time - you need power-save mode. Also if you are interested in power savings you should NEVER let any pin float - when a pin is connected to nothing and configured as input it eats lots of power - you should enable pull-ups for all unconnected pins.

Smajdalf:
It looks like you (and Gammon) are right. The ATMega328p datasheet states:

Beware it is not rule in AVR. For example ATTiny13a doesn't work this way. From its datasheet:

I found it the hard way ATTiny13a CANNOT be waken up by edge interrupt from power down.

I probably confused it with the ATtiny84 or something that I had read before. Doesn't surprise me.

Doh!

Smajdalf:
Do you NEED so precise time you need to use the RTC DS3231 you linked on the picture?

I can't imaging how could be the time drift after 6 months. For something reliable I supposed it is a must have. The posted link tells some trick about saving power. Definitely I'm not able to work with SMT, then I'd prefer that kind of module.

Smajdalf:
If I were you I would try to use 32kHz crystal instead.

This is a great idea. Should I put the 32KHz quartz on the oscillator pins, then before sleeping switching the timer2 over that clock ?
With such layout, I don't think I'll need the RTC, perhaps I may use the swRTC. Though I can't miss to use the SD card. Recording date,time and the value in a plain text may take a couple of Gb.

Smajdalf:
But power-down will stop even the TC2 so you will loose time - you need power-save mode. Also if you are interested in power savings you should NEVER let any pin float

My suppositions were that timer2 would keep running in power-save mode. But I should read some more on the datasheets about it.
Regarding the pins, I thought that I was sufficient the way I wrote in my sketch.

One more think, I'd like to program the MCU alone with my universal programmer. I'm not familiar which fuse I should change.

One should be to disable WDT, another would be to set internal clock to 8 MHz without dividers and last what kind of SUT should I set ?
Couldn't it be better a quick SUT to recover quickly from sleep ?

My suppositions were that timer2 would keep running in power-save mode. But I should read some more on the datasheets about it.

It will if you set Timer2 to asynchronous mode. There's a separate register for that, I haven't memorized the name.

Your sketch shows you using PWR_DOWN mode not PWR_SAVE.

One should be to disable WDT, another would be to set internal clock to 8 MHz without dividers

You can't disable the Watchdog Timer with fuses. The WDTON fuse forces the watchdog on if it's programming, and you can't disable it. If the fuse is unprogrammed, the watchdog is off by default and can be turned on in software.

The internal oscillator is a decent choice for this. 8MHz can operate down to about 2.4V. If you want to run all the way down to 1.8V, you can program CLKDIV8 to start up at 1 MHz. A fast clock probably isn't super critical for this.

and last what kind of SUT should I set ?
Couldn't it be better a quick SUT to recover quickly from sleep ?

Table 13-12 in section 13.6 of the datasheet shows how the SUT fuses affect the internal oscillator during wakeup and RESET conditions.

I've read the specification on the data sheets. But I hardly get a reasonable condition to measure the frequency.

Suppose to run with 32kHz quartz and timer2 in asynchronous mode, I should use a 32 prescaler and arrange OCR2A to get a millisecond correctly, because I need to measure a period when the pulse comes in from INT0.

Perhaps I'll sacrifice some accuracy and go for 4 milliseconds timing, to allow a longer sleep. In case to get low RPM like 13, I need to be able to know the good length of the period, therefore I don't think I would make sleeping much longer.

I appreciate your help, I just have to try it out on the hardware.

Remember that you aren't just limited to the overflow count to get timing. As an example, Timer0 ticks over every 1,024 microseconds and increments an overflow counter. In order to get better resolution for the micros() function, the value in TCNT0 is read and used to add the additional fractional tick time to calculate the microsecond value. 1,024/256 = 4, that's why you commonly see here and in the documentation that micros() has a 4 us resolution.

You can do the same thing with Timer2. Have it tick a counter on each overflow, but also use the TCNT2 value when the external interrupt comes in to interpolate between between tick periods for additional precision.

Jiggy-Ninja:
I probably confused it with the ATtiny84 or something that I had read before. Doesn't surprise me.

Doh!

Strange thing: ATMega 328/P datasheet says I/O clock is needed to detect edge interrupts while I was quoting ATmega48A/PA/88A/PA/168A/PA/328/P Datasheet. I wonder which one is right.

Smajdalf:
Strange thing: ATMega 328/P datasheet says I/O clock is needed to detect edge interrupts while I was quoting ATmega48A/PA/88A/PA/168A/PA/328/P Datasheet. I wonder which one is right.

Check footnote 3 under the table of sleep mode clocks. Both of them say "For INT1 and INT0, only level interrupt." That's what I've been referencing for my statements.

So I'm not the one that was going crazy, it was Atmel.