I finally broke down and wrote replacements for the SF system.bas and wdt.bas modules that take care of this automatically for you.
In system.bas I added statements to detect which device you're compiling for and provided two new macros... CONFIG_WDT_ON() and CONFIG_WDT_OFF() that translate to the correct 'config WDT/config WDTEN' as appropriate. You can use these macros in place of the 'config' statement, and it'll set the correct fuse name. The device list is current as of MPLAB 8.66.
I also made some changes to the wdt.bas module. It now uses those CONFIG_WDT_xx() macros so it should work with all devices, and I changed the Postscale() routine a bit. It now takes care of enabling/restoring interrupts for you, and I have it check the current watchdog postscaler configuration setting and skip reprogramming it if it doesn't need changing. Previously, the routine would always reprogram the CONFIG2 watchdog postscaler setting value no matter what. It takes a few more bytes of code, but it should be less write cycles to the config word unless you are frequently changing the timeout.
You can place these in your user library folder and they will be used instead of the standard SF ones.
I used the system.bas file from the SE version, as this has a few new additions.
System.bas:
Code: Select all
{
****************************************************************
* Name : System.bas *
* Author : David John Barker *
* Notice : Copyright (c) 2006 Mecanique *
* : All Rights Reserved *
* Date : 22/08/2007 *
* Version : 1.2 *
* Notes : 1.1 Added macro param check contants *
* : 1.2 JM added CONFIG_WDT_ON/CONFIG_WDT_OFF macros *
* : to support devices that use WDTEN instead of WDT *
* : The list of devices is from MPLAB 8.66 *
****************************************************************
}
module Sys
public const Nil = 0
public type TEvent = event()
// these are the 25 system registers used by the compiler
public dim
SB_SV0 as byte absolute $00,
SB_SV0H as byte absolute $01,
SB_SV0HH as byte absolute $02,
SB_SV0HHH as byte absolute $03,
SB_SV1 as byte absolute $04,
SB_SV1H as byte absolute $05,
SB_SV2 as byte absolute $06,
SB_SV2H as byte absolute $07,
SB_SV2HH as byte absolute $08,
SB_SV2HHH as byte absolute $09,
SB_SV3 as byte absolute $0A,
SB_SV3H as byte absolute $0B,
SB_SV3HH as byte absolute $0C,
SB_SV3HHH as byte absolute $0D,
SB_SV4 as byte absolute $0E,
SB_SV4H as byte absolute $0F,
SB_SV5 as byte absolute $10,
SB_SV5H as byte absolute $11,
SB_SV5HH as byte absolute $12,
SB_SV5HHH as byte absolute $13,
SB_SV6 as byte absolute $14,
SB_SV6H as byte absolute $15,
SB_SV6HH as byte absolute $16,
SB_SV6HHH as byte absolute $17,
SB_SV7 as byte absolute $18
// more user friendly naming of system registers...
public dim
D0 as SB_SV0,
D1 as SB_SV0H,
D2 as SB_SV0HH,
D3 as SB_SV0HHH,
D4 as SB_SV1,
D5 as SB_SV1H,
D6 as SB_SV2,
D7 as SB_SV2H,
D8 as SB_SV2HH,
D9 as SB_SV2HHH,
D10 as SB_SV3,
D11 as SB_SV3H,
D12 as SB_SV3HH,
D13 as SB_SV3HHH,
D14 as SB_SV4,
D15 as SB_SV4H,
D16 as SB_SV5,
D17 as SB_SV5H,
D18 as SB_SV5HH,
D19 as SB_SV5HHH,
D20 as SB_SV6,
D21 as SB_SV6H,
D22 as SB_SV6HH,
D23 as SB_SV6HHH,
D24 as SB_SV7
// macro CheckParam() constants
// check arg constants
// ex: CheckParam(MyByteValue, cpConst or cpInteger, "This is not an integer constant")
public const
cpConst = $01,
cpVariable = $02,
cpArray = $04,
cpSize01 = $08,
cpSize08 = $10,
cpSize16 = $20,
cpSize32 = $40,
cpInteger = $0100,
cpReal = $0200,
cpString = $0400,
cpChar = $0800,
cpBoolean = $1000
// error/message type constants
// ex: CheckParam(etError, "invalid macro parameter")
public const
etError = 0,
etWarning = 1,
etMessage = 2,
etHint = 3
{
****************************************************************************
* Name : ClrWDT *
* Purpose : Clear the watch dog timer *
****************************************************************************
}
#option WDT = false
#if IsOption(WDT) and not (WDT in (true, false))
#error WDT, "Invalid option. WDT must be true or false."
#endif
// assume the device uses 'config WDT'
#variable _USE_WDTEN = false
// these 112 devices use WDTEN instead of WDT (from MPLAB 8.66)
#if _device in(18F13K22, 18F13K50, 18F14K22, 18F14K50, 18F2331, 18F23K20, 18F23K22, 18F2431)
#variable _USE_WDTEN = true
#elseif _device in(18F24J10, 18F24J11, 18F24J50, 18F24K20, 18F24K22, 18F25J10, 18F25J11, 18F25J50)
#variable _USE_WDTEN = true
#elseif _device in(18F25K20, 18F25K22, 18F25K80, 18F26J11, 18F26J13, 18F26J50, 18F26J53, 18F26K20)
#variable _USE_WDTEN = true
#elseif _device in(18F26K22, 18F26K80, 18F27J13, 18F27J53, 18F4331, 18F43K20, 18F43K22, 18F4431)
#variable _USE_WDTEN = true
#elseif _device in(18F44J10, 18F44J11, 18F44J50, 18F44K20, 18F44K22, 18F45J10, 18F45J11, 18F45J50)
#variable _USE_WDTEN = true
#elseif _device in(18F45K20, 18F45K22, 18F45K80, 18F46J11, 18F46J13, 18F46J50, 18F46J53, 18F46K20)
#variable _USE_WDTEN = true
#elseif _device in(18F46K22, 18F46K80, 18F47J13, 18F47J53, 18F63J11, 18F63J90, 18F64J11, 18F64J90)
#variable _USE_WDTEN = true
#elseif _device in(18F65J10, 18F65J11, 18F65J15, 18F65J50, 18F65J90, 18F65K22, 18F65K80, 18F65K90)
#variable _USE_WDTEN = true
#elseif _device in(18F66J10, 18F66J11, 18F66J15, 18F66J16, 18F66J50, 18F66J55, 18F66J90, 18F66J93)
#variable _USE_WDTEN = true
#elseif _device in(18F66K22, 18F66K80, 18F66K90, 18F67J10, 18F67J11, 18F67J50, 18F67J90, 18F67J93)
#variable _USE_WDTEN = true
#elseif _device in(18F67K22, 18F67K90, 18F83J11, 18F83J90, 18F84J11, 18F84J90, 18F85J10, 18F85J11)
#variable _USE_WDTEN = true
#elseif _device in(18F85J15, 18F85J50, 18F85J90, 18F85K22, 18F85K90, 18F86J10, 18F86J11, 18F86J15)
#variable _USE_WDTEN = true
#elseif _device in(18F86J16, 18F86J50, 18F86J55, 18F86J72, 18F86J90, 18F86J93, 18F86K22, 18F86K90)
#variable _USE_WDTEN = true
#elseif _device in(18F87J10, 18F87J11, 18F87J50, 18F87J72, 18F87J90, 18F87J93, 18F87K22, 18F87K90)
#variable _USE_WDTEN = true
#endif // _device
// define macros that use the appropriate config statement for the current device
// these can be used in place of 'config WDT' or 'config WDTEN'
#if (_USE_WDTEN)
public macro CONFIG_WDT_ON()
config WDTEN = on
end macro
public macro CONFIG_WDT_OFF()
config WDTEN = off
end macro
public macro CONFIG_WDT(x)
config WDTEN = x
end macro
#else
public macro CONFIG_WDT_ON()
config WDT = on
end macro
public macro CONFIG_WDT_OFF()
config WDT = off
end macro
public macro CONFIG_WDT(x)
config WDT = x
end macro
#endif
// if option is set, then enable the wdt configuration setting
#if (WDT)
CONFIG_WDT_ON()
#endif
public inline sub ClrWDT()
#if (WDT)
asm
ClrWDT
end asm
#endif
end sub
{
****************************************************************************
* Name : NOP *
* Purpose : Single NOP instruction *
****************************************************************************
}
public inline sub Nop()
asm
Nop
end asm
end sub
wdt.bas:
Code: Select all
{
*****************************************************************************
* Name : Watchdog.bas *
* Author : David John Barker *
* Notice : Copyright (c) 2007 Mecanique *
* : All Rights Reserved *
* Date : 07/08/2007 *
* Version : 1.0 *
* : 1.1 Jerry Messina 04/15/2011 *
* : - add support for devices with WDTEN (new system.bas) *
* : - change Postscale() to read current config before writing *
* : - add intr disable/restore to Postscale() *
* Notes : Enable or disable the WDT (and postscaler) under software *
* : control. As per the datasheet, enabling or disabling the WDT *
* : under software control will only work when the configuration *
* : bit has disabled the WDT. That is, if you set the WDT *
* : configuration fuse to ON, you CANNOT disable the WDT under *
* : software control *
* : Setting the '#option WDT = true' ensures that any modules with *
* : blocking calls tickle the watchdog timer. Note however that *
* : low level routines such as DelayMS WILL NOT tickle the WDT, as *
* : the fuse setting is disabled - use the delay() routine in this *
* : module for WDT safe delays *
* JM - the previous note may no longer be true. DelayMS/DelayUs tickle the *
* WDT based on the '#option WDT' setting, and not the config fuse setting *
*****************************************************************************
}
module Watchdog
#option WDT = true // ensure blocking module calls tickle WDT
include "system.bas" // import system module
// WDT fuse setting MUST BE OFF for this module to work
// (use the macro in the system.bas module to do this)
CONFIG_WDT_OFF()
// public postscaler value - some devices support up to 32768, some don't
// you need to READ THE DATASHEET to determine:
// (a) what PS values are supported and
// (b) the nominal WDT timeout, in ms
public const
ps32768 = %11110,
ps16384 = %11100,
ps8192 = %11010,
ps4096 = %11000,
ps2048 = %10110,
ps1024 = %10100,
ps512 = %10010,
ps256 = %10000,
ps128 = %01110,
ps64 = %01100,
ps32 = %01010,
ps16 = %01000,
ps8 = %00110,
ps4 = %00100,
ps2 = %00010,
ps1 = %00000
// public dims...
public dim
Enabled as WDTCON.Booleans(0), // enable or disable the WDT (SWDTEN bit)
Reset as sys.ClrWDT // reset the WDT
{
****************************************************************************
* Name : Postscale *
* Purpose : Set the WDT postscale value *
* : V1.1 - read CONFIG2 first, and skip writing if it's already *
* : set to the desired value. Add disable/restore interrupts *
****************************************************************************
}
const GIE = 7 // INTCON.GIE bit
const WR = 1 // EECON1.WR bit
public sub Postscale(pValue as byte)
dim t_intcon as byte // copy of INTCON
t_intcon = INTCON // save state of GIE intr bit
INTCON.bits(GIE) = 0 // disable intr
// point to CONFIG2H reg at 300003h
TBLPTRU = $30
TBLPTRH = $00
TBLPTRL = $03
// read current CONFIG2H setting (get watchdog postscaler setting)
EECON1 = $C0
asm
TBLRD*
end asm
// if the postscaler setting is different, then write the new config word
if (TABLAT <> pValue) then
// enable write to configuration area, then write new value to latch...
EECON1 = $C4
TABLAT = pValue
asm
TBLWT*
end asm
// mandatory write sequence...
EECON2 = $55
EECON2 = $AA
EECON1.bits(WR) = 1 // initiate a WR cycle
Nop // delay
endif
EECON1 = $80 // back to FLASH read...
TBLPTRU = $00 // restore tableptr upper byte
if (t_intcon.bits(GIE) = 1) then // restore GIE intr bit setting
INTCON.bits(GIE) = 1
end if
end sub
{
****************************************************************************
* Name : Delay *
* Purpose : DelayMS WILL NOT tickle the WDT when the WDT has been enabled *
* : through software. Use this routine for WDT safe delays *
****************************************************************************
}
public sub Delay(pDelay as word)
while (pDelay > 0)
delayms(1)
sys.ClrWDT
dec(pDelay)
end while
end sub