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

GIE being cleared accidentally

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



Joined: 10 Oct 2007
Posts: 23

View user's profile Send private message

GIE being cleared accidentally
PostPosted: Tue Nov 08, 2011 1:10 pm     Reply with quote

Been recompiling a big old program that ran fine on a 16F877 to run in a 16F1939 but the program hangs waiting for a timer interrupt that should be continuous, but unexpectedly stops.

When I debug I see that INTCON GIE has been cleared yet I only ever enable GIE in the program. There is no explicit disable in my code so I can't begin to think how it's getting cleared. I know the old gotcha about enabling it but this is the opposite problem. Anyone have any suggestions about how to debug this? Pity we can't break on a write to a register! That would pin it down.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Nov 08, 2011 1:19 pm     Reply with quote

Quote:
Anyone have any suggestions about how to debug this ?

1. Edit the 16F1939.h file and temporarily comment out the #nolist line.

2. In MPLAB, go to Project / Build Options and set the List file format to
Symbolic format.

3. Also, enable "Show Warnings", if you have them disabled.
Then when you compile, look for any warnings about interrupts disabled
to prevent re-entrancy.

4. Compile your program and look at the .LST file. Look for any lines
that write to the INTCON register (bit 7), or that write to the GIE bit.
legion



Joined: 10 Oct 2007
Posts: 23

View user's profile Send private message

PostPosted: Tue Nov 08, 2011 1:37 pm     Reply with quote

OK, done all that but no warnings and I searched the .lst file for GIE and found it being disabled by the compiler in eeprom write routines but can see it being restored afterwards. Searching for INTCON I can see it being o'red with 0xc0 when I call enable_interrupts(global) and that's it.

It's a huge listing so I don't stand a chance if it's something subtle like an indirect write generated by the compiler. I don't have any pointer indirection in my own code (I write C like its BASIC ;) How the heck is the bit getting cleared?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Nov 08, 2011 1:43 pm     Reply with quote

Quote:
When I debug I see that INTCON GIE has been cleared

Are you stepping through an interrupt routine ? The PIC hardware will
clear the GIE bit while the interrupt is handled. The 16F1939 data sheet says:
Quote:

7.1 Operation
The following events happen when an interrupt event
occurs while the GIE bit is set:
• Current prefetched instruction is flushed
• GIE bit is cleared
• Current Program Counter (PC) is pushed onto the
stack
• Critical registers are automatically saved to the
shadow registers (See Section 7.5 “Automatic
legion



Joined: 10 Oct 2007
Posts: 23

View user's profile Send private message

PostPosted: Tue Nov 08, 2011 1:49 pm     Reply with quote

No, I'm in the main() section polling a count that's decremented in a timer interrupt service routine. The count freezes, I halt the program and there it is stuck in a while loop with GIE clear. Nuts.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Nov 08, 2011 2:53 pm     Reply with quote

Are you doing anything unusual in your program, or anything other
than straight simple programming, such as:

- #org, #build, #separate, #int_global, #int_default, etc.
- Rarely used routines such as jump_to_isr(), longjmp(), setjmp(), etc.
- CCS's multiple compilation units.
- Watchdog timer enabled.
- Calling external routines from inside an interrupt routine.
- Using #asm and #endasm
- Using addressmod
- Writing to Flash memory during normal program operation.

Is there anything unusual about your hardware, such as:

- Low voltage operation.
- Very noisy external circuits, such as relays, motors, coils, RF, etc.
- Poor regulation of power supply.
- Missing bypass capacitors on Vdd pin.s
- Poor board layout with power rail stubs and/or thin power rail traces.
- Missing MCLR resistor.
- Missing connections to AVdd and Avss pins on the PIC.
- Strange oscillator configuration, or poor design.
- Using MCLR pin as an input pin.

Or anything that is not ordinary.

Also, what is your compiler version ?

And, does this problem happen outside of a Debugger environment ?
Does it occur during normal "Stand Alone" operation of the program ?
legion



Joined: 10 Oct 2007
Posts: 23

View user's profile Send private message

PostPosted: Tue Nov 08, 2011 3:21 pm     Reply with quote

PCM programmer wrote:
Are you doing anything unusual in your program, or anything other
than straight simple programming, such as:

- #org, #build, #separate, #int_global, #int_default, etc.
- Rarely used routines such as jump_to_isr(), longjmp(), setjmp(), etc.
- CCS's multiple compilation units.
- Watchdog timer enabled.
- Calling external routines from inside an interrupt routine.
- Using #asm and #endasm
- Using addressmod
- Writing to Flash memory during normal program operation.


None of the above.

PCM programmer wrote:

Is there anything unusual about your hardware, such as:

- Low voltage operation.
- Very noisy external circuits, such as relays, motors, coils, RF, etc.
- Poor regulation of power supply.
- Missing bypass capacitors on Vdd pin.s
- Poor board layout with power rail stubs and/or thin power rail traces.
- Missing MCLR resistor.
- Missing connections to AVdd and Avss pins on the PIC.
- Strange oscillator configuration, or poor design.
- Using MCLR pin as an input pin.

Or anything that is not ordinary.

Operation is from regulated 5V. It's a professional double-sided board layout with ground plane, numerous bypass caps etc. It's not in a noisy environment, also it's been working fine with the 16F877 for more than five years. The only code change was to switch off the PLL which defaulted to on with the original fuse statement (7.372800 xtal) and reassign depreciated references to RTCC and ADC elements. Pretty tame stuff really. The only awkward thing is the size of the program which means I'm a bit lost to know how to go about isolating the problem.

However, given that there are no explicit instructions to disable GIE in my code, I can only imagine that the compiler is doing something odd. I appreciate the sensitivity of interrupt service routines which is where I'd always look first for this kind of problem.

PCM programmer wrote:

Also, what is your compiler version ?

And, does this problem happen outside of a Debugger environment ?
Does it occur during normal "Stand Alone" operation of the program ?


PCM 4.122 and it hangs with GIE disabled if I program the 16F1939 and run without the ICD3 connected. The application shunts data about between a handful of RS232 ports so there's quite a few buffers filling with characters.

One buffer is 96bytes so straddles a couple of banks. MPLAB doesn't know how to watch an array like that (says some elements are in reserved memory) so it's awkward already trying to see what goes on.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Nov 08, 2011 3:36 pm     Reply with quote

Here is one previous post on the problem of mysteriously disabled Global
interrupts. He has some diagnostic code to try to find the problem:
http://www.ccsinfo.com/forum/viewtopic.php?p=73166


My suggestion is to comment out large sections of your program and
keep doing that until the problem goes away. Then uncomment it to
locate the trouble spot.
legion



Joined: 10 Oct 2007
Posts: 23

View user's profile Send private message

PostPosted: Wed Nov 09, 2011 5:19 am     Reply with quote

Right, I've tracked it down...

From within main() I call a routine that executes the line printf(com,".... where com is another routine that handles characters sent to the hardware UART. Inside com, a count decremented within a timer ISR is watched for a timeout. This hangs because part way through the printf, before it passes the char to com, the compiler has disabled GIE with the instruction BCF 0xb, 0x7 This happens in instructions following under #device PIC16F1939 in the listing - presumably part of the printf function call.

Linear sequence of events:

printf(com,"........

051F 3058 MOVLW 0x58
0520 0023 MOVLB 0x3
0521 0091 MOVWF 0x11
0522 3002 MOVLW 0x2
0523 0092 MOVWF 0x12
0524 1003 BCF 0x3, 0
0525 3006 MOVLW 0x6
0526 00B6 MOVWF 0x36
0527 0020 MOVLB 0
0528 248D CALL 0x48d

048D 080B MOVF 0xb, W
048E 0023 MOVLB 0x3
048F 00B7 MOVWF 0x37
0490 138B BCF 0xb, 0x7 <<<<<<<< GIE cleared
0491 1795 BSF 0x15, 0x7
0492 1415 BSF 0x15, 0
0493 0000 NOP
0494 0000 NOP
0495 1803 BTFSC 0x3, 0
0496 2CAE GOTO 0x4ae
0497 0813 MOVF 0x13, W
0498 397F ANDLW 0x7f
0499 00B8 MOVWF 0x38
049A 0811 MOVF 0x11, W
049B 00B9 MOVWF 0x39
049C 0812 MOVF 0x12, W
049D 00BA MOVWF 0x3a
049E 0838 MOVF 0x38, W
049F 00BB MOVWF 0x3b
04A0 0020 MOVLB 0
04A1 22DA CALL 0x2da

void com(char c)
1078: {
1079: int i;
1080: #use modem
036E 0020 MOVLB 0
036F 1E11 BTFSS 0x11, 0x4
0370 2B6F GOTO 0x36f
0371 0023 MOVLB 0x3
0372 009A MOVWF 0x1a
1081: while (buffer_ptr || RTS) //is serial input currently restricted?keep sucking until dried up
1082: {
02DA 08F0 MOVF 0x70, F

>>>>>>>>> following code depending on timer ISR hangs with GIE disabled.
Ttelmah



Joined: 11 Mar 2010
Posts: 19363

View user's profile Send private message

PostPosted: Wed Nov 09, 2011 5:31 am     Reply with quote

It sounds as if the code is trying to do the 'right thing', but getting it wrong....
You talk about watching a counter decremented in an ISR. If you are looking at a variable that is updated in an ISR, and the variable is more than 8bits in size, then it is _essential_, to disable interrupts while you access it. Obviously you'd normally re-enable them immediately after reading the variable. For some reason to do with the encapsulation, the compiler is trying to do the right thing, and then getting the re-enabling wrong....
I'd suggest you modify your reading of the variable with something like:
Code:

routine_that_accesses_variable() {
   int16 local_copy;
   //Then whenever you want to access the variable
   disable_interrupts(GLOBAL);
   local_copy=your_variable;
   enable_interrupts(GLOBAL);
   //do what you want with the copy.
}


Best Wishes
legion



Joined: 10 Oct 2007
Posts: 23

View user's profile Send private message

PostPosted: Wed Nov 09, 2011 6:03 am     Reply with quote

Hi Ttelmah. A appreciate the potential issue you raise but my variable is an 8 bit int and it's the fact that the timer ISR isn't firing that's causing the problem. Hey ho, I always try doing the right thing in life but...

(e.g using a compiler instead of hand assembly)
Ttelmah



Joined: 11 Mar 2010
Posts: 19363

View user's profile Send private message

PostPosted: Wed Nov 09, 2011 6:22 am     Reply with quote

Fair enough.
One obvious comment. You haven't got 'disable_ints' in the #use RS232 declaration?. Though it shouldn't cause what you are seeing, and really only applies when using software RS232, it might cause the compiler to think it is meant to do something with the interrupts!...

Best Wishes
legion



Joined: 10 Oct 2007
Posts: 23

View user's profile Send private message

PostPosted: Wed Nov 09, 2011 7:03 am     Reply with quote

Nope. Now I'm unsure what to do. If I try working round it by setting GIE in the non-ISR parts of the program I have on idea how this might interfere with what the compiler's been assuming.
legion



Joined: 10 Oct 2007
Posts: 23

View user's profile Send private message

PostPosted: Wed Nov 09, 2011 7:39 am     Reply with quote

Further investigation shows me that in the case of:

printf(user_function,"%u",int_var)

the compiler disables GIE before calling user_function and leaves it disabled until the end of the completion of the string. However, if the string contains no variables, GIE isn't set. SO under some circumstances the compiler is enforcing a global ban on interrupts while printing - even to a hardware UART.

Can this be intentional? It sure messes with a lot of things and if people here didn't suggest it as the source of my problem I can only guess they hadn't expected it.
Ttelmah



Joined: 11 Mar 2010
Posts: 19363

View user's profile Send private message

PostPosted: Wed Nov 09, 2011 9:10 am     Reply with quote

The one thing that would trigger something like this, is if 'user_function', is internally using a routine that is also used inside one of your ISR's. However the compiler should be giving you a warning in this case.

Now, though you say you have enabled warnings, I'd suspect that somewhere in the code is a line turning one or more of them off.

Prove this is what is happening. Make another function, say 'dummy', that does nothing except perhaps toggle a pin, and returns. Call this in place of user_function. I think you will find the interrupts are not disabled. If so, then you need to track down what is disabling warnings, and what is being called inside your ISR and in the printf. Remember this can be a library function (so for instance a multiplication routine etc..). The fact that the interrupt is disabled round the entire 'user_function', suggests that it is either very fundamental to the routine, or the routine itself.....

Best Wishes
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