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 going into space

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



Joined: 17 Jul 2012
Posts: 3

View user's profile Send private message

Interrupt going into space
PostPosted: Tue Jul 17, 2012 6:10 pm     Reply with quote

I am using a 16F1828 and during initialization TMR0 and globals interrupts are enabled and everything works as expected.

Code:
  CLEAR_INTERRUPT(INT_TIMER0);
  CLEAR_INTERRUPT(INT_EXT);
  CLEAR_INTERRUPT(INT_RA0 | INT_RA1);
  DISABLE_INTERRUPTS(INT_RA0 | INT_RA1);  // Turn off switch interrupts
  ENABLE_INTERRUPTS(INT_TIMER0);
  ENABLE_INTERRUPTS(GLOBAL);    // Enable all interupts (really just tmr0)


During normal operation the initialization is called again (after waking from sleep) and the program hangs somewhere. The TMR0 ISR appears to be running since a code-based wdt using the TMR0 ISR resets the MCU. There is only one ISR (TMR0).

Code:
    wdt_counter++;     // increment the counter   
    if(wdt_counter == 18)     // 18 = about 10 seconds
      reset_cpu();


A wake-on-change makes the code continue after waking (no ISR - GIE cleared). Clearing interrupt flags (TMR0IF, INTF) did not help. I tried clearing IOCIF but it would not clear. It would help if I knew where the code was going but I cannot step through this section of code because ICDDAT, ICDCLK are shared by switches.

How can I determine where the code is hanging?
temtronic



Joined: 01 Jul 2010
Posts: 9247
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Jul 17, 2012 6:41 pm     Reply with quote

One way is to do what every PC does in POST since the 70s....
Add code ( either send a number to terminal,LCD or flash an LED (1 for stage 1,2 for stage 2,etc.) to various sections of your code...

When it fails you know that code was fine up to the last shown number on terminal, LCD or the last sequence of LED flashes.IE if #6 shows up or 6 flashes, then code up to section 7 is OK....

Just google 'PC POST powerup self test' for the details....
multisync



Joined: 17 Jul 2012
Posts: 3

View user's profile Send private message

PostPosted: Tue Jul 17, 2012 7:46 pm     Reply with quote

Good idea and I have been doing that all along. Flashing LEDs and counting the number of flashes to indicate where they occur. I even issued scope pulses to indicate the contents of INTCON. But I need some ideas on where to put more flashes without trying everywhere in a 1500-line program. Since it is likely an interrupt may be causing the problem and there is only one interrupt it may be interrupting to a non-defined interrupt (i.e. no ISR) and running through unprogrammed memory somewhere until the TMR0 ISR fires. In that case there would be nowhere in the code to put LED flashes.

I have been able to trace it using LEDs up to the point where the global interrupts are enabled. It never gets to the next instruction. It does enter the TMR0 ISR after that when expected. But where is it running when it leaves this ISR? It is not the instruction following the enable global interrupt instruction. Stepping the code through the end of the TMR0 ISR would surely show where is is going, but as mentioned in my first post, that cannot be done.

Just had a thought. Maybe I can issue scope pulses to tell me the contents of the PC just before it leaves the TMR0 ISR. Not trivial but surely do-able.
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Wed Jul 18, 2012 1:42 am     Reply with quote

You talk about using 'interrupt on change' to wake the chip.
You are (hopefully) aware, that you _cannot_ clear this interrupt, without reading the PORTB data latch first?. Otherwise this once triggered will remain permanently set, which could then give unexpected behaviour.
The same applies to the clear_interrupt line you have before enabling the other interrupts you want to use. You need to read the pin(s) on PORTB, before this clear will work.
Basically there are two significantly different 'types' of interrupt:
The first covers interrupts like INT_EXT, and INT_TIMERx, which trigger the interrupt flag once, on a specific event (the pin level, or the timer wrapping).
The second covers interrupts like INT_RDA, and INT_RBx, which _continuoulsy retrigger_, until the hardware 'mismatch' causing them is cleared. So in the case of INT_RDA, you _must_ read the character waiting in the input buffer, while for INT_RBx, you need to access the port data latch, so the stored value here matches what is on the pins. These interrupts can't be cleared until the hardware event is cleared.

It is not quite clear what your actual problem 'is', but this may be the heart of it.

Best Wishes
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Wed Jul 18, 2012 2:01 am     Reply with quote

You talk about waking from sleep. Have you got BOR enabled?. Have you looked at the errata sheet for this chip?. Might 8.1 be causing your problem?.

Best Wishes
multisync



Joined: 17 Jul 2012
Posts: 3

View user's profile Send private message

PostPosted: Wed Jul 18, 2012 6:02 pm     Reply with quote

Code:
#fuses INTRC_IO,NOWDT,NOBROWNOUT,PROTECT
Brownout is disabled so BOR should not be an issue.

The problem is occurring after waking by a pin-change-interrupt. LEDs are flashed at 2 points in the code to allow for tracing program flow.
Code:
SLEEP();                      // sleep until one of the switches goes on (active high)

DISABLE_INTERRUPTS(INT_RA0 | INT_RA1); // Turn off switch interrupts
CLEAR_INTERRUPT(INT_RA0);              // Clear both possible sources of interrupt
CLEAR_INTERRUPT(INT_RA1);              // Clear both possible sources of interrupt
CLEAR_INTERRUPT(INT_TIMER0);

SET_TRIS_A(0b00101111);       // Force all I/O into initial data directions and output polarities
SET_TRIS_B(0b00111111);       // Required for use of 'fast_io' compiler directive

SET_TRIS_C(0b00000111);       // TX INIT  Required for use of 'fast_io' compiler directive
OUTPUT_A(0b00010000);
OUTPUT_B(0b10000000);
OUTPUT_C(0b00011100);

setup_adc( ADC_CLOCK_INTERNAL );                 // Use the internal clock
setup_adc_ports( sAN4 | sAN5 | sAN6 | VSS_VDD ); // Setup the analog input channels

initialize_SPI(); //setup SPI port
nrf24l01_initialize_heat(false, 2, 5, true);     // init 24L01 to debug config as TX,
                                                 // 2 data bytes and auto-ack enabled
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_64);

DISABLE_INTERRUPTS(INT_RA0 | INT_RA1);           // Turn off switch interrupts
CLEAR_INTERRUPT(INT_TIMER0);
CLEAR_INTERRUPT(INT_EXT);
CLEAR_INTERRUPT(INT_RA0 | INT_RA1);
port_value = PORTA;
port_value = LATA;                               // PROBABLY NOT REQUIRED: READ PORTS, WRITE LATS
ENABLE_INTERRUPTS(INT_TIMER0);                   // Configure timer0 interrupt
FlashLed();                       // indicate code reached this point (GETS HERE)

ENABLE_INTERRUPTS(GLOBAL);                       // Enable all interupts (really just timer0)
FlashLed();                       // indicate code reached this point (DOES NOT GET HERE)


The code reaches the line after the TMR0 interrupt is enabled but never reaches the line after the Global interrupt is enabled.
A counter is decremented in the TMR0 ISR. When it reaches 0 a reset is issued using RESET_CPU().

Quote:
you _cannot_ clear this interrupt, without reading the PORTB data latch first

Section 13.3 says "The individual status flags (IOCAFx and IOCBfx bits) can be cleared by resetting them to zero." I cannot find where is says to read the port. I added 2 lines to read PORTA and LATA (this should not be required since we write to LATs not read them) but the problem persists.

Where is the program going after the global interrupt is enabled? It seems that it might be going to an undefined ISR and running in an unprogrammed section of memory. TMR0 ISR is still functioning so when the counter times out it resets the MCU.

It should be noted that this code was ported from a 16F677 (where it ran successfully) to the 16F1828. What is different? That might be the clue.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jul 18, 2012 7:06 pm     Reply with quote

This thread has code which shows how to clear the IOCAF or IOCBF
flags inside the isr for the 16F18xx PICs:
http://www.ccsinfo.com/forum/viewtopic.php?t=46331
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