|
|
View previous topic :: View next topic |
Author |
Message |
lukyluke
Joined: 18 Feb 2011 Posts: 7
|
12f629, interrupt on pin change |
Posted: Sun Mar 06, 2011 3:05 pm |
|
|
Hello!
I'm working on a project with a PIC 12F629... A task the PIC should perform is decode a digital signal, applied on a digital PIN. The signal is a square wave with a period of about 120us. I used an 'interrupt on change' on the PIN and tried to optimize my ISR but it doesn't work.
To debug the problem, I wrote a simpler program which should only "move" a PIN on each interrupt:
Code: | #int_ra
void isr() {
output_high(PIN_LED);
output_low(PIN_LED);
}
void main() {
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_DCC);
enable_interrupts(GLOBAL);
while(1) {}
} |
Using a logical analyzer, I drawed the original signal (Track0) and the output (PIN_LED) of the PIC (Track2)... the result is:
As you can see, it takes 36us on the rising edge (T2-T1) and 45us (T4-T3) on the falling one... and sometimes the interrupt is missing.
If I check che ASM of my program, I can see my isr is just 8 instructions, so it should take only 4us (4 instructions at 4MHz) to output_high:
Code: | .................... void isr() {
.................... output_high(PIN_LED);
0040: BSF 03.5
0041: BCF 05.4
0042: BCF 03.5
0043: BSF 05.4
.................... output_low(PIN_LED);
0044: BSF 03.5
0045: BCF 05.4
0046: BCF 03.5
0047: BCF 05.4
.................... } |
But at address 0x0004 (the interrupt vector address) I can see several instructions added by the compiler, I think to detect which interrupt fired and to jump to the correct #int_xx instruction.
As this is the only interrupt I need to manage, is there a way to optimize interrupt routine?
Can you explain the different time my PIC seems to respond to falling and rising changes on the PIN?
Thanks! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Mar 06, 2011 3:12 pm |
|
|
What is this ? I just scanned the whole CCS "Devices" directory and I
don't find that constant in any of the .h files. What's your compiler version ? |
|
|
lukyluke
Joined: 18 Feb 2011 Posts: 7
|
|
Posted: Sun Mar 06, 2011 3:25 pm |
|
|
Sorry it was in my .h file, a way to change the signal PIN:
Code: | #define INT_DCC 0x080B08 |
which comes from 12F629.H:
Code: | #define INT_RA3 0x080B08 |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Sun Mar 06, 2011 3:45 pm |
|
|
It shouldn't take any different time, on the rising or falling edge, and missing edges, suggests a voltage problem (level not actually getting low enough or high enough). However the delay, is the overhead involved in saving _all_ the registers that may be used inside the interrupt, and testing the actual source. The former typically takes perhaps 28 instructions, while using a single interrupt on change, extends the latter, with the compiler having to add code to work out just which pin has actually changed.
If you 'rem' out the option 'nolist' at the start of the processor include file, the 'hidden' code will become visible.
However the missing in this case, may just be running out of time. The handler has to also clear the interrupt, and restore all the registers on exit, taking nearly as long again...
How to reduce this?.
When an interrupt occurs, _one_ handler is called. The 'int_global' handler. It then does the housekeeping, saving all the registers, and working out which interrupt has triggered. On return, it also clears the interrupt, and as you are using it, also reads the port (which is a hardware requirement to clear the int on change).
Now, you can replace this handler, by writing your own 'int_global'. Look at ex_glint. Obviously, provided this is the only interrupt in use, then all the testing for 'which interrupt', is not needed. How many registers you need to save, will depend on what code you then put in your handler. You need to manually work out everything that your handler changes, and make sure these registers are all saved.
You can also gain speed, by switching to 'fast_io' mode. Half of the instructions for each output, are the ones setting the TRIS. Remember though, that if you go DIY, _you_ need to do all the hardware tasks. So must read the port, clear the interrupt flag, save and restore every register used in your code, etc., so it is significant work. However you should be able to reduce the time to perhaps 20uSec in total, depending on what is in your real code.
Best Wsihes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Mar 06, 2011 4:21 pm |
|
|
Code: | #include <12F629.h>
#fuses INTRC_IO, NOWDT, NOMCLR, PUT, BROWNOUT
#use delay(clock=4000000)
#define PIN_LED PIN_A4
#int_ra
void isr() {
output_high(PIN_LED);
output_low(PIN_LED);
}
void main() {
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_RA3);
enable_interrupts(GLOBAL);
while(1) {}
} |
You didn't post a test program, so I made one. You didn't post your
compiler version, so I went back and looked at one of your old posts
and installed vs. 4.057.
I connected a BK4011 function generator to pin A3 with a 120 Hz,
0 to 5v peak-to-peak, 50% duty cycle squarewave. I put a scope
probe on pin A4.
I get an interrupt frequency of 240 Hz, with some slight variation.
I get a solid positive pulse width of 4 us, with no ghosting to longer
pulses.
So to me, it's working. |
|
|
hmnrobots
Joined: 02 Oct 2009 Posts: 11
|
|
Posted: Wed Mar 09, 2011 10:49 am |
|
|
Hi
did you use the 12F629 header (equipped with the 12F629-ICD) or directly the 12F629 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 09, 2011 1:03 pm |
|
|
Just an ordinary 8-pin DIP package 12F629. |
|
|
mars79
Joined: 19 Jun 2013 Posts: 6 Location: Bulgaria, Plovdiv
|
|
Posted: Tue Apr 30, 2024 3:07 am |
|
|
Code: | #include <12F629.h>
#fuses INTRC_IO, NOWDT, NOMCLR, PUT, BROWNOUT
#use delay(clock=4000000)
#define PIN_LED PIN_A4
#int_ra
void isr() {
output_high(PIN_LED);
output_low(PIN_LED);
}
void main() {
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_RA3);
enable_interrupts(GLOBAL);
while(1) {}
} |
I hope I'm not breaking the forum rules, but I decided to use the thread to avoid creating a new one for my problem.
Can I use this code to measure the frequency of the signal applied to the RA3 pin? |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|