News:

;) This forum is the property of Proton software developers

Main Menu

Timer1 Gated Clock Source Question?

Started by Craig, Oct 06, 2026, 06:06 PM

Previous topic - Next topic

Craig

Hi I am busy with an Interrupt on Timer1 Gated Running at MFINTOSC @ 500Khz, I see in the data sheet Page 45 that it can run at 31.25Khz. I have looked on Google and the data sheet but, cannot seem to get a straight answer on this. I See that the Default setting on timer2 is set to 31.25Khz on MFINTOSC and Timer1 MFINTOSC Seems to be fixed at 500Khz?
I did read somewhere that you can divide this down by 16 but, I don't think this is correct as a Pre-scaler of 8 is the highest on timer1 that I can Find?

I need to find a way to run this a bit slower as it is monitoring Led Pulse from a peripheral device which comes in at 1 Pulse per 2 Seconds, 2 Pulses per 2 Seconds 3 Pulses per 2 Seconds, 4 Pulses per 2 Seconds then there are intermediate pulses which can either be mixed or slower or more pulses depending on the condition of the peripheral. With the Timer1 Gated interrupt running at MFINTOSC @ 500Khz with a 1:8 Pre-scaler it is catching most of them but, it is also misreading some of them. I think by lowering it to 31.25Khz will work well.

My whole system is running at 64Mhz Internal Cristal on a Pic 18F47Q10 with a separate RX2 Uart Ring Buffer Interrupt running off the 64Mhz Xtal that is why I have used the MFINTOSC running in the Background to monitor the Timer1 Gated Interrupt.

My Question is it possible to set the MFINTOSC to run at 31.25Khz? and is this the best approach to monitor this LED which has long delays?

Proc Setup()
  Osc_64MHz()                                               ' Set the internal oscillator to 64MHz
  UART2_Setup()                                             ' Setup and open USART2
  INTERRUPT_Initialize()                                    ' Enable Global & Peripheral Interrupts         
  TMR1_Initialize()                                         ' Setup the Timer1 Gate Interrupt
EndProc

'--------------------------------------------------------------------
' Set the PIC18F47Q10 device to 64MHz with the internal oscillator
'--------------------------------------------------------------------
Proc Osc_64MHz()
    OSCCON1 = $60
    OSCFREQ = $080
EndProc

' =================================================
' 2. BAUD RATE CONFIGURATION (115200 @ 64MHz)
' =================================================
Proc UART2_Setup()
  TRISBbits_TRISB6 = 0                                      ' Usart2-Tx Output
  TRISBbits_TRISB7 = 1                                      ' Usart2-Rx Input
  ANSELBbits_ANSELB6 = 0                                    ' All_Digital
  ANSELBbits_ANSELB7 = 0                                    ' All_Digital
  TX2STAbits_BRGH = 1                                       ' High-Speed Asynchronous mode
  BAUD2CONbits_BRG16 = 1                                    ' Use 16-bit Baud Rate Generator
  SP2BRGH = 0x00                                            ' High byte - Load calculated divisor value (138 = 0x008A) Set to 115200 Baud
  SP2BRGL = 138                                             ' Low byte Set to 115200 Baud = 138 or (hex 0x8A)
  TX2STAbits_SYNC = 0                                       ' Asynchronous Mode
  RC2STAbits_SPEN = 1                                       ' Enable Serial Port
  RC2STAbits_CREN = 1                                       ' Enable Continuous Receive
EndProc

'--------------------------------------------------------------------------------
Proc INTERRUPT_Initialize()                                 
  PIE3bits_RC2IE = 1                                       ' Enable Eusart2 RX Receive Bit
  INTCONbits_IPEN = 1                                      ' Enable interrupt priority levels
  INTCONbits_GIEH = 1                                      ' Enable all High Priority Global Interrupts (INTCONbits_GIEL = 1 "For Low Priority")
  INTCONbits_PEIE = 1                                      ' Enable the Peripheral Interrupts
EndProc

'================================================================================
Proc TMR1_Initialize()
  T1GCONbits_GE = 1                                         ' Timer Counting is Controlled by the Timer Gate Function - Enable the Gate 1 Timer
  T1GCONbits_GPOL = 1                                       ' Active High - Counts when Pulse is High coming from the Status LED on PORTB.5 (T1GPPS)
  T1GCONbits_GGO_DONE = 1                                   ' Timer acquistion is ready
  T1GCONbits_GSPM = 1                                       ' Timer Gate Single Pulse Mode is Enabled and is Controlling Timer gate = 1)
  TMR1CLK = 0b00000101                                      ' MFINTOSC @ 500KHz (Each Rising Edge High Pulse is 360.000us_2.778Khz)
  IPR5bits_TMR1GIP = 1                                      ' TMR1GIP - TMR1 Gate Interrupt to High Priority
  PIR5bits_TMR1GIF = 0                                      ' Clearing Gate If Interrupt Flag before Enabling the Interrupt
  PIE5bits_TMR1GIE = 1                                      ' Enable TMR1 Gate Interrupt
  T1CON = 0b00110111                                        ' Timer1 prescaler is 1:8, Timer1 enabled, 16-bit read, not synchronized
EndProc     

All input is very much appreciated.

Regards
Craig

RGV250

Hi,
That seems an awful device to set up unless you need it. I wonder if you want it to be slower could TMR1CK be 100 instead of 101 as that is then LFINTOSC.

Bob

Craig

Hi Bob

Thanks Very much for your input Bob,I will run it on the LFINTOSC and see the Accuracy, Microchip's Data Sheet Stinks with the Explanation on the MFINTOSC

Regards
Craig

trastikata

Quote from: Craig on Oct 06, 2026, 06:06 PMMy Question is it possible to set the MFINTOSC to run at 31.25Khz? and is this the best approach to monitor this LED which has long delays?

MFINTOSC is set to 500 KHz and it is dynamically derived from the HFINTOSC, whatever the HFINTOSC value currently is.

The 31.25 is actually the MFINTOSC/16 and it is not available as clock source for Timer1,3,5 (Page 305), only the 500 KHz without post scaller. 

Timer2,4,6 have it available the MFINTOSC/16 i.e. 31.25 KHz as their clock source, it is a 8b timer though.

But if you look closer at the clock sources for Timer 1 you can see you can select the Timer 3,5 overflow as clock, since those timers can be set to use the MFINTOSC i.e. 500KHz as clock, then you can easily have any frequency, lower than 500KHz, as clock source for Timer1.

Sophie_Bennett

Quote from: trastikata on Oct 07, 2026, 05:59 PM
Quote from: Craig on Oct 06, 2026, 06:06 PMMy Question is it possible to set the MFINTOSC to run at 31.25Khz? and is this the best approach to monitor this LED which has long delays?

MFINTOSC is set to 500 KHz and it is dynamically derived from the HFINTOSC, whatever the HFINTOSC value currently is.

The 31.25 is actually the MFINTOSC/16 and it is not available as clock source for Timer1,3,5 (Page 305), only the 500 KHz without post scaller. 

Timer2,4,6 have it available the MFINTOSC/16 i.e. 31.25 KHz as their clock source, it is a 8b timer though.

But if you look closer at the clock sources for Timer 1 you can see you can select the Timer 3,5 overflow as clock, since those timers can be set to use the MFINTOSC i.e. 500KHz as clock, then you can easily have any frequency, lower than 500KHz, as clock source for Timer1.


ahh yeah that makes sense!) using the timer overflow as the clock source gives you way more flexibility than i first thought:'(

Craig

#5
Thanks Dyanko

That is a very neat way of using timer 3 or 5 to get customizable frequencies.
Just a thought is the above post not a Bot?

Regards
Craig

top204

#6
If it is external pulses that are being counted, why not setup a standard timer overflow interrupt to count milliseconds, or 10s, or 100s of milliseconds, in a large enough variable, and use an IOC (Interrupt On Change), or INTx, so that the pulse on a pin will trigger an interrupt, and then count how many milliseconds have passed from the last pulse, and set a flag to tell the main program loop that a pulse has been detected, or count the pulses within a certain time window.

Then once the pulse is dealt with in the main program, the millisecond counter is reset, ready for the next incoming pulse, and the value held in the milliseconds variable will tell you how long it was since the last pulse. Or count how long the pulse lasted if the IOC is changed to the reverse-state, and the next pulse will sample the 32-bit millisecond timer.

It is not blocking, because if a pulse is not present, the main program goes about its business, and when a pulse is detected, the code within the interrupt can take care of things. All the main program has to do is reset a flag to state that it knows about the pulse, and awaits the next one.

Many years ago, I wrote a slow pulse counter for a PIC18F25K20 device, that you may be able to adapted for your requirement and device. It is listed below:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Very Slow Pulse Rate Counter and display using a compare special event and INT0 interrupt.
' The SFRs are set for a PIC18F25K20 device, operating at 64MHz using its internal oscillator.
' If other 18F devices are to be used, change the configs, SFRs, and bits to suit.
'
' Written by Les Johnson for the Popsitron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook.
'
    Device = 18F25K20                                                   ' 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 to the interrupt handler
    Declare Float_Display_Type = Fast                                   ' Use the compiler's faster floating point display routine
    Declare Auto_Heap_Arrays = On                                       ' Make all arrays "Heap" types, so they always get placed after standard variables
    Declare Auto_Heap_Strings = On                                      ' Make all Strings "Heap" types, so they always get placed after standard variables
    Declare Auto_Variable_Bank_Cross = On                               ' Make sure all multi-byte variables remain within a single RAM bank
'
' Set the USART1 pins for an Amicus8 board
'
    Declare Hserial1_Baud = 9600                                        ' Set USART1 Baud rate to 9600
    Declare HSerout1_Pin  = PORTC.6                                     ' Set the TX pin for USART1
    Declare HSerin1_Pin   = PORTC.7                                     ' Set the RX pin for USART1

$ifndef False
   $define False 0
$endif
$ifndef True
    $define True 1
$endif
'
' Create any global variables, constants and aliases here
'
    Dim tCaptureComplete As Bit                                         ' True if a capture has occured (must be reset in the main program)
    Dim wIntPulseRate As Word Access                                    ' Pulse rate counter used within the interrupt
    Dim wPulseRate    As Word Access                                    ' Pulse rate count for the main program
    Dim wMilliSeconds As Word Access                                    ' Millisecond counter used for a capture window

'------------------------------------------------------------------------------------------------
' General Meta-Macros for an interrupt on a PIC18F25K20 device
'
$define Periph_Int_Enable()  INTCONbits_PEIE = 1                        ' Enable peripheral interrupts
$define Periph_Int_Disable() INTCONbits_PEIE = 0                        ' Disable peripheral interrupts
$define Global_Int_Enable()  INTCONbits_GIE = 1                         ' Enable global interrupts
$define Global_Int_Disable() INTCONbits_GIE = 0                         ' Disable global interrupts

'------------------------------------------------------------------------------------------------
' Meta-Macros for Timer3 on a PIC18F25K20 device
'
$define Timer3_IntBit PIE2bits_TMR3IE                                   ' The SFR and bit used to enable/disable a Timer3 interrupt
$define Timer3_IntFlag PIR2bits_TMR3IF                                  ' The SFR and bit used to clear a Timer3 interrupt
$define Timer3_ClearFlag() Timer3_IntFlag = 0                           ' Clear the Timer3 interrupt flag
$define Timer3_Int_Enable() PIE2bits_TMR3IE = 1                         ' Enable a Timer3 interrupt
$define Timer3_Int_Disable() PIE2bits_TMR3IE = 0                        ' Disable a Timer3 interrupt
$define Timer3_Enable() T3CONbits_TMR3ON = 1                            ' Enable Timer3
$define Timer3_Disable() T3CONbits_TMR3ON = 0                           ' Disable Timer3
$define Timer3_RD16_Enable() T3CONbits_T3RD16 = 1                       ' Enable the Timer RD16
$define Timer3_RD16_Disable() T3CONbits_T3RD16 = 0                      ' Disable the Timer RD16

'------------------------------------------------------------------------------------------------
' The main program starts here
' Detect pulses and count how many of them there were on the INT0 pin
'
Main:
    Setup()                                                             ' Setup the program and any peripherals
'
' Create a loop to display the pulse rate on the serial terminal
'
    Do                                                                  ' Create a loop
        If tCaptureComplete = True Then                                 ' Is there a pulse rate ready?
            HRSOutLn Dec wPulseRate                                     ' Yes. So Display it
            tCaptureComplete = False                                    ' Reset the event flag
        EndIf
    Loop

'------------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    Dim wCCPR2_SFR As CCPR2L.Word                                       ' Combine CCPR2L\H into a 16-bit register
    Osc_64MHz()                                                         ' Set the microcontroller for internal 64MHz operation

    CCP2CON = $0B                                                       ' Compare mode: trigger special event, reset timer, start A/D conversion on CCP2 match (tCCP2IF bit is set)
'
' Setup Timer3
'
    T3CON = %11111100                                                   ' T3_16BIT_RW. T3_PS_1_8. T3_SYNC_EXT_OFF. T3_SOURCE_INT. T3_SOURCE_CCP
    TMR3H = 0
    TMR3L = 0
    Timer3_ClearFlag()                                                  ' Clear the Timer3 interrupt flag
    Timer3_Int_Enable()                                                 ' Enable a Timer3 interrupt
    Timer3_Enable()                                                     ' Enable Timer3

$define cPrescalerValue 8                                               ' Alter this to match the prescaler parameter above. i.e. 4 for T3_PS_1_4, 8 for T3_PS_1_8
$define cMicroSeconds 1000                                              ' Interrupt rate (in uS)
'
' Calculate the value to place into the CCPRx register in order to achieve a certain interrupt rate (in us)
'
    $define cCCPR_Value $eval (cMicroSeconds / cPrescalerValue) * (_xtal / 4)

$if cCCPR_Value > 65535
    $error "Value too large for interrupt duration"
$elseif cCCPR_Value = 0
    $error "Value too small for interrupt duration"
$endif

    wCCPR2_SFR = cCCPR_Value                                            ' Load CCPR2L\H with the value to trigger an interrupt at a certain duration
    PIE2bits_CCP2IE = 1                                                 ' Enable the Special Event Interrupt on CCP2
    wMilliSeconds = 0                                                   ' Clear the millisecond counter
    tCaptureComplete = False                                            ' Clear the event flag
    PinInput PORTB.0                                                    ' Make sure the INT0 pin is an input
    INTCON2bits_INTEDG0 = 1                                             ' INT0 triggers on a rising edge
    INTCONbits_INT0IE = 1                                               ' Enable an INT0 interrupt
    Periph_Int_Enable                                                   ' Enable peripheral interrupts
    Global_Int_Enable()                                                 ' Enable global interrupts
EndProc

'------------------------------------------------------------------------------------------------
' Set the microcontroller for internal 64MHz operation
' Input     : None
' Output    : None
' Notes     : For use with a PIC18F25K20 device
'
Proc Osc_64MHz()
    OSCCON = %01110000                                                  ' 16MHz HFINTOSC
    OSCTUNE = %01000000                                                 ' PLL enabled
    DelayMS 100                                                         ' Give time for clock stability
EndProc

'------------------------------------------------------------------------------------------------
' Interrupt handler
' Operate a time window for pulse samples
' Count pulses using an INT0 event
' Input     : None
' Output    : wPulseRate holds the pulse rate value
'           : tCaptureComplete is true if a capture is complete
' Notes     : Change the value compared with wMilliSeconds to alter the time gate period
'
ISR_Handler:
    Context Save
'
' Service a special event interrupt every x milliseconds
'
    If PIR2bits_CCP2IF = 1 Then                                         ' Was it a Compare Special event on CCP2 that triggered the interrupt?
        Inc wMilliSeconds                                               ' Yes. So increment the milliseconds counter
        If wMilliSeconds >= 1000 Then                                   ' Have we reached the end of the time window?
            wMilliSeconds = 0                                           ' Yes. So clear the millisecond counter
            wPulseRate = wIntPulseRate                                  ' Transfer the pulse count to its working variable
            wIntPulseRate = 0                                           ' Reset the pulse count variable
            tCaptureComplete = True                                     ' Signal that a pulse rate capture is complete
        EndIf
        PIR2bits_CCP2IF = 0                                             ' Clear the interrupt flag
    EndIf
'
' Service an INT0 external interrupt
'
    If INTCONbits_INT0IF = 1 Then                                       ' Was it an INT0 event that triggered the interrupt?
        If tCaptureComplete = False Then                                ' Yes. So is the event flag false?
            Inc wIntPulseRate                                           ' Yes. So increment the pulse counter
        EndIf
        INTCONbits_INT0IF = 0                                           ' Clear the INT0 flag
    EndIf

    Context Restore                                                     ' Exit the interrupt

'------------------------------------------------------------------------------------------------
' Setup the fuses to use the internal oscillator on a PIC18F25K20 device.
' OSC pins RA6 and RA7 are general purpose I/O.
'
Config_Start
    FOSC = INTIO67                                                      ' Internal oscillator block. General purpose I/O on RA6 and RA7
    FCMEN = Off                                                         ' Fail-Safe Clock Monitor disabled
    IESO = Off                                                          ' Internal/External Oscillator Switchover mode disabled
    PWRT = Off                                                          ' Power-up Timer disabled
    BOREN = SBORDIS                                                     ' Brown-out Reset enabled in hardware only (SBOREN is disabled)
    BORV = 18                                                           ' Brown Out Reset Voltage 1.8 V nominal
    WDTEN = Off                                                         ' Watchdog Timer controlled by SWDTEN bit of the WDTCON register
    WDTPS = 128                                                         ' Watchdog Timer Postscale Select 1:128
    CCP2MX = PORTC                                                      ' CCP2 input/output is multiplexed with RC1
    PBADEN = On                                                         ' PORTB<4:0> pins are configured as analogue input channels on Reset
    LPT1OSC = Off                                                       ' Timer1 configured for higher power operation
    HFOFST = On                                                         ' HFINTOSC starts clocking the CPU without waiting for the oscillator to stablise
    MCLRE = On                                                          ' MCLR pin enabled. RE3 input pin disabled
    STVREN = On                                                         ' Stack full/underflow will cause Reset
    LVP = On                                                            ' Single-Supply ICSP enabled
    XINST = Off                                                         ' Extended Instruction Set disabled
    Debug = Off                                                         ' Background debugger disabled, RB6 and RB7 configured as general purpose I/O pins
    Cp0 = Off                                                           ' Block 0 (000800-001FFF) not code-protected
    CP1 = Off                                                           ' Block 1 (002000-003FFF) not code-protected
    CP2 = Off                                                           ' Block 2 (004000-005FFF) not code-protected
    CP3 = Off                                                           ' Block 3 (006000-007FFF) not code-protected
    CPB = Off                                                           ' Boot block (000000-0007FF) not code-protected
    CPD = Off                                                           ' Data EEPROM not code-protected
    WRT0 = Off                                                          ' Block 0 (000800-001FFF) not write-protected
    WRT1 = Off                                                          ' Block 1 (002000-003FFF) not write-protected
    WRT2 = Off                                                          ' Block 2 (004000-005FFF) not write-protected
    WRT3 = Off                                                          ' Block 3 (006000-007FFF) not write-protected
    WRTC = Off                                                          ' Configuration registers (300000-3000FF) not write-protected
    WRTB = Off                                                          ' Boot Block (000000-0007FF) not write-protected
    WRTD = Off                                                          ' Data EEPROM not write-protected
    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
    EBTR2 = Off                                                         ' Block 2 (004000-005FFF) not protected from table reads executed in other blocks
    EBTR3 = Off                                                         ' Block 3 (006000-007FFF) 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

Regards
Les

▲