News:

;) This forum is the property of Proton software developers

Main Menu

18F14Q40 Configuration issue

Started by okmn, May 22, 2024, 07:47 AM

Previous topic - Next topic

okmn

  Now I'm fighting another nonsense,
  The hero of this nonsense is 18F14Q40

i want just simple blink again  but i could not find  where am i making wrong!

"yes" to any coding help.

Device 18F14Q40
Declare Xtal = 64
Declare Optimiser_Level = 3
Config_Start
FEXTOSC = OFF      ' External Oscillator Mode Selection->Oscillator not enabled
RSTOSC = HFINTOSC_64MHZ      ' Power-up Default Value For COSC->HFINTOSC with HFFRQ = 64 MHz And CDIV = 1:1

FCMENP = OFF      ' Fail-Safe Clock Monitor Enable - Primary Xtal Enable->Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on EXTOSC failure.
CLKOUTEN = OFF      ' Clock Out Enable->CLKOUT function is disabled
FCMEN = OFF      ' Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor disabled
CSWEN = On      ' Clock Switch Enable->Writing To NOSC And NDIV is allowed
FCMENS = OFF      ' Fail-Safe Clock Monitor Enable - Secondary Xtal Enable->Fail-Safe Clock Monitor Disabled
PR1WAY = On      ' PRLOCKED One-Way Set Enable->PRLOCKED Bit can be cleared And Set only once

MVECEN = On      ' Multivector Enable->Multi-vector enabled, Vector table used For interrupts
MCLRE = EXTMCLR      ' Master Clear (MCLR) Enable->If LVP = 0, MCLR Pin is MCLR; If LVP = 1, RE3 pin function is MCLR
BOREN = OFF      ' Brown-out Reset Enable->Brown-out Reset disabled
PWRTS = PWRT_OFF      ' Power-up Timer Selection->PWRT is disabled
IVT1WAY = On      ' IVTLOCK One-Way Set Enable->IVTLOCKED Bit can be cleared And Set only once
LPBOREN = OFF      ' Low-Power BOR Enable->Low-Power BOR disabled

XINST = OFF      ' Extended Instruction Set Enable->Extended Instruction Set And Indexed Addressing Mode disabled
LVP = On      ' Low-Voltage Programming Enable->Low voltage programming enabled. MCLR/VPP Pin function is MCLR. MCLRE configuration Bit is ignored
ZCD = OFF      ' ZCD Disable->ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN Bit of ZCDCON
STVREN = On      ' Stack Overflow/Underflow Reset Enable->Stack full/underflow will cause Reset
BORV = VBOR_1P9      ' Brown-out Reset Voltage Selection->Brown-out Reset Voltage (VBOR) Set To 1.9V
PPS1WAY = On      ' PPSLOCKED One-Way Set Enable->PPSLOCKED Bit can be cleared And Set only once; PPS registers remain locked after one clear/set cycle

WDTCPS = WDTCPS_31      ' WDT Period Select->Divider ratio 1:65536; software control of WDTPS
WDTE = OFF      ' WDT Operating Mode->WDT Disabled; SWDTEN is ignored

WDTCWS = WDTCWS_7      ' WDT Window Select->window always open (100%); software control; keyed access not required
WDTCCS = SC      ' WDT Input Clock Selector->Software Control

SAFEN = OFF      ' Storage Area Flash (SAF) Enable->SAF disabled
BBEN = OFF      ' Boot Block Enable->Boot block disabled
BBSIZE = BBSIZE_512      ' Boot Block Size Selection->Boot Block size is 512 words

WRTB = OFF      ' Boot Block Write Protection->Boot Block not Write protected
WRTC = OFF      ' Configuration Register Write Protection->Configuration registers not Write protected
WRTD = OFF      ' Data EEPROM Write Protection->Data EEPROM not Write protected
WRTAPP = OFF      ' Application Block Write Protection->Application Block not write protected
WRTSAF = OFF      ' Storage Area Flash (SAF) Write Protection->SAF not Write Protected

Cp = On      ' User Program Flash Memory And Data EEPROM Code Protection->PFM And Data EEPROM Code protection enabled
Config_End
OSCCON1 = $62
OSCCON2 = $60
OSCCON3 = 0
OSCEN = 0
OSCFRQ = 8
OSCTUNE = 0
ACTCON = 0
While OSCSTATbits_PLLR = 0
Wend

LATA = 0
LATB = 0
LATC = 0

TRISA = $20
TRISB = 0
TRISC = $1C

ANSELA = 0
ANSELB = 0
ANSELC = 0
WPUA = $20
WPUB = 0
WPUC = 0

ODCONA = 0
ODCONB = 0
ODCONC = 0

SLRCONA = $37
SLRCONB = $F0
SLRCONC = $FF

INLVLA = $3F
INLVLB = $F0
INLVLC = $FF
RB4I2C = 0
RB6I2C = 0
IOCAP = 0
IOCAN = 0
IOCAF = 0
IOCBP = 0
IOCBN = 0
IOCBF = 0
IOCCP = 0
IOCCN = $10
IOCCF = 0
IOCCFbits_IOCCF4 = 0
INTCON0bits_GIE = 0

Symbol Blink_Led_1 = PORTC.0
Symbol Blink_Led_2 = PORTA.2
Symbol Switch = PORTA.5
Do

    Toggle Blink_Led_1
    DelayMS 500
    Toggle Blink_Led_2
    DelayMS 500

Loop


the video showing running code produce by Mplab XC8



Frizie

What happens if you don't use TOGGLE but actually switch the ports with HIGH and LOW.
As far as I know, the TOGGLE instruction reads the PORT and then controls the PORT inversely.
But if the PORT is slightly overloaded, the same level is always assumed.

So try:

DO
  HIGH PORTC
.0
  DELAYMS 500
  HIGH PORTA.2
  DELAYMS 500
  LOW  PORTC.0
  DELAYMS 500
  LOW  PORTA.2
  DELAYMS 500
LOOP

Ohm sweet Ohm | www.picbasic.nl

top204

There were a few things incorrect in your code listing.

The While-Wend loop after the oscillator SFR settings will never exit because that is waiting for the PLL to become stable, but the internal 64MHz oscillator does not use the PLL peripheral the same as if it is enabled by the program (RSTOSC = HFINTOSC_64MHZ). The SFR settings were also set for a different fuse setting and enabling the PLL, so this would interfere with the HFINTOSC_64MHZ fuse and timings would be incorrect if the While-Wend were replaced with a simple delay to allow the oscillator to become stable before the main program starts. For the waiting loop for the PLL and the frequency altered using SFRs, the RSTOSC fuse needs to be set as: HFINTOSC_1MHZ.

With the HFINTOSC_64MHZ fuse setting, no SFR manipulation is required for the device's frequency. It will automatically operate at 64MHz on power-up.

Also, in the fuse settings the vectored interrupt was enabled and PPS single use lock and some other single use locks were enabled, so a program would not be able to alter them, and interrupts would not work at all because the compiler does not use vectored interrupts.

Below is a tested and working program to operate a PIC18F14Q40 device using its internal 64MHz oscillator, and flashing LEDs at the correct speed:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A working demo of a PIC18F14Q40 device flashing LEDs using its internal 64MHz oscillator.
' Written by Les Johnson for the Positron8 compiler.
'
    Device 18F14Q40                         ' Tell the compiler what device to compile for
    Declare Xtal = 64                       ' Tell the compiler what frequency the device is operating at
    Declare Optimiser_Level = 3             ' Set the highest level of optimisation (not recommended until normal optimisation proves the code runs correctly)
'
' Setup some pin alias names
'
    Symbol Blink_LED_1 = PORTC.0
    Symbol Blink_LED_2 = PORTA.0
    Symbol Switch_Pin = PORTA.5

'-----------------------------------------------------------------------------------------------------
' The main program starts here
'
Main:
    Setup()                                 ' Setup the program and peripherals

    Do
        Toggle Blink_LED_1
        DelayMS 500
        Toggle Blink_LED_2
        DelayMS 500
    Loop

'-----------------------------------------------------------------------------------------------------
' Setup the program and peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    PinLow Blink_LED_1
    PinLow Blink_LED_2
    PinMode Switch_Pin, Input_PullUp        ' Set the switch pin as an input with the pin's internal pull-up resistor enabled
EndProc

'-----------------------------------------------------------------------------------------------------
' Setup the config fuses for internal oscillator at 64MHz, with OSC pins as I/O lines.
' For PIC18F14Q40 and PIC18F05Q41 devices, and most other 18FxxQ4x devices.
'
Config_Start
    FEXTOSC = Off                           ' External Oscillator not enabled
    RSTOSC = HFINTOSC_64MHZ                 ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
    CLKOUTEN = Off                          ' CLKOUT function is disabled
    PR1WAY = Off                            ' PRLOCKED bit can be set and cleared repeatedly
    CSWEN = On                              ' Writing to NOSC and NDIV is allowed
    FCMEN = On                              ' Fail-Safe Clock Monitor enabled
    FCMENP = On                             ' Fail-Safe Clock Monitor enabled.
    FCMENS = On                             ' Fail-Safe Clock Monitor enabled.
    MCLRE = EXTMCLR                         ' MCLR pin is MCLR
    PWRTS = PWRT_OFF                        ' PWRT is disabled
    MVECEN = Off                            ' Interrupt controller does not use vector table to prioritise interrupts
    IVT1WAY = On                            ' IVTLOCKED bit can be cleared and set only once
    LPBOREN = On                            ' Low-Power BOR enabled
    BOREN = On                              ' Brown-out Reset enabled according to SBOREN
    BORV = VBOR_1P9                         ' Brown-out Reset Voltage (VBOR) set to 1.9V
    ZCD = Off                               ' ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                           ' PPSLOCKED bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = On                             ' Stack full/underflow will cause Reset
    LVP = Off                               ' HV on MCLR/VPP must be used for programming
    XINST = Off                             ' Extended Instruction Set and Indexed Addressing Mode disabled
    WDTCPS = WDTCPS_17                      ' WDT Period Divider ratio 1:4194304
    WDTE = Off                              ' WDT disabled
    WDTCWS = WDTCWS_7                       ' WDT window always open (100%)
    WDTCCS = SC                             ' WDT input clock Software Control
    BBSIZE = BBSIZE_512                     ' Boot Block size is 512 words
    BBEN = Off                              ' Boot block disabled
    SAFEN = Off                             ' SAF disabled
    Debug = Off                             ' Background Debugger disabled
    WRTB = Off                              ' Boot Block not Write protected
    WRTC = Off                              ' Configuration registers not Write protected
    WRTD = Off                              ' Data EEPROM not Write protected
    WRTSAF = Off                            ' SAF not Write Protected
    WRTAPP = Off                            ' Application Block not write protected
    Cp = Off                                ' PFM and Data EEPROM code protection disabled
Config_End

Also, all your original code that was copied and adapted from the MPLABX IDE is just not needed in the vast majority of programs, and the Positron compilers set pins to digital mode before a user's program starts. All of those SFR settings produced by the MPLABX MCC plugin actually creates a huge amount of wasted code, and can cause problems themselves. The MCC plugin comes in handy sometimes, but not just used "as-is". :-)

One good thing about the newer 18FxxQ4x devices is that they appear to have a standard for their peripherals and SFRs, so code for one should work on another, within limits.

They are new devices with some new, and quear, features, but after time they will become really nice devices to use. However, never take what the MCC plugin spits out too literally. It is microchip after all ! And it is paid third parties who probably do not actually use the devices, that are creating the code generation. So what is good on paper, does not always work in the real world unless you use it practically and understand it fully, as my dad always used to tell me. :-)

tnencon

#3
Hello friends;
I want to run Timer0 interrupt with PIC18F14Q40. I made the timer0 settings as follows, so that there is an interrupt every 100uS.
T0CON0 = $93 (16 bit, Prescaler: 16, Postscaler: 4, clock source:Fosc/4)
T0CON1 = $44
TMR0H = $FF
TMR0L = $E7
However, the interrupt occurs approximately every 200mS, instead of every 100uS.
The crystal frequency is internally set to 64MHz.
t= Prescaler*Postscaler*(65536-65511)/(Fosc/4)
I calculated it with the formula.
What is the point I missed? I would appreciate it if you could help me.
(After solving this problem, I want to experiment with Timer2 interrupt.)

tnencon

Quote from: tnencon on Jul 27, 2024, 12:53 PMHello friends;
I want to run Timer0 interrupt with PIC18F14Q40. I made the timer0 settings as follows, so that there is an interrupt every 100uS.
T0CON0 = $93 (16 bit, Prescaler: 16, Postscaler: 4, clock source:Fosc/4)
T0CON1 = $44
TMR0H = $FF
TMR0L = $E7
However, the interrupt occurs approximately every 200mS, instead of every 100uS.
The crystal frequency is internally set to 64MHz.
t= Prescaler*Postscaler*(65536-65511)/(Fosc/4)
I calculated it with the formula.
What is the point I missed? I would appreciate it if you could help me.
(After solving this problem, I want to experiment with Timer2 interrupt.)
When I define Timer0 as 8-Bit and not 16-Bit, it works fine. In this situation
'16-Bit
' TMR0H = $FF
' TMR0L = $E7
'8-Bit
    TMR0H = $18
    TMR0L = 0
'T0OUTPS 1:4; T0EN enabled; T016BIT 16-bit;
'T0CON0 = $93
'T0OUTPS 1:4; T0EN enabled; T016BIT 8-bit;
T0CON0 = $83
should be set as .
But why does it work correctly when we set it to 8-bit, but not when we set it to 16-bit?

top204

In past projects I've used Timer0 operating in 16-bit mode on a PIC18F05Q41 device and it works well.

The smaller Q devices seem to match each other, for now, with SFRs, and the demonstration template code listing I have just created below compiles correctly, so it should work on a PIC18F14Q40 device.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Timer0 routines for a PIC18F14Q40 device.
' Written by Les Johnson for the Positron8 compiler.
'
    Device = 18F14Q40                                               ' Tell the compiler what device to compile for
    Declare Xtal = 64                                               ' Tell the compiler what frequency the device is operating at (in MHz)
    On_Hardware_Interrupt Goto ISR_Handler                          ' Point the compiler to the interrupt handler
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600
    Declare HRSOut1_Pin   = PORTC.4
'
' Timer0 meta-macros to make the code easier to read and use
'
$define Timer0_Flag() PIR3bits_TMR0IF                               ' Timer0 flag
$define Timer0_FlagClear()  Timer0_Flag() = 0                       ' Clear the Timer0 flag
$define Timer0_IntEnable()  PIE3bits_TMR0IE = 1                     ' Enable a Timer0 interrupt
$define Timer0_IntDisable() PIE3bits_TMR0IE = 0                     ' Disable a Timer0 interrupt
$define Timer0_Start() T0CON0bits_T0EN = 1                          ' Start Timer0
$define Timer0_Stop()  T0CON0bits_T0EN = 0                          ' Stop Timer0

$define Periph_IntEnable()  INTCON0bits_GIEL = 1                    ' Enable peripheral interrupts
$define Periph_IntDisable() INTCON0bits_GIEL = 0                    ' Disable peripheral interrupts
$define Global_IntEnable()  INTCON0bits_GIE = 1                     ' Enable global interrupts
$define Global_IntDisable() INTCON0bits_GIE = 0                     ' Disable global interrupts
'
' Create any Global variables here
'
    Dim wTimer0ReloadVal As Word Heap                               ' Holds the Timer0 reload value for the interrupt handler
    Dim wTimer0_SFR As TMR0L.Word                                   ' Create a 16-bit SFR from TMR0L\H

'-------------------------------------------------------------------------------------------------
' The main program starts here
'
Main:
    Setup()                                                         ' Setup the program and any peripherals
    Do
    '
    ' Main program code goes here
    '
    Loop

'-------------------------------------------------------------------------------------------------
' Setup the program's variables, and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    Timer0_Init_100us()                                             ' Setup Timer0 for an overflow every 100us with a 64MHz oscillator
    Periph_IntEnable()                                              ' Enable peripheral interrupts (not needed for a Timer0 interrupt, but better safe than sorry)
    Global_IntEnable()                                              ' Enable global interrupts
EndProc

'-------------------------------------------------------------------------------------------------
' Setup Timer0 for an overflow every 100us with a 64MHz oscillator
' Input     : None
' Output    : None
' Notes     : None
'
Proc Timer0_Init_100us()
    T0CON1 = %01000000                                              ' Timer0 uses FOSC/4. Prescaler is 1:1. Set for not synchronised
    wTimer0_SFR = $F9C0                                             ' Set Timer0 for a 100us overflow at 64MHz device operation
    wTimer0ReloadVal = wTimer0_SFR                                  ' Load the 16-bit TMR0L\H values to the 16-bit reload variable
    Timer0_FlagClear()                                              ' Clear the Timer0 interrupt flag
    Timer0_IntEnable()                                              ' Enable a Timer0 interrupt
    T0CON0 = %10010000                                              ' Postscaler is 1:1. Timer0 enabled and set for 16-bit mode
EndProc

'-------------------------------------------------------------------------------------------------
' Read the 16-bit Timer0 registers value
' Input     : None
' Output    : Returns the 16-bit Timer0 value
' Notes     : None
'
Proc Timer0_Read(), Word
    Result.Byte0 = TMR0L
    Result.Byte1 = TMR0H
EndProc

'--------------------------------------------------------------------------
' Write 16-bits to the Timer0 registers
' Input     : pTimerVal holds the 16-bit value to write to Timer0
' Output    : None
' Notes     : None
'
Proc Timer0_Write16(pTimerVal As Word)
    TMR0H = pTimerVal.Byte1
    TMR0L = pTimerVal.Byte0
EndProc

'-------------------------------------------------------------------------------------------------
' Interrupt Handler
' Input     : None
' Output    : None
' Notes     : Interrupts on a Timer0 overflow
'
ISR_Handler:
    Context Save                                                    ' Save any compiler system variables and certain SFRs used within the interrupt handler
    If Timer0_Flag() = 1 Then                                       ' Was it a Timer0 overflow that triggered the interrupt?
        '
        ' Yes. So code goes here for the Timer0 interrupt
        '
        wTimer0_SFR = wTimer0ReloadVal                              ' Load TMR0L\H with the reload value for the duration required
        Timer0_FlagClear()                                          ' Clear the Timer0 flag
    EndIf
    Context Restore                                                 ' Restore any compiler system variables and SFRs used within the interrupt handler, and exit the interrupt

'-------------------------------------------------------------------------------------------------
' Setup the config fuses for internal oscillator at 64MHz, with OSC pins as I/O
' For a PIC18F14Q40 device
'
Config_Start
    FEXTOSC = Off                           ' External Oscillator not enabled
    RSTOSC = HFINTOSC_64MHZ                 ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1

    CLKOUTEN = Off                          ' CLKOUT function is disabled
    PR1WAY = Off                            ' PRLOCKED bit can be set and cleared repeatedly
    CSWEN = On                              ' Writing to NOSC and NDIV is allowed
    FCMEN = Off                             ' Fail-Safe Clock Monitor disabled
    FCMENP = Off                            ' Fail-Safe Clock Monitor will not flag FSCMP bit and OSFIF interrupt on EXTOSC failure
    FCMENS = Off                            ' Fail-Safe Clock Monitor will not flag FSCMP bit and OSFIF interrupt on SOSC failure

    MCLRE = EXTMCLR                         ' MCLR pin is MCLR
    PWRTS = PWRT_OFF                        ' PWRT is disabled
    MVECEN = Off                            ' Interrupt controller does not use vector table
    IVT1WAY = On                            ' IVTLOCKED bit can be cleared and set only once
    LPBOREN = On                            ' Low-Power BOR enabled
    BOREN = On                              ' Brown-Out Reset enabled according to SBOREN

    BORV = VBOR_1P9                         ' Brown-out Reset Voltage (VBOR) set to 1.9V
    ZCD = Off                               ' ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                           ' PPSLOCKED bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = On                             ' Stack full/underflow will cause reset
    LVP = Off                               ' Higher Voltage on MCLR/VPP must be used for programming
    XINST = Off                             ' Extended Instruction Set disabled

    WDTCPS = WDTCPS_17                      ' WDT Period Divider ratio 1:4194304
    WDTE = Off                              ' WDT disabled

    WDTCWS = WDTCWS_7                       ' WDT window always open (100%); software control; keyed access not required
    WDTCCS = SC                             ' WDT input clock Software Control

    BBSIZE = BBSIZE_512                     ' Boot Block size is 512 words
    BBEN = Off                              ' Boot block disabled
    SAFEN = Off                             ' SAF disabled
    Debug = Off                             ' Background Debugger disabled

    WRTB = Off                              ' Boot Block not Write protected
    WRTC = Off                              ' Configuration registers not Write protected
    WRTD = Off                              ' Data EEPROM not Write protected
    WRTSAF = Off                            ' SAF not Write Protected
    WRTAPP = Off                            ' Application Block not write protected

    Cp = Off                                ' PFM and Data EEPROM code protection disabled
Config_End

tnencon

Quote from: top204 on Jul 27, 2024, 05:37 PMI've used Timer0 operating in 16-bit mode on a PIC18F05Q41 device and it works well.

The smaller Q devices seem to match each other, for now, with SFRs, and the demonstration template code listing I have just created below compiles correctly, so it should work on a PIC18F14Q40 device.

'
'  /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\    \/\\\                                                /\\\          /\\\
'  \/\\\\\\\\\\\/        /\\\\\    /\\\\\\\\\\    /\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'    \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\    \/\\\        \/\\\        /\\\\\\\\\\
'      \/\\\    \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\    \/\\\ /\\  /\\\/////\\\
'      \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\  \//\\\\\\\\/\\
'        \///        \///    \/////    \//////////    \//////////      \/////        \/////    \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Timer0 routines for a PIC18F14Q40 device.
' Written by Les Johnson for the Positron8 compiler.
'
    Device = 18F14Q40                                              ' Tell the compiler what device to compile for
    Declare Xtal = 64                                              ' Tell the compiler what frequency the device is operating at (in MHz)
    On_Hardware_Interrupt Goto ISR_Handler                          ' Point the compiler to the interrupt handler
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600
    Declare HRSOut1_Pin  = PORTC.4
'
' Timer0 meta-macros to make the code easier to read and use
'
$define Timer0_Flag() PIR3bits_TMR0IF                              ' Timer0 flag
$define Timer0_FlagClear()  Timer0_Flag() = 0                      ' Clear the Timer0 flag
$define Timer0_IntEnable()  PIE3bits_TMR0IE = 1                    ' Enable a Timer0 interrupt
$define Timer0_IntDisable() PIE3bits_TMR0IE = 0                    ' Disable a Timer0 interrupt
$define Timer0_Start() T0CON0bits_T0EN = 1                          ' Start Timer0
$define Timer0_Stop()  T0CON0bits_T0EN = 0                          ' Stop Timer0

$define Periph_IntEnable()  INTCON0bits_GIEL = 1                    ' Enable peripheral interrupts
$define Periph_IntDisable() INTCON0bits_GIEL = 0                    ' Disable peripheral interrupts
$define Global_IntEnable()  INTCON0bits_GIE = 1                    ' Enable global interrupts
$define Global_IntDisable() INTCON0bits_GIE = 0                    ' Disable global interrupts
'
' Create any Global variables here
'
    Dim wTimer0ReloadVal As Word Heap                              ' Holds the Timer0 reload value for the interrupt handler
    Dim wTimer0_SFR As TMR0L.Word                                  ' Create a 16-bit SFR from TMR0L\H

'-------------------------------------------------------------------------------------------------
' The main program starts here
'
Main:
    Setup()                                                        ' Setup the program and any peripherals
    Do
    '
    ' Main program code goes here
    '
    Loop

'-------------------------------------------------------------------------------------------------
' Setup the program's variables, and any peripherals
' Input    : None
' Output    : None
' Notes    : None
'
Proc Setup()
    Timer0_Init_100us()                                            ' Setup Timer0 for an overflow every 100us with a 64MHz oscillator
    Periph_IntEnable()                                              ' Enable peripheral interrupts (not needed for a Timer0 interrupt, but better safe than sorry)
    Global_IntEnable()                                              ' Enable global interrupts
EndProc

'-------------------------------------------------------------------------------------------------
' Setup Timer0 for an overflow every 100us with a 64MHz oscillator
' Input    : None
' Output    : None
' Notes    : None
'
Proc Timer0_Init_100us()
    T0CON1 = %01000000                                              ' Timer0 uses FOSC/4. Prescaler is 1:1. Set for not synchronised
    wTimer0_SFR = $F9C0                                            ' Set Timer0 for a 100us overflow at 64MHz device operation
    wTimer0ReloadVal = wTimer0_SFR                                  ' Load the 16-bit TMR0L\H values to the 16-bit reload variable
    Timer0_FlagClear()                                              ' Clear the Timer0 interrupt flag
    Timer0_IntEnable()                                              ' Enable a Timer0 interrupt
    T0CON0 = %10010000                                              ' Postscaler is 1:1. Timer0 enabled and set for 16-bit mode
EndProc

'-------------------------------------------------------------------------------------------------
' Read the 16-bit Timer0 registers value
' Input    : None
' Output    : Returns the 16-bit Timer0 value
' Notes    : None
'
Proc Timer0_Read(), Word
    Result.Byte0 = TMR0L
    Result.Byte1 = TMR0H
EndProc

'--------------------------------------------------------------------------
' Write 16-bits to the Timer0 registers
' Input    : pTimerVal holds the 16-bit value to write to Timer0
' Output    : None
' Notes    : None
'
Proc Timer0_Write16(pTimerVal As Word)
    TMR0H = pTimerVal.Byte1
    TMR0L = pTimerVal.Byte0
EndProc

'-------------------------------------------------------------------------------------------------
' Interrupt Handler
' Input    : None
' Output    : None
' Notes    : Interrupts on a Timer0 overflow
'
ISR_Handler:
    Context Save                                                    ' Save any compiler system variables and certain SFRs used within the interrupt handler
    If Timer0_Flag() = 1 Then                                      ' Was it a Timer0 overflow that triggered the interrupt?
        '
        ' Yes. So code goes here for the Timer0 interrupt
        '
        wTimer0_SFR = wTimer0ReloadVal                              ' Load TMR0L\H with the reload value for the duration required
        Timer0_FlagClear()                                          ' Clear the Timer0 flag
    EndIf
    Context Restore                                                ' Restore any compiler system variables and SFRs used within the interrupt handler, and exit the interrupt

'-------------------------------------------------------------------------------------------------
' Setup the config fuses for internal oscillator at 64MHz, with OSC pins as I/O
' For a PIC18F14Q40 device
'
Config_Start
    FEXTOSC = Off                          ' External Oscillator not enabled
    RSTOSC = HFINTOSC_64MHZ                ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1

    CLKOUTEN = Off                          ' CLKOUT function is disabled
    PR1WAY = Off                            ' PRLOCKED bit can be set and cleared repeatedly
    CSWEN = On                              ' Writing to NOSC and NDIV is allowed
    FCMEN = On                              ' Fail-Safe Clock Monitor enabled
    FCMENP = On                            ' Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on EXTOSC failure.
    FCMENS = On                            ' Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on SOSC failure.

    MCLRE = EXTMCLR                        ' MCLR pin is MCLR
    PWRTS = PWRT_OFF                        ' PWRT is disabled
    MVECEN = Off                            ' Interrupt controller does not use vector table to prioritze interrupts
    IVT1WAY = On                            ' IVTLOCKED bit can be cleared and set only once
    LPBOREN = On                            ' Low-Power BOR enabled
    BOREN = On                              ' Brown-out Reset enabled according to SBOREN

    BORV = VBOR_1P9                        ' Brown-out Reset Voltage (VBOR) set to 1.9V
    ZCD = Off                              ' ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                          ' PPSLOCKED bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = On                            ' Stack full/underflow will cause Reset
    LVP = Off                              ' HV on MCLR/VPP must be used for programming
    XINST = Off                            ' Extended Instruction Set and Indexed Addressing Mode disabled

    WDTCPS = WDTCPS_17                      ' WDT Period Divider ratio 1:4194304
    WDTE = Off                              ' WDT disabled

    WDTCWS = WDTCWS_7                      ' WDT window always open (100%); software control; keyed access not required
    WDTCCS = SC                            ' WDT input clock Software Control

    BBSIZE = BBSIZE_512                    ' Boot Block size is 512 words
    BBEN = Off                              ' Boot block disabled
    SAFEN = Off                            ' SAF disabled
    Debug = Off                            ' Background Debugger disabled

    WRTB = Off                              ' Boot Block not Write protected
    WRTC = Off                              ' Configuration registers not Write protected
    WRTD = Off                              ' Data EEPROM not Write protected
    WRTSAF = Off                            ' SAF not Write Protected
    WRTAPP = Off                            ' Application Block not write protected

    Cp = Off                                ' PFM and Data EEPROM code protection disabled
Config_End

Thanks for the reply Les;
If the postscaler is selected as 1:1 in the code, my code works properly. However, when we change the postscaler ratio, the code works incorrectly as I mentioned before.
Note: There is no problem with the prescaler ratio, I can make adjustments by making any changes I want.
Thanks in advance.

joesaliba

Just came across this thread.

I would like to setup a timer to 100Hz with an 18F05Q41.

Before I had a calculator for interrupts, but it is not suitable for these devices.

Can someone tell me where to look in the datasheet to calculate prescaler / postscaler and value of wTimer0_SFR to achieve a desired frequency please?

Regards

Joe 

Stephen Moss

Quote from: joesaliba on Oct 09, 2024, 08:43 PMBefore I had a calculator for interrupts, but it is not suitable for these devices.
Why? At first glance the timer look fairly standard in its operation.

Quote from: joesaliba on Oct 09, 2024, 08:43 PMCan someone tell me where to look in the datasheet to calculate prescaler / postscaler and value of wTimer0_SFR to achieve a desired frequency please?
Appears to the in the usual place (in the relevant Timer section), Postscaler is T0CON0 on page 359 of the datasheet, Prescaler & clock source selection is T0CON1 on page 360.
As for Timer value, that depends on you preferred clock source, some prefer a slower clock to try and get something close enough that they can avoid having to count rollovers, while others may prefer a higher clock and to count the number of rollovers as it may be more accurate.

JonW

#9
Stephen is right; this is no different than any other PIC timer, so standard calculators should work.
Here is a good Gui based one GUI CALC : See Les's code at bottom too

Or this Python script with calculate it based on the timeout needed and xtal freq

import math

def calculate_timer0_values(timeout_ms, crystal_freq_hz):
    # Timer0 is 16-bit, so it can count up to 65536
    max_timer_value = 65536
   
    # Available prescaler values for Timer0
    prescaler_values = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
   
    # Calculate the timer clock frequency (Fosc/4)
    timer_clock = crystal_freq_hz / 4
   
    best_prescaler = 1
    best_preload = 0
    min_error = float('inf')
   
    for prescaler in prescaler_values:
        # Calculate timer tick period
        tick_period = prescaler / timer_clock
       
        # Calculate number of ticks needed
        ticks_needed = timeout_ms / 1000 / tick_period
       
        # If ticks needed is greater than max timer value, skip this prescaler
        if ticks_needed > max_timer_value:
            continue
       
        # Calculate preload value
        preload = math.ceil(max_timer_value - ticks_needed)
       
        # Calculate actual timeout
        actual_timeout = (max_timer_value - preload) * tick_period * 1000
       
        # Calculate error
        error = abs(actual_timeout - timeout_ms)
       
        # Update best values if this is the most accurate so far
        if error < min_error:
            min_error = error
            best_prescaler = prescaler
            best_preload = preload
   
    if best_prescaler == 1 and best_preload == 0:
        return None, None, None, None  # No suitable combination found
   
    actual_timeout = (max_timer_value - best_preload) * (best_prescaler / timer_clock) * 1000
   
    return best_preload, best_prescaler, 1, actual_timeout  # Postscaler is always 1 for Timer0

def main():
    # Get user input
    timeout_ms = float(input("Enter desired timeout in milliseconds: "))
    crystal_freq_mhz = float(input("Enter crystal frequency in MHz: "))
   
    # Convert MHz to Hz
    crystal_freq_hz = crystal_freq_mhz * 1_000_000
   
    # Calculate timer values
    preload, prescaler, postscaler, actual_timeout = calculate_timer0_values(timeout_ms, crystal_freq_hz)
   
    # Print results
    if preload is None:
        print("No suitable combination found for the given timeout and crystal frequency.")
    else:
        print(f"\nResults for {crystal_freq_mhz} MHz crystal:")
        print(f"Preload value: {preload} (0x{preload:04X})")
        print(f"Prescaler: 1:{prescaler}")
        print(f"Postscaler: 1:{postscaler}")
        print(f"Actual timeout: {actual_timeout:.3f} ms")
        print(f"Error: {abs(actual_timeout - timeout_ms):.3f} ms")

if __name__ == "__main__":
    main()

Enter desired timeout in milliseconds: 10
Enter crystal frequency in MHz: 32

Results for 32.0 MHz crystal:
Preload value: 25536 (0x63C0)
Prescaler: 1:2
Postscaler: 1:1
Actual timeout: 10.000 ms
Error: 0.000 ms




top204

#10
Also see my post in the "Interrupts" section of the forum's WIKI:

Timer overflow interrupt calculation within the BASIC source code

Once a Timer's SFRs are known and $defined by examining the datasheet, the calculation for the interrupt interval is the same for all Timers.

joesaliba

Thanks so much. Been a while away from PIC's

JonW

#12
added 8, 16 32-bit timers and option of post and Prescaler divisors

import math

def calculate_timer_values(timeout_ms, crystal_freq_hz, timer_bits, prescaler_values, postscaler_values):
    max_timer_value = 2**timer_bits
   
    best_prescaler = 1
    best_postscaler = 1
    best_preload = 0
    min_error = float('inf')
   
    timer_clock = crystal_freq_hz / 4  # Assuming Fosc/4 as timer clock

    for prescaler in prescaler_values:
        for postscaler in postscaler_values:
            tick_period = prescaler / timer_clock
            effective_timeout = timeout_ms / postscaler
            ticks_needed = effective_timeout / 1000 / tick_period
           
            if ticks_needed > max_timer_value:
                continue
           
            preload = math.ceil(max_timer_value - ticks_needed)
            actual_timeout = (max_timer_value - preload) * tick_period * 1000 * postscaler
            error = abs(actual_timeout - timeout_ms)
           
            if error < min_error:
                min_error = error
                best_prescaler = prescaler
                best_postscaler = postscaler
                best_preload = preload

    if best_prescaler == 1 and best_postscaler == 1 and best_preload == 0:
        return None, None, None, None  # No suitable combination found
   
    actual_timeout = (max_timer_value - best_preload) * (best_prescaler / timer_clock) * 1000 * best_postscaler
   
    return best_preload, best_prescaler, best_postscaler, actual_timeout

def get_timer_config():
    timer_bits = int(input("Enter timer size in bits (8, 16, or 32): "))
    if timer_bits not in [8, 16, 32]:
        raise ValueError("Invalid timer size. Please enter 8, 16, or 32.")

    prescaler_input = input("Enter available prescaler values (comma-separated, e.g., 1,2,4,8,16): ")
    prescaler_values = [int(x.strip()) for x in prescaler_input.split(',')]

    postscaler_input = input("Enter available postscaler values (comma-separated, e.g., 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16): ")
    postscaler_values = [int(x.strip()) for x in postscaler_input.split(',')]

    return timer_bits, prescaler_values, postscaler_values

def main():
    print("MWAVE Universal PIC Timer Calculator")
    print("==============================")

    timeout_ms = float(input("Enter desired timeout in milliseconds: "))
    crystal_freq_mhz = float(input("Enter crystal frequency in MHz: "))
    crystal_freq_hz = crystal_freq_mhz * 1_000_000

    timer_bits, prescaler_values, postscaler_values = get_timer_config()

    preload, prescaler, postscaler, actual_timeout = calculate_timer_values(
        timeout_ms, crystal_freq_hz, timer_bits, prescaler_values, postscaler_values
    )

    if preload is None:
        print("\nNo suitable combination found for the given parameters.")
    else:
        print(f"\nResults for {crystal_freq_mhz} MHz crystal and {timer_bits}-bit timer:")
        print(f"Preload value: {preload} (0x{preload:X})")
        print(f"Prescaler: 1:{prescaler}")
        print(f"Postscaler: 1:{postscaler}")
        print(f"Actual timeout: {actual_timeout:.6f} ms")
        print(f"Error: {abs(actual_timeout - timeout_ms):.6f} ms")
       
        frequency = 1000 / actual_timeout
        print(f"Frequency: {frequency:.2f} Hz")

        # Timer register calculations
        if timer_bits == 8:
            print(f"Timer register value: 0x{preload:02X}")
        elif timer_bits == 16:
            high_byte = (preload >> 8) & 0xFF
            low_byte = preload & 0xFF
            print(f"Timer high byte: 0x{high_byte:02X}")
            print(f"Timer low byte: 0x{low_byte:02X}")
        elif timer_bits == 32:
            print(f"Timer register value: 0x{preload:08X}")

if __name__ == "__main__":
    main()
Enter desired timeout in milliseconds: 0.512
Enter crystal frequency in MHz: 64
Enter timer size in bits (8, 16, or 32): 16
Enter available prescaler values (comma-separated, e.g., 1,2,4,8,16): 1,2,4,8,16
Enter available postscaler values (comma-separated, e.g., 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16): 1,2,3,4,5,6,7,8

Results for 64.0 MHz crystal and 16-bit timer:
Preload value: 57344 (0xE000)
Prescaler: 1:1
Postscaler: 1:1
Actual timeout: 0.512000 ms
Error: 0.000000 ms
Frequency: 1953.12 Hz
Timer high byte: 0xE0
Timer low byte: 0x00
PS C:\MWAVE\MWAVE_GITHUB_REPO\PYTHON-DEV\PIC CALC>

joesaliba

Finally I got something working.

The below code should run the code at around 100Hz.

device = 18f05q41

 declare Xtal = 64

 '==================================================================================================
 '--------------------------------------------------------------------------------------------------
 ' Variables

  ' Global variables

    Dim Hz             As word  = 0         ' Variable used to hold Hz value

 '--------------------------------------------------------------------------------------------------
 ' Timing variables

    dim TMR0_REL    as word heap
    Dim Tim0        As TMR0L.word   ' Variable used to hold Timer0 ISR timing

 '==================================================================================================

 Declare Dead_Code_Remove = 1           ' Remove dead code
 Declare Optimiser_Level  = 2

 ' Setup USART1

    Declare Hserial1_Baud = 57600
    Declare HRSOut1_Pin   = PORTA.4
    Declare HRSIn1_Pin    = PORTC.5

  ' Setup USART2

    Declare Hserial2_Baud = 9600
    Declare HRSOut2_Pin   = PORTC.2
    Declare HRSIn2_Pin    = PORTC.0


 Declare Hserial1_Clear = On        ' Clear overflow automatically
 Declare Hserial2_Clear = On        ' Clear overflow automatically

 'Declare Hserial1_Parity even

 '--------------------------------------------------------------------------------------------------
 '==================================================================================================
 '************
 '* Includes *
 '************
 '>>>Includes<<<

 '===================================================================================================
 '*********************
 '* Set Pic registers *
 '*********************
 '>>>Analog, comparators etc..<<<

 CM1CON0  = %00000000       ' Turn OFF comparator 1
 CM2CON0  = %00000000       ' Turn OFF comparator 2


 ADCON0   = %00000000       ' Disable analog on startup
 ADCON1   = %00000000       '
 ADCON2   = %00000000       '
 ADCON3   = %00000000       '

 TRISA    = %00000000       ' Configure PORTB I/O
 TRISC    = %00000000       ' Configure PORTB I/O

 portc    = 0               ' Turn OFF PORTA
 PORTC    = 0               ' Turn OFF PORTC

 '--------------------------------------------------------------------------------------------------
 '==================================================================================================
 '******************
 ' DECLARE SYMBOLS *
 '******************

 Symbol OUTPS0   = T0CON0.0     ' TMR0 Output Prescaler (Divider) Select bit 0
 Symbol OUTPS1   = T0CON0.1     ' TMR0 Output Prescaler (Divider) Select bit 1
 Symbol OUTPS2   = T0CON0.2     ' TMR0 Output Prescaler (Divider) Select bit 2
 Symbol OUTPS3   = T0CON0.3     ' TMR0 Output Prescaler (Divider) Select bit 3
 Symbol MD16     = T0CON0.4     ' TMR0 8-bit/16-bit timer
 Symbol OUT      = T0CON0.5     ' TMR0 Output
 Symbol T0_NA    = T0CON0.6     ' Not in uSe
 Symbol T0_EN    = T0CON0.7     ' TMR0 Enable / Disable
 
 '--------------------------------------------------------------------------------------------------

 Symbol T0CKPS0  = T0CON1.0     ' TMR0 Prescaler Rate select bit 0
 Symbol T0CKPS1  = T0CON1.1     ' TMR0 Prescaler Rate select bit 1
 Symbol T0CKPS2  = T0CON1.2     ' TMR0 Prescaler Rate select bit 2
 Symbol T0CKPS3  = T0CON1.3     ' TMR0 Prescaler Rate select bit 3
 Symbol ASYNC    = T0CON1.4     ' TMR0 Input Asynchronization Enable
 Symbol CS0      = T0CON1.5     ' Timer0 Clock Source Select bit 0
 Symbol CS1      = T0CON1.6     ' Timer0 Clock Source Select bit 1
 Symbol CS2      = T0CON1.7     ' Timer0 Clock Source Select bit 2

 '--------------------------------------------------------------------------------------------------

 symbol T1_EN    = t1con.0      ' TMR1 Enable / Disable
 symbol RD16     = t1con.1      ' 16-Bit Read/Write Mode Enable
 symbol SYNC     = t1con.2      ' Timer External Clock Input Synchronization Control
 symbol T1CKPS0  = T1con.4      ' Timer Input Clock Prescaler Select bit 0
 symbol T1CKPS1  = t1con.5      ' Timer Input Clock Prescaler Select bit 1

 '--------------------------------------------------------------------------------------------------

 Symbol INT0EDG = INTCON0.0     ' External Interrupt 0 Edge Select
 Symbol INT1EDG = INTCON0.1     ' External Interrupt 1 Edge Select
 Symbol INT2EDG = INTCON0.2     ' External Interrupt 2 Edge Select
 Symbol IPEN    = INTCON0.5     ' Interrupt Priority Enable
 Symbol GIEL    = INTCON0.6     ' Global Low-Priority Interrupt Enable
 Symbol GIE     = INTCON0.7     ' Global Interrupt Enable

 '--------------------------------------------------------------------------------------------------

 symbol STAT0   = intcon1.6     ' Interrupt State Status
 symbol STAT1   = intcon1.7     ' Interrupt State Status

 '--------------------------------------------------------------------------------------------------

 symbol INT0IE  = pie1.0        ' External Interrupt 0 Interrupt Enable

 Symbol TMR1IE  = PIE3.4        ' TMR1 Interrupt Enable bit
 Symbol TMR0IE  = PIE3.7        ' TMR0 Interrupt Enable bit

 symbol INT0IF  = pir1.0        ' External Interrupt 0 Interrupt Flag
 symbol TMR1IF  = pir3.4        ' TMR1 Interrupt Flag
 Symbol TMR0IF  = PIR3.7        ' TMR0 Interrupt Flag bit

 '--------------------------------------------------------------------------------------------------
 '==================================================================================================
 ' Alias PORT pins

 symbol ICSPDAT = porta.0       ' ICSPDAT
 symbol ICSPCLK = porta.1       ' ICSPCLK
 symbol pStrobe = lata.2        ' Strobe light output
 symbol MCLR    = porta.3       ' MCLR pin
 Symbol TX1     = porta.4       ' USART transmitt to FrSky receiver
 symbol pFlow   = porta.5       ' Flow sensor input pin

 symbol RX2     = portc.0       ' USART receive from ECU
 symbol St_LED  = latc.1        ' Status LED
 symbol TX2     = portc.2       ' USART transmitt to ECU
 symbol Spare1  = portc.3       ' Spare 1
 Symbol Spare2  = portc.4       ' Spare 2
 symbol RX1     = portc.5       ' USART receive from FrSky receiver

 '==================================================================================================
 ' Setup any peripherals

 InitPPS()

 '==================================================================================================

 On_Interrupt Isr               ' Where to go on an Interrupt

 GoTo Over_ISR                  ' Jump over ISR

 '==================================================================================================
 '*********************
 '* INTERRUPT ROUTINE *
 '*********************

 Isr:                               ' Interrupt Service Routine
 Context Save                       ' Save registers before continue ISR

 if tmr0if = 1 then
   ' tmr0_rel = 25212
    Tim0 = TMR0_rel
    inc hz

    if hz = 50 then
        toggle st_led
        hz = 0
    endif

   ' Clear TMR0IF                    ' Reset TMR0 interrupt flag
   ' goto Int_Exit1

 endif

 '--------------------------------------------------------------------------------------------------

 Clear TMR0IF                       ' Reset TMR0 interrupt flag

 '--------------------------------------------------------------------------------------------------

 Int_Exit1:                         ' Interrupt Exit label

 Context Restore                    ' END OF INTERRUPT ROUTINE

 '==================================================================================================
 '**********************************
 '* Over Interrupt Service Routine *
 '**********************************

 Over_ISR:                          ' Over ISR label

 While GIE = 1  : GIE = 0 : Wend    ' Make sure that global interrupts are disabled
 While giel = 1 : giel = 0 :Wend    ' Make sure that peripheral interrupts are disabled

 '--------------------------------------------------------------------------------------------------
 ' External interrupt

 INT0IF  = 0            ' Clear the interrupt flag now

 TMR0IE  = 0            ' TMR0 External Interrupt Enable bit; 0 = Disabled, 1 = Enabled

 int0edg = 1            ' Interrupt on rising edge of the INT0 pin

 int0ie  = 0            ' External Interrupt 0 Interrupt Enable

 '--------------------------------------------------------------------------------------------------
 ' Timer 0

 TMR0IF  = 0            ' Clear the TMR0 Interrupt Flag bit

 T0ckps0 = 0            ' \
 T0ckps1 = 1            '   Timer0 Prescaler Select bits                      this was for a 1:4
 T0ckps2 = 0            '  /
 t0ckps3 = 0            ' /
 async   = 0            ' The input to the TMR0 counter is synchronized to Fosc/4
 cs0     = 0            ' \
 cs1     = 1            '  Timer0 Clock Source Select
 cs2     = 0            ' /

 t0_en   = 0            ' TMR0 Enabled

 TMR0IE  = 1            ' TMR0 Interrupt enabled

 T0CON0 = %10010000     ' Postscaler is 1:1. Timer0 enabled and set for 16-bit mode

 '--------------------------------------------------------------------------------------------------

 Clear TMR0H            ' Reset Timer0 to 0
 Clear TMR0L

 tmr0_rel = 25212

 Tim0 = TMR0_rel        ' Load Timer 0 offset value

 GIE  = 1               ' Enables all masked interrupts

 '==================================================================================================
 '****************
 '* Main routine *
 '****************

 Main:

 toggle pstrobe
 delayms 500
 toggle pstrobe
 delayms 500

 goto main

 '--------------------------------------------------------------------------------------------------
 ' Setup the program and any peripherals
 ' Input     : None
 ' Output    : None
 ' Notes     : Assign and setup USART1 and USART2 pins
 '

 Proc InitPPS()
    PPS_UnLock()
    RA5PPS  = 0x5   'INT0(RA5) Input to EXT_INT
    RA4PPS  = 0x10  'TX1(RA4) Output from UART1
    U1RXPPS = 0x15  'RX1(RC5) Input to UART1
    RC2PPS  = 0x13  'TX2(RC2) Output from UART2
    U2RXPPS = 0x10  'RX2(RC0) Input to UART2
    PPS_Lock()
 EndProc

 '==================================================================================================
 '--------------------------------------------------------------------------------------------------
 '**** Added by Fuse Configurator ****
 ' Use the Fuses Tab to change these settings

 Config_Start
  FEXTOSC = OFF              ;Oscillator not enable
  RSTOSC = HFINTOSC_64MHZ    ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:
  CLKOUTEN = OFF             ;CLKOUT function is disable
  PR1WAY = OFF               ;PRLOCKED bit can be set and cleared repeatedly
  CSWEN = ON                 ;Writing to NOSC and NDIV is allowe
  FCMEN = ON                 ;Fail-Safe Clock Monitor enable
  FCMENP = ON                ;Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on EXTOSC failur
  FCMENS = ON                ;Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on SOSC failur
  MCLRE = INTMCLR            ;If LVP=0, MCLR pin function is port defined function; If LVP=1, RE3 pin fuction is MCL
  PWRTS = PWRT_OFF           ;PWRT is disable
  MVECEN = OFF               ;Interrupt contoller does not use vector table to prioritze interrupt
  IVT1WAY = ON               ;IVTLOCKED bit can be cleared and set only onc
  LPBOREN = ON               ;Low-Power BOR enable
  BOREN = ON                 ;Brown-out Reset enabled according to SBORE
  BORV = VBOR_1P9            ;Brown-out Reset Voltage (VBOR) set to 1.9
  ZCD = OFF                  ;ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCO
  PPS1WAY = ON               ;PPSLOCKED bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle
  STVREN = ON                ;Stack full/underflow will cause Rese
  LVP = OFF                  ;HV on MCLR/VPP must be used for programmin
  XINST = OFF                ;Extended Instruction Set and Indexed Addressing Mode disable
  WDTCPS = WDTCPS_7          ;Divider ratio 1:409
  WDTE = OFF                 ;WDT Disabled; SWDTEN is ignore
  WDTCWS = WDTCWS_7          ;window always open (100%); software control; keyed access not require
  WDTCCS = SC                ;Software Contro
  BBSIZE = BBSIZE_512        ;Boot Block size is 512 word
  BBEN = OFF                 ;Boot block disable
  SAFEN = OFF                ;SAF disable
  DEBUG = OFF                ;Background Debugger disable
  WRTB = OFF                 ;Boot Block not Write protecte
  WRTC = OFF                 ;Configuration registers not Write protecte
  WRTD = OFF                 ;Data EEPROM not Write protecte
  WRTSAF = OFF               ;SAF not Write Protecte
  WRTAPP = OFF               ;Application Block not write protecte
  CP = OFF                   ;PFM and Data EEPROM code protection disable
 Config_End

 '**** End of Fuse Configurator Settings ****
 '--------------------------------------------------------------------------------------------------

@JonW I should try that calculator to get the correct timing.