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 CCS Technical Support

Interrupt re-entrany problems

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
JBM



Joined: 12 May 2004
Posts: 54
Location: edinburgh, Scotland

View user's profile Send private message

Interrupt re-entrany problems
PostPosted: Tue Apr 04, 2006 10:22 am     Reply with quote

I'm currently writing a program which has a loop which takes a temperature reading, does a delay_ms(200), writes out to a MMC, and continutes looping.

Since MMCs need to be written to in 512 byte blocks, I wait until I have a full 512 bytes to write. Having a power failure before the buffer has been written to memory reults in data loss, and a file not being properly closed, both of which are bad.

I'm using a PIC18LF6720, which allows me to use a low voltage interrupt. My isr looks something like

Code:
#INT_LOWVOLT
void lowvolt_isr(void)
{
int8 i;
for(i=0; i < MAXFILES; i++);
   fclose(i);
}


The problem is that fclose() is aslo called from outside the isr (when the user wants to stop logging). Since I'm calling the same funciton from inside and outisde an isr, it has disabled interrupts all over the place, (most notably, during the 200ms delay) meaning the isr stands very little chance of being called.

My question is this: Bearing in mind that I never need to return from the low voltage isr, is there a way for me to be able to stop all the interrupts being automatically disabled by the compilimacator?
-JBM
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Tue Apr 04, 2006 10:52 am     Reply with quote

Try this.

In the low voltage interrupt, simply set a flag:

Code:
power_fail = TRUE;


Down in the main loop of your program have this:

Code:
if (power_fail) {
   power_fail = FALSE;
   // save & close everything here
}


That will solve the reentrancy problem. Whether or not you'll have enough time to save & close everything is another issue.
JBM



Joined: 12 May 2004
Posts: 54
Location: edinburgh, Scotland

View user's profile Send private message

PostPosted: Tue Apr 04, 2006 10:56 am     Reply with quote

Nice idea, but i have a statement
Code:
delay_ms(200);

which rather prohibits that - checking for a set bit every 200ms just isn't fast enough when power is going down.

I know i could call the 200ms delay as 200 separate 1ms delays, but that's really not addressing the fundamental problem.

Thanks for the reply

Any suggestions for a cheap-and-dirty hack? I like those....
-JBM
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Tue Apr 04, 2006 11:01 am     Reply with quote

It seems to me that your issue is that interrupts are being disabled which delays your ability to do an fclose() in time?? However, this only occurs during the fclose(). Since the lowvolt isr is actually calling the fclose function, what is the problem? You will still have to call fclose from the ISR, so what if it is called from main? Once the "main" fclose() is completed, the ISR will trigger and the rest of the files will be closed. You won't miss the interrupt, it will just be delayed which shouldn't hurt since the amount of the delay is still required when the function is called from an ISR.
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Tue Apr 04, 2006 11:04 am     Reply with quote

JBM wrote:
Nice idea, but i have a statement
Code:
delay_ms(200);

which rather prohibits that - checking for a set bit every 200ms just isn't fast enough when power is going down.

I know i could call the 200ms delay as 200 separate 1ms delays, but that's really not addressing the fundamental problem.

Thanks for the reply

Any suggestions for a cheap-and-dirty hack? I like those....
-JBM


Change the delay to something like this:

Instead of:

Code:
delay_ms(200);


Change to:

Code:
int16 i = 0;

while (i < 2000 && okay_to_delay) {
   delay_us(100);
   i++;
}


Your low voltage interrupt routine now also includes:
Code:
okay_to_delay = FALSE;


Quick & dirty yes, elegant no! Very Happy
JBM



Joined: 12 May 2004
Posts: 54
Location: edinburgh, Scotland

View user's profile Send private message

PostPosted: Tue Apr 04, 2006 11:04 am     Reply with quote

Well, yes and no.

fclose() calls other functions, one of which is delay_ms(). So any time delay_ms() is called (like during the 200ms delay in the main loop) , interrupts are disabled.

Any other ideas?

-JBM
dyeatman



Joined: 06 Sep 2003
Posts: 1934
Location: Norman, OK

View user's profile Send private message

PostPosted: Tue Apr 04, 2006 3:02 pm     Reply with quote

I never use the delay() routines unless they are for very short intervals (1ms or less). Instead I have a 5ms or 10ms (depending on how fine a control I need) timer running that counts a variable down when the timer interrupts. This can control any number of counters and, by testing the counters inside the interrupt, set a flag at any special count or time. If you need precise timing you have to do some cycle counting to get the 10ms interval perfect (I cheat and use a scope with an output bit toggle) but most cases I don't need that much precision.
**************************************************
EXAMPLE:

Code:
#INT_TIMER1
Timer1_int()
// first we must start the counter for the next 10ms interval
    set_timer1(TIMER1START); 
//
// ***** Then we can do whatever we need to do here....
    // count the 10ms intervals for a seconds or heartbeat counter
    if (--_10mscntr < 1)
        {
          _10mscntr = 100;  // reset for one second counter

          // decrement a seconds counter
          if (seconds > 0)
                seconds--; // you can have up or down counters

          if (seconds==0) // you can have up or down counters
            {
            //reset seconds to 60 etc. at this point
               seconds-60;
               mins++;
            }
        }  // if --10mscntr < 1

// *****
    if (_delay1 > 0)  // count 10ms intervals
         _delay1--;

    if (_delay2 > 0) // another timer I can use for something
        _delay2--;

    if (_delay3 > 0) // another timer I can use for something
        _delay3--;
}


With this, I simply set a variable (e.g. delay1) for the total time in 10ms intervals that I need to delay then wait for the counter to reach zero and set a flag to trigger an action in the background loop. I do a lot of real time state machine control using this type of routine. This was just an example. There are many possible variations of this type of timing that would accomplish the same thing.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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