CCP2 Capture - where am I going wrong?
Moderators: David Barker, Jerry Messina
-
- Posts: 219
- Joined: Wed Sep 11, 2013 1:27 pm
- Location: Chesterfield
CCP2 Capture - where am I going wrong?
I'm trying to use the capture function of the CCP2 module on the PIC18F26K22 and I'm struggling! I've used CCP1 on the 14K22 before without problem but I can't seem to get any interrupts generated with this new setup.
Has anyone used this before and noticed anything to keep an eye out for?
I've done the following:
In Config, set CCP2MX = PORTB3.
Defined CCP2IE = PIE2.0 and CCP2IF = PIR2.0 and initialised these to 1/0 respectively.
Set all inputs as analogue and done Input(PORTB.3).
Set CCP2CON = %00000100, T3CON = 0 and T1CON = %00110010.
And finally done Enable(OnInt)
I've stripped the ISR down to just setting a flag when it sees a CCP2IF interrupt but that flag never gets set! I've confirmed there is a pulse train coming in - I have an LED available which I set to be the inverse of PORTB.3 and that flashes as expected.
Any ideas at all why I'm not getting this interrupt? From what I can see (and this works on other code) I don't need to set PEIE as Swordfish works will all interrupts high priority so GEIE enables everything. Not that this has stopped me trying this and numerous other things!
This really is one of those things that should take 2 minutes but has now taken over 3 hours...
Has anyone used this before and noticed anything to keep an eye out for?
I've done the following:
In Config, set CCP2MX = PORTB3.
Defined CCP2IE = PIE2.0 and CCP2IF = PIR2.0 and initialised these to 1/0 respectively.
Set all inputs as analogue and done Input(PORTB.3).
Set CCP2CON = %00000100, T3CON = 0 and T1CON = %00110010.
And finally done Enable(OnInt)
I've stripped the ISR down to just setting a flag when it sees a CCP2IF interrupt but that flag never gets set! I've confirmed there is a pulse train coming in - I have an LED available which I set to be the inverse of PORTB.3 and that flashes as expected.
Any ideas at all why I'm not getting this interrupt? From what I can see (and this works on other code) I don't need to set PEIE as Swordfish works will all interrupts high priority so GEIE enables everything. Not that this has stopped me trying this and numerous other things!
This really is one of those things that should take 2 minutes but has now taken over 3 hours...
-
- Swordfish Developer
- Posts: 1473
- Joined: Fri Jan 30, 2009 6:27 pm
- Location: US
Re: CCP2 Capture - where am I going wrong?
Just off the top of my head from the description...
>>Set all inputs as analogue and done Input(PORTB.3)
You need RB3 (CCP input) to be digital
>> T1CON = %00110010
You didn't mention that you're turning on the timer anywhere (TMR1ON, T1CON.bits(0))
>>Defined CCP2IE = PIE2.0 and CCP2IF = PIR2.0 and initialised these to 1/0 respectively.
Move this step to after: Set CCP2CON = %00000100, T3CON = 0 and T1CON = %00110010.
You should always clear the IF after changing the CCP mode/setup
I didn't actually try it, so there might be something else going on too. Might help to have the real code.
>>Set all inputs as analogue and done Input(PORTB.3)
You need RB3 (CCP input) to be digital
>> T1CON = %00110010
You didn't mention that you're turning on the timer anywhere (TMR1ON, T1CON.bits(0))
>>Defined CCP2IE = PIE2.0 and CCP2IF = PIR2.0 and initialised these to 1/0 respectively.
Move this step to after: Set CCP2CON = %00000100, T3CON = 0 and T1CON = %00110010.
You should always clear the IF after changing the CCP mode/setup
I didn't actually try it, so there might be something else going on too. Might help to have the real code.
-
- Posts: 219
- Joined: Wed Sep 11, 2013 1:27 pm
- Location: Chesterfield
Re: CCP2 Capture - where am I going wrong?
Sorry, typo there... All ports set to digital, not analogue.
I'm not turning on the timer but my understanding is that this isn't a pre-requisite for a capture interrupt to be generated?
The plan is that when I see the first capture interrupt I turn the timer on so the subsequent capture in effect starts from zero.
Hard to post code as there is a lot in there not relevant, I'll see if I can cut it down and post something.
One thing, I've read elsewhere that CCP2CON isn't in access RAM on some PICs, not sure if this applies to the 26K22 but presumably Swordfish (full version, not SE) should deal with this anyway? The ASM generated to set CCP2CON is:
I'm not turning on the timer but my understanding is that this isn't a pre-requisite for a capture interrupt to be generated?
The plan is that when I see the first capture interrupt I turn the timer on so the subsequent capture in effect starts from zero.
Hard to post code as there is a lot in there not relevant, I'll see if I can cut it down and post something.
One thing, I've read elsewhere that CCP2CON isn't in access RAM on some PICs, not sure if this applies to the 26K22 but presumably Swordfish (full version, not SE) should deal with this anyway? The ASM generated to set CCP2CON is:
Code: Select all
MOVLW 4
MOVWF CCP2CON,0
-
- Posts: 219
- Joined: Wed Sep 11, 2013 1:27 pm
- Location: Chesterfield
Re: CCP2 Capture - where am I going wrong?
Actually, I will post all the code as it may be relevant:
This has the capture interrupt enabling commented out as I'm trying just polling the flag and toggling an LED to show captures are being detected - still nothing!
The code works with a bootloader to explain the offset and uses your SetAllDigital routine.
This has the capture interrupt enabling commented out as I'm trying just polling the flag and toggling an LED to show captures are being detected - still nothing!
The code works with a bootloader to explain the offset and uses your SetAllDigital routine.
Code: Select all
Device = 18F26K22
Clock = 64
Config
DEBUG = OFF,
FCMEN = OFF,
IESO = OFF,
PWRTEN = ON,
BOREN = OFF,
WDTEN = OFF,
WDTPS = 4096,
MCLRE = INTMCLR,
STVREN = OFF,
XINST = OFF,
LVP = OFF,
CCP2MX = PORTB3
#option org_reset = 2048
#option WDT = true // Enable Watchdog, include code in SF libraries to clear watchdog
#option SWORDFISH_SE = false
Include "IntOsc_K22.bas"
Include "SetDigitalIO.bas"
Include "System.bas"
Const Fosc = _clock * 250000 // Instruction clock frequency.
Const BTCBaudGen As Word = ( Fosc / 115200 ) - 1 + 0.5 // Adding 0.5 'rounds up' to the nearest
Const BTCBaudH As Byte = BTCBaudGen / 256
Const BTCBaudL As Byte = BTCBaudGen Mod 256
// Define pulse limits. Running at 64Mhz with a divider of 8 on the timer input we have 2MHz in. This gives a pulse time of 0.5usec. We only use the MSB so divide pulse count by 256 to get
// these values. i.e. Lead Pulse is 9msec = 9000 * 2 / 256 = 70.3. Set a range of 67 to 73 to allow for variation.
// Other pulses: Leading space is 4.5msec, pulse for either data bit is 562us, space for 0 is also 562us, space for 1 is 1687us, space for repeated data is 2250usec.
Const LeadPulseMin As Byte = 67
Const LeadPulseMax As Byte = 73
Const LeadSpaceMin As Byte = 33
Const LeadSpaceMax As Byte = 37
Const RepeatSpaceMin As Byte = 16
Const RepeatSpaceMax As Byte = 19
Const BitShortMin As Byte = 3
Const BitShortMax As Byte = 6
Const BitLongMin As Byte = 11
Const BitLongMax As Byte = 15
// Timer 1
Dim Timer1H As TMR1H
Dim Timer1L As TMR1L
Dim Timer1IF As PIR1.booleans(0)
Dim Timer1IE As PIE1.booleans(0)
Dim Timer1On As T1CON.booleans(0)
Dim CCP2IE As PIE2.booleans(0)
Dim CCP2IF As PIR2.booleans(0)
Dim IRReceive As LongWord
Dim IRAddress As IRReceive.Word1
Dim IRData As IRReceive.Word0
Dim IRBitCount As Byte
Structure FlagsIR
Flags As Byte
Edge As Flags.Booleans(0)
First As Flags.Booleans(1)
Invalid As Flags.Booleans(2)
Timeout As Flags.Booleans(3)
LeadPulse As Flags.Booleans(4)
LeadSpace As Flags.Booleans(5)
Data As Flags.Booleans(6)
Decoded As Flags.Booleans(7)
End Structure
Dim DecodeIR As Boolean
Dim IRFlags As FlagsIR
Dim LED As PORTB.0
// ISR. Processes timer interrupts
Interrupt OnInt()
Save(0,FSR0,FSR1) // Save FSR and variables. May need streamlining.
If CCP2IF Then
Timer1H = 0
Timer1L = 0
DecodeIR = true
If IRFlags.Edge Then
CCP2CON = 0
CCP2CON = %00000100
IRFlags.Edge = false
Else
CCP2CON = 0
CCP2CON = %00000101
IRFlags.Edge = true
EndIf
If IRFlags.First Then
IRFlags.First = false
IRFlags.LeadPulse = true
Timer1On = true
Else
DecodeIR = true
EndIf
CCP2IF = false
EndIf
If Timer1IF Then
Timer1IF = false
IRFlags.Timeout = true
EndIf
Restore // Restore saved registers
End Interrupt
// Set which port pins are inputs and which are outputs. Also configures pull-ups.
Sub SetIO()
PORTA = 0 // Set all outputs low before configuring pins
PORTB = 0
PORTC = 0
TRISA = %00000000 // All Port A output
TRISB = %00001100 // All Port B output apart from button input (RB2) and CCP input (RB3)
TRISC = %11111101 // RN42 CTS input set as output, Rest inputs. (TX/RX controlled by UART module)
Input(PORTB.3)
Input(PORTB.2)
Output(LED)
SLRCON = %11111011 // Remove slew rate limiting on port C - this is used for the serial port and I2C
WPUB = %00000100 // Enable pull-up for button
INTCON2.7 = 0 // Global pull-up enable
End Sub
Sub PutChar(sdata As Char)
Repeat
ClrWDT
Until PIR1.booleans(4)
TXREG = sdata
End Sub
Sub InitIR()
CCP2CON = %00000100 // Capture on falling edge
T3CON = 0 // Ensure timer 1 selected for capture
T1CON = %00110010 // 1:8 Prescale using Fosc/4, 16 bit RW mode, timer off
Timer1H = 0
Timer1L = 0
Timer1IF = false
Timer1IE = true
IRFlags.Flags = 0
DecodeIR = false
IRBitCount = 0
IRFlags.Edge = false
IRFlags.First = true
IRReceive = 0
// CCP2IF = false
// CCP2IE = true
// Enable(OnInt) // Enable interrupts
End Sub
Sub ProcessIR()
If IRFlags.Invalid = false Then
If IRFlags.LeadPulse Then
If CCPR2H < LeadPulseMin Or CCPR2H > LeadPulseMax Then
IRFlags.Invalid = true
Else
IRFlags.LeadPulse = false
IRFlags.LeadSpace = true
EndIf
ElseIf IRFlags.LeadSpace Then
If CCPR2H < LeadSpaceMin Or CCPR2H > LeadSpaceMax Then
IRFlags.Invalid = true
Else
IRFlags.LeadSpace = false
IRFlags.Data = false
EndIf
Else
If CCPR2H < BitShortMin Then
IRFlags.Invalid = true
ElseIf CCPR2H > BitLongMax Then
IRFlags.Invalid = true
Else
If IRFlags.Data Then // Decoding space
IRFlags.Data = false
IRReceive = IRReceive >> 1
Inc(IRBitCount)
If IRBitCount = 32 Then IRFlags.Decoded = true EndIf
If CCPR2H > BitShortMax Then // Long space = 1
If CCPR2H < BitLongMin Then
IRFlags.Invalid = true
EndIf
IRReceive.31 = 1
Else // Short space = 0
IRReceive.31 = 0
EndIf
Else // Decoding pulse
If CCPR2H > BitShortMax Then
IRFlags.Invalid = true // Pulse is always short
EndIf
IRFlags.Data = true
EndIf
EndIf
EndIf
EndIf
End Sub
// program start...
ClearRAM
SetAllDigital // All port pins digital (disable analogue peripherals)
SetIO // Configure which pins are inputs and which outputs, and set default levels for outputs.
// Configure UART
SLRCON = %11111011 // Remove slew rate limiting on port C.
BAUDCON1 = %00001000 // 16 bit BRG, no autodetect
SPBRGH1 = BTCBaudH // Set BRG to give 115200 baud.
SPBRG1 = BTCBaudL
RCSTA1 = %10010000 // Set 8 bit TX and RX modes and ascyn mode, enable TX and RX
TXSTA1 = %00100110
InitIR
While true
ClrWDT
If PORTB.2 = 0 Then
Asm
Reset
End Asm
EndIf
if CCP2IF then
CCP2IF = false
toggle(LED)
endif
// LED = Not PORTB.3
If DecodeIR Then
DecodeIR = false
ProcessIR
If IRFlags.Timeout Then PutChar("T") EndIf
If IRFlags.Invalid Then PutChar("I") EndIf
If IRFlags.Decoded Then
PutChar(IRAddress.byte0)
PutChar(IRAddress.byte1)
PutChar(IRData.byte0)
PutChar(IRData.byte1)
InitIR
EndIf
EndIf
Wend
-
- Swordfish Developer
- Posts: 1473
- Joined: Fri Jan 30, 2009 6:27 pm
- Location: US
Re: CCP2 Capture - where am I going wrong?
I've never tried to use it that way, so you might be right about not needing the timer to be on.I'm not turning on the timer but my understanding is that this isn't a pre-requisite for a capture interrupt to be generated?
The plan is that when I see the first capture interrupt I turn the timer on so the subsequent capture in effect starts from zero.
Normally, I'd let the timer run. On the first CCPIF, save the captured value. On the next CCPIF, read the new capture and subtract the two to get the time difference.
If you wait until the 1st CCPIF to turn on the timer you'll be off by the interrupt latency + the time it takes to get everything rolling.
I'll take a look over the code to see if I spot anything funny...
-
- Posts: 219
- Joined: Wed Sep 11, 2013 1:27 pm
- Location: Chesterfield
Re: CCP2 Capture - where am I going wrong?
I've just tried enabling the timer and no change.
Interrupt latency isn't a major issue here - I'm decoding pulses from an IR transmitter so I'm only looking for the pulse width to be within a fairly wide range. I'm basing this on some code I found online which does the same and they claim works - seems easier when your timing isn't critical to just reset the timer rather than have to look out for roll-overs.
Also, I (and they) use the timer roll-over interrupt to signal a timeout.
I've just tried changing to keeping the timer running and toggling the LED on Timer1IF and this works as expected.
I'm suspecting the capture isn't being set up properly and so interrupts aren't being generated...
Interrupt latency isn't a major issue here - I'm decoding pulses from an IR transmitter so I'm only looking for the pulse width to be within a fairly wide range. I'm basing this on some code I found online which does the same and they claim works - seems easier when your timing isn't critical to just reset the timer rather than have to look out for roll-overs.
Also, I (and they) use the timer roll-over interrupt to signal a timeout.
I've just tried changing to keeping the timer running and toggling the LED on Timer1IF and this works as expected.
I'm suspecting the capture isn't being set up properly and so interrupts aren't being generated...
-
- Posts: 219
- Joined: Wed Sep 11, 2013 1:27 pm
- Location: Chesterfield
Re: CCP2 Capture - where am I going wrong?
Totally stumped by this one!
I've cut the code back to the very basics and the CCP2IF flag is just not getting set. I'm even creating pulses on the CCP2 line and verifying the logic state with a multimeter but the flag is not getting set.
Unfortunately I'm limited on this hardware and can't change to another CCP input to see if it is an issue with the module itself...
I've cut the code back to the very basics and the CCP2IF flag is just not getting set. I'm even creating pulses on the CCP2 line and verifying the logic state with a multimeter but the flag is not getting set.
Unfortunately I'm limited on this hardware and can't change to another CCP input to see if it is an issue with the module itself...
-
- Swordfish Developer
- Posts: 1473
- Joined: Fri Jan 30, 2009 6:27 pm
- Location: US
Re: CCP2 Capture - where am I going wrong?
I uncommented the lines in InitIR()
and commented out the
in the main loop and I get both TMR1 and CCP2 interrupts as I wiggle a line connected to RB3
I have some other minor mods (running on a 25K22 w/out bootloader) but I don't think they'd have much effect. Sure your bootloader is redirecting the ISR ok?
Code: Select all
CCP2IF = false
CCP2IE = true
Enable(OnInt) // Enable interrupts
and commented out the
Code: Select all
if CCP2IF then
CCP2IF = false
toggle(LED)
endif
I have some other minor mods (running on a 25K22 w/out bootloader) but I don't think they'd have much effect. Sure your bootloader is redirecting the ISR ok?
-
- Posts: 219
- Joined: Wed Sep 11, 2013 1:27 pm
- Location: Chesterfield
Re: CCP2 Capture - where am I going wrong?
Hi Jerry,
I'm sure it isn't to do with the ISR as even just testing the flag I wasn't getting anything.
I've not found the cause but I have got somewhere. After a bit of track hacking I managed to connect the input to CCP1. Changed the code to suit and bingo, I'm getting capture interrupts.
This must be to do with configuring the CCP module....
I'm sure it isn't to do with the ISR as even just testing the flag I wasn't getting anything.
I've not found the cause but I have got somewhere. After a bit of track hacking I managed to connect the input to CCP1. Changed the code to suit and bingo, I'm getting capture interrupts.
This must be to do with configuring the CCP module....
-
- Swordfish Developer
- Posts: 1473
- Joined: Fri Jan 30, 2009 6:27 pm
- Location: US
Re: CCP2 Capture - where am I going wrong?
That's odd. I'm using your setup code... the only thing I've changed is
But that should be the default setting.
I connected the "LED" output (RB0) up to RB3, shut off the interrupts and toggled RB0 high/low and I see CCP2IF get set.
Code: Select all
Sub InitIR()
CCP2CON = %00000100 // Capture on falling edge
' T3CON = 0 // Ensure timer 1 selected for capture
CCPTMRS0.bits(3) = 0 // CCP2 uses Timer1 for capture/compare
CCPTMRS0.bits(4) = 0
....
I connected the "LED" output (RB0) up to RB3, shut off the interrupts and toggled RB0 high/low and I see CCP2IF get set.
-
- Posts: 219
- Joined: Wed Sep 11, 2013 1:27 pm
- Location: Chesterfield
Re: CCP2 Capture - where am I going wrong?
You know what, Jerry? I've just realised what a numpty I am...
One down-side of my bootloader is that it doesn't write the config bits - I thought it safest not to change them.
So, while my code sets the fuse to alter which pin CCP2 is on, the bootloader doesn't alter this from the default so the reason I'm not getting CCP2 interrupts is that I'm using the wrong pin...
Thanks for your help, I'm sure it pushed me towards the solution faster than I'd have got there myself!
One down-side of my bootloader is that it doesn't write the config bits - I thought it safest not to change them.
So, while my code sets the fuse to alter which pin CCP2 is on, the bootloader doesn't alter this from the default so the reason I'm not getting CCP2 interrupts is that I'm using the wrong pin...
Thanks for your help, I'm sure it pushed me towards the solution faster than I'd have got there myself!
-
- Swordfish Developer
- Posts: 1473
- Joined: Fri Jan 30, 2009 6:27 pm
- Location: US
Re: CCP2 Capture - where am I going wrong?
>>One down-side of my bootloader is that it doesn't write the config bits - I thought it safest not to change them.
That's a good thing (until it isn't!). It can be a real disaster if you screw it up. What I've done w/mine is to not allow the bootloader to do config changes by default, but there's an override command to allow the config to be changed. I still cringe and cross my fingers whenever I use that feature...
Of course, I'd probably have forgotten about having to update them and ended up in the same boat as you!
That's a good thing (until it isn't!). It can be a real disaster if you screw it up. What I've done w/mine is to not allow the bootloader to do config changes by default, but there's an override command to allow the config to be changed. I still cringe and cross my fingers whenever I use that feature...
Of course, I'd probably have forgotten about having to update them and ended up in the same boat as you!