News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Still learning - need clarification on Interrupts

Started by Ecoli-557, Dec 14, 2024, 07:05 PM

Previous topic - Next topic

Ecoli-557

Hello Again-
I am trying to get a 'Heartbeat' LED and cannot use Timer0 output to my LED <nutz>.
So, in following the documentation I have what I think will work but the compiler barks at the register bit names.
Such as TMR0IE which is in the register PIR0.  I have tried PIR0_TMR0IE and it barks again.
So, how do I correct the following?
Device = 18F67K40
Declare Xtal = 64
On_Hardware_Interrupt GoTo HB_Flash


'------------  Initialization Here   --------------------------------------------------------------- 
    High Heartbeat                          'Sets Heartbeat OFF 
   
'---------------------------------------------------------------------------------------------------
'       Main Code Here
'---------------------------------------------------------------------------------------------------
    TMR0IP = 1                              'Timer0 has High Priority
    TMR0 = 0                                'Clear TMR0 initially
    TMR0IE = 1                              'Timer0 interrupt enable
    INTCON = 0b10100000                     'Enable global interrupts
    Cls                                     'Clear display

    Print At 1,1, "Hello World"
    Print At 2,1, "LCD is working"
    Print At 3,1, "I am on my way"
    Print At 4,1, "to understanding"   

    Do ' Create an infinite loop
        High Stat1                          'Stat1 ON
        DelayMS 500                         'Wait a while
        Low Stat1                           'Turns OFF Stat1
        DelayMS 500                         'Wait a while
    Loop
   
   
;*******************************************************************************
'---   Heartbeat Interrupt   ---
HB_Flash:
    Context Save                            'Nifty..Save any variables or SFRs before the interrupt starts
    If TMR0IF = 1 Then                      'Timer0 Interrupt Flag
        PORTE.1 = PORTE.1 ^ 1               'Yes. So. Xor PORTE.1
        TMR0IF = 0                          'Clear the TMR0 overflow flag
    EndIf
    Context Restore                         'Restore any variables or SFRs and exit the interrupt     

Ecoli-557

Ha!
Getting used to the SYMBOL needs.
That part has been fixed by:
    Symbol TMR0IP = IPR0.5                  'Timer0 Interrupt Priority bit
    Symbol TMR0IF = PIR0.5                  'Timer0 Interrupt Flag bit
    Symbol TMR0IE = PIE0.5                  'Timer0 Interrupt enable bit

but my Heartbeat LED does not flash.....
On to looking what else is wrong.....

John Lawton

Try defining register bit names if the IDE/compiler doesn't recognise them:

e.g.
Symbol TMR0IE = PIE0.5
Symbol TMR0IP = IPR0.5

John

Ecoli-557

Thanks John, I did figure that out eventually and it does work - just before you wrote <grin>.
I don't seem to be able to get yet how to set up TIMER0 in order to get a Heartbeat indication however.
I have looked at sever other somewhat related posts but nothing yet.

RGV250

Hi,
I am not sure how you got the code to compile as you have not created symbols for Heartbeat or Stat1.

I think you are trying to toggle the bit PORTE.1 so you should use toggle ~
I think this is the correct us PORTE.1 = ~ PORTE.1   

Bob

Ecoli-557

#5
Thanks RGV250, I did not post the whole program, just the most relevant parts.
Here is a bit more:
Device = 18F67K40
Declare Xtal = 64
On_Hardware_Interrupt GoTo HB_Flash

  FEXTOSC = OFF ;Oscillator not enabled
  RSTOSC = HFINTOSC_64MHZ ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1

    Symbol Heartbeat = PORTE.1                        'Heartbeat is a Pin, Active Low
    Symbol Stat1 = PORTE.2                            'Stat1 is a Pin, Active Low   
    Symbol Err = PORTE.3                              'Err is a Pin, Active Low - Error is a reserved word

    Symbol TMR0IP = IPR0.5                  'Timer0 Interrupt Priority bit
    Symbol TMR0IF = PIR0.5                  'Timer0 Interrupt Flag bit
    Symbol TMR0IE = PIE0.5                  'Timer0 Interrupt enable bit
    Symbol Timer0_cValue = $F3CB            ' Set for Timer0 interval at ??ms with a 32768 prescaler and the device operating at 64MHz

    T0CON1 = 0b01111111                     'Timer0 source is HFINTOSC, not syncronized, 32768 prescaler
    $define Timer0_Write16(pValue) '
    TMR0H = pValue.Byte1       '
    TMR0L = pValue.Byte0
    Dim wTimer0 As TMR0L.Word               ' Create a 16-bit SFR from TMR0L\H
    wTimer0 = Timer0_cValue                 ' Set Timer0 value

    TMR0IP = 1                              'Timer0 has High Priority
'    TMR0 = 0                                'Clear TMR0 initially
    TMR0IF = 0                              'Clear the TMR0 overflow flag before enabling interrupt
    TMR0IE = 1                              'Timer0 interrupt enable
    INTCON = 0b10100000                     'Enable global interrupts

'Main code would go here
    Do ' Create an infinite loop
        High Stat1                          'Stat1 ON
        DelayMS 500                         'Wait a while
        Low Stat1                           'Turns OFF Stat1
        DelayMS 500                         'Wait a while
    Loop

Proc Timer0_Read16(), Word
    Result.Byte0 = TMR0L
    Result.Byte1 = TMR0H
EndProc

'---   Heartbeat Interrupt   ---
HB_Flash:
    Context Save                            'Nifty..Save any variables or SFRs before the interrupt starts
    If TMR0IF = 1 Then                      'Timer0 Interrupt Flag
        Toggle Heartbeat                    'Yes. So. Toggle Heartbeat LED
        TMR0IF = 0                          'Clear the TMR0 overflow flag
        Timer0_Write16(Timer0_cValue)       ' Reload Timer0 for the same timing of the next interrupt
    EndIf
    Context Restore                         'Restore any variables or SFRs and exit the interrupt     

This all of the code related to the Heartbeat - I have read and used parts from the Documentation, searched interrupts, Timer0, etc.
It does not offer any errors, so I must be close?
All I need is a 500ms pulse, do I need to load a number each time?
Any insight would be great.

RGV250

Hi,
You will need to pre load the timer to get 500ms, there are programs to calculate it but I am propping up a bar now.
It might flash with what you have but a 16bit timer it might be a long time. You might also need to play with pre/post scalers.

Bob

Ecoli-557

Thanks again RGV250, I will be having my Adult Beverage soon.
Agreed, just need to mess with pre-post scalers to get what I want.
When you think about it and have the notion, point me in the direction of a program to calculate.
Regards!

RGV250

#8
Hi,
Back in the land of the sober :)

I had a look at some old code and I think you will not get a 500ms pulse from the timer as it is too fast. Below is some code I have stripped down and tested in the VSM. As you can see I do a count in the interrupt and then in the main loop toggle the bit when a value is reached.
It is for an Amicus18 18F25K20 but should port over. I would sugeest getting an Amicus board as the Inc file has all the settings for most purposes so one less thing to worry about until the code is working.
It uses Timer 2 as the project used the others for CCP modules.

I have just noticed the comments are for 40mhz xtal where the Amicus.inc uses 64mhz. I will have a look to see what values you need for 500ms.

'****************************************************************
'*  Name    : Lathe Tacho                                       *
'*  Author  : Bobby Garrett                                     *
'*  Notice  : Copyright (c) 2014 Bobby Garrett                  *
'*          : All Rights Reserved                               *
'*  Date    : 27/04/2014                                        *
'*  Version : 1.0                                               *
'*  Notes   : TIMER2 is used for general purpose timing issues  *
'*          :                                                   *
'**************************************************************** 


    Include "Amicus18.inc"
     
        Clear                       'Clear all RAM before we start
     
        T2CON = %00000111   'Turn timer on / PSA of 16:1
        PR2 = 250           '250 and PSA of 16 gives 400uS interrupt with 40mhz xtal

        Dim GP_TIMER_1 As Word
 
'**************************************************************** 
' User defined configuration settings                           *
'****************************************************************     
 
'****************************************************************
' End of user defined settings                                  *
'****************************************************************

'INTERRUPT setup 

'Used for general purpose timer functions
'   PIE1.1 = 1                      'Timer2 = PR2 interrupt enable
'   IPR1.1 = 0                      'Timer2 = PR2 interrupt = LOW PRIORITY
       
        PIE1 = %00000111
        IPR1 = %00000111 
        PIE2 = %00000011
        IPR2 = %00000000   

'Enable priority interrupts   
        RCON.7 = 1
   
'****************************************************************
'* Interrupt service vector initialization                      *
'****************************************************************

On_Hardware_Interrupt GoTo INTERRUPT_ROUTINE  'Point the interrupt handler to the subroutine. 
                                                         
        GoTo OVER_INT 

INTERRUPT_ROUTINE:

        Context Save
     
TIMED_FUNCTIONS:
'This routine is called approx every 400uS
'PR2 = 250 and PSA of 16 gives 400uS interrupt with 40mhz xtal
'Use it to increment counters and compare them for various tasks.
'A count of
'25 =   10mS   (100 / sec) intervals.
'250 =  100mS  (10 / sec) intervals.
'1250 = 500mS  (2 / sec) intervals.
'2500 = 1000mS (1 / sec) intervals.     

        Inc GP_TIMER_1
       
        PIR1.1 = 0

        Context Restore                 'Exit ISR and re-enable interrupts 

'****************************************************************
'* End of Interrupt routines                                    *
'****************************************************************       

OVER_INT:     

'***********************************************
'* Start of Main Code                          *
'***********************************************
START:
        DelayMS 100                     'Wait for the PICmicro to stabilise
        Cls                             'Clear the LCD
       
        INTCON = %11000000      'Turn interrupts on   
           
'***********************************************
'* Main program LOOP                           *
'***********************************************
MAIN_LOOP:
   
        If GP_TIMER_1 >= 1250 Then Toggle PORTB.0 : GP_TIMER_1 = 0

        GoTo MAIN_LOOP                 

Bob

Ecoli-557

Thanks RGV250, 1st, what was the Adult Beverage?
2nd, let me parse through this to see whats what.
Appreciate it.

top204

#10
As Bob has shown, a Special Event Interrupt using a CCP peripheral and a Timer gives excellent timing results. However there are other methods of timing using a single Timer as well, but they are not as accurate with certain time intervals, so below is a code listing for a Timer0 overflow interrupt with a 499.97ms interval on a PIC18F47K40 device operating at 64MHz with its internal oscillator:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A standard program setup for a PIC18F47K40 device operating at 64MHz with its internal oscillator.
' Demonstrate a Timer0 interrupt of an overflow duration of 499.97ms
'
' The code should work on all 18FxxK40 devices.
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F47K40                                       ' Tell the compiler what device to compile for
    Declare Xtal = 64                                       ' Tell the compiler what frequency the device will be operating at (in MHz)
    On_Hardware_Interrupt Goto ISR_Handler                  ' Point the device to the interrupt handler

    Declare Auto_Heap_Strings = On                          ' Set so all String variables will be created after standard variables in RAM
    Declare Auto_Variable_Bank_Cross = On                   ' Set so that all multi-byte variable types will be within the same RAM bank
'
' Setup USART1
'
    Declare Hserial_Baud = 9600
    Declare HRSOut1_Pin  = PORTC.6
    Declare HRSIn1_Pin   = PORTC.7

'------------------------------------------------------------------------------------------------
' Timer0 SFRs and bits for a PIC18FxxK40 device
'
$define Timer0_Int_Bit() PIE0bits_TMR0IE                    ' The interrupt enable/disable bit for Timer0
$define Timer0_Flag() PIR0bits_TMR0IF                       ' Timer0 Flag
$define Timer0_FlagClear()  PIR0bits_TMR0IF = 0             ' Clear the Timer0 interrupt flag
$define Timer0_Start() T0CON0bits_T0EN = 1                  ' Start Timer0
$define Timer0_Stop()  T0CON0bits_T0EN = 0                  ' Stop Timer0
$define Timer0_IntEnable()  Timer0_Int_Bit() = 1            ' Enable a Timer0 interrupt
$define Timer0_IntDisable() Timer0_Int_Bit() = 0            ' Disable a Timer0 interrupt

'---------------------------------------------------------------------------------
' Calculate the value to place into the TMR0L\H registers in order to achieve a certain overflow interrupt rate (in us)
' The calculation will also work for other 16-bit timers
'
    $define Timer0_cFOSC $eval (_xtal / 4)                  ' The fOSC of the microcontroller device (_xtal / 4)
    $define Timer0_cPrescalerValue 128                      ' The prescaler used for the timer (must be the same prescaler as used for the timer's setup)
    $define Timer0_cMicroSeconds 500000                     ' Interrupt rate (in uS). Note exact interrupt timings may not always be possible
    $define Timer0_cTweakValue 0                            ' Holds a tweak value for the timer calculation

    $define Timer0_cValue $eval ((65536 + Timer0_cTweakValue) - ((Timer0_cMicroSeconds / Timer0_cPrescalerValue) * Timer0_cFOSC))

$if Timer0_cPrescalerValue >= Timer0_cMicroSeconds
    $error "Timer0_cPrescalerValue is too large for the value in Timer0_cMicroSeconds"
$endif
$if Timer0_cValue > 65534
    $error "Timer0_cValue is too large for the interrupt duration"
$elseif Timer0_cValue <= 0
    $error "Timer0_cValue is too small for the interrupt duration"
$endif

'------------------------------------------------------------------------------
' Alter the bits for a required Timer0 prescaler on a PIC18FxxK40 device
'
$define Timer0_Prescaler(pPrescaler)'
    $if pPrescaler = 1              '
        T0CON1bits_T0CKPS0 = 0      '
        T0CON1bits_T0CKPS1 = 0      '
        T0CON1bits_T0CKPS2 = 0      '
        T0CON1bits_T0CKPS3 = 0      '
    $elseif pPrescaler = 2          '
        T0CON1bits_T0CKPS0 = 1      '
        T0CON1bits_T0CKPS1 = 0      '
        T0CON1bits_T0CKPS2 = 0      '
        T0CON1bits_T0CKPS3 = 0      '
    $elseif pPrescaler = 4          '
        T0CON1bits_T0CKPS0 = 0      '
        T0CON1bits_T0CKPS1 = 1      '
        T0CON1bits_T0CKPS2 = 0      '
        T0CON1bits_T0CKPS3 = 0      '
    $elseif pPrescaler = 8          '
        T0CON1bits_T0CKPS0 = 1      '
        T0CON1bits_T0CKPS1 = 1      '
        T0CON1bits_T0CKPS2 = 0      '
        T0CON1bits_T0CKPS3 = 0      '
    $elseif pPrescaler = 16         '
        T0CON1bits_T0CKPS0 = 0      '
        T0CON1bits_T0CKPS1 = 0      '
        T0CON1bits_T0CKPS2 = 1      '
        T0CON1bits_T0CKPS3 = 0      '
    $elseif pPrescaler = 32         '
        T0CON1bits_T0CKPS0 = 1      '
        T0CON1bits_T0CKPS1 = 0      '
        T0CON1bits_T0CKPS2 = 1      '
        T0CON1bits_T0CKPS3 = 0      '
    $elseif pPrescaler = 64         '
        T0CON1bits_T0CKPS0 = 0      '
        T0CON1bits_T0CKPS1 = 1      '
        T0CON1bits_T0CKPS2 = 1      '
        T0CON1bits_T0CKPS3 = 0      '
    $elseif pPrescaler = 128        '
        T0CON1bits_T0CKPS0 = 1      '
        T0CON1bits_T0CKPS1 = 1      '
        T0CON1bits_T0CKPS2 = 1      '
        T0CON1bits_T0CKPS3 = 0      '
    $elseif pPrescaler = 256        '
        T0CON1bits_T0CKPS0 = 0      '
        T0CON1bits_T0CKPS1 = 0      '
        T0CON1bits_T0CKPS2 = 0      '
        T0CON1bits_T0CKPS3 = 1      '
    $elseif pPrescaler = 512        '
        T0CON1bits_T0CKPS0 = 1      '
        T0CON1bits_T0CKPS1 = 0      '
        T0CON1bits_T0CKPS2 = 0      '
        T0CON1bits_T0CKPS3 = 1      '
    $elseif pPrescaler = 1024       '
        T0CON1bits_T0CKPS0 = 0      '
        T0CON1bits_T0CKPS1 = 1      '
        T0CON1bits_T0CKPS2 = 0      '
        T0CON1bits_T0CKPS3 = 1      '
    $elseif pPrescaler = 2048       '
        T0CON1bits_T0CKPS0 = 1      '
        T0CON1bits_T0CKPS1 = 1      '
        T0CON1bits_T0CKPS2 = 0      '
        T0CON1bits_T0CKPS3 = 1      '
    $elseif pPrescaler = 4096       '
        T0CON1bits_T0CKPS0 = 0      '
        T0CON1bits_T0CKPS1 = 0      '
        T0CON1bits_T0CKPS2 = 1      '
        T0CON1bits_T0CKPS3 = 1      '
    $elseif pPrescaler = 8192       '
        T0CON1bits_T0CKPS0 = 1      '
        T0CON1bits_T0CKPS1 = 0      '
        T0CON1bits_T0CKPS2 = 1      '
        T0CON1bits_T0CKPS3 = 1      '
    $elseif pPrescaler = 16384      '
        T0CON1bits_T0CKPS0 = 0      '
        T0CON1bits_T0CKPS1 = 1      '
        T0CON1bits_T0CKPS2 = 1      '
        T0CON1bits_T0CKPS3 = 1      '
    $elseif pPrescaler = 32768      '
        T0CON1bits_T0CKPS0 = 1      '
        T0CON1bits_T0CKPS1 = 1      '
        T0CON1bits_T0CKPS2 = 1      '
        T0CON1bits_T0CKPS3 = 1      '
    $else                           '
        $error "Unknown Timer0 prescaler value. Supported values for this device are 1 to 32768 in powers of 2" '
    $endif

'------------------------------------------------------------------------------
' General Interrupt SFRs and bits for a PIC18FxxK40 device
'
$define Global_IntEnable() INTCONbits_GIE = 1                   ' Enable global interrupts
$define Global_IntDisable() INTCONbits_GIE = 0                  ' Disable global interrupts
$define Periph_IntEnable() INTCONbits_PEIE = 1                  ' Enable peripheral interrupts
$define Periph_IntDisable() INTCONbits_PEIE = 0                 ' Enable peripheral interrupts
'
' Create any global variables and constants here
'
    Dim wTimer0_SFR As TMR0L.Word                               ' Combine TMR0L\H into a 16-bit SFR

'------------------------------------------------------------------------------
' The Main program starts here
'
Main:
    Setup()                                                     ' Setup the program and any peripherals
    HRsoutLn "Start"                                            ' Transmit to a serial terminal to make sure things are operating
'
' The main code loop can start here
'
    Do
    '
    ' Code within, if required...
    '
    Loop

'------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    Timer0_Init()                                               ' Initialise Timer0
    Timer0_Start()                                              ' Start Timer0
    Timer0_IntEnable()                                          ' Enable a Timer0 interrupt
    Global_IntEnable()                                          ' Enable Global interrupts
EndProc

'--------------------------------------------------------------------------
' Initialise Timer0
' Input     : None
' Output    : None
' Notes     : Timer0 configured for 16-bit
'           : Does not enable Timer0
'
Proc Timer0_Init()
    wTimer0_SFR = Timer0_cValue                                 ' Set TMR0L\H for the interrupt duration
    Timer0_FlagClear()                                          ' Clear the Timer0 Interrupt flag
    T0CON0 = %00010000                                          ' Postscaler 1:1. Timer0 disabled. 16-bit operation
    T0CON1 = %01010010                                          ' fOSC/4. Prescaler 1:1. Not synchronised
    Timer0_Prescaler(Timer0_cPrescalerValue)                    ' Adjust Timer0 prescaler to the value used in the above calculation meta-macros
EndProc

'------------------------------------------------------------------------------
' Interrupt handler
' Input     : None
' Output    : None
' Notes     : Interrupts on a Timer0 overflow
'
ISR_Handler:
    Context Save                                                ' Save any used compiler system variables and important SFRs

    If Timer0_Int_Bit() = 1 Then                                ' Is a Timer0 interrupt enabled?
        If Timer0_Flag() = 1 Then                               ' Yes. So has Timer0 overflowed?
            '
            ' Yes. So create code here when Timer0 overflows
            '
            wTimer0_SFR = Timer0_cValue                         ' Set TMR0L\H for the interrupt duration
            Timer0_FlagClear()                                  ' Clear the Timer0 interrupt flag
        EndIf
    EndIf

    Context Restore                                             ' Restore any used compiler system variables and important SFRs, and exit the interrupt

'------------------------------------------------------------------------------
' Setup the config fuses to use the internal oscillator at 64MHz on PIC18FxxK40 devices.
' With pins RA6 and RA7 as general purpose I/O.
'
Config_Start
    RSTOSC = HFINTOSC_64MHZ         ' HFINTOSC with HFFRQ = 64MHz and CDIV = 1:1
    FEXTOSC = Off                   ' External Oscillator not enabled
    WDTE = Off                      ' Watchdog Timer disabled
    CLKOUTEN = Off                  ' CLKOUT function is disabled
    CSWEN = On                      ' Writing to NOSC and NDIV is allowed
    FCMEN = Off                     ' Fail-Safe Clock Monitor disabled
    MCLRE = EXTMCLR                 ' If LVP = 0, MCLR pin is MCLR. If LVP = 1. RE3 pin function is MCLR
    PWRTE = On                      ' Power up timer enabled
    LPBOREN = Off                   ' ULPBOR disabled
    BOREN = Off                     ' Brown-out disabled
    BORV = VBOR_245                 ' Brown-out Reset Voltage (VBOR) set to 2.45V
    ZCD = Off                       ' ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                   ' PPSLOCK bit can be set and cleared repeatedly (After the unlock sequence)
    STVREN = Off                    ' Stack full/underflow will not cause Reset
    Debug = Off                     ' Background debugger disabled
    XINST = Off                     ' Extended Instruction Set and Indexed Addressing Mode disabled
    SCANE = Off                     ' Scanner module is Not available for use. SCANMD bit is ignored
    LVP = Off                       ' Low Voltage programming disabled
    WDTCPS = WDTCPS_2               ' Watchdog Divider Ratio 1:128 (4 milliseconds)
    WDTCWS = WDTCWS_7               ' Window always open (100%). Software control. Keyed access not required
    WDTCCS = LFINTOSC               ' WDT reference clock is the 31.2kHz HFINTOSC output
    WRT0 = Off                      ' Block 0 (000800-001FFF) not write-protected
    WRT1 = Off                      ' Block 1 (002000-003FFF) not write-protected
    WRTC = Off                      ' Configuration registers (300000-30000B) not write-protected
    WRTB = Off                      ' Boot Block (000000-0007FF) write-protected
    WRTD = Off                      ' Data EEPROM not write-protected
    CP = Off                        ' User NVM code protection disabled
    CPD = Off                       ' Data NVM code protection disabled
    EBTR0 = Off                     ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1 = Off                     ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTRB = Off                     ' Boot Block (000000-0007FF) not protected from table reads executed in other blocks
Config_End

The code should run an all 18FxxK40 devices.

The 499.97ms is the most accurate I can achieve with the single timer over-flow method operating on a device running at 64MHz. However, other overflow times that are a multiple of 4 can be tried with the calculation, then a variable counter method within the interrupt handler to give the desired time.