I'm following a Microchip document including a section "Using Timer 1 to Measure Frequency. It uses the method of triggering the gate with the input signal to measure the number of clock pulses that occur between input pulses.
I probably don't have the interrupts set up properly - I never get the gate interrupt that triggers reading the timer count that can then be converted to a frequency. There are many registers to set up but I believe I've translated from the 'bare metal" section of the above document, which was done with a different chip than the 18F25k22 that I'm using.
This is my translation of the different registers.
Code: Select all
/* Timer controlled by gate function */
T1GCONbits.GE = 1;
* T1GCON.7 = 1 *
/* Timer gate toggle mode enabled */
T1GCONbits.GTM = 1;
* T1GCON.5 = 1 *
/* Timer gate active high */
T1GCONbits.GPOL = 1;
* T1GCON.6 = 1 *
/* Timer acquistion is ready */
T1GCONbits.GGO_nDONE = 1;
* T1GCON.3 =1 *
/* Timer gate single pulse mode enabled */
T1GCONbits.T1GSPM = 1;
* T1GCON.4 = 1 *
/* Source Clock FOSC/4 */
T1CLKbits.CS = 0x1;
* T1CON.7 = 0 *
* T1CON.6 = 0 *
/* Clearing gate IF flag before enabling the interrupt */
PIR5bits.TMR1GIF = 0;
* PIR3.0 = 0 *
/* Enabling TMR1 gate interrupt */
PIE5bits.TMR1GIE = 1;
* PIE3.0 = 1 *
/* CLK Prescaler 1:8 */
T1CONbits.CKPS = 0x3;
* T1CON.5 = 1 *
* T1CON.4 = 1 *
/* TMR1 enabled */
T1CONbits.ON = 1;
* T1CON.0 = 1 *
}
-----------------------------------
Enable interurupts
/* Enable the Global Interrupts */
INTCONbits.GIE = 1;
* INTCON.7 = 1 *
/* Enable the Peripheral Interrupts */
INTCONbits.PEIE = 1;
* INTCON.6 = 1 *
--------------------------------
When the timer finishes measuring the frequency of the external signal, an interrupt will occur in the interrupt manager. It will check for the source of the interrupt and, if it is from TMR1 gate, will call a handler function. The following function is used:
/* Interrupt handler function */
static void __interrupt() INTERRUPT_InterruptManager(void)
{
// interrupt handler
if(INTCONbits.PEIE == 1)
{
if(PIE5bits.TMR1GIE == 1 && PIR5bits.TMR1GIF == 1)
{
TMR1_GATE_ISR();
}
else
{
//Unhandled Interrupt
}
}
else
{
//Unhandled Interrupt
}
}
*******
INTERRUPT OnTimer()
IF INTCON.6 = 1 then
if PIE3.0 = 1 AND PIR3.0 = 1 THEN
TMR1_GATE_ISR
end if
END IF
end interrupt
*******
The handler needs to clear the Interrupt flag, read the counted value and reset it afterward, and re-enable the timer gate control for a new acquisition. The following function is used:
COPY/* TMR1 gate ISR function */
static void TMR1_GATE_ISR(void)
{
volatile uint16_t value = 0;
/* Clearing gate IF flag */
PIR5bits.TMR1GIF = 0;
/* Read TMR1 value */
value = TMR1_readTimer();
/* Reset the counted value */
TMR1_writeTimer(0);
/* Prepare for next read */
T1GCONbits.GGO_nDONE = 1;
}
******************
SUB TMR1_GATE_ISR()
PIR3.0 = 0
VALUE.H = TMR1H
VALUE.L = TMR1L
TMR1H = 0
TMR1L = 0
T1GCON.3 = 1
*************
static uint16_t TMR1_readTimer(void)
{
/* Return TMR1 value */
return ((uint16_t)TMR1H << 8) | TMR1L;
}
static void TMR1_writeTimer(uint16_t timerValue)
{
/* Write TMR1H value */
TMR1H = timerValue >> 8;
/* Write TMR1L value */
TMR1L = timerValue;
}
Here's my Swordfish code. My input is PortB.5. LED3 should flash on an interrupt but never does. LED4 mirrors the status of PortB.5 to show there is an intput (which is a square wave) and it is flashing as expected.
Code: Select all
Device = 18f25k22
Clock = 20
Config 'for K-series device
FOSC = HSHP ,'HS oscillator (high power > 16 MHz)
PLLCFG = Off ,'Oscillator used directly
PRICLKEN = Off ,'Primary clock can be disabled by software
FCMEN = Off ,'Fail-Safe Clock Monitor disabled
IESO = Off ,'Oscillator Switchover mode disabled
'PWRTEN = Off ,'Power up timer disabled
PWRTEN = on ,'Power up timer enabled
BOREN = Off ,'Brown-out Reset disabled in hardware and software
'BOREN = on ,'Brown-out Reset enabled
BORV = 285 ,'VBOR set to 2.85 V nominal
WDTEN = Off ,'Watch dog timer is always disabled. SWDTEN has no effect.
WDTPS = 256 ,'1:256
PBADEN = Off ,'PORTB<5:0> pins are configured as digital I/O on Reset
HFOFST = Off ,'HFINTOSC output and ready status are delayed by the oscillator stable status
MCLRE = EXTMCLR ,'MCLR pin enabled, RE3 input pin disabled
STVREN = On ,'Stack full/underflow will cause Reset
LVP = On ,'Single-Supply ICSP enabled if MCLRE is also 1
'LVP = Off ,'Single-Supply ICSP disabled
XINST = Off ,'Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
Debug = Off'Disabled
Include "utils.bas"
Include "usart.bas"
Include "convert.bas"
Include "math.bas"
Const LEDon = 0
Const LEDoff = 1
Const Pressed = 0
Const NotPressed = 1
Dim LED1 As PORTA.5
Dim LED2 As PORTB.3
Dim LED3 As PORTC.0
Dim LED4 As PORTA.3
' Dim S1 As PORTB.5
Dim S2 As PORTB.4
Dim TMR1Gate As PORTB.5
Dim Counter As Word
Sub TMR1_GATE_ISR()
PIR3.0 = 0
Counter.Byte1 = TMR1H
Counter.byte0 = TMR1L
TMR1H = 0
TMR1L = 0
T1GCON.3 = 1
USART.write ("Counter = ", DecToStr(Counter), 13, 10)
Toggle (LED3)
End Sub
Interrupt OnTimer()
If INTCON.6 = 1 Then
If PIE3.0 = 1 And PIR3.0 = 1 Then
TMR1_GATE_ISR
End If
End If
End Interrupt
SetAllDigital
T1CON.0 = 1
USART.SetBaudrate(br115200)
Input(TMR1Gate)
Output(LED1)
Output(LED2)
Output(LED3)
Output(LED4)
LED1 = LEDoff
LED2 = LEDoff
LED3 = LEDoff
LED4 = LEDoff
LED1 = LEDon
USART.write ("yeah, what's it to you?", 13, 10)
TMR1 = 0
While 1 = 1
If PORTB.5 = 1 Then
LED4 = LEDon
Else
LED4 = LEDoff
End If
USART.write (DecToStr(TMR1)," ", DecToStr(PIR3.0),13, 10)
' USART.write(DecToStr(PIR3.0), 13, 10)
Wend
Jon