View previous topic :: View next topic |
Author |
Message |
future
Joined: 14 May 2004 Posts: 330
|
How to detect both edges in EXT interrupt |
Posted: Sun Jun 06, 2004 5:12 pm |
|
|
I need to detect both edges in an interrupt pin, because I want to add a configurable delay in the comparator output pin.
Once it gets the Low to High interrupt it sets the comparator output pin (PIN_C2) high. When a High to Low interrupt occurs, CCP1 is loaded with the desired delay and timer1 is started.. when timer1=ccp1 PIN_C2 is set low, so the high pulse width (in PIN_C2) is the time between interrupts plus a configurable delay.
Code: | #int_ext fast
void ext_isr(void) {
if(input(PIN_B0)) { // rising edge detected
setup_ccp1(CCP_OFF); // stop comparator so
output_high(PIN_C2); // we can set output high
} else {
CCP_1=255; // here we set the delay time
set_timer1(0); // clear timer to start from 0
setup_ccp1(CCP_COMPARE_CLR_ON_MATCH); // here we go!
}
} |
In MPLAB simulator I get interrupts in both H_to_L and L_TO_H, but in the real PIC the ELSE section is never executed. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jun 06, 2004 5:22 pm |
|
|
You can change the active edge with this CCS function:
ext_int_edge(L_TO_H);
or
ext_int_edge(H_TO_L); |
|
|
future
Joined: 14 May 2004 Posts: 330
|
|
Posted: Sun Jun 06, 2004 5:47 pm |
|
|
Already tried before the post but nothing yet.
Code: | #int_ext fast
void ext_isr(void) {
if(input(PIN_B0)) { // rising edge detected
setup_ccp1(CCP_OFF); // stop comparator so
output_high(PIN_C2); // we can set output high
ext_int_edge(H_TO_L); // change next edge to High to low
} else {
ext_int_edge(L_TO_H); // return edge to normal
CCP_1=255; // here we set the delay time
set_timer1(0); // clear timer to start from 0
setup_ccp1(CCP_COMPARE_CLR_ON_MATCH); // here we go!
}
} |
|
|
|
future
Joined: 14 May 2004 Posts: 330
|
|
Posted: Sun Jun 06, 2004 6:23 pm |
|
|
Just found what I was looking for..
http://www.ccsinfo.com/forum/viewtopic.php?t=18914&highlight=interrupt+read
Code: | #int_ext
void ext_isr(void) {
if(input(PIN_B0)) { // rising edge detected
setup_ccp1(CCP_OFF); // stop comparator so
output_high(PIN_C2); // we can set output high
ext_int_edge(H_TO_L);
output_high(pin_d3); //
output_low(pin_d2); ////
} else { ///// alternate leds to show what
output_high(pin_d2); //// is happening
output_low(pin_d3); //
ext_int_edge(L_TO_H);
CCP_1=255; // here we set the advance timing
set_timer1(0); // clear timer to start from 0
setup_ccp1(CCP_COMPARE_CLR_ON_MATCH); // here we go!
}
} |
I tracked down the problem and without fast interrupts the code works fine.
But with this I lost the fast interrupt and got a big overhead in context saving.
Any sugestions? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Jun 07, 2004 12:18 pm |
|
|
I'm doing something similar in my code and this works perfect. A difference is that for determining which edge caused the interrupt to be calld I test the setting of the interrupt register i.s.o. PIN-B0.
I'm a bit worried about the lack of context saving in your FAST interrupt version. Are you sure the compiler is using no registers at all?
Can you post the assembly listing of your FAST interrupt function? There might be a problem with the BSR settings. |
|
|
future
Joined: 14 May 2004 Posts: 330
|
|
Posted: Mon Jun 07, 2004 12:57 pm |
|
|
I´m at work right now and will complete this post tonight with the asm listing.
In your application, do you use fast interrupt for EXT?
In the test, do you use something like if(INTCON2&&MASK) {}
EDIT1: Attached files with and without fast interrupt.
http://future.gotdns.com:8080/ccs
EDIT2: Lots of edits... Your solution really worked, testing INTCON2.6 instead PORTB.0 did the job.
Thank you for you attention |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Jun 07, 2004 5:02 pm |
|
|
My function is mostly written in assembler because I had an example program to work from that was in assembler and for interrupts I like having total control.
So my assembly code for the test on a PIC18F458 looks like
Code: |
btfss intcon,intf ; external interrupt?
goto intovfl ; no, go
bcf intcon,intf ; yes. Clear external interrupt flag
btg intcon2,intedge0 ; trigger on opposite edge
; do something usefull
goto int_exit
intovfl:
; handle other interrupts
int_exit:
|
or the C equivalent
Code: |
if bit_test(intcon, intf)
{
bit_clear(intcon, intf);
bit_toggle(intcon2, intedg0);
}
|
Further I think you better read your own thread of a few days ago again http://www.ccsinfo.com/forum/viewtopic.php?t=19498....
Here Ttelmah explains that using an index in your interrupt handler requires saving several of the table pointer registers and a couple of scratch registers. Then looking at the FAST example I posted there you can see I save the FSROL, FSROH and #3 registers. I'm sure you will see these same registers being used in your code. Not saving these registers will corrupt your main program loop with unpredictable results.
One other small gotcha: Make sure you have set the timer for synchronous clock input as the data sheets say that compare is not guaranteed with the asynchronous counter. Setting this wrong will make you loose an occasional edge change. |
|
|
future
Joined: 14 May 2004 Posts: 330
|
|
Posted: Mon Jun 07, 2004 5:40 pm |
|
|
At the time of the other post, I needed only one edge.. When I needed to detect the 2 edges I got the bug, because I was wrong thinking that testing portb.0 would show me what edge it was.
You can see in the links I post that none of the registers are used.
One thing that I dont know is why if(input(PIN_B0)) does not work with fast interrupts. if(INTCON2.6) works in all cases.
What I understand for "synchronous clock input" is when it is derived from the internal crystal/4 clock.. If this is correct, then yes, timer1 is incremented every 4 internal clock ticks.
When was bit_toggle statement added to CCS? I cant see it even in the changes from version 3.000+ |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Jun 08, 2004 2:17 am |
|
|
I don't know why testing port.b is not working, the only reason I can think of is that you have a very fast changing input signal and that the level has changed again before your test.
The function bit_toggle() is my own code, something I think is missing from CCS. The PIC18 provides a single instruction for toggling a bit, trying to do the same with C code will result in at least two instructions.
Code: | #define bit_toggle(byte, bit) { \
#ASM \
btg byte,bit \
#ENDASM}
|
With the "synchronous clock" the internal clock is mentioned, as opposed to an external clock. |
|
|
hydrogene
Joined: 23 May 2004 Posts: 11 Location: Montreal
|
|
Posted: Sat Jun 12, 2004 3:47 pm |
|
|
Hi,
You can do your own edge detector. Here is the code:
Code: |
//Global var
int1 btn_state = 0;
#int_ext
void interrupt_B_zero();
{
btn_state = ~btn_state; // change 1 for 0 and 0 for 1
if(btn_state)
what you want to do on down edge
else
what you want to do on up edge
}
|
Good luck
David |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sat Jun 12, 2004 4:12 pm |
|
|
Hydrogene,
Your solution is one way to implement an edge detector and I have thought of doing it like that, but there are a few reasons why I decided otherwise:
1) It is not a real edge detector, but more like a semaphore remembering the last state. A programming error could cause the semaphore to get out of sync and you will be executing code for the wrong edge.
2) It requires an extra variable (RAM) and code to set it (ROM).
Testing for the value of INTCON2.6 doesn't have these disadvantages. |
|
|
|