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

Why would #int_rda stop responding?

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



Joined: 21 Nov 2006
Posts: 129

View user's profile Send private message

Why would #int_rda stop responding?
PostPosted: Thu Feb 01, 2007 4:11 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 01, 2007 4:21 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 01, 2007 4:22 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 01, 2007 4:36 pm     Reply with quote

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







PostPosted: Thu Feb 01, 2007 5:14 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 01, 2007 5:21 pm     Reply with quote

Here is one of my old posts on reset_cpu() and the stack pointer:
http://www.ccsinfo.com/forum/viewtopic.php?t=17571
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Thu Feb 01, 2007 6:23 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 01, 2007 11:18 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 01, 2007 11:21 pm     Reply with quote

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);
  }
}
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