|
|
View previous topic :: View next topic |
Author |
Message |
cypher
Joined: 05 Oct 2007 Posts: 31
|
Problem with ISR - code inside not being executed |
Posted: Wed Aug 05, 2009 6:27 pm |
|
|
Hi,
I seem to be having an unusual problem. It seems as though I have an intermittent problem with code being executed inside the #int_RB isr. Intermittently I notice that some of the code does not get executed inside this isr. I know I should make my isr short, but is there a limit of how much code I can put in my ISR?
Here are my ISR routines for the #int_RB and #int_timer0, maybe I'm not declaring them correctly:
Code: |
#int_RB
void MCW_isr(void)
{
disable_interrupts(int_rb);
delay_us(100);
state[0] = input(ENABLE);
state[1] = input(SELECT_A); //State A select line
state[2] = input(SELECT_B); //State B select line
state[3] = input(SELECT_C); //State C select line
delay_us(100);
chip_select1 = input(ENABLE);
status_a1 = input(SELECT_A);
status_b1 = input(SELECT_B);
status_c1 = input(SELECT_C);
delay_us(50);
chip_select2 = input(ENABLE);
status_a2 = input(SELECT_A);
status_b2 = input(SELECT_B);
status_c2 = input(SELECT_C);
if((chip_select1 == chip_select2) && (status_a1 == status_a2) && (status_b1 == status_b2) && (status_c1 == status_c2))
{
if (chip_select2 == 0 && !(chip_select2 == prev_state)) //To check MCW's, state[0] must be 0 and previous state must've been a 1
{
check_MCW();
}
else// if (state[0] == 1 && !(state[0] == prev_state)) //On rising edge, tri-state data bus
{
set_tris_e(0xFF); //Tri-states data bus
}
prev_state = chip_select2; //Stores previous state of ENABLE
MCW_ISR_flag = 1;
}
clear_interrupt(int_rb); //Clear the RB interrupt
enable_interrupts(int_rb); //Enable the RB interrupt
}
#int_timer0
void seconds_isr(void)
{
disable_interrupts(int_timer0);
one_second_timer = 1; //Set the global variable one_second_timer
set_timer0(0xE000); //Reload the timer0 register with this value - you can change the length of time of the clock with this number
clear_interrupt(int_timer0); //Clear the timer0 interrupt
enable_interrupts(int_timer0);//Enable the timer0 interrupt
}
|
I notice that sometimes some of the code in some of the sub routines that the ISR calls does not get executed. I know this because I put printf statements before and after glowing some LEDs in the code. The printf statements get executed but I do not see the LEDs glow. This happens intermittently though, 90% of the time it works. What could be causing this intermittent problem? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Aug 05, 2009 6:52 pm |
|
|
You don't need to disable/enable INT_RB interrupts inside the isr.
There are no nested interrupts. You don't need to clear the interrupt
flag at the end of the isr, because CCS puts in code (unseen) to do that
anyway. You do have some long delays in the isr. You might want
to read Port B, or at least one pin on Port B, just before you exit the isr.
This would clear the "mismatch" condition that causes an INT_RB interrupt.
Are you trying to debounce something with delays ?
You should explain what your overall project is about, and tell us some
details about the signals on the pins used in the INT_RB isr.
You should post at least the framework of a test program, so that we
can look at your PIC, #fuses, #use delay() etc.
Also post your compiler version. |
|
|
mskala
Joined: 06 Mar 2007 Posts: 100 Location: Massachusetts, USA
|
|
Posted: Wed Aug 05, 2009 8:10 pm |
|
|
There is no limit to the amount of code you can have in an ISR. Before I changed my architecture around, I had essentially my whole program in one (everything ran from timer interrupt and had to be in right slices) with just a while (1) {} in the main. |
|
|
cypher
Joined: 05 Oct 2007 Posts: 31
|
|
Posted: Thu Aug 06, 2009 12:38 pm |
|
|
Thanks for the reply.
So, I tried removing the disable/enable interrupts inside the INT_RB isr but that didn't make any difference. I also tried adding an input_b(); at the end of the isr with no luck.
So, a brief explanation of what i'm trying to do here:
I have 1 single EN line which I hooked up to PIN_B4 and depending on the rising or falling edge of this line, I read a state bus (PIN_B5-B7) and decide what command was received and hence what operation to perform. In my case I am having this intermittent problem with the microscale() subroutine. In the microscale subroutine, I can either go microscale_high, microscale_low or microscale_off. The intermittent problem occurs when I go from high to off. I notice that all the statements inside the else if statement take place except:
heater_status = 0; I know this because I output heater_status and it is 1
And within DC_heaters_off(), I notice the LED does not turn off and some SWs do not turn off, however, the HOFF1 and HOFF2 printf take place. Hence why I say these statements don't get executed.
This is the intermittent problem i'm having. Now I realize that 90% of the time it works, so I don't think (and i've checked) that there are other places in my code where I do heater_status = 1 or turn on the LED again, otherwise I would see the problem happen every single time right?
Here are some sections of my code below that are related to the issue, please let me know if you see something or have a clue to what is happening. I will try using the debugger and see where all it goes in code once I issue the OFF command just to make sure it isn't re-writing the heater_status flag somewhere and turning the LED on again.
Code: |
#include <18F6722.h>
#device ADC=10
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
/* --- C Compiler Settings --- */
#use delay(clock=8000000, internal)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8, force_sw, invert)
#use standard_io(A) /* Thermistor */
#use standard_io(B) /* SW-PIN */
#use standard_io(C) /* RS232C */
#use standard_io(D) /* Heater */
#use standard_io(E) /* HW-PIN */
#use standard_io(F) /* Thermistor */
#use standard_io(G) /* LED and Temp */
#fuses NOBROWNOUT,FCMEN,IESO,PUT,INTRC_IO,NODEBUG,NOWDT,NOLVP
#ID 0x4D4C,0x342D,0x6552,0x3176
#bit RST = 0x0FD0.4
#bit WDT = 0x0FD0.3
#bit POR = 0x0FD0.1 //Power-on-Reset flag
#bit BOR = 0x0FD0.0
void main(void)
{
clear_interrupt(int_timer0); //Clear the Timer0 interrupt
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256); //Set-up the timer0, internal clock, 256 divide
set_timer0(0xE000); //Put this value in the timer0 register to get about 1 second
enable_interrupts(int_timer0);//Enable timer0 interrupt
enable_interrupts(GLOBAL); //Enable all interupts
while (1)
{
if(one_second_timer)
{
read_reg_sr();
}
}
}
#int_timer0 //This is the ISR for the one-second timer
void seconds_isr(void) //Just set a global variable to get out of the ISR incase the MCW_ISR is called
{
disable_interrupts(int_timer0);
one_second_timer = 1;
set_timer0(0xE000);
clear_interrupt(int_timer0); //Clear the timer0 interrupt
enable_interrupts(int_timer0);//Enable the timer0 interrupt
// enable_interrupts(global); //Enable all interrupts
}
#int_RB //This is the ISR for MCW reads and writes
void MCW_isr(void) //You can stay in this ISR longer, regulation won't suffer
{
disable_interrupts(int_rb);
delay_us(100); //This is a switch debounce delay
state[0] = input(ENABLE); //Enable pin on DC - don't branch if interrupt is not enable
state[1] = input(SELECT_A); //State A select line
state[2] = input(SELECT_B); //State B select line
state[3] = input(SELECT_C); //State C select line
delay_us(100);
chip_select1 = input(ENABLE);
status_a1 = input(SELECT_A);
status_b1 = input(SELECT_B);
status_c1 = input(SELECT_C);
delay_us(50);
chip_select2 = input(ENABLE);
status_a2 = input(SELECT_A);
status_b2 = input(SELECT_B);
status_c2 = input(SELECT_C);
if((chip_select1 == chip_select2) && (status_a1 == status_a2) && (status_b1 == status_b2) && (status_c1 == status_c2))
{
if (chip_select2 == 0 && !(chip_select2 == prev_state)) //To check MCW's, state[0] must be 0 and previous state must've been a 1
{
check_MCW(); //Calls the check_MCW function to determine state
}
else// if (state[0] == 1 && !(state[0] == prev_state)) //On rising edge, tri-state data bus
{
set_tris_e(0xFF); //Tri-states data bus
}
prev_state = chip_select2; //Stores previous state of ENABLE
MCW_ISR_flag = 1;
}
clear_interrupt(int_rb); //Clear the RB interrupt
enable_interrupts(int_rb); //Enable the RB interrupt
}
void check_MCW(void) //Function to select the state function based on select lines
{
state[1] = input(SELECT_A); //State A select line
state[2] = input(SELECT_B); //State B select line
state[3] = input(SELECT_C); //State C select line
if (state[1] == 0 && state[2] == 0 && state[3] == 0) //State 0b000
{
read_therm(); //Calls temperature READ function
}
if (state[1] == 1 && state[2] == 0 && state[3] == 0) //State 0b001
{
read_temp(); //Calls Setpoint READ function
}
if (state[1] == 0 && state[2] == 1 && state[3] == 0) //State 0b010
{
write_temp(); //Calls Setpoint WRITE function
}
if (state[1] == 1 && state[2] == 1 && state[3] == 0) //State 0b011
{
reset(); //Calls RESET function
}
if (state[1] == 0 && state[2] == 0 && state[3] == 1) //State 0b100
{
microscale(); //Calls Microscale function
}
if (state[1] == 1 && state[2] == 0 && state[3] == 1) //State 0b101
{
PC_codes(); //Calls Additional features function
}
if (state[1] == 0 && state[2] == 1 && state[3] == 1) //State 0b110
{
test_mode(); //Calls Test Mode function
}
if (state[1] == 1 && state[2] == 1 && state[3] == 1) //State 0b111
{
run(); //Calls RUN function
}
check_state_flag = 1;
}
void read_reg_sr(void) //This is the subroutine called by the WHILE loop before, every second
{
output_low(LED1); //Set blue LED on to enter subroutine
count_time(); //Count the present elapsed time
read_thermistors(); //Read the current thermistor values
FAULTS(flag); //Check if there is a thermistor FAULT
printf("Reg = %d\r",regulation_enable);
if ((dead_therms <3) && (regulation_enable == 1)) //If at least one therm is working and regualtion is true, then regulate
{
printf("*\r");
regulation(); //Calls the regulation function
}
if(temp_therm1 != prev_temp1 || temp_therm2 != prev_temp2 || temp_therm3 != prev_temp3) //If therms have changed since their previous values, then call report_therms
{
report_temp(); //Calls the report_therm function
}
if (save_error_codes)
{
error_word = make32(error_codes[4],error_codes[3],error_codes[2],error_codes[1]);
write_ee_32(error_codes_ee_address,error_word);
write_ee_32(error_codes_ee_address + 4,error_word);
}
one_second_timer = 0; //Resets the global variable to call this fuction (set by ISR)
ten_minute_timer = 0;
// restart_wdt(); //Reset the WDT counter
print_MCW_status();
output_high(LED1); //Turn OFF blue LED
}
void microscale(void)
{
int microscale_input = 0; //Set-up temp variable
microscale_input = input_e(); //Read input from data bus
if (microscale_input == microscale_high && microscale_byte_1 == 1) //If keycode is met and high-temp pattern recognized, keep going
{
current_temp = set_temp_high; //Set current_temp to set_temp_high
current_temp_comp = set_temp_high_comp;
regulation_enable = 1;
operating_mode = 0xFE;
// write_ee_8(previous_state_address,0xFE);
microscale_high_flag = 1;
}
else if (microscale_input == microscale_low && microscale_byte_1 == 1) //If keycode is met and low-temp pattern recognized, keep going
{
current_temp = set_temp_low; //Set current_temp to set_temp_low
current_temp_comp = set_temp_low_comp;
regulation_enable = 1;
operating_mode = 0xB8;
write_ee_8(previous_state_address,0xB8);
microscale_low_flag = 1;
}
else if (microscale_input == microscale_off && microscale_byte_1 == 1) //If keycode is met and off pattern recognized, keep going
{
current_temp = 0;
heater_status = 0;
DC_heaters_off();
regulation_enable = 0;
operating_mode = 0x23;
write_ee_8(previous_state_address,0x23);
microscale_off_flag = 1;
printf("Done\r");
}
else //If second word is wrong code
{
microscale_byte_1 = 0; //Reset first keycode bit
}
if (microscale_input == write_pattern_1 && microscale_byte_1 == 0) //Compare first word to keycode
{
reset_regs(); //Reset all intermediate MCW flags
microscale_byte_1 = 1; //Set keycode successful bit
microscale_keycode_flag = 1;
}
}
void DC_heaters_off(void) //Function to immediately shut-off heater circuits
{
printf("HOFF1\r");
output_bit(SW1,0);
output_bit(SW2,0);
output_bit(SW3,0);
output_bit(SW4,0);
output_bit(SW5,0);
output_bit(SW6,0);
output_high(LED2);
printf("HOFF2\r");
}
|
|
|
|
cypher
Joined: 05 Oct 2007 Posts: 31
|
|
Posted: Thu Aug 06, 2009 12:55 pm |
|
|
I was just thinking because this problem happens only intermittently, maybe its to do with timing of some type.
Is there a need for me to do some interrupt priority handling, for example the int_rb gets higher priority than #int_timer0? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Aug 06, 2009 3:18 pm |
|
|
Your program has so much code in it that I don't want to look at it.
A test program posted on this board, should be as short as possible.
For example, standard i/o mode is the default mode of the compiler.
You don't have to specify it. Next, you four #bit variables that are
not used. All those lines aren't needed for us to look at your problem.
They just get in the way.
Consider the way we like to work: You post a very short, compilable
test program. We look at it for a few seconds and solve it by inspection,
and type in an answer. That's the ideal way for us. Try to post a short
program and help us to do it that way. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Thu Aug 06, 2009 3:38 pm |
|
|
you observe that there is no limit to the amount of code
you can put in an ISR
AND you are correct - in the sense of VOLUME of code
but unless you get a concept of the TIME domain
and the execution profile of your program
you will never make the mess you have work
decide what is the MINIMUM code you need in the isr and go with JUsT that
then use global variables to report out what HAPPENED in the ISR most recently - or use a buffer to report MULTIPLE events and trim the buffer as your MAIN makes use of that data
HINT: BYTE or INT8 vars are the best reporting method since you don't have the issue of a possible half/read - disturbed by INT Update
the rare exceptions are the buffered registers of the TIMERS themselves in 16 bit mode
until you grasp that concept - you should leave INTS alone
as i fear you are exceding the speed of THOUGHT |
|
|
Ttelmah Guest
|
|
Posted: Fri Aug 07, 2009 2:27 am |
|
|
Realistically, the most likely cause for code not executing at times, is _hardware_.
The commonest problems, are things like LED's without current limiting resistors, poor supply supression etc., which leads to the chip actually resetting intermittently when certain instructions are exected.
The second, is not understanding your own hardware. So (for instance), what happens if the INT_RB code is called unexpectedly, when the 'signal' you are expecting hasn't been received?. You clear the timer interrupt, but don't read the PORTB register, at the start of the main. INT_RB, is almost certain to have been set during boot (unless the incoming line(s) you are monitoring, are stable before the internal register latches, the interrupt _will_ be set). So, what will happen to the logic of your interrupt, if this happens?.
Now, I see references to heaters. Almost certainly implies reasonable currents involved. How are these switched?. How is the power line supressed?. Are this possibly inductive (any 'coil', _will_ have significant inductance)?. If so, what are you doing to trap inductive spikes?. Does your drive circuit on each heater, and LED, allow the logic line from the processor to reach it's 'high' level?. What capacitances are involved in the drive circuits?.
Best Wishes |
|
|
cypher
Joined: 05 Oct 2007 Posts: 31
|
|
Posted: Fri Aug 07, 2009 7:09 pm |
|
|
Thanks for all your help guys. I will keep your pointers in mind for the future.
I have found the problem I was having. It is a logical problem related to interrupts taking place but has nothing to do with timing or hardware problems. Basically what was happening is that when an interrupt happens and I execute a particular command, I was setting a bunch of flags related to that event. And when the ISR would end, the place where the code would resume would re-initialize the flags that I just set in my ISR, overwriting the things I did in my ISR.
So, the intermittent problem only happened when I was at a particular place in my code AND the interrupt took place at that time. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Fri Aug 07, 2009 10:27 pm |
|
|
Welcome to "race" conditions.
Gotta watch that stuff...
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
|
|
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
|