View previous topic :: View next topic |
Author |
Message |
multisync
Joined: 17 Jul 2012 Posts: 3
|
Interrupt going into space |
Posted: Tue Jul 17, 2012 6:10 pm |
|
|
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
|
|
Posted: Tue Jul 17, 2012 6:41 pm |
|
|
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
|
|
Posted: Tue Jul 17, 2012 7:46 pm |
|
|
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
|
|
Posted: Wed Jul 18, 2012 1:42 am |
|
|
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
|
|
Posted: Wed Jul 18, 2012 2:01 am |
|
|
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
|
|
Posted: Wed Jul 18, 2012 6:02 pm |
|
|
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
|
|
|
|