 |
 |
View previous topic :: View next topic |
Author |
Message |
benoitstjean
Joined: 30 Oct 2007 Posts: 578 Location: Ottawa, Ontario, Canada
|
PIC24EP512GP806 - Timer interrupt while sleeping |
Posted: Wed Apr 30, 2025 7:28 pm |
|
|
Device: PIC24EP512GP806
Compiler: 5.116
Good evening,
I never attempted this but I'd like to put my entire device to sleep but keep timer 1 interrupt active. Is this possible? If so, then what happens with the main() code where the interrupt is really handled (that's how I do it anyhow...)?
Not sure how you guys do it but in my timer 1 ISR, really, all I have are a bunch of flags that are checked and if set, increase a counter and exit. That's it. So in this timer ISR, I have like 20 different counters that I use mainly for delays and timeouts. This way, the ISR is entered and exited as quickly as possible and leaves the main do the hard work where I have a simple while loop that checks the count value of the counters and when they reach a certain value, execute the code for that counter.
Example:
Code: |
#INT_TIMER1
void TIMER1_isr( void )
{
if( Counter_ABC.IsActive == TRUE )
{
Counter_ABC.Count ++;
}
if( Counter_DEF.IsActive == TRUE )
{
Counter_DEF.Count ++;
}
if( Delay_123.IsActive == TRUE )
{
Delay_123.Count ++;
}
... and so on
}
main()
{
while( 1 )
{
if( Counter_ABC.Count == count_value_x )
{
// Do stuff here
}
if( Counter_DEF.Count == count_value_y )
{
// Do stuff here
}
if( Delay_123.Count == count_value_z )
{
// Do stuff here
}
}
} |
The reason I'm asking is that currently, the device is tied to a LoRa module and when all is running, it draws around 42mA @ 12V and when the entire device goes to sleep, it drops down to 320nA.... but this is the entire circuit, including the MCU and the only way to wake it up is through the accelerometer that will generate an interrupt if it detects motion.
I tried setting just the LoRa module to sleep but the current draw drops only to around 22mA. That's still far from the 320nA....
So what is the best approach for what I want to accomplish, that is, put LoRa and mostly everything on the MCU to sleep except for timer 1 that will stll interrupt and run code every once in a while? Ultimately, all I want is for the timer to wake-up the entire circuit, including the LoRa module, contact the remote end then go back to sleep and repeat every 3-4 minutes.... or get woken-up by the accelerometer.
Thanks,
Ben |
|
 |
benoitstjean
Joined: 30 Oct 2007 Posts: 578 Location: Ottawa, Ontario, Canada
|
|
Posted: Wed Apr 30, 2025 7:39 pm |
|
|
UPDATE: I guess the only way is to use SLEEP_IDLE because I am using setup_timer1( TMR_INTERNAL | TMR_DIV_BY_1 ); and don't have an external oscillator?
Using SLEEP_IDLE, it drops in half from 22mA to around 11-12mA. This is pretty decent.... but feel free to provide more suggestions if you think I can take it down even lower.
Thanks again!
Ben |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19808
|
|
Posted: Thu May 01, 2025 5:51 am |
|
|
You are missing one key thing.
PMD.
This chip allows you to switch on/off each peripheral separately. So you do
need to use the IDLE mode, but you can reduce what is drawn in this by
switching off the other parts you don't need. This is controlled by PMD
(Peripheral Module Disable). You set bits in the PMD registers to turn off
the modules you are not using. This stops their clock.
Look at section 10.4 in the data sheet.
Unfortunately there are so many bits (50+), that you have to work out
for yourself the pattern needed to leave just what you want running, and
(of course), need to clear the bits when you want to power back up. However
with these you can individually control which parts of the chip are actually
powered. |
|
 |
benoitstjean
Joined: 30 Oct 2007 Posts: 578 Location: Ottawa, Ontario, Canada
|
|
Posted: Thu May 01, 2025 6:20 am |
|
|
Hi,
Yeah, I already have the following below that you had given me years ago and it worked for what I was doing at the time which required that particular circuit to go in full sleep but this new thing I'm working-on requires me to be able to wake-up the device once in a while....
// Disable all peripherral power
#byte PMD1 = getenv("byte:PMD1")
#byte PMD2 = getenv("byte:PMD2")
#byte PMD3 = getenv("byte:PMD3")
#byte PMD4 = getenv("byte:PMD4")
#byte PMD5 = getenv("byte:PMD5")
#byte PMD6 = getenv("byte:PMD6")
#byte PMD7 = getenv("byte:PMD7")
PMD1 = 0xFF;
PMD2 = 0xFF;
PMD3 = 0xFF;
PMD4 = 0xFF;
PMD5 = 0xFF;
PMD6 = 0xFF;
PMD7 = 0xFF;
I guess timer 1 is T1MD - bit 11 of PMD1 register.
But as for the coding goes with respect to my explanation, let's say the timer 1 interrupt is available, while the device is sleeping in idle mode, where should the code be executed? I mean, if the device is sleeping, I would guess that the main() is not running, correct?
If this is the case, then does this mean that the only thing ticking is the timer interrupt? If yes, then I guess I'd need a special piece of code in there that runs only when the device is sleeping? Because as I explained in my initial message, the timer 1 interrupt, when the device runs normally, only increases a variable for a given "timer" if that timer is enabled though the TimerX.IsActive flag.... so TimerX.Count ++.
Then the code for that timer is executed in the main() with if( TimerX.Count == some_value ) {execute code}.
So if the main is not running, then that code needs to be in the timer interrupt directly under a special condition if( Device.IsSleeping == true ) {execute_this_code}.
Does this make sense?
Thanks again!
Ben |
|
 |
jeremiah
Joined: 20 Jul 2010 Posts: 1386
|
|
Posted: Thu May 01, 2025 7:48 am |
|
|
I use timer1 to wake from full sleep (not just idle) on all of my PIC24 projects. The key is that timer1 needs to be using an asynchronous external clock (like a 32khz crystal oscillator for example) or an internal LPRC clock
If you are trying to wake up the timer with the standard internal clock it won't work unless your chip has an internal LPRC clock that timer1 can access as a clock source (varies by chip). Note that these LPRC clocks are generally pretty imprecise (large tolerance often times)
Here is an example setup for an external 32khz clock connected to a pic24FJ256GA406
Code: |
setup_timer1(TMR_EXTERNAL_RTC, 0x7FFF); // 1 second external crystal using 32khz input
|
Your chip should have some similar option
If you cannot use an external clock, then see if your timer1 has access to an LPRC clock as a source
Here is an example setup for an internal LPRC clock on the pic24F32KA302
Code: |
setup_timer1(T1_INTERNAL_LPRC | TMR_DIV_BY_1,0x7A12); // 31.250 kHz, inc every 1 s
|
|
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19808
|
|
Posted: Thu May 01, 2025 10:26 am |
|
|
and the code remains wherever it was when you called the sleep. It will
jump to the ISR if the interrupt is enabled, and when the ISR exits
return to the main code. |
|
 |
jeremiah
Joined: 20 Jul 2010 Posts: 1386
|
|
Posted: Thu May 01, 2025 12:50 pm |
|
|
Now that I have had some time to look at your chip's datasheet and the CCS header file, it looks like your only options for waking up from sleep on a timer involve some sort of external clock source tied to the pin T1CK.
Below is some basic test code for a 32khz crystal oscillator:
Code: |
#case
#include <24EP512GP806.h>
#int_timer1
void timer1_isr(){
output_toggle(PIN_B0);
}
void main(){
// Connect a 32768 Hz crystal oscillator with appropriate capacitors
// to pin T1CK
setup_timer1(TMR_EXTERNAL_RTC, 0x7FFF); // 1s period for 32768 Hz crystal
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
while(TRUE){
sleep();
}
}
|
Another potential option to play with is to use 2 pins and an RC circuit. Use one pin to charge the circuit and another to read the voltage. You turn off the "charging" pin right before going to sleep and when the pin discharges enough an edge triggered interrupt can be used to wake the PIC up (immediately turning on the charging pin when waking up). This obviously can be fairly inaccurate, but if you don't need precise, it is something to play with. |
|
 |
temtronic
Joined: 01 Jul 2010 Posts: 9464 Location: Greensville,Ontario
|
|
Posted: Thu May 01, 2025 2:55 pm |
|
|
outside the box thinking....
..could you add a RTC module ? Those you can program for say 1 interrupt per minute(depends on device of course ). Usually projects 'need' to have a clock on display so a battery backed, external RTC severs several purposes. |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|