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

global interrupts disabled mysteriously
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
dgi



Joined: 07 Jan 2004
Posts: 11
Location: Philadelphia, USA

View user's profile Send private message Visit poster's website

global interrupts disabled mysteriously
PostPosted: Wed Dec 06, 2006 10:20 am     Reply with quote

I am using CCS 3.249 (having read that it is the most stable) to program a PIC18F2420, crystal clocked at 20 Mhz.

My program sets up a single periodic interrupt to perform a high priority polling task, and enables it like this:

Code:

   setup_timer_2 ( T2_DIV_BY_1, 250, 5);

   // At 20mhz, the timer will increment every 200ns,
   // will overflow every 50us,
   // and will interrupt every 250us.
   // Dividing by 4 gives a millisecond count

   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);


In my main() loop, I run a "user interface" which reads the UART and parses various commands. My problem is that after running for several minutes, the interrupt is somehow disabled although the user interface keeps working. By checking the INTCON register like this:

Code:

#BIT GIE = 0xFF2.7
#BIT TMR2E = 0xF9D.1


and then reading the values of these bits, I find that what has happened is somehow the global interrupt enable "GIE" has been permanently disabled. However, there is no code anywhere in my program that disables global interrupts. In other words, I never call "disable_interrupts". Setting GIE back to 1 from the main() loop starts the interrupt again. It seems that either the compiler or the PIC itself is disabling interrupts (this happens automatically during execution of the interrupt) and forgetting to enable them again.

Has anyone ever seen something like this, or, do you know of any code that might have the unexpected side-effect of disabling global interrupts? I have a strncmp() in my program to parse commands, which is the only exotic thing besides simple integer arithmetic, checksumming a command line, and some printf()s.
Ttelmah
Guest







PostPosted: Wed Dec 06, 2006 10:23 am     Reply with quote

What is in your interrupt handler?.
The interrupts are disabled by the hardware, when the handler is called. If this has a problem, and overruns, or jumps back into the main, then you will see the effect described.

Best Wishes
dgi



Joined: 07 Jan 2004
Posts: 11
Location: Philadelphia, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Dec 06, 2006 1:16 pm     Reply with quote

Thank you Ttelmah for the advice. I haven't found anything wrong in the interrupt yet, but I may have found the problem in main(). My printf actually itself calls printf:

Code:

VOID AppendChecksum(char nextChar) // used for OUTGOING messages
{
   // call \n for a line break without ETX
   // use \r to end with 03 (ETX) character

   IF ((nextChar == '\n') || (nextChar == '\r'))
   {
      printf(send_uart, " %X\n\r", OutgoingChecksumRunningTotal);
      OutgoingChecksumRunningTotal = 0;
      if (nextChar == '\r')
               send_uart(3); // ETX = \x03
   }
   ELSE
   {
      OutgoingChecksumRunningTotal += nextChar;
      send_uart(nextChar);
   }
}

main()
...
printf (AppendChecksum, "uptime %lu seconds\r",uptime);


Could this somehow result in disabling global interrupts? Is it bad to use recursive function calls? The code for printf is not included in the LST file so it's hard to trace what the compiler is doing.
Ttelmah
Guest







PostPosted: Thu Dec 07, 2006 6:20 am     Reply with quote

Probably not directly.
Though recursion (which this is), is not supported, printf itself is normally coded as 'inline', and in this case, the printf being called uses a different output routine to the caller, so it might actually work!.
However though it'll probably crash the code, I'd not expect it to disable interrupts.
The way to do this, is to not use printf in the output routine. Just output the two hex digits yourself.
The other things that would cause the problem, is if printf is being called in the interrupt handler, since then interrupts will be disabled in printf...

Best Wishes
davekelly



Joined: 04 Oct 2006
Posts: 53
Location: Berkshire, England

View user's profile Send private message

PostPosted: Thu Dec 07, 2006 6:48 am     Reply with quote

I am using 3.249 also, for the 18F242

I have also experienced this problem, and am still trying to track it down.
dgi



Joined: 07 Jan 2004
Posts: 11
Location: Philadelphia, USA

View user's profile Send private message Visit poster's website

PostPosted: Thu Dec 07, 2006 9:24 am     Reply with quote

Thank you for the guidance, folks.

Working or not, I removed all recursive function calls as described above. However, I still have the problem of interrupts getting disabled after several minutes of the program running.

I still don't know why the global interrupt enable bit gets cleared in the middle of execution. I don't know whether it is a problem in the interrupt, in the main program, or in the compiler. But here is what I have done so far, which seems to help. I instrumented my code so that I can figure out exactly where GIE get disabled:
Code:

#BIT GIE = 0xFF2.7

void main()
{
   intproblem = 0; // means no problem
   while(true)
   {
     dosomething;
     if (!(GIE) && !(intproblem) ) intproblem = (__line__ % 256);
     dosomethingelse;
     if (!(GIE) && !(intproblem) ) intproblem = (__line__ % 256);
     dosomething;
     if (!(GIE) && !(intproblem) ) intproblem = (__line__ % 256);
     /// etc ...


Then, by checking the value of intproblem, I can find out where GIE first got cleared.

So far, GIE has been getting cleared during various string parsing operations such as strncmp() and printf(). Each time it happens, I rewrite the offending code to use different functions. Now my code has been running for 12 hours without a problem. However it is very unsatisfying to fail to find the source of the problem and positively fix it.

Let us know, Davekelly, if you learn what caused your problem.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Dec 07, 2006 11:27 am     Reply with quote

Quote:
However, there is no code anywhere in my program that disables global interrupts

There might be code in the CCS library functions that does this.

My advice is to create a complete .LST file and search it for all
references to register FF2. Look for a line of code like this:
Code:
BCF    FF2.7

This is clearing the GIE bit in the INTCON register.

To generate a full .LST file, edit the 18F2420.H file and comment out
the #nolist statement at the start of the file. Example:
Code:
// #nolist

When you do that, you will see the ASM code for library functions
that are normally hidden from the .LST file.
Spiteful



Joined: 09 Jul 2007
Posts: 2

View user's profile Send private message

PostPosted: Mon Jul 09, 2007 7:54 am     Reply with quote

I have same problem Sad

CCS v3.236
PIC12F629

defined:

unsigned int8 TRISIO;
#locate TRISIO=0x85
#bit TRISIO5=0x85.5
#bit TRISIO4=0x85.4
#bit TRISIO3=0x85.3
#bit TRISIO2=0x85.2
#bit TRISIO1=0x85.1
#bit TRISIO0=0x85.0

compilled:

.................... // pin A5 as input
.................... TRISIO5 = 1;
0345: BSF 03.5
0346: BSF 05.5
0347: BCF 03.5
0348: CLRF 2E
0349: BTFSC 0B.7
034A: BSF 2E.7
034B: BCF 0B.7
....................

when 2E is:

02E @INTERRUPT_AREA

What can i do with it? Why compiller clearing 2E and test GIE?
Ttelmah
Guest







PostPosted: Mon Jul 09, 2007 8:42 am     Reply with quote

0x2E, contains a value used by the compiler to reflect the interrupt status.
The compiler is checking if interrupts are enabled, and changing the value of bit 7 in this register to reflect this.
On these chips, if you change the TRIS, it can result in an interrupt on change being triggered.
This not 'the same problem'. The original poster had the GIE bit being changed. In your case, it is only being tested. In your case, there may well be some logic to this (though you would have to look at where 0x2E is used to work out the implications).

Best Wishes
Spiteful



Joined: 09 Jul 2007
Posts: 2

View user's profile Send private message

PostPosted: Mon Jul 09, 2007 11:47 pm     Reply with quote

Thanks.
nurquhar



Joined: 05 Aug 2006
Posts: 149
Location: Redditch, UK

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 15, 2012 5:49 am     Reply with quote

Compiler v4.130

I found this post after having similar problem with printf() turning off the global interrupt enable.

In my case I am using printf() with my own putc() to handle a data output from a timer interrupt function. My putc() accesses some 8 bit ints used within the timer isr(), this should be safe because the accesses will be atomic. CCS, as described above turns off GIE in printf() prior to calling my putc() because it thinks I will be changing a variable used with an interrupt. Although in my case this is misguided and not neccessary the compiler does not generate any Warnings to give me a clue as to why my program hangs unexpectedly.

If CCS is smart enough to put the GIE off when it sees something being used inside AND outside the interrupt (even though I don't want it) it could least generate a warning Question

Even better it could have looked at the access and decided they are 8bit and thererfor safe. THus no need to turn GIE off. Perhaps this is asking too much of the compiler.

I am fixing my code by using a somewhat brutel GIE = 1 inside my putc().

This is my code and build info :


Code:

#ignore_warnings NONE     

#include <12F1822.h>


#device adc=8

//////// Program memory: 2048x14  Data RAM: 112  Stack: 16
//////// I/O: 12   Analog Pins: 8
//////// Data EEPROM: 256
//////// C Scratch area: 20   ID Location: 8000
//////// Fuses: LP,XT,HS,RC,INTRC_IO,ECL,ECM,ECH,NOWDT,WDT_SW,WDT_NOSL,WDT
//////// Fuses: PUT,NOPUT,NOMCLR,MCLR,PROTECT,NOPROTECT,CPD,NOCPD,NOBROWNOUT
//////// Fuses: BROWNOUT_SW,BROWNOUT_NOSL,BROWNOUT,CLKOUT,NOCLKOUT,NOIESO
//////// Fuses: IESO,NOFCMEN,FCMEN,WRT,WRT_EECON400,WRT_EECON200,NOWRT
//////// Fuses: PLL_SW,PLL,NOSTVREN,STVREN,BORV25,BORV19,DEBUG,NODEBUG,NOLVP
//////// Fuses: LVP
////////
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES NOCPD                    //No EE protection
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOMCLR                     //Master Clear pin enabled
//#FUSES MCLR                     //Master Clear pin enabled
#FUSES PUT                      //Power Up Timer
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES NOIESO                     //Internal External Switch Over mode disabled
//#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES NOFCMEN                    //Fail-safe clock monitor enabled
//#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES DEBUG                     //Debug mode for ICD
//#FUSES WDT_NOSL             
#FUSES NOWRT                      //Program Memory Write Protected
//#FUSES PLL                // PLL Enabled
#FUSES PLL_SW               // PLL under software control, disabled
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES BORV24                   //Brownout reset at 2.5V
#FUSES NOCLKOUT                   //Output clock on OSC2


#use delay (clock=32000000)
#use fast_io(A)

#use rs232(UART1, baud=9600,parity=N,bits=8,stop=1) 


#byte APFCON = getenv("SFR:APFCON")
#bit RXDTSEL = getenv("bit:RXDTSEL")
#bit TXCKSEL = getenv("bit:TXCKSEL")

#byte IOCAP = getenv("SFR:IOCAP")
#byte IOCAN = getenv("SFR:IOCAN")
#byte IOCAF = getenv("SFR:IOCAF")

#bit GIE = getenv("bit:GIE")
#byte INTCON = getenv("SFR:INTCON")


#byte TMR0 = getenv("SFR:TMR0")


// RTS Monitor Input
#define   RTS      PIN_A2
#define UART_TX   PIN_A4
#define   UART_RX   PIN_A5      // PC TX Pin
// Tris Reg A     --543210 - 0=O/P 1==I/P
#define   TRIS_A   0b00001110
#define IOCA   0b00100100

// Pulse width modulation communication
int8 pwmc1 ;            // Control/Status
int8 pwmc_ch ;            // Data
int8 pwmc_cnt ;            // Data Count

int timer0_isr_cnt ;
int pwmc_putc_cnt ;
int putc_intcon ;

#define PWMC1_IO   0      // State of TX op
#define PWMC1_MARK   1      // Put marker pulse shape
#define PWMC1_D0   2      // Put data bit pulse shape

#define PWMC_TM      64         // No of counter ticks
#define PWMC_TMR1X   (PWMC_TM)
#define PWMC_TMR2X   (2 * PWMC_TM)

//#define PWMC_POS_LOGIC

#ifdef PWMC_POS_LOGIC
   #define PWMC_IO_LOW()      output_low(UART_TX)
   #define PWMC_IO_HIGH()      output_high(UART_TX)
   #define PWMC_IO_STATE()      input_state(UART_TX)   
#else
   #define PWMC_IO_LOW()      output_high(UART_TX)
   #define PWMC_IO_HIGH()      output_low(UART_TX)
   #define PWMC_IO_STATE()      !input_state(UART_TX)   
#endif

#INT_TIMER0
void timer0_isr()
{
   // Debug - keep track of ints
   timer0_isr_cnt++ ;

   if(PWMC_IO_STATE()) {
      // Set the timer according to bit pattern
      if(bit_test(pwmc1, PWMC1_MARK)) {
         TMR0 -= PWMC_TMR1X ;
      } else if(bit_test(pwmc1, PWMC1_D0)) {
         TMR0 -= PWMC_TMR2X ;
      } else {
         TMR0 -= PWMC_TMR1X ;
      }
      bit_clear(pwmc1, PWMC1_IO) ;
      PWMC_IO_LOW() ;
   } else {
      if(bit_test(pwmc1, PWMC1_MARK)) {
         TMR0 -= PWMC_TMR1X ;
      } else if(bit_test(pwmc1, PWMC1_D0)) {
         TMR0 -= PWMC_TMR1X ;
      } else {
         TMR0 -= PWMC_TMR2X ;
      }
      bit_set(pwmc1, PWMC1_IO) ;
      PWMC_IO_HIGH() ;

      // Get next bit
      if(pwmc_cnt) {
         bit_clear(pwmc1, PWMC1_MARK) ;
         if(pwmc_ch & 0x01) {
            bit_set(pwmc1, PWMC1_D0) ;
         } else {
            bit_clear(pwmc1, PWMC1_D0) ;
         }
         shift_right(&pwmc_ch,1,0) ;
         pwmc_cnt-- ;
      } else {
         bit_set(pwmc1, PWMC1_MARK) ;
      }
   }
}

void pwmc_putc(int ch)
{
   // Debug - keep track of putc calls
   pwmc_putc_cnt++ ;

   // FIX - Force GIE back on after printf turned it off !!
   //GIE = 1 ;

   // Debug - keep copy of GIE
   putc_intcon = INTCON ;

   // Wait for empty
   while(pwmc_cnt) ;   // <= View of variable used in the interrupt, not a problem
   pwmc_ch = ch ;      // <= Change of variable used in the interrupt, causes compiler to clear GIE in printf, no warning given
   pwmc_cnt = 8 ;      // <= Change of variable used in the interrupt, causes compiler to clear GIE in printf, no warning given
}

/*** NOT USED YET
void pwmc_puts(char *s)
{
   char *p;
   for (p = s; *p != '\0'; p++)
      pwmc_putc(*p) ;

   pwmc_putc('\r') ;
   pwmc_putc('\n') ;
}
***/

void pwmc_init()
{
   PWMC_IO_HIGH() ;
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256) ;
}

void pwmc_start()
{
   PWMC_IO_HIGH() ;
   TMR0 = 256 - PWMC_TMR1X ;
   clear_interrupt(int_timer1);
   enable_interrupts(int_timer0);

   bit_set(pwmc1, PWMC1_IO) ;         // Default to high
   bit_set(pwmc1, PWMC1_MARK) ;      // Default to mark bit
   bit_clear(pwmc1, PWMC1_D0   ) ;         // Default to '1' bit

   pwmc_cnt = 0 ;
}



void main()
{
   int8 ch ;

   // Switch to internal 32Mhz Osc, ie 4xPLL x 8Mhz = 32Mhz
   setup_oscillator(OSC_8MHZ | OSC_NORMAL | OSC_PLL_ON);
   setup_comparator(NC_NC);

   // Set port directions for fast I/O
   set_tris_a(TRIS_A) ;

   // Set pullups RA5(PC_RX)
   port_a_pullups(0x20) ;

   // Keep PC TX PIN High
   output_high(UART_RX) ;   

   timer0_isr_cnt = 0 ;
   pwmc_putc_cnt = 0 ;

   enable_interrupts(global);

   pwmc_init() ;
   pwmc_start() ;

   // To HW UART
   printf("Start\r") ;

   ch = 0x41 ;

   while(1) {

      printf(pwmc_putc, "Hello World %u ", ch) ;

      delay_ms(10) ;
   }
}


    Executing: "C:\Program Files\PICCv4\Ccsc.exe" +FM "H-BridgeManager01.c" +DF +LN +T +A +M -Z +ICD +Y=9 +EA
    >>> Warning 203 "H-BridgeManager01.c" Line 226(1,1): Condition always TRUE
    Memory usage: ROM=22% RAM=14% - 31%
    0 Errors, 1 Warnings.
    Build Successful.
    Loaded N:\Projects\Nusoft\2WireComms\PIC\H-BridgeManager01.cof.
    BUILD SUCCEEDED: Thu Mar 15 11:19:48 2012

Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Thu Mar 15, 2012 11:53 am     Reply with quote

Seriously, 'of course' it has to disable interrupts. I'm amazed it doesn't just explode!....
You do realise that the routine you use in a printf, is called repeatedly for every character in the output?. Your 'pwmc_putc' routine will be called up to 16 times, with three of the calls depending on the value of 'ch'. Each call then changes the value of pwmc_ch, inside itself, and the routine must ensure that variables don't change between successive calls.
If you want to send text characters to the ISR, use sprintf to generate a string, and transfer these yourself.
nurquhar



Joined: 05 Aug 2006
Posts: 149
Location: Redditch, UK

View user's profile Send private message Visit poster's website

PostPosted: Fri Mar 16, 2012 1:30 am     Reply with quote

Dear Ttelmah

Yes you are correct pwmc_putc does alter the pwmc_ch. But the code has been carefully designed ! pwmc_ch is only altered in the interrupt when pwmc_cnt IS NOT zero. pwmc_putc only alters it when pwmc_cnt IS zero.
nurquhar



Joined: 05 Aug 2006
Posts: 149
Location: Redditch, UK

View user's profile Send private message Visit poster's website

PostPosted: Fri Mar 16, 2012 4:27 am     Reply with quote

Thinking some more about using printf() inconjuction with a user supplied putc(). It seems there must be many many applications that use it to push data into a FIFO buffer that then use an interrupt handler to pop the data for output to the hardware.

This is a pretty standard scenario for an interrupt driven serial port transmitter, a model I first used on Z80's back in the 80's. For the buffer you have a head & tail pointer and a contents count. The interrupt takes data out at the head pointer and reduces the count. The putc() puts data in at the tail pointer and increases the count. The count is used for the buffers tests, ie buffer full, empty or space left.

If you can use an atomic operation operation for the buffer contents count there should be no need to disable interrupts for the buffer push in the putc() function. If you were using a 16bit buffer count on an 8bit CPU then you would have to disable interrupts whist the count is being changed in putc() to prevent the interrupt "seeing" a half changed value.

My code above effectivly uses a this model but with a 1 byte buffer size.

My beef with the CCS complier is that it does'nt warn that it is disabling the interrupts prior to entering the users code.

What would be nice to have is way of telling the compiler that it does not need to take responsibility of checking if a certain variable is used inside and outside an interrupt handler and disable interrupts to protect it.

Some new preprocessor directive like this might do it.

#INT_IGNORE
int8 pwmc_ch ;

You never know CCS might be looking for something to do Wink
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Fri Mar 16, 2012 4:48 am     Reply with quote

The point is the compiler can't tell this. It looks for simple things. "can this routine modify something that is inside another routine called in the interrupt". If answer is 'yes', is _has_ to protect the code.
You can write the code so there is no possibility of such a crossover, and if so, then the compiler will not implement it's protection.
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  Next
Page 1 of 2

 
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