|
|
View previous topic :: View next topic |
Author |
Message |
evsource
Joined: 21 Nov 2006 Posts: 129
|
Why would #int_rda stop responding? |
Posted: Thu Feb 01, 2007 4:11 pm |
|
|
Every once in awhile, for reasons I haven't been able to detect, my PIC 16F876A stops responding to the int_rda interrupt. The program just keeps plugging away with what it was doing, but no interrupt.
Here's the interrupt code - if you need more code than that, let me know.
Code: |
#int_rda
void data_ready() {
input=fgetc(external);
if(input==0x80) { // reset - bootloader sends this command
delay_ms(150);
reset_cpu();
}
}
|
Thanks,
Ryan |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Feb 01, 2007 4:21 pm |
|
|
Most likely the hardware UART is stalling on a receive buffer overflow (at reception of the 3rd character). Some CCS functions will disable the interrupt, for example when writing to the eeprom which could cause these problems at higher baudrates.
What does your '#use rs232' line look like?
Adding the ERRORS directive to the #use RS232 line causes the compiler to generate code for restarting the UART, it will not stop you from missing data but at least the UART won't stall anymore. |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Thu Feb 01, 2007 4:22 pm |
|
|
First, make sure you have ERRORS in your #use RS232 line. This will clear errors that happen due to overrun. Next, never... ever.... ever... have delay commands of any kind in an ISR. ISR's are meant to be as short as possible. A strong suggestion would be to set a flag, in the ISR, and then evaluate that flag in main() or another routine and then do whatever it is you want accomplished.
Ronald |
|
|
evsource
Joined: 21 Nov 2006 Posts: 129
|
|
Posted: Thu Feb 01, 2007 4:36 pm |
|
|
Here's the RS232 line:
Code: |
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, stream=external, errors)
|
Are there really never any exceptions to putting a delay in an ISR? In the given case, I'm just delaying before restarting - the ISR will never actually return. The delay is to give the bootloader (who issues the reboot command) time to start streaming out it's own triggering command to the resident bootloader code on the PIC.
The ideas presented seem reasonable for causing the interrupt to stop responding, but since I have "errors" in the #use rs232 line, I don't think it's a third-byte problem. Any other ideas (thanks in advance)? |
|
|
Ttelmah Guest
|
|
Posted: Thu Feb 01, 2007 5:14 pm |
|
|
Because you have the delay in the ISR, interrupts will be disabled, in any external delays (unless you force the compiler to generate two sets of delay code). This in itself could cause problems. 'Errors', will clear overrun errors, _but only if the getc routine is called_. Now, your reset system, could actually then cause a problem. If a couple of characters arrive after the '80', while the code is in the delay, the UART will be physically hung on the next restart. Depending on how the initialisation code is handled, getc, may then not be called, resulting in data loss.
Calling 'restart_cpu', should itself never be needed. You may also corrupt the stack, since the stack will be imbalanced on the restart (because it is called in the interrupt), and may then overflow in normal use latter. The approach is 'messy'.
It is a bit like the driver, who works out how to stop a car, by driving it into a wall...
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Thu Feb 01, 2007 6:23 pm |
|
|
Calling 'restart_cpu' inside an interrupt handler is a disaster invitation, it would cause
a stack imbalance as Ttelmah stated, which will keep unnoticed until it becomes
deeper enough to provoke a crash. I understand that when return from a deep nested
subroutine with in an umbalanced stack, the stack pointer will recover a value from
the stack anyway, but such value will not be equal to the pushed value and because
of this, will cause a jump to an arbitrary address if the recovered value is an address,
or will generate an uncontrolled behavior if the recovered value is a data. Any of them will cause a crash in a short term.
Fortunatelly this kind of error was more frequent in old micros when we use to code
in assembly language, when it was the programmer responsability to manage the
stack, PUSHing and POPing registers in it.
Final comment regarding your problem: I would try setting a flag in the interrupt and
trigger the restart_cpu function inside main.
Humberto |
|
|
evsource
Joined: 21 Nov 2006 Posts: 129
|
|
Posted: Thu Feb 01, 2007 11:18 pm |
|
|
Taking the restart_cpu out of the interrupt is easy enough - it's in main now. No delays in the interrupt either:
Code: | #int_rda
void data_ready() {
input=fgetc(external);
} |
Look better?
But I'm still not convinced that the delay and restart_cpu in the interrupt are the cause of my problems (i.e. the int_rda interrupt ceasing to respond - I implied it, but didn't say that other interrupts are working fine). My reasoning is that the problem occurs even when I haven't done a restart from within the interrupt handler after a hard reboot. The UART just decides it doesn't want to respond to incoming data anymore - it does continue to spit data out just fine.
Any more ideas? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Feb 01, 2007 11:21 pm |
|
|
When the reset_cpu() function is called in a 16F chip, it jumps to
address 0x0000. The stack is 8-deep and it's circular. The stack
pointer is a modulo-8 counter. The initial value of the stack pointer
at the start of a program doesn't matter.
In the program shown below, a Timer1 interrupt occurs about 524 ms
after the start of the program. Inside the isr, the reset_cpu() function
is called. This function will jump to address 0x0000 and thus restart
the program, while leaving the return address on the stack. No hardware
reset is performed by the PIC.
The program runs OK. It restarts every time and there's no problem
with the stack. Here's the output of the program:
Quote: |
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
ABCDEFT
etc.
|
Here's the test program:
Code: |
#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#int_timer1
void timer1_isr(void)
{
putc('T');
putc('\n');
putc('\r');
reset_cpu();
}
//===============================
void main()
{
int8 value;
// Setup Timer1 to interrupt every 524 ms (with 4 MHz crystal).
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
set_timer1(0x0000);
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
value = 'A';
while(1)
{
putc(value);
value++;
delay_ms(100);
}
} |
|
|
|
|
|
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
|