Missing edge interrupts on Xmega256

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi All, 

 

I am having some issues with GPIO edge interrupts on the ATXmega256A3U, I seem to be missing some interrupts, to demonstrate this I set up an interrupt on PORTE pin 0 set to trigger on BOTH_EDGES, in the body of that interrupt I toggle PORTR pin 0 and I can see that not every change on PORTE0 has a corresponding PORTR0 change.

 

I do some additional processing in the ISR but I clear the interrupt flag before this, so as far as I understand that should not hide any interrupts.

 

My code is along these lines:

 


   	 // initial setup
	PORTE.INTCTRL = PORT_INT0LVL_HI_gc;
	PORTE.INT0MASK = PIN0_bm
	PORTE.PIN0CTRL = PORT_ISC_BOTHEDGES_gc;
	PORTE.INTFLAGS = VPORT_INT0IF_bm;

	// interrupt service routine
	ISR(INPUT_PORT_EXP_CHANGE_ISR_VECTOR)
    	{
    		PORTR.OUTTGL = PIN0_bm;

    		// clear the interrupt flag
    		PORTE.INTFLAGS = VPORT_INT0IF_bm;

    		// additional processing here
    	}
    

  

I have taken some scope printouts to demonstrate what I am seeing, the Pink channel 3 is the PORTE0 input and the yellow channel 1 is the PORTR0 toggled output. 

 

 

As can be seen, the second and fourth falling edges do not have a corresponding toggle of the output. 

 

I have seen from the datasheet that only pin 2 has full asynchronous support, but the software does not sleep and there are plenty of clock cycles between each state change (~100mS @ 20MHz). 

 

Hoping for some help, 

Graham

 

Arduinos are cheating. Discuss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GLong wrote:
I do some additional processing in the ISR

Don't do this, keep your ISR()'s short, set a flag and exit.

do processing in main based on flag states!

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

it is minimal, I just add an I2C task to a queue to be processed in main.

Arduinos are cheating. Discuss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was fascinated by your post.   So I tried it out on an A4U

/*
* A4U_PCINT.c
*
* Created: 12-Sep-19 11:37:03
* Author : David Prentice
*
* PWM on PE0 with 10us period, 25% duty cycle
* INT0 interrupt on PE0 toggles PB0 GPIO pin
*/

#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
    OSC.CTRL |= OSC_RC32MEN_bm;
    while ((OSC.STATUS & OSC_RC32MRDY_bm)==0);
    _PROTECTED_WRITE(CLK.CTRL, CLK_SCLKSEL_RC32M_gc);
    _PROTECTED_WRITE(CLK.PSCTRL, CLK_PSBCDIV_1_1_gc);
    _PROTECTED_WRITE(PMIC.CTRL, PMIC_HILVLEN_bm);

    PORTE.INTCTRL = PORT_INT0LVL_HI_gc;
    PORTE.INT0MASK = PIN0_bm;
    PORTE.PIN0CTRL = PORT_ISC_BOTHEDGES_gc;
    PORTE.INTFLAGS = PORT_INT0IF_bm;
    PORTB.DIRSET = PIN0_bm;

    TCE0.CTRLA = TC_CLKSEL_DIV1_gc;
    TCE0.CTRLB = TC0_CCAEN_bm | TC_WGMODE_SS_gc;
    TCE0.PER = F_CPU / 1 / 100000;  // 100000Hz (10us period)
    TCE0.CCA = TCE0.PER / 4;        // 25% duty cycle
    PORTE.DIRSET = PIN0_bm;         // OC0A as output

    // life is much easier in the debugger with VPORTs
    PORTCFG.VPCTRLA = PORTCFG_VP13MAP_PORTB_gc | PORTCFG_VP02MAP_PORTE_gc;
    sei();
    while (1)
    {
        asm("nop");
    }
}

ISR(PORTE_INT0_vect)
{
    // clear the interrupt flag first
    PORTE.INTFLAGS = PORT_INT0IF_bm;
    PORTB.OUTTGL = PIN0_bm;
    asm("nop");
}

The code should work on your 256A3U chip.   Change PB0 to PR0

However,  are you sure that PR0 is safe to use as GPIO ?

 

I originally wrote this without a PWM signal.   i.e. manually triggering ISR() in the Simulator.

The PWM signal should test the interrupt latency.    You can see it quite clearly in a Logic Analyser.   Or measure it exactly in the Simulator.

 

David.

Last Edited: Thu. Sep 12, 2019 - 04:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Clearing the interrupt flag will not allow additional interrupts. The PMIC has status flags that track when an ISR is executing. If you have another High priority ISR that takes a long time, you could miss edges.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Even if you only have one High Priority interrupt you can lose edges.

    //TCE0.CCA = TCE0.PER / 4;        // 25% duty cycle
    TCE0.CCA = 21;        // 6.5% duty cycle.  Any shorter and second edge is missed.

The whole point of IRQ Priority is that you can ensure an important IRQ is serviced promptly.

But you still have the hardware vectoring and software preamble before you "clear the interrupt flag".

 

If I set TCE0.CCA to 20,  I  miss some edges.   i.e. my example requires 21 CPU cycles before it clears the flag.

If the second edge occurs before 21 cycles,  the flag clears both edges.

 

The OP is running at 20MHz.   His scope trace implies edges are missed after 100ms (2000000 CPU cycles)

I don't believe the OP.   Without real compilable code,  we can't replicate it.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That Scope screen capture was just an example, there seemed to be no consistent time when it fails.

 

I found a solution to the issue was to set that pin to a level triggered interrupt, in the ISR I could then disable interrupts on that pin until the I2C task had been run, the callback from which re enabled level interrupts on that pin. 

 

david.prentice wrote:

Even if you only have one High Priority interrupt you can lose edges.

    //TCE0.CCA = TCE0.PER / 4;        // 25% duty cycle
    TCE0.CCA = 21;        // 6.5% duty cycle.  Any shorter and second edge is missed.

The whole point of IRQ Priority is that you can ensure an important IRQ is serviced promptly.

But you still have the hardware vectoring and software preamble before you "clear the interrupt flag".

 

If I set TCE0.CCA to 20,  I  miss some edges.   i.e. my example requires 21 CPU cycles before it clears the flag.

If the second edge occurs before 21 cycles,  the flag clears both edges.

 

The OP is running at 20MHz.   His scope trace implies edges are missed after 100ms (2000000 CPU cycles)

I don't believe the OP.   Without real compilable code,  we can't replicate it.

 

David.

Arduinos are cheating. Discuss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I2C service routines should be pretty quick.    There is little point in making them have any priority.    But you would certainly give them a lower priority than your "edge" handling.

 

Note that the "edge" should only look at specific Port bits.

If your I2C is running on the same Port,   it should ignore any wiggles from I2C.

 

Please post a minimal project that exhibits your problem.    e.g. ZIP up an AS7.0 project.  Attach the ZIP file.

 

David.