View previous topic :: View next topic |
Author |
Message |
starfire151
Joined: 01 Apr 2007 Posts: 195
|
problem with WDT in 16LF1825 |
Posted: Mon May 10, 2021 10:47 am |
|
|
First, the basics:
Windows 10 x64
PCWHD 5.071
I'm trying to get a PIC16LF1825 to run in a low power mode by using the WDT and an external interrupt. As a test case, I have the WDT set for 2 seconds (I plan to use 128 seconds in the final version). I loop a total of 10 times, restarting the WDT for the full 2 second count and then going to to sleep. When the final loop is done, I'm trying to turn off the WDT so I can do some activity, which will take longer than the watchdog time. In this test case, I'm using a couple of pins to monitor status.
I see the background timeouts work correctly. I see the peripheral output pin get turned on after the loops. ...but... I see the peripheral get turned off after one watchdog period (2 seconds) instead of waiting for the 10 second peripheral period. It's as if the setup_wdt(WDT_OFF) command is not being recognized.
I put the PIN_C2 on a scope and I see the voltage go from low to high and stay high for 2 seconds and then start to decay off. It decays from +3.3VDC to about 0.5VDC in about 40ms then shoots up to +3.3VDC again briefly (around 10us) before decaying off to 0VDC again.
I'm including the test code below:
Code: |
#include <16LF1825.h>
#device adc=10 // 10-bit ADC => 1024 steps
#device *=16
#FUSES NODEBUG // No Debug mode for ICD
#FUSES WDT // Watch Dog Timer
#FUSES HS // High speed osc
#FUSES NOPROTECT // Code not protected from reading
#FUSES IESO // Internal External Switch Over mode enabled
#FUSES NOBROWNOUT // No brownout reset
#FUSES STVREN // Stack full/underflow will cause reset
#FUSES NOLVP // No low volt prgm, B3(PIC16) or B5(PIC18) used for I/O
#FUSES MCLR // Master Clear pin enabled
#define clk_freq 16000000
#use delay(internal=clk_freq)
#define PA_TRIS 0b11001111
#define PA_DEF 0b11011111
#define PC_TRIS 0b11100000
#define PC_DEF 0b11100000
typedef unsigned int8 uint8;
typedef unsigned int16 uint16;
typedef unsigned int32 uint32;
int1 extIntFlag; // TRUE=external int seen
int1 wdFlag; // TRUE=doing WDT loops
uint16 loopCntr; // current WDT loop count
uint16 bgLoopCntr; // background loop count for peripheral acitvity
// ---- external interrupt service ----
// if ext int seen from light sensor, set flag for background
#int_EXT
void ExtISR(void)
{
extIntFlag = TRUE;
}
// ---- main background routine ----
#zero_ram
void main(void)
{
set_tris_a(PA_TRIS);
set_tris_c(PC_TRIS);
set_rtcc(0);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256 | RTCC_8_BIT);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED, 0, 1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
output_a(PA_DEF);
output_c(PC_DEF);
extIntFlag = FALSE;
wdFlag = TRUE;
bgLoopCntr = 0; // reset background loop counter
delay_ms(100); // system stability time
ext_int_edge(L_TO_H); // external int from light sensor through 74AHC14
clear_interrupt(INT_EXT); // clear any pending interrupt
enable_interrupts(INT_EXT); // enalbe external interrupts
enable_interrupts(GLOBAL); // global activation of enabled ints
setup_wdt(WDT_ON | WDT_2S); // enable WDT and set for 2 second timeout
while(TRUE) // background
{
if(wdFlag)
{
loopCntr = 0; // reset loop counter
while((loopCntr < 10) && (extIntFlag == FALSE))
{
restart_wdt(); // restart WDT to get full 2 second delay time
sleep(); // go to sleep now
output_high(PIN_A5); // flash test pin to show awake now
delay_ms(100);
output_low(PIN_A5);
loopCntr++; // if no ext int, just increment loop counter
}
// enable an output pin to show active now
output_high(PIN_C2); // turn peripheral power on
setup_wdt(WDT_OFF); // turn off WDT
wdFlag = FALSE; // don't do WDT loops until done with activity
output_high(PIN_A5); // flash test pin to show it got to here
delay_ms(50);
output_low(PIN_A5);
delay_ms(50);
output_high(PIN_A5);
delay_ms(50);
output_low(PIN_A5);
extIntFlag = FALSE; // verify ext int flag reset, if it was set
}
delay_ms(1);
if(++bgLoopCntr == 10000) // delay to allow background activity
{
bgLoopCntr = 0; // reset for next time
// disable 3V and 6V supplies and turn off LEDs now
output_low(PIN_C2); // turn peripheral power off
setup_wdt(WDT_ON | WDT_2S);
restart_wdt();
wdFlag = TRUE; // tell the WDT to loop again
}
}
}
|
Does anyone have any idea what's happening?
Thanks for any help. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: problem with WDT in 16LF1825 |
Posted: Mon May 10, 2021 2:22 pm |
|
|
starfire151 wrote: | It's as if the setup_wdt(WDT_OFF) command is not being recognized.
#FUSES NODEBUG // No Debug mode for ICD
#FUSES WDT // Watch Dog Timer
#FUSES HS // High speed osc
#FUSES NOPROTECT // Code not protected from reading
#FUSES IESO // Internal External Switch Over mode enabled
#FUSES NOBROWNOUT // No brownout reset
#FUSES STVREN // Stack full/underflow will cause reset
#FUSES NOLVP // No low volt prgm, B3(PIC16) or B5(PIC18) used for I/O
#FUSES MCLR // Master Clear pin enabled
|
On page 569 of the CCS manual, in the section on setup_wdt(), it says:
Quote: |
Note: For PCH parts and PCM parts with software controlled WDT, setup_wdt( ) would enable/disable watchdog timer only if NOWDT fuse is set. If WDT fuse is set, watchdog timer is always enabled. |
You need to change your fuse to NOWDT. |
|
|
starfire151
Joined: 01 Apr 2007 Posts: 195
|
|
Posted: Mon May 10, 2021 2:44 pm |
|
|
Hi PCM programmer. Thanks for responding so quickly.
I changed the #FUSES WDT to #FUSES NOWDT and tried it again. I don't even see the loops counting now on the PIN_A5 output.
When I activate the external interrupt, though, it turns on the peripheral pin on PIN_C2 and it stays active for 10 seconds, like its supposed to. It appears the setup_wdt(WDT_OFF) is working now ...progress...
Why wouldn't the PIN_A5 output work in the loop now, though? Shouldn't program execution continue after the sleep() command when the WDT times out?
Thanks for your help. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue May 11, 2021 12:47 am |
|
|
Did you put the IDE into Debug mode ? That would disable the WDT. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Tue May 11, 2021 2:18 am |
|
|
One little change that may affect things:
Code: |
sleep(); // go to sleep now
delay_cycles(1);
output_high(PIN_A5); // flash test pin to show awake now
|
The instruction _after_ the sleep, is 'prefetched' when you go to sleep.
As a result, it may not actually execute correctly when you wake.
Hence this instruction should always be a NOP. delay_cycles(1) codes
as a NOP.
It may affect how the code behaves when it wakes.
You don't actually need the restart_wdt when entering sleep. The act of
entering the sleep mode always restarts the WDT. |
|
|
starfire151
Joined: 01 Apr 2007 Posts: 195
|
|
Posted: Tue May 11, 2021 8:33 am |
|
|
Hi PCM programmer -
I included the #FUSES NODEBUG so I think the WDT should be enabled?
Hi Ttelmah -
I included the delay_cycles(1); after the sleep() command. This didn't appear to make any difference. It's as if it's not being awakened by the WDT timeout. I removed the restart_wdt() before going to sleep(), also. Thanks for that info.
One question on how to start the WDT. I've tried setup_wdt(WDT_ON | WDT_2S), setup_wdt(WDT_2S), and both setup_wdt(WDT_2S) then setup_wdt(WDT_ON). All three conditions give the same result. What is the correct method. The documentation is kind of vague about this.
In all three cases, though, when I trigger the external interrupt, the code after the sleep() statement all works correctly. I see the flashes to the PIN_A5, the PIN_C2 turns on and stays on for the expected 10 seconds before turning off the PIN_C2 and returning to the loop.
Thanks for your continued help in resolving this issue. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Tue May 11, 2021 9:47 am |
|
|
re: I included the #FUSES NODEBUG so I think the WDT should be enabled?
NOT necessarily if you're using an IDE. IDEs can overwrite the pgm code setups....
Also, if you're using MPLAB, you must compiler in 'release' mode not 'debug' mode......
so... is the hardware totally 'standalone'? IE burn the PIC then test in the 'real World' ?? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue May 11, 2021 10:06 am |
|
|
starfire151 wrote: | Hi PCM programmer -
I included the #FUSES NODEBUG so I think the WDT should be enabled?
|
Temtronics answered the question, but here is some more:
Using MPLAB vs. 8.92, I set the Release/Debug drop-down box
to DEBUG, and compiled your program. I then looked at the bottom
of the .LST file to see the fuses set by the compiler:
Quote: | Configuration Fuses:
Word 1: 19E4 INTRC_IO NOWDT NOPUT MCLR NOPROTECT NOCPD NOBROWNOUT NOCLKOUT IESO NOFCMEN
Word 2: 0EFF NOWRT PLL_SW STVREN BORV19 DEBUG NOLVP
Some fuses have been forced to be compatible with the ICD debugger.
|
Note that the drop-down box setting has over-ridden the NODEBUG
in your program.
That's why I mentioned it. What IDE are you using and is it
accidentally set for DEBUG mode ? |
|
|
starfire151
Joined: 01 Apr 2007 Posts: 195
|
|
Posted: Tue May 11, 2021 5:20 pm |
|
|
Hi PCM programmer and temtronic
I checked the bottom of the .lst file and get this:
Configuration Fuses:
Word 1: 39C4 INTRC_IO NOWDT PUT MCLR NOPROTECT NOCPD NOBROWNOUT NOCLKOUT IESO FCMEN
Word 2: 1EFF NOWRT PLL_SW STVREN BORV19 NODEBUG NOLVP
It appears I am not in debug mode.
I'm using V5.071 of the compiler. I'm using the ICD-USB module to program the PIC. I use the "Build and Run" option from the menu. It compiles and downloads the program to the PIC and then starts operation. Since this test case isn't using the PClk or PDat lines, the program runs OK. I have also disconnected the ICD-USB module from the PIC and done a reset to the system but it still responds the same way.
As an aside, I also just compiled the program and loaded it to the PIC with the ccsload program but that also showed the same results. The WDT appears to not be working but the EXT interrupt still works. |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Tue May 11, 2021 6:06 pm |
|
|
Have you read the errata for that processor?
Item 1.1: LFINTOSC, Item summary: Wake from sleep. Revision A0 affected.
Item 1.2: Clock switching, Item summary: clock switching can cause a single corrupted instruction. Revision A0 affected.
Item 1.3: Oscillator start-up timer, Item summary: OSTS bit remains set. Revisions A0 and A2 affected.
These are, to my mind, 3 possibilities in terms of your troubles.
Use CCSLoad to read the HW rev of your processor. |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Tue May 11, 2021 6:15 pm |
|
|
starfire151 wrote: | Hi PCM programmer and temtronic
I checked the bottom of the .lst file and get this:
Configuration Fuses:
Word 1: 39C4 INTRC_IO NOWDT PUT MCLR NOPROTECT NOCPD NOBROWNOUT NOCLKOUT IESO FCMEN
Word 2: 1EFF NOWRT PLL_SW STVREN BORV19 NODEBUG NOLVP
It appears I am not in debug mode. |
Your WDT is completely disabled. It cannot function in SW controlled mode because it's off. From the data sheet, chapter 4, page 48:
WDTE bits (4:3): 00 = watchdog disabled.
You want 01 = WDT controlled by the SWDTEN bit in the WDTCON register. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue May 11, 2021 7:35 pm |
|
|
On page 569 of the CCS manual, in the section on setup_wdt(), it says:
Quote: |
Note: For PCH parts and PCM parts with software controlled WDT, setup_wdt( ) would enable/disable watchdog timer only if NOWDT fuse is set. If WDT fuse is set, watchdog timer is always enabled. |
|
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Tue May 11, 2021 8:32 pm |
|
|
Manual appears to be wrong.
Test program:
Code: | #include <16LF1825.h>
#device ADC=10
#FUSES PUT //Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#fuses WDT_SW //No Watch Dog Timer, enabled in Software
#fuses INTRC_IO //Internal RC Osc, no CLKOUT
#use delay(internal=4000000)
void main(void) {
setup_wdt(WDT_ON | WDT_512MS);
while(TRUE) {
}
} |
List file:
Code: | CCS PCM C Compiler, Version 5.093, 46949 11-May-21 20:21
Filename: C:\temp\main.lst
ROM used: 19 words (0%)
Largest free fragment is 2048
RAM used: 5 (0%) at main() level
16 (2%) worst case
Stack used: 0 locations
Stack size: 16
0000: MOVLP 00
0001: GOTO main
0002: NOP
.................... #include <16LF1825.h>
.................... //////////// Standard Header file for the PIC16LF1825 device ////////////////
.................... ///////////////////////////////////////////////////////////////////////////
.................... //// (C) Copyright 1996, 2014 Custom Computer Services ////
.................... //// This source code may only be used by licensed users of the CCS C ////
.................... //// compiler. This source code may only be distributed to other ////
.................... //// licensed users of the CCS C compiler. No other use, reproduction ////
.................... //// or distribution is permitted without written permission. ////
.................... //// Derivative programs created using this software in object code ////
.................... //// form are not restricted in any way. ////
.................... ///////////////////////////////////////////////////////////////////////////
.................... #device PIC16LF1825
....................
.................... #list
....................
.................... #device ADC=10
....................
.................... #FUSES PUT //Power Up Timer
.................... #FUSES NOBROWNOUT //No brownout reset
.................... #fuses WDT_SW //No Watch Dog Timer, enabled in Software
.................... #fuses INTRC_IO //Internal RC Osc, no CLKOUT
....................
.................... #use delay(internal=4000000)
....................
.................... void main(void) {
0003: MOVLW 6A
0004: MOVLB 01
0005: MOVWF OSCCON
0006: MOVLB 03
0007: CLRF ANSELA
0008: CLRF ANSELC
0009: MOVLB 02
000A: CLRF CM1CON1
000B: CLRF CM1CON0
000C: CLRF CM2CON1
000D: CLRF CM2CON0
.................... setup_wdt(WDT_ON | WDT_512MS);
000E: MOVLW 13
000F: MOVLB 01
0010: MOVWF WDTCON // this is correct
....................
.................... while(TRUE) {
0011: GOTO 011
....................
.................... }
.................... }
0012: SLEEP
Configuration Fuses:
Word 1: 39CC INTRC_IO WDT_SW PUT MCLR NOPROTECT NOCPD NOBROWNOUT NOCLKOUT IESO FCMEN // correct
Word 2: 1EFF NOWRT PLL_SW STVREN BORV19 NODEBUG NOLVP |
If the WDT fuse is changed to disable it:
Code: | CCS PCM C Compiler, Version 5.093, 46949 11-May-21 20:26
Filename: C:\temp\main.lst
ROM used: 19 words (0%)
Largest free fragment is 2048
RAM used: 5 (0%) at main() level
16 (2%) worst case
Stack used: 0 locations
Stack size: 16
0000: MOVLP 00
0001: GOTO main
0002: NOP
.................... #include <16LF1825.h>
.................... //////////// Standard Header file for the PIC16LF1825 device ////////////////
.................... ///////////////////////////////////////////////////////////////////////////
.................... //// (C) Copyright 1996, 2014 Custom Computer Services ////
.................... //// This source code may only be used by licensed users of the CCS C ////
.................... //// compiler. This source code may only be distributed to other ////
.................... //// licensed users of the CCS C compiler. No other use, reproduction ////
.................... //// or distribution is permitted without written permission. ////
.................... //// Derivative programs created using this software in object code ////
.................... //// form are not restricted in any way. ////
.................... ///////////////////////////////////////////////////////////////////////////
.................... #device PIC16LF1825
....................
.................... #list
....................
.................... #device ADC=10
....................
.................... #FUSES PUT //Power Up Timer
.................... #FUSES NOBROWNOUT //No brownout reset
.................... #fuses NOWDT //No Watch Dog Timer
.................... #fuses INTRC_IO //Internal RC Osc, no CLKOUT
....................
.................... #use delay(internal=4000000)
....................
.................... void main(void) {
0003: MOVLW 6A
0004: MOVLB 01
0005: MOVWF OSCCON
0006: MOVLB 03
0007: CLRF ANSELA
0008: CLRF ANSELC
0009: MOVLB 02
000A: CLRF CM1CON1
000B: CLRF CM1CON0
000C: CLRF CM2CON1
000D: CLRF CM2CON0
.................... setup_wdt(WDT_ON | WDT_512MS);
000E: MOVLW 13
000F: MOVLB 01
0010: MOVWF WDTCON // same as before
....................
.................... while(TRUE) {
0011: GOTO 011
....................
.................... }
.................... }
0012: SLEEP
Configuration Fuses:
Word 1: 39C4 INTRC_IO NOWDT PUT MCLR NOPROTECT NOCPD NOBROWNOUT NOCLKOUT IESO FCMEN // setup_wdt() doesn't change the fuse - the WDT is killed
Word 2: 1EFF NOWRT PLL_SW STVREN BORV19 NODEBUG NOLVP
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Tue May 11, 2021 11:40 pm |
|
|
No, the manual is right, except it dates from older chips that only had
WDT and NOWDT fuses. This chip has WDT, NOWDT, WDT_NOSL, and
WDT_SW options.
You have to look at and understand what the fuses actually 'do' (data sheet).
For this chip it says:
Quote: |
bit 4-3 WDTE<1:0>: Watchdog Timer Enable bit
11 = WDT enabled
10 = WDT enabled while running and disabled in Sleep
01 = WDT controlled by the SWDTEN bit in the WDTCON register
00 = WDT disabled
|
Note that only the third (which is WDT_SW), allows the SWDTEN bit to
control the watchdog.
On the earlier chips, you had:
Quote: |
bit 3 WDTE: Watchdog Timer Enable bit
1 = WDT enabled
0 = WDT disabled and can be enabled by SWDTEN bit (WDTCON<0>)
|
So to use the SWDTEN, you simply had to disable the WDT in the fuses.
The manual has not been updated for these later chips.
The key thing always is to look at the data sheet. |
|
|
starfire151
Joined: 01 Apr 2007 Posts: 195
|
|
Posted: Wed May 12, 2021 8:32 am |
|
|
Hi Ttelmah, newguy, and PCM programmer -
GREAT HELP EVERYBODY! I changed the #FUSES NOWDT line to #FUSES WDT_SW, recompiled, and loaded it. It worked right off the bat completely correctly!
I'm seeing the 100ms pulse every 2 seconds on PIN_A5 during the WDT counting loop, I see the PIN_C2 get enabled after the end of the counting loop, I see the background operation run correctly for 10 seconds with no WDT timeout, I see the PIN_C2 get disabled at the end of the 10 second background operation, and I see the PIN_A5 100ms pulse every 2 seconds from the WDT for another 10 loops, etc.
I didn't see WDT_SW as a fuse option in the device file. It worked great!
Thanks, again, everyone!
I'm off to the races... |
|
|
|