|
|
View previous topic :: View next topic |
Author |
Message |
elm383
Joined: 13 Jul 2007 Posts: 7
|
Main loop locks up after using Interrupt |
Posted: Sun Sep 14, 2008 11:04 pm |
|
|
Hi,
I am very puzzled here. This is the scenario.
I'm turning on a LCD back light every time there is a button press.
Code: |
//Inside the main loop
while(1)
{
CurrTime = getTime();
printf(lcd_putc, "\f%02d:%02d %02d/%02d/%02d\n",
CurrTime.hour24, CurrTime.minute, CurrDate.day, CurrDate.month, CurrDate.year);
if(input(GO)==0)
{
onLCDbacklight() ;
delay_ms(555);
doSomething();
}
} |
At the same time it activates a timer interrupts that counts the time to turn off the light.
Code: |
void onLCDbacklight()
{
timer1_counter=0;
output_high(LCD_LIGHT_EN);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
} |
The light is turned off in the TIMER1 ISR. Also the timer and the interrupt.
Code: | #int_timer1
void timer1_isr()
{
if(++timer1_counter>50)
{
output_low(LCD_LIGHT_EN);
setup_timer_1(T1_DISABLED);
disable_interrupts(INT_TIMER1);
}
clear_interrupt(INT_TIMER1);
} |
The problem is that the main loop will hang/stop working. But still the light will turn off after the main loop hangs/stops working. This happens not immediately but just before the timer1_counter reaches it limit.
Do hope anyone could give some suggestions on how to troubleshoot this. (And I do hope I've given sufficient information)
Thank you ...
Compiler version 4.057
PIC18f4685 using Tiny bootloader
Standard Run Mode
Target voltage: 5V
Target oscillator speed, type: 20Mhz crystal |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Sep 14, 2008 11:41 pm |
|
|
I don't see a fault at first look. There may a problem with the order of enabling and disabling interrupts and the timer. If it's a 3.xx compiler, the issue would be caused by a >255 delay value, needing a long_delay instead.
Generally, the programming style looks somewhat like making simple things complicated. I would use a tick timer interupt, thats active during application lifetime, and a count-down timer variable, you may use as many of them for different timer purposes as you need. The solution is also prepared for other kinds of periodical operations, that are usually needed in an application.
Code: | // Inside the timer tick interupt:
if (cntdwn1) cntdwn1--;
// In main loop
if(input(GO)==0) cntdwn1 = ONTIME;
output_bit(LCD_LIGHT_EN,cntdwn1!=0); |
|
|
|
elm383
Joined: 13 Jul 2007 Posts: 7
|
|
Posted: Mon Sep 15, 2008 12:41 am |
|
|
Thanks for the prompt reply . Took some time to try to understand what you're trying to tell me though.
Correct me if I'm wrong, the tick timer is just a normal timer (timer0, 1, 2, etc.) right? If it is, I think I got what you mean.
However, there is a another problem if I implement it this way though. The program has to go back to the main loop if the backlight were to turn off (right?). For my application, the program would stay inside the function until the user decides to exit; and there are multiple nested functions like this. In those functions, there would be more button presses similar to the main loop. I would like to have the light turn off after some time after the button press regardless whether if I'm in the main loop or not.
Still, I really like this technique though (taking note). Would've made my live easier for my previous projects. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Sep 15, 2008 3:45 am |
|
|
The tick timer is a timer interrupt function, but permanently active.
I assume, that an application has a main loop, that is serviced continuously (at least multiple times each second). If your application is staying in a particular state for extended periods, e. g. during entering data from a keyboard), a special work function may do the same. |
|
|
Ttelmah Guest
|
|
Posted: Mon Sep 15, 2008 4:20 am |
|
|
The obvious comment, is that the fault is not here, but in 'DoSomething'. If this never returns, the code will behave as you describe....
You don't need to clear the interrupt in the handler. Unless interrupts are declared using the 'no_clear' directive, the compiler does this for you.
I'd set the timer to a value (0), and clear the interrupt, before enabling it in the keypress detection. Also set the counter (timer1_counter) to zero, otherwise if the event happens again, the backlight will clear immediately.
Best Wishes |
|
|
Guest
|
|
Posted: Mon Sep 15, 2008 4:26 am |
|
|
Ah, now I really understand about the tick timer... Heard about it but never quite knew its intention.
FvM wrote: | If your application is staying in a particular state for extended periods, e. g. during entering data from a keyboard), a special work function may do the same. |
I don't get the 'special work function' part. Could you give some explanation or resource on it. |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Mon Sep 15, 2008 6:55 am |
|
|
What makes you think the main loop stops working ?
Does the button no longer turn the backlight on ?
With the backlight off, can you still makeout the time and does it stop incrementing ?
What does the dosomething() routine do ?
You have posted snippets of code which do not make a compilable, runnable routine. There is still alot of un answered questions including what are your fuses set to, How does the getTime routine work ? does it use timer 1 ?
There are a few things you don't need but as it stands the code looks like it should work ok so I would look at other areas of your code.
The interrupt will fire even if the pic is stuck in a loop somewhere in your code.
How do you know the backlight goes off "just before the timer1_counter reaches it limit" ? |
|
|
elm383
Joined: 13 Jul 2007 Posts: 7
|
|
Posted: Mon Sep 15, 2008 7:06 pm |
|
|
Thanks for the reply.
Ttelmah wrote: | The obvious comment, is that the fault is not here, but in 'DoSomething'. If this never returns, the code will behave as you describe....
|
The function returns alright, but only on user consent. Besides, if I run the code without the onLCDbacklight() everything works out fine. I don't think the problem lies in there since there is no change in code other than the onLCDbacklight(). What do you think?
Ttelmah wrote: | You don't need to clear the interrupt in the handler. Unless interrupts are declared using the 'no_clear' directive, the compiler does this for you.
I'd set the timer to a value (0), and clear the interrupt, before enabling it in the keypress detection. Also set the counter (timer1_counter) to zero, otherwise if the event happens again, the backlight will clear immediately. |
Did that and there was no visible change. I don't think the set_timer1(0) would have much effect since I'm counting the amount of overflow instead of just one overflow. If the timer were to be at the overflow end, the time would be less by about 100ms or so from the 5(+-) seconds count. But I've permanently added it to the function though. Just in case . |
|
|
elm383
Joined: 13 Jul 2007 Posts: 7
|
|
Posted: Mon Sep 15, 2008 7:44 pm |
|
|
Thanks for the reply.
Wayne_ wrote: | What makes you think the main loop stops working ?
Does the button no longer turn the backlight on ?
With the backlight off, can you still makeout the time and does it stop incrementing ? |
Yes, the all the button presses no longer respond and also the time stops to increment. Everything just freezes.
Wayne_ wrote: | What does the dosomething() routine do ? |
The dosomething() routine in this case enters into the time setting mode where the user will be able to set the time and the date.
Wayne_ wrote: | You have posted snippets of code which do not make a compilable, runnable routine. |
Yeah, I understand but I don't think posting all the code would be wise though. There are a few thousand lines spread out to multiple files. But I will post the necessary snippets though; upon request.
Wayne_ wrote: | There is still alot of un answered questions including what are your fuses set to, How does the getTime routine work ? does it use timer 1 ? |
The getTime routine uses an external IC; theDS1307. It just retrieves the information, processes it a little to make it readable and that is it.
As for the fuses:-
Code: | #FUSES HS //High speed Osc (> 4mhz)
#FUSES NOFCMEN //Fail-safe clock monitor enabled
#FUSES NOIESO //Internal External Switch Over mode enabled
#FUSES NOPUT //No Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES BORV20 //Brownout reset at 2.0V
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES NOPBADEN //PORTB pins are configured as analog input channels on RESET
#FUSES LPT1OSC //Timer1 configured for low-power operation
#FUSES MCLR //Master Clear pin enabled
#FUSES NOSTVREN //Stack full/underflow will cause reset
#FUSES NOLVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES BBSIZ4K //4K words Boot Block size
#FUSES NOXINST //Extended set extension and Indexed Addressing mode enabled
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOCPB //No Boot Block code protection
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
|
Wayne_ wrote: | There are a few things you don't need but as it stands the code looks like it should work ok so I would look at other areas of your code. |
Could you be so kind to highlight that. I'm still searching out different and new techniques of coding. Still, thanks for the reply .
Wayne_ wrote: | The interrupt will fire even if the pic is stuck in a loop somewhere in your code. |
However, the interrupt is enabled only on button press and is disabled after the overflow count (timer1_count) meets it limit.
Wayne_ wrote: | How do you know the backlight goes off "just before the timer1_counter reaches it limit" ? |
A bit of a misunderstanding here. The main loop stops working before the backlight turns off. I know this because all the buttons do not function and the time freezes. |
|
|
Guest
|
|
Posted: Mon Sep 15, 2008 9:45 pm |
|
|
When I'm faced with this kind of problem, I use an led to indicate how far the code gets. If you can narrow it down to the last statement executed, you stand a much better chance of solving the issue.
So do something like this:
Code: |
void onLCDbacklight()
{
output_high(LED_PIN);
timer1_counter=0;
output_high(LCD_LIGHT_EN);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
}
|
If the light turns on, advance the output_high statement one line and recompile.
Code: |
void onLCDbacklight()
{
timer1_counter=0;
output_high(LED_PIN);
output_high(LCD_LIGHT_EN);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
}
|
Continue this process until the LED doesn't turn on. |
|
|
elm383
Joined: 13 Jul 2007 Posts: 7
|
|
Posted: Mon Sep 15, 2008 10:52 pm |
|
|
I practice a somewhat similar technique. Instead of using a LED I used printf to the PC. However in this case, I deduced that the onLCDbacklight() has no problems since it is able to turn on the backlight and also off the backlight after the desired time. The only problem is that the main loop freezes after the light turns on. Not immediately but either just before it turns off, a little after it turns off or after 2-3 times of usage.
To say that there might be some problem in the main loop, it works fine without using the backlight. Furthermore, in the main loop and in the whole program, timer1 is only used for the backlight display. hmmm... |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
Re: Main loop locks up after using Interrupt |
Posted: Tue Sep 16, 2008 2:32 am |
|
|
Code: |
//Inside the main loop
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(GLOBAL);
while(1)
{
CurrTime = getTime();
printf(lcd_putc, "\f%02d:%02d %02d/%02d/%02d\n",
CurrTime.hour24, CurrTime.minute, CurrDate.day, CurrDate.month, CurrDate.year);
if(input(GO)==0)
{
onLCDbacklight() ;
// delay_ms(555); // Why is this required ?
// doSomething(); // comment this out so only the backlight and time routine is running
}
}
void onLCDbacklight()
{
timer1_counter=0;
output_high(LCD_LIGHT_EN);
enable_interrupts(INT_TIMER1);
}
#int_timer1
void timer1_isr()
{
if(++timer1_counter>50)
{
output_low(LCD_LIGHT_EN);
disable_interrupts(INT_TIMER1);
}
} |
Some minor changes, don't realy improve the code just tidies it up a little.
You say there are a few thousand lines of code spread out over multiple files. I would start by comment in out the do_something routine so that you have only the minimal amount of code left and see if it works properly.
There is a delay in the main loop, what is it for ?
If it still fails, comment the get_time line out.
If it still fails, comment the printf line out. You may want to change it so that you can still see it running !
CurrTime.hour24++; // something like this ?
By the way where is CurrDate set ?
Also we need your #use instructions, any tris statements that you have.
If you comment everything out so only the code shown above is running does it still fail ? |
|
|
elm383
Joined: 13 Jul 2007 Posts: 7
|
|
Posted: Tue Sep 16, 2008 3:29 am |
|
|
WOHOOOU!!!!
Now I know whats wrong. I had a hunch that there was something wrong with getting the time but never actually gave it a try. However when Wayne_ asked to give it a try, it further urged me to try to comment out the CurrTime = getTime() (Thanks Wayne_ !). It turns out that when the backlight turns on, the power supply was unable to deliver sufficient current for all the components and the DS1307 IC current was sucked up by the LCD backlight. This causes the IC to not respond to the getTime() call.
When I changed to another power supply, everything works out fine. I guess I need to make a timeout for the getTime() function (or just make sure the power supply is always sufficient ).
Thanks for the help. I learned a few new techniques especially the nifty tick timer (Thanks FvM!). If there is any suggestions, tips, techniques, I really would appreciate it.
Thanks again!
P/S: Where did you learn all the coding techniques? Share some resouces will yeh... |
|
|
|
|
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
|