EmbeddedRelated.com
Forums

Interrupts and Analog Devices ADuC842

Started by Walter Smits October 4, 2004
Hi,

We are experiencing some issues with external interrupts resetting an 
Analog Devices ADuC842 controller (8051 family).  The system we are 
working on analyses sensorial data from a rotary encoder connected to 
EX0.  The interrupt is configured to be level-triggering.  In our 
current set-up, the controller spontaneously resets when the rate with 
which the sensor interrupts occur exceeds certain level.  We know from 
counting the number of CPU instructions in our ISR and estimating the 
number of interrupts, that the problem is likely to stem from the 
controller not being able to process the interrupts quick enough.  What 
we fail to understand, though, is why this would reset the controller 
as we would expect the interrupt system to either queue interrupts 
occurring too soon to be processed, or to ignore them altogether.

Can someone help us understand what is / might be going on?

To set up the interrupt we've got the following code:

IT0 = 0;  /* Configure interrupt to be level triggering. */
EX0 = 1; /* Enable external interrupt 0. */
EA = 1; /* Global interrupt enable. */

Our ISR:

static void
encoder_isr(void) interrupt 0 {
	unsigned int new_AB;
	unsigned int old_and_new;

	/* Get the new A and B values by masking the entire port
	   byte to avoid interference from pending interrupts: */
	new_AB = (P1 & 0x18) >> 3;	

	/* Combine the old and new A and B values.  The resulting
	   bit pattern indicates the direction of movement.
	   eg:  old = 0000 0011
	              --------- << 2x
	              0000 1100
	        new = 0000 0001
    		      --------- OR
		      0000 1101 = 13d = negative movement. */
	old_and_new = (old_AB << 2) | new_AB;

	/* Determine direction: */
	if ((old_and_new == 0x02) ||
	    (old_and_new == 0x0B) ||
	    (old_and_new == 0x0D) ||
	    (old_and_new == 0x04)) position--;
	else
	    position++;

	old_AB = new_AB;

	/* The interrupt is high-level triggered.  The output
	   of the pin corresponding to TOGGLE is XOR'ed with
	   the pin being monitored by the interrupt to clear
	   the interrupt. */
	TOGGLE ^= 1;
}


Thanks in advance.
Walter


Walter Smits wrote:

> Hi, > > We are experiencing some issues with external interrupts resetting an > Analog Devices ADuC842 controller (8051 family). The system we are > working on analyses sensorial data from a rotary encoder connected to > EX0. The interrupt is configured to be level-triggering. In our > current set-up, the controller spontaneously resets when the rate with > which the sensor interrupts occur exceeds certain level. We know from > counting the number of CPU instructions in our ISR and estimating the > number of interrupts, that the problem is likely to stem from the > controller not being able to process the interrupts quick enough. What > we fail to understand, though, is why this would reset the controller > as we would expect the interrupt system to either queue interrupts > occurring too soon to be processed, or to ignore them altogether. > > Can someone help us understand what is / might be going on? > > To set up the interrupt we've got the following code: > > IT0 = 0; /* Configure interrupt to be level triggering. */ > EX0 = 1; /* Enable external interrupt 0. */ > EA = 1; /* Global interrupt enable. */ > > Our ISR: > > static void > encoder_isr(void) interrupt 0 { > unsigned int new_AB; > unsigned int old_and_new; > > /* Get the new A and B values by masking the entire port > byte to avoid interference from pending interrupts: */ > new_AB = (P1 & 0x18) >> 3; > > /* Combine the old and new A and B values. The resulting > bit pattern indicates the direction of movement. > eg: old = 0000 0011 > --------- << 2x > 0000 1100 > new = 0000 0001 > --------- OR > 0000 1101 = 13d = negative movement. */ > old_and_new = (old_AB << 2) | new_AB; > > /* Determine direction: */ > if ((old_and_new == 0x02) || > (old_and_new == 0x0B) || > (old_and_new == 0x0D) || > (old_and_new == 0x04)) position--; > else > position++; > > old_AB = new_AB; > > /* The interrupt is high-level triggered. The output > of the pin corresponding to TOGGLE is XOR'ed with > the pin being monitored by the interrupt to clear > the interrupt. */ > TOGGLE ^= 1; > } > > Thanks in advance. > Walter
First you should use the "using" statement so you do not have to push everything on to the stack (like encoder_isr(void) interrupt 0 using 1) you could be over flowing the stack. You could be spending so much time in the interrupt that your watchdog resets. the 8051 does not queue interrupts. But since you are level sensing you could go right back to the int on the next instruction.
On 2004-10-05 05:50:47 +0200, Neil Kurzman <nsk@mail.asb.com> said:

> > > Walter Smits wrote: > >> Hi, >> >> We are experiencing some issues with external interrupts resetting an >> Analog Devices ADuC842 controller (8051 family). The system we are >> working on analyses sensorial data from a rotary encoder connected to >> EX0. The interrupt is configured to be level-triggering. In our >> current set-up, the controller spontaneously resets when the rate with >> which the sensor interrupts occur exceeds certain level. We know from >> counting the number of CPU instructions in our ISR and estimating the >> number of interrupts, that the problem is likely to stem from the >> controller not being able to process the interrupts quick enough. What >> we fail to understand, though, is why this would reset the controller >> as we would expect the interrupt system to either queue interrupts >> occurring too soon to be processed, or to ignore them altogether. >> >> Can someone help us understand what is / might be going on? >> >> To set up the interrupt we've got the following code: >> >> IT0 = 0; /* Configure interrupt to be level triggering. */ >> EX0 = 1; /* Enable external interrupt 0. */ >> EA = 1; /* Global interrupt enable. */ >> >> Our ISR: >> >> static void >> encoder_isr(void) interrupt 0 { >> unsigned int new_AB; >> unsigned int old_and_new; >> >> /* Get the new A and B values by masking the entire port >> byte to avoid interference from pending interrupts: */ >> new_AB = (P1 & 0x18) >> 3; >> >> /* Combine the old and new A and B values. The resulting >> bit pattern indicates the direction of movement. >> eg: old = 0000 0011 >> --------- << 2x >> 0000 1100 >> new = 0000 0001 >> --------- OR >> 0000 1101 = 13d = negative movement. */ >> old_and_new = (old_AB << 2) | new_AB; >> >> /* Determine direction: */ >> if ((old_and_new == 0x02) || >> (old_and_new == 0x0B) || >> (old_and_new == 0x0D) || >> (old_and_new == 0x04)) position--; >> else >> position++; >> >> old_AB = new_AB; >> >> /* The interrupt is high-level triggered. The output >> of the pin corresponding to TOGGLE is XOR'ed with >> the pin being monitored by the interrupt to clear >> the interrupt. */ >> TOGGLE ^= 1; >> } >> >> Thanks in advance. >> Walter > > First you should use the "using" statement so you do not have to push > everything on to the stack (like encoder_isr(void) interrupt 0 using 1) > you could be over flowing the stack. You could be spending so much time in > the interrupt that your watchdog resets. the 8051 does not queue > interrupts. But since you are level sensing you could go right back to the > int on the next instruction.
Thanks for your reply. We solved the problem after we got in touch with Analog's tech support: the ADuC842 has a bug that resets the instruction pointer to 0 if a level-triggering interrupt is cleared too early (within 9 core clock cycles). In case someone else runs into the same kind of problem: see anomaly er10, http://www.analog.com/en/prodRes/0,2889,ADUC842%5F876,00.html. Fortunately for us we could easily adopt our design to be edge triggering. Walter