CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

BUG ? delay_ms() function in ISR
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

BUG ? delay_ms() function in ISR
PostPosted: Mon May 15, 2006 3:28 am     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

PostPosted: Mon May 15, 2006 3:43 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 15, 2006 3:47 am     Reply with quote

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







PostPosted: Mon May 15, 2006 3:49 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 15, 2006 4:04 am     Reply with quote

I know the practice, still this is a bug in CCS software.

The debounce delay really is needed there..
Ttelmah
Guest







PostPosted: Mon May 15, 2006 4:13 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 15, 2006 5:19 am     Reply with quote

I cannot change the hardware anymore. (You mean RC network prob.)
What do you mean by triggering a timer for debouncing?
Ttelmah
Guest







PostPosted: Mon May 15, 2006 5:27 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 15, 2006 5:44 am     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

PostPosted: Mon May 15, 2006 6:00 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue May 16, 2006 8:52 am     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

PostPosted: Tue May 16, 2006 9:53 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 17, 2006 3:25 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 17, 2006 6:57 am     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

PostPosted: Wed May 17, 2006 10:05 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
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