View previous topic :: View next topic |
Author |
Message |
koenbielen
Joined: 23 Apr 2009 Posts: 42
|
fprintf prints %u instead of variable |
Posted: Wed Oct 05, 2016 5:36 am |
|
|
hi
In my code i have
Code: | fprintf(NETWERK,"<II PWM %u %Ld %d>", nPWMValueF, nPreviousPWMValue, nNumber); |
data on serial port in good condition is:
II PWM 0 0 36
Sometimes i get this:
II PWM %u %Ld %d
The function actually prints the %d %Ld %d
I'm wondering what I'm doing wrong in my code. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Wed Oct 05, 2016 8:09 am |
|
|
Not really possible to tell.
Chip?.
Compiler version number?. etc. etc..
The only time I've seen odd behaviours like this, was when a programmer had turned off STVREN, and had overflowed the stack. Then started seeing all sorts of odd things from the const variables being displayed.
Sounds quite similar..... |
|
|
koenbielen
Joined: 23 Apr 2009 Posts: 42
|
hi |
Posted: Wed Oct 05, 2016 11:07 am |
|
|
hi
Yes you are correct.
I gave less information, so here is more.
PIC : 18F26K22
compiler version : 4.134
You gave me a good hint about the STVREN its actually off.
I try again with this set to on. I can see if i get lots of reboots meaning stack is overflowing.
I use interrupts Timer 1 and RDA with priority on RDA.
But I'm not sure if this is the problem.
I have compiled code with int_rda HIGH and without.
Problem is the same.
I must say the processor is 98% full maybe this is an issue.
I use for 9 years compiler version of CCS and this is the first time I see this behaviour. So I'm sure it's code but not sure where to start.
So if someone has some good directions for me to look at... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Oct 05, 2016 11:42 am |
|
|
koenbielen wrote: |
You gave me a good hint about the STVREN its actually off.
I try again with this set to on. I can see if i get lots of reboots meaning
stack is overflowing.
|
What's your stack usage ? Post the top part of the .LST file, where it
gives a report on ROM, RAM and stack. I'm interested in seeing how
many stack levels you are using.
Quote: | I must say the processor is 98% full maybe this is an issue. |
It could be. You are at compiler vs. 4.134. With every major version
(eg. 5.xxx), CCS gets better at optimizing and partitioning the code.
Another reason could be accidentally writing past the end of a RAM array.
If you left off the space for the 0x00 at the end of a string array, you
would overwrite the next variable in RAM (if it's allocated just after the
end of the array by the compiler). |
|
|
koenbielen
Joined: 23 Apr 2009 Posts: 42
|
|
Posted: Thu Oct 06, 2016 1:08 am |
|
|
CCS PCH C Compiler, Version 5.001, 3xxxx 06-okt-16 08:37
Filename: test.c
ROM used: 64362 bytes (98%)
Largest free fragment is 1170
RAM used: 3212 (82%) at main() level
3350 (86%) worst case
Stack used: 17 worst case (7 in main + 10 for interrupts)
Stack size: 31
*
00000: GOTO C108
*
00008: GOTO 00A6
0000C: NOP
0000E: NOP
00010: NOP
00012: NOP
00014: NOP
00016: NOP
00018: MOVWF 04
0001A: MOVFF FD8,05
0001E: MOVFF FE0,06 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Thu Oct 06, 2016 1:32 am |
|
|
Er. You say you are using 4.134, then show code using 5.001.
No hope. 5.001, was the very first 'alpha' release of V5. You want to be on something like 5.012 as the earliest. 4.134, is a better working compiler than 5.001.
The point PCM_programmer is making is that there is no hardware 'limit protection' in the PIC. If using pointers (or arrays - the same thing in C), _you_ have to make sure that you never work outside the indexes you have selected for the array. If (for instance), you have a buffer array, with 20 entries, if you then copy a 20 character string into this, you will have overflowed it (a string in C always has a terminating NULL). The same applies when talking to data arrays etc.. Writing beyond the limits will result in other variables being corrupted...
I see you are using interrupts. What is happening, could very easily be the result of incorrect code in these. Something like an 'enable_interrupts(GLOBAL)', inside an interrupt handler could cause this, or an interrupt handler changing a value 'while' it is being printed (you need to protect against this yourself). |
|
|
koenbielen
Joined: 23 Apr 2009 Posts: 42
|
|
Posted: Thu Oct 06, 2016 2:52 am |
|
|
OK
so this means this item is solved in new version of compiler?
I will check, double check and triple check my code.
And yes I use disable_interrupts(GLOBAL) and enable_interrupts(GLOBAL) inside an interrupt.
is the update for free? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Thu Oct 06, 2016 3:02 am |
|
|
No.
On a PIC, you must _never_ use enable_interrupts(GLOBAL) inside an interrupt handler. Doing so, _will_ lead to problems, and will almost certainly be what is causing your problem.
PIC does not support re-entrancy (code called inside itself). The PIC _hardware_ automatically disables interrupts when the interrupt handlers are called, and automatically re-enables them _the instruction after the chip returns from an interrupt_. If you enable them yourself inside the handler, the routine can get called inside itself. Result disaster.
Chips where enable_interrupts is used in the handler function differently to the PIC. They either do support re-entrancy (so this doesn't matter), or they do not actually perform the re-enable, till the next instruction is executed (which should be the exit return).
Go back to 4.137, which was the compiler you originally said you had. 5.001, was an early test compiler for V5, and really should be avoided.
An upgrade is a charged for thing, and would be worthwhile (we now are on 5.062, and a lot of features are fixed or have improved, but your problem is almost certainly your use of enable_interrupts(GLOBAL) in the interrupts. This must never be done on a PIC. |
|
|
koenbielen
Joined: 23 Apr 2009 Posts: 42
|
|
Posted: Thu Oct 06, 2016 4:57 am |
|
|
OK thank you for this valuable information
I use this global on of interrupt a lot.
So i removed and am testing.
So is it ok to disable a timer interrupt like example below?
To make sure the serial data is first received and before leaving the int routine enabling the timer1 interrupt?
Code: |
#INT_RDA HIGH
void SerialDataAvailable()
{
if(kbhit(NETWERK))
{
disable_interrupts(INT_TIMER1);
ReadSerialData();
enable_interrupts(INT_TIMER1);
}
}
|
And this is BAD code if I understand your info correct,
the disable_interrupt(INT_RDA) is handled by the routine itself?
Code: |
#INT_RDA HIGH
void SerialDataAvailable()
{
if(kbhit(NETWERK))
{
disable_interrupts(INT_RDA);
disable_interrupts(INT_TIMER1);
ReadSerialData();
enable_interrupts(INT_RDA);
enable_interrupts(INT_TIMER1);
}
}
|
Thanks again for the info. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Thu Oct 06, 2016 7:21 am |
|
|
It's perfectly OK to enable an individual interrupt inside interrupts. For instance if you want to have a timer 'started' by another interrupt (perhaps an external edge trigger), then you could enable this timer interrupt inside the edge interrupt routine.
However it is unnecessary to disable interrupts inside handlers (a couple of exceptions later).
What you must never do is enable the global interrupt.
The interrupt protection is handled in hardware.
With 'single level' interrupts, when an interrupt occurs, the global flag is disabled as soon as the handler is called, and is automatically re-enabled only after you exit the handler. This stops all other interrupts.
With the two level interrupts, exactly the same thing happens for all other interrupts on the same level. If a 'low' interrupt occurs all the other low interrupts are stopped until this is serviced. If a 'high' interrupt occurs the same applies for high interrupts, and low interrupts are also blocked.
If you enable_interrupts(GLOBAL) inside the handler, you destroy the hardware protection. You are still inside the handler (you are for a long time after you leave your routine, the compiler has to do all the housekeeping of restoring everything saved when the interrupt was called). With global re-enabled, an interrupt can occur, and will then overwrite the previously stored values. Result 'garbage'. The return address has been lost, and anything can happen.....
The 'exceptions' for disabling, are things like INT_TBE, where if the event is not satisfied (you have no more data to send), then you have to disable this interrupt or it'll keep re-triggering.
There is also another comment on your INT_RDA code shown.
INT_RDA, means _one_ character is waiting to be read. Just one. The routine should just retrieve this one character, store it, and exit. Your code has the nasty look that it may be going off and doing a lot more.
EX_SISR.C, shows a typical PIC serial receive handler. Study.
Turning off INT_TIMER1 inside the receive routine, does nothing. You are already in the receive routine, it won't be exited by the timer (unless the timer has high priority set). The interrupt flag will get set, and the timer handler will be called when the RDA routine exits. With the interrupt disabled, exactly the same will still occur (the flag still gets set, and the routine will still be called after you re-enable it and exit the RDA routine). |
|
|
koenbielen
Joined: 23 Apr 2009 Posts: 42
|
|
Posted: Thu Oct 06, 2016 8:02 am |
|
|
Ok understand your info.
The RDA interrupt is exactly doing what you say,
It grabs the single byte from the buffer and stores it inside an array of data.
The data always has a start and stop char. So i know when i can set the dataready flag.
Data will be handled when the processor enters timer 1 interrupts routine.
this is done every 40 ms.
For the last 2 hours it seems to be stable and working as it should be when removed the global interrupt.
I also understand to buy a new compiler version. so i will ask my boss
So thank you for your help and for now i can with some precaution say its solved. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Thu Oct 06, 2016 8:22 am |
|
|
Good. |
|
|
|