Menu

Low power "Snooze" delay.

mkstevo
2021-02-06
2021-02-28
  • mkstevo

    mkstevo - 2021-02-06

    In my Beeping Clock I was looking at a way to reduce the power consumption and extend the battery life. Something similar to "Sleep" but without the hassle of setting a timer or using the watchdog to wake the device after a few cycles.

    As ever, whilst I was trying to sleep, an idea hit me. Why not switch the PIC to a low frequency clock, wait for a few cycles and then switch back to full speed? I tried this with the reduced frequency set to 100kHz, and with a "SleepTime" set to 500mS the idling current drain went from a measured 3.8mA (at 32MHz) to 1.9mA (at 125kHz), a halving of the current. As the clock spends most of the time doing very little, this should extend the battery life by a decent amount.

    The routine sets the frequency of the device to 32kHz, performs the delay while running at 32kHz, once the delay has expired the frequency is set to 32MHz. If you are running your device at another frequency, the "exit" frequency will need to be changed.

    Here's the code.

    Sub SleepTime(In Snooze As Word)
    
    #Define  Frq003 2   '32kHz
    #Define  Frq006 4   '62kHz
    #Define  Frq01  5   '125kHz
    #Define  Frq05  7   '500kHz
    #Define  Frq1   11  '1MHz
    #Define  Frq2   12  '2MHz
    #Define  Frq4   13  '4MHz
    #Define  Frq8   14  '8MHz
    #Define  Frq16  15  '16MHz
    #Define  Frq32  30  '32MHz
    
    Dim SnoozeTime  As Word
    
        Let SnoozeTime = 0
    
        SetFreq(Frq003)   '32kHz
        Do
            Repeat 10    'With other commands included, this should is ~10 mS at 32kHz
                NOP
            End Repeat
            Let SnoozeTime = SnoozeTime + 1
        Loop Until SnoozeTime >= Snooze
        SetFreq(Frq32)   '32MHz
        NOP
        'May take a cycle or two to get back up to speed
    
    End Sub
    
    Sub SetFreq(In Freq As Byte)
    
        If Freq.0 = 1 Then
            Set IRCF0 On
        Else
            Set IRCF0 Off
        End If
    
        If Freq.1 = 1 Then
            Set IRCF1 On
        Else
            Set IRCF1 Off
        End If
    
        If Freq.2 = 1 Then
            Set IRCF2 On
        Else
            Set IRCF2 Off
        End If
    
        If Freq.3 = 1 Then
            Set IRCF3 On
        Else
            Set IRCF3 Off
        End If
    
        If Freq.4 = 1 Then
            Set SPLLEN On
        Else
            Set SPLLEN Off
        End If
    
    End Sub
    

    The Routine "SleepTime" is called with the parameter that sets the amount of low power snoozing you want. The value is a Word value, SleepTime(1) gives a delay time of close to 10mS.

    The chip I used was a 16F1829, other devices might need the frequency constants adjusting to reflect the frequency registers in the specific device. I used nearly the same code in a 12F1840 so I am assuming that this range of devices will work without modification.

    Realised that because I hadn't used 32kHz or 64kHz in the original white noise generator, I hadn't included them here. Tweaked to use 32kHz instead of 125kHz, updated frequency constant list to include 32kHz and 64kHz. I've not measured the saving in current consumption lowering down from 100kHz to 32kHz.

     

    Last edit: mkstevo 2021-02-06
  • stan cartwright

    stan cartwright - 2021-02-06

    i didn't know you could set the clock in code while running. Does this work on avr?

     
    • mkstevo

      mkstevo - 2021-02-06

      Well, the code as written is for PIC. It certainly works on the 12F1840 and 16F1829. I used this to change the speed "on the fly" in my white noise generator sleeping aid (12F1840). It seems to work on the Beeping Clock which is where the code above came from (16F1829).

      I imagined that the PicAxe used similar to allow changing frequency "on the fly" which is what often happened before/after issuing serial in/out commands to ensure the serial communication ran at the correct speed. That gave me the original inspiration to try it on the white noise generator.

      Can you address the frequency registers on an AVR directly? If so, this technique might work.

       
  • stan cartwright

    stan cartwright - 2021-02-06

    I can only use what is in gcb help/forums...I am rubbish at data sheets.
    It would be handy to change the clock freq when wanted... but this is first
    I've heard of.

    I use a touch display with #chip mega328p,16 and it works with hwspi.
    I use same touch display with #chip LGT328p32 and it does not work with hwspi
    only software spi....because it's too fast.
    So changing clock could an answer.. but I'm just speculating.

     
    • mkstevo

      mkstevo - 2021-02-06

      Try something like this: {Absolutely UNTESTED - if it all goes wrong and you can't reprogram your AVR, don't blame me!}

      It is suggested that you need to issue both commands consecutively. To return it, you would need both commands, with the second one set to the original value.

      'Code "borrowed" from diy0t.com'
      Let CLKPR = 0x80 '1000 0000 enable change in clock frequency'
      Let CLKPR = 0x01 '0000 0001 use clock division factor 2 to reduce the frequency from 16 MHz to 8 MHz'
      

      It might work? You'd have to check quite what CLKPR should be for standard operation so you can return it to the correct frequency.

       

      Last edit: mkstevo 2021-02-06
      • Anobium

        Anobium - 2021-02-06

        LGTs are different from PICs and the registers are very different.

        I have asked Stan, via email, to so some frequency tests. We need to know what frequencies work, and, this can be done easily on the #chip line.

        Once we have confirmed the frequency then we can sort the library.

         
        • mkstevo

          mkstevo - 2021-02-06

          The "CLKPR" code was from an Arduino site so might be relevant?

           
  • stan cartwright

    stan cartwright - 2021-02-06

    I can only say that #chip LGT328p,16 works mega328p programs ok.
    at 32 it does hwspi glcd very fast.
    I've posted glcd demos and they are faster on LGT.
    Not mentioned is interrupts work the same as mega328.
    which is not inferred to in the interrupt lgt demo...like it's special.

    What test like moving ram? I don't know how to write code that writes
    xxxx bytes from address zzzz to address yyyy.
    is copying arrays the same?.... as a test.

    I tested your demos, except speaker,,, and all ok
    Can't you do the necessary speed tests for the techy stuff? :)
    I'll run any code you want as a comparison.... but it is a faster chip "in many ways"
    useful ways I hope.

    Why can't hwspi pins be defined and software spi pins be defined and swap them
    in program?

     
  • stan cartwright

    stan cartwright - 2021-02-06

    stevo --- The "CLKPR" code was from an Arduino site so might be relevant?
    gcb uses different stuff to arduino. lot of gcb is there but unknown sorted of hidden.
    avr interrupts and the calculator link .
    cheers

     
    • mkstevo

      mkstevo - 2021-02-07

      I'd meant that it may be relevant for the AVR (Atmel) processor range, I should have said that in retrospect.

       
  • mkstevo

    mkstevo - 2021-02-28

    I've slightly updated my SleepTime routine so that it is now called with the time in tens of mS and the exit frequency. This way if you are running your device at 16MHz you could call SleepTime thus:

    SleepTime(100, Frq16)
    

    This will perform a low power sleep for one second (100 x 10mS) and then set the PIC operation to 16MHz once complete.

    Longer delays are not timed accurately. A five minute delay I was using ended up at around five minutes and 30 seconds.

    For me, the power saving is superb, far and away better than I had hoped. Using this to sleep for 500ms, every 500 mS has nearly doubled the battery life compared to the same circuit with no power saving.

    Sub SleepTime(In Snooze As Word, In ExitFreq As Byte)
    
    #Define  Frq003 2   '32kHz
    #Define  Frq006 4   '62kHz
    #Define  Frq01  5   '125kHz
    #Define  Frq05  7   '500kHz
    #Define  Frq1   11  '1MHz
    #Define  Frq2   12  '2MHz
    #Define  Frq4   13  '4MHz
    #Define  Frq8   14  '8MHz
    #Define  Frq16  15  '16MHz
    #Define  Frq32  30  '32MHz
    
    Dim SnoozeTime  As Word
    
        Let SnoozeTime = 0
    
        SetFreq(Frq003)   '32kHz
        Do
            Repeat 10    'This should be ~10 mS at 32kHz
                NOP
            End Repeat
            Let SnoozeTime = SnoozeTime + 1
        Loop Until SnoozeTime >= Snooze
        SetFreq(ExitFreq)   '32MHz
        NOP
        'May take a cycle or two to get back up to speed
    
    End Sub
    
    Sub SetFreq(In Freq As Byte)
    
        If Freq.0 = 1 Then
            Set IRCF0 On
        Else
            Set IRCF0 Off
        End If
    
        If Freq.1 = 1 Then
            Set IRCF1 On
        Else
            Set IRCF1 Off
        End If
    
        If Freq.2 = 1 Then
            Set IRCF2 On
        Else
            Set IRCF2 Off
        End If
    
        If Freq.3 = 1 Then
            Set IRCF3 On
        Else
            Set IRCF3 Off
        End If
    
        If Freq.4 = 1 Then
            Set SPLLEN On
        Else
            Set SPLLEN Off
        End If
    
    End Sub
    
     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.