View previous topic :: View next topic |
Author |
Message |
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
Multiple Interrupt Help |
Posted: Thu Dec 29, 2005 12:34 pm |
|
|
Please excuse the minimal effort on my part to understand my problem. I've finally deduced that my problem is being caused by multiple interrupts and I've wasted alot of time getting to this point so I'm going to impose on the kindness of the experts for, what I hope is, a quick solutuon/explanation.
(I found one relevant post by RJ but didn't understand it.)
18LF4620 @ 20MHz & 3.3v
3.236
Interrupts are:
Code: | //setup counter for firmware RTC
int_count = INTS_PER_SECOND;
set_rtcc(0);
setup_counters (RTCC_INTERNAL, (RTCC_DIV_256 | RTCC_8_BIT));
enable_interrupts (INT_RTCC); //(RTCC_ZERO);
//software PWM for LEDs timer
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
enable_interrupt(INT_TIMER1);
enable_interrupts(int_rda);
enable_interrupts(GLOBAL);
/*******************************
Software PWM ISR
*******************************/
#int_timer1
void tick_interrupt(void) {
static int8 loop = LOOPCNT;
static int8 pulse;
if(--loop == 0) {
loop = LOOPCNT;
pulse = width;
}
if(pulse) {
output_low(ENABLE);
pulse--;
} else {
output_high(ENABLE);
}
SET_TIMER1(0xFFFFFF00); //preload timer to prevent blinking
}
|
Their usage is: (in order of importance)
Timer_1 for a software PWM to control brightness on LEDs (using PCM's code.. I think) Any fishiness here will cause varying brightness.
RDA serial radio.
A software RTC/Timer for flashing a heartbeat LED and house keeping.
My problem is that when I shorten up the pulse I think I'm blowing the stack. Code continues to run but serial receives don't work.
My question is how do I prevent interference between interrupts?
Thanks guys,
John |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Dec 29, 2005 1:03 pm |
|
|
Quote: | My problem is that when I shorten up the pulse I think I'm
blowing the stack. Code continues to run but serial receives don't work. |
1. Use the #priority statement to put INT_RDA first.
2. Put the ERRORS directive in your #use rs232 statement. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Dec 29, 2005 1:18 pm |
|
|
Quote: | Code: | SET_TIMER1(0xFFFFFF00); //preload timer to prevent blinking |
| Timer1 is 16 bits, you are loading it with a 32 bit value.
Why don't you use the inbuilt PWM hardware? It will be more precise and better adjustable with much less software overhead. |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Thu Dec 29, 2005 1:52 pm |
|
|
ckielstra wrote: | Timer1 is 16 bits, you are loading it with a 32 bit value.
|
Ouch. Thanks. I missed that one!
ckielstra wrote: | Why don't you use the inbuilt PWM hardware? |
I hadn't planned on using PWM for controlling LEDs so hardware isn't set up for it. I was hoping the software version would work....
PCM,
I had "errors" in my RS232 setup. I tried the #priority option and that didn't help.
When I comment out the OUTPUT_HIGH and OUTPUT_LOW lines in the ISR, problems are greatly reduced. Time consumed there is the problem?
Also, another manifestation of the problem is bad ADC readings. I have a TC1047 for internal temp readings. When I start reducing the width the ADC starts spitting out bad readings....
Thanks, I'll continue to try things as I think of them.
John |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Dec 29, 2005 2:14 pm |
|
|
Quote: | When I comment out the OUTPUT_HIGH and OUTPUT_LOW lines in the ISR, problems are greatly reduced. Time consumed there is the problem? |
I didn't look closely at your code before. I did now, and I can see
that you're doing long delays inside your isr. Interrupts are disabled
while an isr is executing. If you have a long enough delay in the isr,
you'll start missing incoming RS-232 characters. |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Thu Dec 29, 2005 6:25 pm |
|
|
I've tried moving the output_hi/lo commands outside the ISR and it isn't functional. The LEDs flicker.
I don't think the problem is necessarily missing incoming RS232 comms. I've found a couple of lines of code that seem to be the most to blame. If I comment them out and use a work around I don't have the problems I originally had. (really all the workaround is, is preventing the offending functions from executing each time through the main loop, and only allowing them to run every other second or so...)
Even with the workaround code the ICD locks up. This is leading me to believe I'm screwing up the stack, etc.
I'm new to the ICD so I don't know if there is a way to keep track of everything up to the point where it blows up. I've tried stepping through to the armageddon point but that hasn't been successful.
Any other ideas would be greatly appreciated.
Thanks,
John
PS Here is the suspect code:
Code: |
#define NUM_OF_CABLES 15
int8 fetch_chip_pwr(int1 chip, int8 cable) {
int8 i;
int8 j;
int8 pins_powered = 0;
if(cable > NUM_OF_CABLES) { //return 0 for non-existent cable
return(0);
}
if(chip == 1) {
for(j = 0; j < 2; j++) {
for(i = 0; i < 8; i++) {
//correction for array indexing
if(bit_test(LED_out[cable - 1][j], i)) pins_powered++;
}
}
}
if(chip == 2) {
for(j = 0; j < 2; j++) {
for(i = 0; i < 8; i++) {
//correction for array indexing
if(bit_test(LED_out[cable - 1][j + 2], i)) pins_powered++;
}
}
}
return(pins_powered);
}
int16 fetch_system_pwr(void) {
int8 i;
int8 j;
int16 total_pins_powered = 0;
for(i = 1; i <= NUM_OF_CABLES; i++) {
for(j = 1; j < 3; j++) {
total_pins_powered = total_pins_powered + (int16)fetch_chip_pwr(j, i);
}
}
return(total_pins_powered);
} |
|
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1634 Location: Perth, Australia
|
|
Posted: Thu Dec 29, 2005 8:45 pm |
|
|
Quote: | I didn't look closely at your code before. I did now, and I can see
that you're doing long delays inside your isr. Interrupts are disabled
while an isr is executing. If you have a long enough delay in the isr,
you'll start missing incoming RS-232 characters. |
Was the original posted code modified because I don't see any unreasonably long delays.
Quote: | Any other ideas would be greatly appreciated. |
I cannot comment on the behaviour of the ICD you are using however, from the information you have given, there is another likely cause of problem. You have not listed all your interrupt handler code but I speculate you are using a function inside one of the other interrupt handlers that you are also using outside the handler. When this situation occurs the compiler inserts disable and reenable sequences in the code outside the handler. If there are long delays in these procedures then interrupt handling becomes erratic and interrupts might be missed. The compiler warns you that it is doing this. I suspect the root cause it outside the code segments you have listed.
Also in your listed priorities, the PWM is not the highest priority interrupt handling functio required for your application. This is because persistence, both the LED and the human eye, mean it would be impossible to differentiate the incremental delay of processing a serial rx interrupt. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
Last edited by asmallri on Thu Dec 29, 2005 9:26 pm; edited 1 time in total |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Thu Dec 29, 2005 9:11 pm |
|
|
Andrew,
Thanks for the input. The interrupt (rda) being disabled outside the handler starts to sound more like the symptom. Essentially, everything works except for the serial interrupt. As for the function inside and outside the ISR it doesn't look as though that's happening (most of my code is cut and paste from the CCS pros :-)
I finally gave up and, luckily, I had an open CCP/PWM pin available and tried the hardware option (thanks ckielstra). And it looks as though that maybe the solution to all my problems. However, I'd really like to understand what I was doing to myself so I could learn something from the past three days that have gone down the crapper.
Thanks to all,
John |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Dec 30, 2005 10:04 am |
|
|
Quote: | However, I'd really like to understand what I was doing to myself so I could learn something from the past three days that have gone down the crapper. | From the little program code you have given us it is not possible to tell where you went wrong.
Interrupts have some side effects that even advanced programmers have problems with, for example what Asmallri already pointed out is that the CCS compiler sometimes disables interrupts (calling the strcpy, memcpy and read_eeprom functions are examples of this).
An important thing to notice is that your software PWM routine was taking an awfull lot of processing power. You were triggering this interrupt every 256 instruction cycles. On a PIC18 processor the overhead for an interrupt is about 75 instruction cycles, add to this the overhead of your interrupt function and you get a total of almost 100 instruction cycles for every PWM interrupt. This means your processor was 40% of it's time busy controlling the LED.....
It is possible to use a software PWM when the hardware PWM pins are not available, but the implementation chosen here was not optimal for your project. This software PWM was most likely designed for use with an 8 bit timer, hence your SET_TIMER1(0xFF00) at the end of the ISR. With the 16-bit timer available in your project I would have chosen another approach where you don't use a 'pulse' variable but instead vary the time between interrupts by manipulating the Timer1 counter. This way it should be possible to reduce the number of Timer1 interrupts by at least a factor 10. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Dec 30, 2005 4:02 pm |
|
|
Quote: | Was the original posted code modified because I don't see any unreasonably long delays |
You are correct. I screwed up. |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Fri Dec 30, 2005 8:59 pm |
|
|
ckielstra,
Thanks for the additional info. I understand your more efficient use of the timer for a software PWM, I will keep that in my bag of tricks. Luckily, as I said before, I modified the board to use the available CCP/PWM pin and it works great. The ICD even works now, probably a pretty good indication I'm not totally destroying registers, pointers, and the like?
I still do have one odd manifestation. When I run particular piece of code the ADC will start to wander from a previous stable report. I won't post a bunch of code (yet) but, is there some place where I could start to look for the problem?
Thanks,
John |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Fri Dec 30, 2005 9:10 pm |
|
|
Well.... as always I had a momentary lapse in ignorance after the last post and thought to try this:
Code: | setup_ccp2(CCP_OFF);
check_analog();
setup_ccp2(CCP_PWM); |
And that cleaned up everything, and it isn't even noticable in the LEDs.
Thanks again to all,
John |
|
|
|