Author Topic: 32.768Hz oscillator  (Read 3909 times)

pgillesdepelichy

  • NewMember
  • *
  • Posts: 1
32.768Hz oscillator
« on: August 07, 2018, 03:30:08 AM »
Felix,

I wanted to suggest you to replace the 8-16MHz oscillator with a 32.768Hz crystal in order to allow the use of the Timer2 of the Mega as an accurate RTC that can be used to precisely schedule tasks in Moteino, especially when sleep mode is involved.

As timing of the main clock is, in most cases, not critical, the Moteino would benefit of such an improvement with a single change in the fuses to use the internal RC oscillator as the main clock. User applications should not be affected by such an improvement.

Power consumption using Timer2 and external cristal is mimimal as only the Power Down beat it (but requires an external source of interrupt to wake the MCU up).

Such implementation has been used by Panstamp for their devices :
https://github.com/panStamp/panstamp/wiki/panStamp-AVR.-Technical-details

In addition to the benefit of a RTC, the internal register of TIMER 2 can be used to debounce pulse counting (pin change) within interrupt routine while in sleep mode :

Example :

Code: [Select]
/**
 * Pulse Counters Inputs
 */
#define COUNTER_DEBOUNCE_TICKS 2                      // This means 2 * 1/32 of a second

volatile unsigned long pulseCount_B[2] = {0, 0};        // Initial counter values for Port B


/************************************************************************/
/* Interrupt Service Routines                                           */
/************************************************************************/
// RTC Interrupt Service Routine
ISR(TIMER2_COMPA_vect)
{
    currentTime += timeIncrement;
    interruptByTimer2 = true;              // This is to avoid the PCInt to fully wake up the MCU
}

// Pin Change Interrupt vectors
SIGNAL(PCINT0_vect)
{
    static int                 previousState[2]  =  {-1, -1 };       // Initial pin states
    static byte               previousTicks[2] =  {0,  0  };
    static unsigned long previousTime[2]  =  {0, 0};
    static int                 elapsedTicks;
    static int                 currentState;

    for (byte counterIndex = 0; counterIndex < 2; counterIndex++)
    {
        currentState = bitRead(PINB, counterIndex);
        if (previousState[counterIndex] != currentState)
        {
            previousState[counterIndex] = currentState;
            if (currentState == LOW)
            {
                elapsedTicks = ((TCNT2 + (kernel.OCR2A_SavedValue+1)) - previousTicks[counterIndex]) % (kernel.OCR2A_SavedValue+1);
                // Check if pulse is valid : One timeIncrement elapsed OR at least COUNTER_DEBOUNCE_TICKS ticks
                if ((kernel.currentTime > previousTime[counterIndex]) || (elapsedTicks >= COUNTER_DEBOUNCE_TICKS))
                {
                    pulseCount_B[counterIndex]++;
                    previousTicks[counterIndex] = TCNT2;
                    previousTime[counterIndex]  = kernel.currentTime;
                }
            }
        }
    }
}

/**
* start_RTC
*
* Start RTC configured according to the periodicity of Task 0 (default task, similar to previous behavior)
*/
void KERNEL::start_RTC(unsigned long timestamp)
{
// Set timer 2 to asynchronous mode (32.768KHz crystal)
ASSR = (1 << AS2);

// Calculate the optimal sleep period in order to minimize power consumption
// Could start with 8 but easier with 5 for periodicity and lag
for (timeIncrement=5; timeIncrement>1; timeIncrement--)
{
if ((task[0].periodicity % timeIncrement) == 0)
break;
}

// Put Timer2 in CTC mode (using "Output Compare A Match" interrupts)
TCCR2A = (1 << WGM21);

// Set Output Compare Register A to value corresponding to the requested periodicity
// Save OCR2A value so that it can be used in the goToSleep loop
OCR2A_SavedValue = (32 * (timeIncrement - 1)) + 31;
OCR2A  = OCR2A_SavedValue;

// Enable Timer2 "Output Compare A Match" interrupts
TIMSK2 = (1 << OCIE2A);

// Adjust Timer Counter and currentTime in order to synchronize the RTC
TCNT2 = (byte)(32 * (timestamp % ((unsigned long) timeIncrement)));
currentTime =  (timestamp / ((unsigned long) timeIncrement)) * ((unsigned long) timeIncrement);

// Set Timer2 Prescaler to 1024 in order to start the timer with 1/32 of a second beat
TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20);

// Wait for all registers to be updated
while (ASSR & B00011111) {}
}

/**
* stop_RTC
*
* Stop RTC by setting TCCR2B to 0, stopping Timer2
*/
void KERNEL::stop_RTC()
{
// Clear TIMSK2 register to disable interrupts
TIMSK2 = 0;
// Clear TCCR2B register to stop timer/counter
TCCR2B = 0;
// Wait for TCCR2 register to be updated
while (ASSR & (1 << TCR2BUB)){}
}

« Last Edit: August 09, 2018, 10:24:27 AM by Felix »

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: 32.768Hz oscillator
« Reply #1 on: August 09, 2018, 10:23:56 AM »
Hi pgillesdepelichy,
Thanks for the suggestion and the research you've shared,

Looking at the datasheet briefly, I do not see if the 1284p has a PLL or other mechanisms to run at higher speeds from the low crystal oscillator (32768khz), but the low frequency clock source section talks about it being optimized for low power. If the low frequency cannot be made fractional to increase the speed, I don't think a lot of people would prefer to run at such low speeds.
Update - I initially missed your suggestion about internal RC as main clock, oops! Yes that could work but still making this variant mainstream would be challenging, and making it as an alternative is possible but would actually increase costs and support.

So while it might provide some benefits as you suggested, my overall impression is I think it would be an uphill battle.

But maybe I don't know enough, I am open to discussion. Have you actually tried using a 32768khz crystal?
There was an interesting thread about using the radio module (if you have one on the Moteino) crystal as a precise low timer which would also eliminate the need to use the WDT to wake up (an extra savings of a few uA). Have you considered that option?
« Last Edit: August 10, 2018, 09:09:03 AM by Felix »

Uncle Buzz

  • Full Member
  • ***
  • Posts: 146
  • Country: fr
Re: 32.768Hz oscillator
« Reply #2 on: August 09, 2018, 04:31:25 PM »
As I understand pgillesdepelichy, the goal is to use the internal 8 MHz RC clock, then the 32kHz crystal when sleeping, keeping a correct time synchronisation at low consumption (0.7µA from datasheet) and a Timer counter to wake up the MCU with better accuracy and lower consumption than the watchdog clock.

I'm not sure if fuses can be set to use internal RC and external clock while sleeping but I think it's what pgillesdepelichy is showing.

From datasheet, crystal can be use as system clock, or as timer clock (different capacitance in each case), so we could use the 8 MHz internal RC as system clock and a 32kHz crystal as timer clock
« Last Edit: August 09, 2018, 04:36:15 PM by Uncle Buzz »

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: 32.768Hz oscillator
« Reply #3 on: August 09, 2018, 04:41:44 PM »
What Uncle Buzz said! I was half way through my response so here it is:

You'd use the 8MHz internal RC oscillator for the CPU, the 32.768kHz watch crystal would drive TCNT2 only. When asleep the internal oscillator stops but TCNT2 continues to count, you could accurately calibrate the RC oscillator relatively easily in software if you wanted, the TCNT2 can be programmed to wake the MCU at accurate times. you could implement a RTC even when asleep. It's really quite attractive, it opens up all sorts of things like frequency hopping or battery operated gateways. I use xmega chips in this way.

Mark.
« Last Edit: August 09, 2018, 04:43:56 PM by perky »

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: 32.768Hz oscillator
« Reply #4 on: August 09, 2018, 06:56:23 PM »
You'd use the 8MHz internal RC oscillator for the CPU, the 32.768kHz watch crystal would drive TCNT2 only. When asleep the internal oscillator stops but TCNT2 continues to count, you could accurately calibrate the RC oscillator relatively easily in software if you wanted, the TCNT2 can be programmed to wake the MCU at accurate times. you could implement a RTC even when asleep.
If I'm reading the datasheet correctly, the best you can do with this combination is an 8 second sleep period.  My math is:
32768Hz/1024 max prescaler = 32Hz, TC2 is 8 bits (256 max count before roll over), 256/32 = 8 seconds...

I'm not seeing a lot of power savings in this equation. 

Now if the processor has some REAL counters (eg M0), then we'd have something to talk about...  However, there's the power equation and the configuration complexity gets hard to manage for other reasons.

Then again, if we had a real low power ARM processor that had easy to configure timer/counters and signal routing, and 32 bit RTC counters, etc, etc... then we'd be talking about a Nordic Semiconductor device rather than some Atmel thing...

Sorry, I got carried away...  or was it 'should be' carried away  :)

ChemE

  • Sr. Member
  • ****
  • Posts: 419
  • Country: us
Re: 32.768Hz oscillator
« Reply #5 on: August 09, 2018, 10:35:11 PM »
I bought 4 of these watch crystals to mess with this and I recall my sleep current being very unimpressive.  I don't recall for sure what it was, but it was clear to me that I was better off getting the TPL5110 or the AB1815 working.

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: 32.768Hz oscillator
« Reply #6 on: August 10, 2018, 09:05:36 AM »
My same thoughts.

FWIW I got busy reading the DS after the first paragraph and I totally missed the part about internal RC .. I need more coffee ::)

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: 32.768Hz oscillator
« Reply #7 on: August 12, 2018, 01:38:07 PM »
@Felix
If you changed the MCU to an xmega32E5, that has a 16 bit asychronous counter and allows low current sleeping with very accurate timing even while asleep ;)  I've actually implemented virtual counters too which allows timing multiple things with it and getting sub uA sleep current.

I can't see how it would be uphill struggle TBH, the physical size wouldn't change and from my experience it's pretty easy to implement. The 328P async counter is limited to 8 bits, so a trade off between resolution of timing and wake up time, but you could always wake up, increment a counter, and immediately sleep again on a rollover to get longer times.

Mark.

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: 32.768Hz oscillator
« Reply #8 on: August 13, 2018, 11:38:18 AM »
I can't see how it would be uphill struggle TBH, the physical size wouldn't change and from my experience it's pretty easy to implement.

It's more about all the variables and logistics involved with developing a new board with a completely new MCU.
I have to think about what it takes to achieve the wanted features, and balance that with how much time/effort/recources/money I will invest in making it happen, plus estimating how many people will jump to buy the board in order to make it worth those investments on my part. Besides that I usually make things that I tend to use myself one way or another. As I mentioned before, going from a few uA to sub uA to me is not as important as other things. Yes maybe shocking to some people, but to me a few years on a small battery running a sub 10uA is more than good enough for my needs and probably most user's needs.

I have to ask myself - can I make a super duper low power Moteino? - Yes - you could actually do it NOW with a TPL5110 (35nA sleep) if you really want to. Beats anything in terms of low power, though it will not have the sleep timer accuracy if that's really the wanted feature. But see TomWS's posts about TPL/sleep, he is very much a promoter of this configuration.

Could I spend hundreds of hours in design, prototyping, education of potential users and unknown future support, only to satisfy a few current interested users? Sure, but I have to worry about many other things in the interim. Look at the Moteino M0 as an example (which is not sub uA but I made it for other reasons and even with the many available web resources - it's quite a challenge for most users), just a simple board that doesn't seem like much but took a lot of resources to make happen.

But does it make sense to make something very new based on a relatively unpopular/unused/unknown MCU? Quite a discussion there.
Most users of my products are Arduino based and they want their code and libraries and what's out there on github to just work or they won't be interested. It's about less than 1% of the users that are savvy and willing to experiment and get deep in C++ to mod and tweak libraries to make them work on new boards.

There is no "official" arduino based on xmegas, (maybe 3rd party boards with limited library support) so right there it will be a support drain to make all the released code compile and work on the new board. Just a few things that came to mind.

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: 32.768Hz oscillator
« Reply #9 on: August 14, 2018, 07:09:33 AM »
Sorry, I was suggesting using the 328P, that's what wouldn't be an uphill struggle (I should have included your quote before it because it was that I was referring to). Xmegas are significantly different to megas and I could imagine that being very time consuming indeed.

I'm suggesting using exactly the same hardware as a current Moteino, with a 328P, but with a watch crystal in place of the 16MHz crystal. That's basically it. What I referred to as 'relatively simple to implement' is the software changes.

But any new thing requires support so I completely understand where you are coming from on that.

Mark

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: 32.768Hz oscillator
« Reply #10 on: August 14, 2018, 09:10:14 AM »
Sorry, I was suggesting using the 328P, that's what wouldn't be an uphill struggle (I should have included your quote before it because it was that I was referring to). Xmegas are significantly different to megas and I could imagine that being very time consuming indeed.

I'm suggesting using exactly the same hardware as a current Moteino, with a 328P, but with a watch crystal in place of the 16MHz crystal. That's basically it. What I referred to as 'relatively simple to implement' is the software changes.
Mark,
Oh I see now, thanks for clarifying, sorry I missed that part. Totally changes what we're dealing with of course.

So it would be a 8Mhz Moteino right? And the 32.768Khz would be only for precise timing/sleep. That could eliminate the LDO and allow for sleep currents. Perhaps the current 8Mhz Moteino could move towards that direction. Currently it has the original 16mhz resonator in place but unused since fuses are set for 8mhz internal RC. Since you mentioned you had some experience with this, what's involved other than fuses to run on internal 8mhz RC?

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: 32.768Hz oscillator
« Reply #11 on: August 14, 2018, 12:31:00 PM »
So it would be a 8Mhz Moteino right? And the 32.768Khz would be only for precise timing/sleep. That could eliminate the LDO and allow for sleep currents. Perhaps the current 8Mhz Moteino could move towards that direction. Currently it has the original 16mhz resonator in place but unused since fuses are set for 8mhz internal RC. Since you mentioned you had some experience with this, what's involved other than fuses to run on internal 8mhz RC?

I don't think it matters whether it's the 8MHz variant per se, but the system clock would need to be 8MHz if using the internal RC source. My experience was for an xmega32E5, but basically not a lot needs to be done. You'd set the fuses to use the internal RC oscillator, and configure the TCNT2 to asynchronously continuously count using the 32kHz oscillator. If you want to get more accuracy for the system clock for things like serial accesses you could software calibrate the 8MHz using the TCNT2 counter and use another counter running from the 8MHz clock domain (the xmega internal oscillator, which is either 32MHz or 8MHz, was accurate enough in my system not to bother). The rest is really about using the TCNT2 as a timed wakeup and real time counting source. It is only 8 bits so some tradeoff between timing resolution and wakeup time, but you could always just wake up, increment a counter, and go back to sleep immediately. There's a minor issue regarding reading the asynchronous counter if you use a prescaler as there's a clock domain synchronizing delay that can catch you out, but that's relatively easy to get around. The xmega32E5 is a nice chip for this, but represents a pretty big step change for support.

Mark.
« Last Edit: August 14, 2018, 12:36:48 PM by perky »