MORE AT32UC3A1512 External INT Woos - SOLVED!!!!!

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

I recently posted about not being able to get external interrupts working and had a suggestion that fixed the problem - now I have run into another problem. . . . 

 

I am working on an electronic ignition for a motorcycle engine.  This is a 4 cylinder engine with two coils - one fires for cylinders 1 & 3 and the other for cylinders 2 &4.  There are two pulse generators on the crank shaft that are used to determine when to fire the spark plugs.  So I have the pulse generators go through an opto and a Schmitt trigger before being handed to the UC3.  

 

The outputs of the Schmitt triggers go to pins PA20 and PA22, which are set up as the external interrupts.  A timer/counter is set up with a 5us time interval.  This counts the number of 5us between the rising edge of each pulse from the 1st pulse generator - from this I derive the period and then the advance for each pair of spark plugs.

 

The setup- I currently have an emulator acting as the pulse generators on the motorcycle engine.  The emulator puts out - on two different io lines - a pulse 1 and then 90 degrees later for the current RPM, pulse 2.

In trying to debug - each of my external interrupts set and clear a different io pin (Spark_1_3 and Spark_2_4) so I can see when the two pulse generators cause the interrupts to fire.

 

The problem - when pulse 1 fires, I get a 224ns pulse from extint_1, and then 2.14us later I get a pulse from extint_2 - EVEN though pulse 2 has not fired!  If I remove the io statments from extint_1, the I still get a pulse from extint_2, 2.1 usec after the rising edge of pusle 1 generator.  And just to make things REALLY interesting, I get the same pulse output pattern after the falling edge of pulse 1 generator, except when I leave out the pulse generated by pulse 1, I get multiple pulse from extint 2.

 

I don't understand why extint 2 is firing when it is not receiving a pulse.  Suggestions most welcome!

The attached picture shows pulse generator 1 as it is feed to the UC3 (ch 3), ch 2 shows the output of extint 2 and ch 4 shows the output of extint 1

Parts of code below:

//Part of VF700_bsp.h

#define PulsGen_1_IN		AVR32_PIN_PA20
#define PulsGen_2_IN	    AVR32_PIN_PA22
#define Timer_0_OUT			AVR32_PIN_PB23
#define PulsGen_1_OUT		AVR32_PIN_PB20
#define TEST				AVR32_PIN_PA00
#define SPARK_1_3			AVR32_PIN_PA02
#define SPARK_2_4			AVR32_PIN_PA03

#define PulsGen_1				&AVR32_EIC
#define PulsGen_1_PIN			AVR32_EIC_EXTINT_1_PIN
#define PulsGen_1_FUNCTION		AVR32_EIC_EXTINT_1_FUNCTION
#define PulsGen_1_LINE			EXT_INT1
#define PulsGen_1_IRQ			AVR32_EIC_IRQ_1
#define PulsGen_1_IRQ_PRIORITY	AVR32_INTC_INT1
#define PulsGen_2				&AVR32_EIC
#define PulsGen_2_PIN			AVR32_EIC_EXTINT_2_PIN
#define PulsGen_2_FUNCTION		AVR32_EIC_EXTINT_2_FUNCTION
#define PulsGen_2_LINE			EXT_INT2
#define PulsGen_2_IRQ			AVR32_EIC_IRQ_2
#define PulsGen_2_IRQ_PRIORITY	AVR32_INTC_INT2

#define TC_CHANNEL    0

//! \note TC module is used in this example.
#define BASE_TC                 (&AVR32_TC)
//! \note TC Channel 0 is used.
#define BASE_TC_CHANNEL         0
//! \note IRQ0 line of channel 0 is used.
#define BASE_TC_IRQ             AVR32_TC_IRQ0
//! \note IRQ Group of TC module
#define BASE_TC_IRQ_GROUP       AVR32_TC_IRQ_GROUP
//! \note Interrupt priority 0 is used for TC in this example.
#define BASE_TC_IRQ_PRIORITY    AVR32_INTC_INT0
part of init.c
		EIC_OPTIONS[0].eic_line = PulsGen_1_LINE;
		EIC_OPTIONS[0].eic_mode = EIC_MODE_EDGE_TRIGGERED;
		EIC_OPTIONS[0].eic_edge = EIC_EDGE_RISING_EDGE;
	    EIC_OPTIONS[0].eic_filter = EIC_FILTER_ENABLED;
		EIC_OPTIONS[0].eic_async = EIC_SYNCH_MODE;
		EIC_OPTIONS[1].eic_line = PulsGen_2_LINE;
		EIC_OPTIONS[1].eic_mode = EIC_MODE_EDGE_TRIGGERED;
		EIC_OPTIONS[1].eic_edge = EIC_EDGE_RISING_EDGE;
	    EIC_OPTIONS[1].eic_filter = EIC_FILTER_ENABLED;
		EIC_OPTIONS[1].eic_async = EIC_SYNCH_MODE;
	static const gpio_map_t EIC_GPIO_MAP =
	{
		{PulsGen_1_PIN, PulsGen_1_FUNCTION},
		{PulsGen_2_PIN, PulsGen_2_FUNCTION}
	};
			 // Assign GPIO to EXTINT3
		gpio_enable_module_pin(PulsGen_1_PIN, PulsGen_1_FUNCTION);
		sysclk_enable_peripheral_clock(PulsGen_1);
		gpio_enable_module_pin(PulsGen_2_PIN, PulsGen_2_FUNCTION);
		sysclk_enable_peripheral_clock(PulsGen_2);
		Disable_global_interrupt();
			    // Initialize interrupt vectors.
		INTC_init_interrupts();
				// Register the RTC interrupt handler to the interrupt controller.
		INTC_register_interrupt(&tc_irq, BASE_TC_IRQ, BASE_TC_IRQ_PRIORITY);
		INTC_register_interrupt(&extint1_irq, PulsGen_1_IRQ, PulsGen_1_IRQ_PRIORITY);
		tc_init(tc);
		eic_init(PulsGen_1, &EIC_OPTIONS, PulsGen_NB_LINES);
		eic_enable_line(PulsGen_1, EIC_OPTIONS[0].eic_line);
		eic_enable_interrupt_line(PulsGen_1, EIC_OPTIONS[0].eic_line);
		INTC_register_interrupt(&extint2_irq, PulsGen_2_IRQ, PulsGen_2_IRQ_PRIORITY);
		eic_init(PulsGen_2, &EIC_OPTIONS, PulsGen_NB_LINES);
		eic_enable_line(PulsGen_2, EIC_OPTIONS[1].eic_line);
		eic_enable_interrupt_line(PulsGen_2, EIC_OPTIONS[1].eic_line);
		 // Enable all interrupts.
		Enable_global_interrupt();
part of timer_0.c

__attribute__((__interrupt__))
static void extint1_irq(void)		//pulse generator #1
{ /* Interrupt */
	eic_clear_interrupt_line(&AVR32_EIC,PulsGen_1_LINE);
gpio_local_set_gpio_pin(SPARK_1_3);//for test purposes only
	if (Last_Puls_Gen == 1)
	{
			gpio_local_clr_gpio_pin(SPARK_1_3);//for test purposes only

		return;
	}
	else
		Last_Puls_Gen = 1;
	CTR_PulsGen_1 = PulsGen_1_CTR;
	PulsGen_1_CTR = 0;
	PulsGen_1_FLAG = HIGH;
	gpio_local_clr_gpio_pin(SPARK_1_3);//for test purposes only
	return;

}

__attribute__((__interrupt__))
static void extint2_irq(void)		//pulse generator #2
{ /* Interrupt */
	eic_clear_interrupt_line(&AVR32_EIC, PulsGen_2_LINE);
gpio_local_set_gpio_pin(SPARK_2_4);//for test purposes only
	 if(Last_Puls_Gen == 2)
	 {
		 gpio_local_clr_gpio_pin(SPARK_2_4);//for test purposes only
		return;
	 }
	else
	Last_Puls_Gen = 2;
	PulsGen_2_FLAG = HIGH;
	gpio_local_clr_gpio_pin(SPARK_2_4);//for test purposes only
	return;
}

//Función de interrupción por desbordamiento del timer
//Configurado para que se desborde cada 5us
__attribute__((__interrupt__))
static void tc_irq(void)		//counter set for 10us interval
{
//	gpio_set_pin_high(SPARK_1_3);			//4.16us from pin high to pin low
  tc_read_sr(BASE_TC, BASE_TC_CHANNEL);
	PulsGen_1_CTR++;
	ADVANCE_TIME--;
    PulsGen_2_TMR--;
	PulsGen_2_FIRE_TIME--;
	SPARK_TIME++;

 

Attachment(s): 

This topic has a solution.
Last Edited: Sun. Mar 5, 2017 - 12:52 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your input hardware sounds very suspect. Why would you use an opto? The pulse generators are isolated anyways. Do you need to look at both edges? Common circuits use some transistors or the later model ones use a comparator. No optos needed.
I've had no exposure to AVR32, but the usual method would be to feed the signals into input captures for the timers, not external interrupts. For your application you probably only need a 8 bit micro and at 5V for better noise tolerance.

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

The (commented-out) // gpio_set_pin_high(SPARK_1_3); //4.16us from pin high to pin low in tc_irq() makes me suspect that some other section of your code is manipulating SPARK_2_4 (PA03)


It might help to also pulse the TEST output in tc_irq().
(Probably a coincidence, but the time from the rising edge of pulse-generator-1 to the falling edge of the extint_2 is your TC0 interval of 5 us)


Minor point..., I am guessing that PulsGen_NB_LINES is 2, in which case you only need to call eic_init(,,) once.

Last Edited: Sat. Mar 4, 2017 - 04:21 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My thanks for the comments- I have never thought about over designing for the safety of the uprocessor since I started working with uprocessors in the mid 70's.  It is quite possible to use something smaller than the UC3, but it is the processor I use for most everything i do.  The hardware was fine - the problem was in the setting up of the external interrupts.

 

I do have the number of lines set to 2, but the two eic_enables statements were different, an both were needed.

 

I now get a single pulse from the extint_irq routines - the pulse occurs 1.9us after the falling edge of the incoming pulse generator pulse.  Which is great except I want the CPU generated pulse to occur on the RISING EDGE!

 

I have changed the EIC_OPTIONS every which way I can find, but cannot get the pulse to occur anytime but the falling edge of the incoming pulse.  Anyone got any ideas?

init.c
void board_init(void)
{
	sysclk_init();
	// Enable the clock to the selected example Timer/counter peripheral module.
	sysclk_enable_peripheral_clock(BASE_TC);
	gpio_local_init()
	delay_init(66000000UL);
//	gpio_configure_pin(Timer_0_OUT,OUT);
//	gpio_configure_pin(PulsGen_1_OUT,OUT);                               // enable output pins
	gpio_configure_pin(TEST,OUT);
	gpio_configure_pin(PulsGen_1_IN,IN);
	gpio_configure_pin(PulsGen_2_IN,IN);
	gpio_configure_pin(SPARK_1_3,OUT);
	gpio_configure_pin(SPARK_2_4,OUT);
		EIC_OPTIONS[0].eic_line = PulsGen_1_LINE;
		EIC_OPTIONS[0].eic_mode = EIC_MODE_LEVEL_TRIGGERED;
		EIC_OPTIONS[0].eic_edge = EIC_EDGE_RISING_EDGE;
	    EIC_OPTIONS[0].eic_filter = EIC_FILTER_DISABLED;
//		EIC_OPTIONS[0].eic_async = EIC_SYNCH_MODE;
		EIC_OPTIONS[1].eic_line = PulsGen_2_LINE;
		EIC_OPTIONS[1].eic_mode = EIC_MODE_LEVEL_TRIGGERED;
		EIC_OPTIONS[1].eic_edge = EIC_EDGE_RISING_EDGE;
	    EIC_OPTIONS[1].eic_filter = EIC_FILTER_DISABLED;
//		EIC_OPTIONS[1].eic_async = EIC_SYNCH_MODE;
	static const gpio_map_t EIC_GPIO_MAP = 
	{
		{PulsGen_1_PIN, PulsGen_1_FUNCTION},
		{PulsGen_2_PIN, PulsGen_2_FUNCTION}
	};
	gpio_enable_module(EIC_GPIO_MAP,sizeof(EIC_GPIO_MAP) / sizeof(EIC_GPIO_MAP[0]));
			 // Assign GPIO to EXTINT3 
		gpio_enable_module_pin(PulsGen_1_PIN, PulsGen_1_FUNCTION);
		sysclk_enable_peripheral_clock(PulsGen_1);
		gpio_enable_module_pin(PulsGen_2_PIN, PulsGen_2_FUNCTION);
		sysclk_enable_peripheral_clock(PulsGen_2);
		Disable_global_interrupt();
			    // Initialize interrupt vectors. 
		INTC_init_interrupts(); 
				// Register the RTC interrupt handler to the interrupt controller. 
		INTC_register_interrupt(&tc_irq, BASE_TC_IRQ, BASE_TC_IRQ_PRIORITY);
		INTC_register_interrupt(&extint1_irq, PulsGen_1_IRQ, PulsGen_1_IRQ_PRIORITY);
		INTC_register_interrupt(&extint2_irq,PulsGen_2_IRQ, PulsGen_2_IRQ_PRIORITY);
		tc_init(tc);
		eic_enable_lines(&AVR32_EIC,
		(1<<EIC_OPTIONS[1].eic_line)|(1<<EIC_OPTIONS[0].eic_line));
		eic_enable_interrupt_lines(&AVR32_EIC,
		(1<<EIC_OPTIONS[1].eic_line)|(1<<EIC_OPTIONS[0].eic_line));
		 // Enable all interrupts.
		Enable_global_interrupt(); 

return;
}

Timer_0.c
__attribute__((__interrupt__))
static void extint1_irq(void)		//pulse generator #1
{ /* Interrupt */
	eic_clear_interrupt_line(&AVR32_EIC,PulsGen_1_LINE);
gpio_local_set_gpio_pin(SPARK_1_3);//for test purposes only

 	if (Last_Puls_Gen == 1)
	{
			gpio_local_clr_gpio_pin(SPARK_1_3);//for test purposes only

		return;
	}
	else
		Last_Puls_Gen = 0;
	CTR_PulsGen_1 = PulsGen_1_CTR;
	PulsGen_1_CTR = 0;
	PulsGen_1_FLAG = HIGH;
	gpio_local_clr_gpio_pin(SPARK_1_3);//for test purposes only

}

__attribute__((__interrupt__))
static void extint2_irq(void)		//pulse generator #2
{ /* Interrupt */
	eic_clear_interrupt_line(&AVR32_EIC, EXT_INT1);
gpio_local_set_gpio_pin(SPARK_2_4);//for test purposes only
	 if(Last_Puls_Gen == 2)
	 {
		 gpio_local_clr_gpio_pin(SPARK_2_4);//for test purposes only
		return;
	 }
	else
	Last_Puls_Gen = 2;
	PulsGen_2_FLAG = HIGH;

	gpio_local_clr_gpio_pin(SPARK_2_4);//for test purposes only
	
}

 

 

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

Where do you call eic_init(,,) ?
The reset default is MODE=0 (edge triggered) and EDGE=0 (falling edge).

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I HAVE MET WITH SUCCESS!

 

After much trial and error, reading on the Internet, I now have external interrupts firing on the rising edge of an incoming pulse.

 

The secret was to have the following code in the init.c function:     (USING Atmel Studio 7 (Version 7.0.634)

		eic_init(&AVR32_EIC,&EIC_OPTIONS[0],1);
		eic_init(&AVR32_EIC,&EIC_OPTIONS[1],1);
		eic_enable_line(&AVR32_EIC,EIC_OPTIONS[0].eic_line);
		eic_enable_interrupt_line(&AVR32_EIC,EIC_OPTIONS[0].eic_line);
		eic_enable_line(&AVR32_EIC,EIC_OPTIONS[1].eic_line);
		eic_enable_interrupt_line(&AVR32_EIC,EIC_OPTIONS[1].eic_line);

I had not been running the eic_init statements.

 

So for those wishing to have an external interrupt trigger in your UC3 (specifically AT32UC3A1512), here is what you need:

In an include file (something.h)
#define PulsGen_1_IN	    AVR32_PIN_PA21  // incoming pulse for extint_0 
#define PulsGen_2_IN	    AVR32_PIN_PA22  // incoming pulse for extint_1

#define PulsGen_1			&AVR32_EIC 
#define PulsGen_1_PIN			AVR32_EIC_EXTINT_0_PIN
#define PulsGen_1_FUNCTION		AVR32_EIC_EXTINT_1_FUNCTION 
#define PulsGen_1_LINE			EXT_INT0 
#define PulsGen_1_IRQ			AVR32_EIC_IRQ_0 
#define PulsGen_1_IRQ_PRIORITY	        AVR32_INTC_INT0
#define PulsGen_2			&AVR32_EIC 
#define PulsGen_2_PIN			AVR32_EIC_EXTINT_1_PIN 
#define PulsGen_2_FUNCTION		AVR32_EIC_EXTINT_1_FUNCTION 
#define PulsGen_2_LINE			EXT_INT1 
#define PulsGen_2_IRQ			AVR32_EIC_IRQ_1 
#define PulsGen_2_IRQ_PRIORITY	        AVR32_INTC_INT1

In init.c function
	gpio_configure_pin(PulsGen_1_IN,IN);
	gpio_configure_pin(PulsGen_2_IN,IN);
		EIC_OPTIONS[0].eic_line = PulsGen_1_LINE;
		EIC_OPTIONS[0].eic_mode = EIC_MODE_EDGE_TRIGGERED;
		EIC_OPTIONS[0].eic_edge = EIC_EDGE_RISING_EDGE;
	        EIC_OPTIONS[0].eic_filter = EIC_FILTER_DISABLED;
		EIC_OPTIONS[1].eic_line = PulsGen_2_LINE;
		EIC_OPTIONS[1].eic_mode = EIC_MODE_EDGE_TRIGGERED;
		EIC_OPTIONS[1].eic_edge = EIC_EDGE_RISING_EDGE;
	        EIC_OPTIONS[1].eic_filter = EIC_FILTER_DISABLED;
	    
	static const gpio_map_t EIC_GPIO_MAP = 
	{
		{PulsGen_1_PIN, PulsGen_1_FUNCTION},
		{PulsGen_2_PIN, PulsGen_2_FUNCTION}
	};
		Disable_global_interrupt();
			    // Initialize interrupt vectors. 
		INTC_init_interrupts(); 
				// Register the RTC interrupt handler to the interrupt controller. 
		INTC_register_interrupt(&extint1_irq, PulsGen_1_IRQ, PulsGen_1_IRQ_PRIORITY);
		INTC_register_interrupt(&extint2_irq,PulsGen_2_IRQ, PulsGen_2_IRQ_PRIORITY);
		eic_init(&AVR32_EIC,&EIC_OPTIONS[0],1);
		eic_init(&AVR32_EIC,&EIC_OPTIONS[1],1);
		eic_enable_line(&AVR32_EIC,EIC_OPTIONS[0].eic_line);
		eic_enable_interrupt_line(&AVR32_EIC,EIC_OPTIONS[0].eic_line);
		eic_enable_line(&AVR32_EIC,EIC_OPTIONS[1].eic_line);
		eic_enable_interrupt_line(&AVR32_EIC,EIC_OPTIONS[1].eic_line);
		 // Enable all interrupts.
		Enable_global_interrupt(); 

in Timer.c function
static void extint1_irq(void);
static void extint2_irq(void);

__attribute__((__interrupt__))
static void extint1_irq(void)		//pulse generator #1
{ /* Interrupt */
	eic_clear_interrupt_line(&AVR32_EIC,PulsGen_1_LINE);
    ////////// perform need tasks - MAKE IT SHORT  /////////////////////
}
__attribute__((__interrupt__))
static void extint2_irq(void)		//pulse generator #2
{ /* Interrupt */
	eic_clear_interrupt_line(&AVR32_EIC, EXT_INT1);

    ////////// perform need tasks - MAKE IT SHORT  /////////////////////
	
}

 

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

Hi Mike - as noted in the solution below, I had discovered that I had not called eic_init, and it was following the exact behavior you described - edge trigger on falling edge.

 

If I had not already discovered this, your comment would have been the answer to my problems!

 

I appreciate your taking the time to respond.

Kind regards,

David