|
|
View previous topic :: View next topic |
Author |
Message |
EdWaugh
Joined: 07 Dec 2004 Posts: 127 Location: Southampton, UK
|
fprintf cause interrupts to be disabled |
Posted: Tue Nov 11, 2008 4:02 pm |
|
|
Hi all,
I feel a lot like this is a topic that has been covered before but my searching of the forum turns up loads of results that are not even slightly related. Sorry if you've answered this before but I have found that using fprintf to display a 32 bit int causes interrupts to be disabled while it is executing.
Is there a way around this or can someone explain the reason for it? I am using compiler v3.249.
cheers
ed |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Nov 11, 2008 4:21 pm |
|
|
Post a little program that shows the problem. Post a description of
the serial interface (RS-485 ?, using hardware or software UART ?). |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Wed Nov 12, 2008 3:18 am |
|
|
You are probably using fprintf within an interrupt routine.
CCS functions are not re-entrant meaning that if your main code is within the fprintf function when the interrupt occurs, if the interrupt went into the same function (fprintf) it would overwrite the registers/memory with the new call. When the interrupt finishes and returns to where it interrupted (the fprintf routine), all the variables are corrupt and the pic will crash!
To prevent this, rather than stopping you from calling the same routine from within an interrupt it just disables interrupts for that function, thus preventing the problem.
Your solutions are,
A. Create a separate routine to be called from your interrupt. With fprintf this would be a lot of work, and you must ensure that this routine does not call other functions which are also used outside the interrupt.
B. Set a flag in the interrupt to indicate to the main loop that the fprintf needs to be called.
Option B is the preferred method as functions like fprintf are quite long and your interrupt routines should be as short as possible.
There may be the problem that the interrupt occurs again before you managed to call the fprintf and overwrite the first set of values, you would need to work around this, either disabling interrupts yourself, using mutex/locks to prevent the interrupt routine from corrupting the first set of values or buffer them.
With the mutex/lock option you may miss a set of values as you would with the disable interrupts BUT if you do other things in the interrupt then this will still happen.
With buffering, if the interrupts occur to quickly you will run out of buffer before the fprintf is called and you will miss values as well.
Have fun. |
|
|
EdWaugh
Joined: 07 Dec 2004 Posts: 127 Location: Southampton, UK
|
|
Posted: Wed Nov 12, 2008 8:00 am |
|
|
It's a bit hard to show the output as I am looking at it with a scope on some debug lines but whenever the fprintf is active I get a period of no interrupts triggering. I am using an interrupt to collect A2D data and then I FIR filter it and at the moment just want to display the result. The A2D interrupt is 'high' the RS232 output interrupt is 'normal' and fprintf is called from the main while() loop on a flag.
In the example below the string with the uint32s causes the problem but the plain text string does not.
Code:
while(1)
{
fir_process_filters(&ui32_result0, &ui32_result1);
//fprintf(RS232A, "Ra: %lu, Sa: %lu\r", ui32_result0, ui32_result1);
fprintf(RS232A, "A string of approximately equal length\r");
}
cheers
ed |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Wed Nov 12, 2008 9:14 am |
|
|
Quote: |
the RS232 output interrupt is 'normal'
|
Have you written your own transmit interrupt ?
As only 1 interrupt can happen at a time it would appear that it is spending alot longer in the rs232 tx interrupt when doing the fprintf routine with the UINT32's. The fprintf with the params will take alot longer to process than the other one but this should not be stopping your interrupt from triggering unless you have done something in your code.
You need to show more, inpaticular your interrupt routines.
You could try using sprintf to put the string into a buffer before fprinting it e.g.
int buf[80];
sprintf(buf, "Ra: %lu, Sa: %lu\r", ui32_result0, ui32_result1);
fprintf(RS232A, buf); |
|
|
EdWaugh
Joined: 07 Dec 2004 Posts: 127 Location: Southampton, UK
|
|
Posted: Wed Nov 12, 2008 9:31 am |
|
|
Hi Wayne,
I'm pretty sure this is an old problem that I've read about before somewhere.
I'm actually only using rs232 interrupts for receiving data, transmit is handled linearly from the main while loop.
Interestingly when I do as you suggest the problem goes away:
Code: |
sprintf(str_temp, "Ra: %lu, Sa: %lu\r", ui32_result0, ui32_result1);
fprintf(RS232A, "%s\r", str_temp);
|
|
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Wed Nov 12, 2008 12:37 pm |
|
|
EdWaugh wrote: | Hi Wayne,
...Interestingly when I do as you suggest the problem goes away:
Code: |
sprintf(str_temp, "Ra: %lu, Sa: %lu\r", ui32_result0, ui32_result1);
fprintf(RS232A, "%s\r", str_temp);
|
|
This may just be reducing the problem, not actually eliminating it. This combination of functions eventually calls the same functions are in your original
fprintf(RS232A, "Ra: %lu, Sa: %lu\r", ui32_result0, ui32_result1);
The difference is that using two calls allows a period between them where interrupts are enabled. This may be enough to make it appear that interrupts are enabled all the time, but they are probably not.
I think Wayne's first suggestion of looking for functions that are called from both interrupt and non-interrupt time is worth doing. I thought the compiler usually warns about this. You didn't see any compiler warings about interrupts being disabled around some of your main code? _________________ Robert Scott
Real-Time Specialties
Embedded Systems Consulting |
|
|
EdWaugh
Joined: 07 Dec 2004 Posts: 127 Location: Southampton, UK
|
|
Posted: Wed Nov 12, 2008 1:41 pm |
|
|
Hi Robert,
No I don't get any compiler warnings but I am using v3 not v4 where I think it started warning about that. Perhaps it is time I moved up if it is looking stable enough, there were a lot of bugs when I first tried it.
I am a bit confused about why having the same function called from both and interrupt and not would be a problem, surely when the interrupt is triggered the state of any function is put on the stack and a new one created in the current machine state. Why would the temporary variable locations in a function be reused? In the instance we are discussing I am not using any of the same functions in the interrupt and in the main while loop, as they are just triggered by flags set by interrupts.
Does anyone know a way I can get v3 to warn me about this? I have set warnings to their maximum level, although my experience is that it never warns me about anything and pretty much just syntax checks. Maybe I could look at the call tree file and figure this out?
cheers
ed |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 12, 2008 2:29 pm |
|
|
The reason it is a problem, is that the PIC, _does not have a variable stack_. The only stack present, is the one for function calls.
Hence functions cannot be recursive.
This is a hardware limitation of the chips...
Best Wishes |
|
|
EdWaugh
Joined: 07 Dec 2004 Posts: 127 Location: Southampton, UK
|
|
Posted: Wed Nov 12, 2008 3:33 pm |
|
|
Hey Ttelmah,
Surely this is just a software issue tho? Why would the PIC need a variable stack in hardware? Surely it's just a register acting as a stack pointer where the stack is held in normal RAM? Then when performing a context switch the compiler would just record the data to the stack including the last value of the stack pointer and then point the hardware register (or even just a fixed RAM location) at the new stack entry?
Maybe I have misunderstood how this system should work!
cheers
ed |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Thu Nov 13, 2008 3:19 am |
|
|
I have a feeling that you have actually moved on from the interrupts disabled issue as you are now setting a flag and doing the fprintf within the main loop.
Correct me if I am wrong but the first issue was because you were calling fprintf from within your interrupt routine but now you have changed that to using a flag ?
Now the question is why it LOOKS like interrupts are disabled when you do the fprintf with parameters but not when you use sprintf !
I say looks like because it is possible that another interrupt is causing the problem or interrupts have been disabled or the way you are testing for the interrupt is questionable.
How is the interrupt triggered ?
What other interrupts are enabled ?
Are you using any CCS libraries/drivers which may be using interrupts ?
How are you monitoring the interrupts, you say you are using debug lines!
Are you toggling the debug lines from within your interrupt ?
Unfortunately there is very liitle code to look at.
If you could minimise your code but still have the same problem then we could examine/test it and perhaps help. |
|
|
EdWaugh
Joined: 07 Dec 2004 Posts: 127 Location: Southampton, UK
|
|
Posted: Thu Nov 13, 2008 4:10 am |
|
|
Hi Wayne,
No I was never calling fprintf in an interrupt.
I think that the compiler is disabling the interrupts because it thinks there is another use of fprintf somewhere. I suspect scott is correct and using the two calls just allows a window of interrupts to do the processing I need. I might try and compile it with v4 and see if I get a warning. I'm still not sure why this effect needs to exist tho, do all C compilers for the PIC work this way?
cheers
ed |
|
|
Ttelmah Guest
|
|
Posted: Thu Nov 13, 2008 5:19 am |
|
|
EdWaugh wrote: | Hey Ttelmah,
Surely this is just a software issue tho? Why would the PIC need a variable stack in hardware? Surely it's just a register acting as a stack pointer where the stack is held in normal RAM? Then when performing a context switch the compiler would just record the data to the stack including the last value of the stack pointer and then point the hardware register (or even just a fixed RAM location) at the new stack entry?
Maybe I have misunderstood how this system should work!
cheers
ed |
Think about size.
The problem is that there are about 20 hardware registers that need to be saved (more on the latter PICs), to save the system 'state'. On most PICs there is not that much RAM to implement a stack to hold this, so only a single save is available. A genuine variable 'stack', allowing multiple calls inside one another, would take more space, than is normally available. Especially when to handle this for functions in general, you would also have to save all the local variables used inside the functions....
Hence it is made _your_ responsibility to think of, and handle this. If you want to call the same function inside the interrupt, then declare a second copy with a different name and use this. This then allocates a single seperate set of memory for this to use, without having to handle the 'generic' situation.
Handling generic recursion, is something that is not normally implemented on really small processors.
It is down to what you want. You could implement a software stack, but on most of the chips, the code to do this, and the RAM space needed, would take more room than is really available....
Best Wishes |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Thu Nov 13, 2008 5:40 am |
|
|
Does the compiler still give a warning that it is disabling interrupts ? |
|
|
EdWaugh
Joined: 07 Dec 2004 Posts: 127 Location: Southampton, UK
|
|
Posted: Thu Nov 13, 2008 10:18 am |
|
|
Hi all,
The compiler never gives me any warnings of any kind, but then I am on v3.
I see what Ttelmah is saying about size but I disagree a little, 20 8 bit registers is not a lot on a PIC with 4 KB of RAM like the 18f6723. Especially as they only get used for two layers of interrupt. The local variables in a function using recursion would grow without limit until the RAM was full but this would be down to the particular application, having a generic approach seems very sensible to me.
Am I correct in understanding that the CCS approach is to assume that all functions local variables could be used simultaneously, keeping one copy of each so RAM is not reused? Are all PIC compilers working in this way?
How would I go about declaring a second copy of fprintf if I thought this was the problem?
cheers
ed |
|
|
|
|
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
|