|
|
View previous topic :: View next topic |
Author |
Message |
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
BUG ? delay_ms() function in ISR |
Posted: Mon May 15, 2006 3:28 am |
|
|
Hi,
whenever I use the function delay_ms() in any ISR; my software hangs. I am sure that that is the problem.
Anyone has the same experienced?
Why could this happen? |
|
|
kender
Joined: 09 Aug 2004 Posts: 768 Location: Silicon Valley
|
|
Posted: Mon May 15, 2006 3:43 am |
|
|
In general, a delay in the ISR is not a good practice.
Could you post your ISR code and tell us how often, approximately, the interrupt occurs? |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Mon May 15, 2006 3:47 am |
|
|
Code: | //************************** EXTERNAL interrupt ******************************//
//Interrupt als de AAN/UIT schakelaar wordt bewogen
#INT_EXT
void ext_isr()
{
int8 i,k;
for (i = 0; i < 30; i++) // Debounce
{
delay_us(999);
}
if (input(AAN_UIT))
{
// setup_uart(TRUE);
//E3_SLEEP = FALSE;
//setup_timer_1(T1_DISABLED);
//sleep_mode = FALSE;
if (E3_OFF)
{
BUZZER();
BOOT_E3_NEEDED = TRUE;
}
// }
// else
for (k = 0; k < 200 ;k++)
{
printf("%c",0);
}
printf("%c%S%c", COMMANDO_BYTE, WAKE_COMMANDO,0);
ext_int_edge(H_TO_L);
}
else
{
if (SPACE_PRESSED)
{
SPACE_PRESSED_WHILE_SHDN = TRUE;
//BUZZER();
}
printf("%c%c%S%c",0 ,COMMANDO_BYTE, SLEEP_COMMANDO,0);
ext_int_edge(L_TO_H);
}
} |
See the for loop? If I replace that with delay_ms(30); software hangs. |
|
|
Ttelmah Guest
|
|
Posted: Mon May 15, 2006 3:49 am |
|
|
Remember too, that if a delay_ms, is used in an ISR (awful practice), and is also used in the external code, interrupts will be dsabled for the entire time the code is in the external delay. Depending on the interrupt involved, this could easily lead to hardware overflows, which if not handled, can lead to some peripherals effectively being stopped (serial overflows etc.), which could result in the code 'hanging'.
Using delays of more than a very few closk cycles in an interrupt, really destroys the reason fo having interrupts in the first place.
General rule, is _keep interrupt handlers short_. If you need a delay triggered by an interrupt event, then start a timer, and use a timer interrupt from this.
Best Wishes |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Mon May 15, 2006 4:04 am |
|
|
I know the practice, still this is a bug in CCS software.
The debounce delay really is needed there.. |
|
|
Ttelmah Guest
|
|
Posted: Mon May 15, 2006 4:13 am |
|
|
Without seeing if you use 'delay_ms' elsewhere in your code, and what other interrupts are in use, we can't tell what is happening. However the debounce delay _is not_ needed here. Trigger a timer, and do it in hardware instead. 30mSec, is _awful_. If you are using almost any other hardware device, the result will be data loss at the very least.
The fault, is not in CCS, but is a limitation of the hardware (not supporting re-entrant code). You can bodge round this, by adding a second '#use delay' statement, for the interrupt only (a search here will find details of this), which results in _seperate_ delay code being generated. However I would fix the problem, rather than doing this.
Best Wishes |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Mon May 15, 2006 5:19 am |
|
|
I cannot change the hardware anymore. (You mean RC network prob.)
What do you mean by triggering a timer for debouncing? |
|
|
Ttelmah Guest
|
|
Posted: Mon May 15, 2006 5:27 am |
|
|
No, I don't mean 'RC network problem'. I am talking about the software problem you have. Use one of the hardware timers. In this interrupt code, when you see the first edge, trigger this, to interrupt in about 30mSec. Then leave this interrupt handler. When the timer interrupts, do your 'debounce' test, and if the signal is still valid, you have a valid signal.
Code to do this for keyboards, has been published here in the past.
Best Wishes |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Mon May 15, 2006 5:44 am |
|
|
I understand your point. Instead of waiting and doing nothing, you continue your while(TRUE) loop. After 30mS timerX interupts. Then I can read the position of the on/off switch.
What if no more hardware timers are available?
Btw signal still valid? Signal is always valid; always 0 or 1 on port B0. |
|
|
kender
Joined: 09 Aug 2004 Posts: 768 Location: Silicon Valley
|
|
Posted: Mon May 15, 2006 6:00 am |
|
|
Christophe wrote: | What if no more hardware timers are available? |
You don't need to dedicate a timer to this debounce functionality. If you already have a timer that overflows every 30ms or faster, you can add the bounce test code to one of your existing timer ISRs. BTW, you EXT ISR will be called for every bounce of a switch (it's not necessarily a problem).
Christophe wrote: | Btw signal still valid? Signal is always valid; always 0 or 1 on port B0. |
I guess, Ttelman meant that while the switch is bouncing, you can't immediately tell what the actual state of the switch is. |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Tue May 16, 2006 8:52 am |
|
|
Kender explain "adding to an existing timer" ?
I allready have Timer0 that overflows every 65 ms to measure battery voltage:
Code: | //************************** Timer0 interrupt ********************************//
//Timer0 overloopt elke 256 * 256 us = 65,536 ms en bewaakt de batterijspanning
//Batterijspanning wordt gemeten elke 65,536 s
#int_RTCC
RTCC_isr()
{
teller++;
if (teller == 1000)
{
Meet_Vbat(&Vbat); // Vbat meten
if (!E3_SLEEP) // Stuur de batterijspanning door naar E3 als deze
{ // niet in sleep staat
if ((0 < Vbat) && (Vbat < 4.3))
Send_Vbat(Vbat);
}
teller = 0;
}
}// TIMER0 |
Now you have this every time for a changing edge on RB0:
Code: | //************************** EXTERNAL interrupt ******************************//
//Interrupt als de AAN/UIT schakelaar wordt bewogen
/*
#INT_EXT
void ext_isr()
{
int8 i,k;
for (i = 0; i < 30; i++) // Debounce
{
delay_us(999);
}
if (input(AAN_UIT))
{
// setup_uart(TRUE);
//E3_SLEEP = FALSE;
//setup_timer_1(T1_DISABLED);
//sleep_mode = FALSE;
if (E3_OFF)
{
//BUZZER();
BOOT_E3_NEEDED = TRUE;
}
// }
// else
for (k = 0; k < 200 ;k++)
{
printf("%c",0);
}
printf("%c%S%c", COMMANDO_BYTE, WAKE_COMMANDO,0);
ext_int_edge(H_TO_L);
}
else
{
if (SPACE_PRESSED)
{
SPACE_PRESSED_WHILE_SHDN = TRUE;
}
printf("%c%c%S%c",0 ,COMMANDO_BYTE, SLEEP_COMMANDO,0);
ext_int_edge(L_TO_H);
}
}
*/ |
What is the link between them? |
|
|
kender
Joined: 09 Aug 2004 Posts: 768 Location: Silicon Valley
|
|
Posted: Tue May 16, 2006 9:53 am |
|
|
Christophe wrote: | Kender explain "adding to an existing timer" ? |
In the INT_EXT you set two flags: an expected new state of the PIN and
Code: |
// global declares
int1 g_iNewState; // new expected stste of a pin
int8 g_iDebounceCount; // debounce delay timer, initialize to 255 in the main()
int8 g_iTimerCount; // counter for skipping timer interrupts
#INT_EXT
void ext_isr()
{
g_iNewState = input(PIN_);
g_iDebounce = 6; // begin debouncing
}
|
In the ISR for a timer that you are already using, you check these flags:
Code: |
#INT_RTCC
void RTCC_isr // triggered every 5ms
{
++g_iTimerCount;
if (g_iTimerCount == 13)
{
// your existing
// time ISR code here
// it will be called every 65ms
g_iTimerCount = 0;
}
// end debouncing
if (g_iDebounceCount == 0)
{
if (g_iNewState == input(PIN_))
{
// debouncing is over handle the pin transition
}
g_iDebounceCount = 255;
}
else if (g_iDebounceCount < 255) // 255 is a special value that means that no debouncing is happening
{
--g_iDebounceCount;
}
}
|
Do you think this would work?
Last edited by kender on Wed May 17, 2006 4:04 pm; edited 1 time in total |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Wed May 17, 2006 3:25 am |
|
|
doesn't the
g_iDebounce = FALSE; // debouncing is over. clear the flag
has to be inside the 'if'
It can only be set to False when debouncing is actually over.
I will now try to implement this |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Wed May 17, 2006 6:57 am |
|
|
Seems to be working; this is my implementation. Can you verify:
External interrupt handler:
Code: | //************************** EXTERNAL interrupt ******************************//
//Interrupt als de AAN/UIT schakelaar wordt bewogen
#INT_EXT
void ext_isr()
{
On_Off_State = input(Aan_uit); // status aan / uit schakelaar
Debounce = TRUE; // begin debouncing
} |
Timer0 interrupt handler. Interrupt every 16,4 ms:
Code: | setup_timer_0( RTCC_INTERNAL | RTCC_DIV_64 ); // Start de Timer0 |
Code: | //************************** Timer0 interrupt ********************************//
//Timer0 overloopt elke 64 * 256 us = 16,4 ms en bewaakt de batterijspanning
//Batterijspanning wordt doorgestuurd elke minuut.
#int_RTCC
RTCC_isr()
{
teller++;
if (teller == 3658) // 3658 * 16ms = 01m00s
{
Meet_Vbat(&Vbat); // Vbat meten
if (!E3_SLEEP) // Stuur de batterijspanning door naar E3 als deze
{ // niet in sleep staat
Send_Vbat(Vbat);
}
teller = 0;
}
// Debounce indien nodig
if (Debounce && (On_Off_State == input(AAN_UIT)))
{
if (input(AAN_UIT)) // swich naar boven
{
// if (E3_OFF)
// {
// BOOT_E3_NEEDED = TRUE;
// }
for (k = 0; k < 20 ;k++)
{
printf("%c",0);
}
printf("%c%S%c", COMMANDO_BYTE, WAKE_COMMANDO,0);
ext_int_edge(H_TO_L);
}
else // swich naar beneden
{
if (SPACE_PRESSED)
{
SPACE_PRESSED_WHILE_SHDN = TRUE;
}
printf("%c%c%S%c",0 ,COMMANDO_BYTE, SLEEP_COMMANDO,0);
ext_int_edge(L_TO_H);
}
Debounce = FALSE; // debouncing is over. clear de flag
} // if debounce nodig
}// TIMER0 |
|
|
|
kender
Joined: 09 Aug 2004 Posts: 768 Location: Silicon Valley
|
|
Posted: Wed May 17, 2006 10:05 am |
|
|
Christophe wrote: | doesn't the
Code: | g_iDebounce = FALSE; // debouncing is over. clear the flag |
has to be inside the 'if'? |
No, I think, it should be outside 'if'. This 'if' statement checks if there truly was a transition from one state of a pin to the other. Regardless of the relsult, the debouncing is over.
Your code looks OK. However, you do a lot of serial communication in the timer ISR. Just like a delay that might cause a loss of an interrupt. |
|
|
|
|
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
|