Analog Comparator speed - output vs interrupt

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

I was testing the analogue comparator inside the AVR128DB28. I wrote a simple example code below:

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

ISR(AC0_AC_vect)
{
	PORTA.OUTTGL = 1 << 6;
	AC0.STATUS = 1;	// Reset AC0 int flag
}

int main(void)
{
	PORTA.DIRSET = 1 << 6 | 1 << 7;
	PORTA.OUT = 0;
	
	PORTD.PIN2CTRL &= ~PORT_ISC_gm;
	PORTD.PIN2CTRL |= PORT_ISC_INPUT_DISABLE_gc;
	PORTD.PIN2CTRL &= ~PORT_PULLUPEN_bm;
	
	VREF.ACREF = VREF_REFSEL_1V024_gc;
	
	AC0.DACREF = 0xff;
	AC0.MUXCTRL = AC_MUXPOS_AINP0_gc | AC_MUXNEG_DACREF_gc;
	AC0.INTCTRL = AC_INTMODE_NORMAL_BOTHEDGE_gc | AC_CMP_bm;
	AC0.CTRLA = AC_OUTEN_bm | AC_HYSMODE_MEDIUM_gc | AC_ENABLE_bm;
	
	sei();
    /* Replace with your application code */
    while (1) 
    {
    }
}

I input a 1MHz sinusoidal signals with 3.3Vpp and 1.5V DC offset. The outputs of both pins are shown below (Yellow is the interrupt output and Pink is the direct AC0 output):

analog comparator output comparison

 

Why the interrupt output cannot handle a frequency greater than 62kHz? Is there a method to get over it? Or could I connect the AC0 output pin to one digital input pin externally as an external interrupt to achieve such high frequency?

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

 

IRQ's may take a long time to enter/exit, due to C inefficient overhead....not sure how long.  There are some compiler adjustments that can be made (I don't recall what they are).

 

Do this instead....in the IRQ turn ON the LED, in main turn OFF the LED...post your result.

 

Now you will be able to better see the timing of what is gong on.

It looks like the response is very fast...but it might actually be responding to the previous pulse.

Slow down your pulse rate a whole bunch (almost single shot).   You want to measure the time from pulse to IRQ response (LED ON)and then back to main (LED OFF).  These numbers will tell you how fast things can go with faster pulses. Right now, one pulse can be confused with another when trying to measure the numbers.  

 

Also, how fast is the AVR running---that will certainly affect the software IRQ overhead.

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sat. Aug 6, 2022 - 01:19 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the reply. I have modified the code as you said. I only use the internal clock (4MHz). The code is as below:

#include <avr/io.h>
#define F_CPU 4000000UL
#include <avr/interrupt.h>

ISR(AC0_AC_vect)
{
	PORTA.OUTSET = 1 << 6;
	AC0.STATUS = 1;	// Reset AC0 int flag
}

int main(void)
{
	PORTA.DIRSET = 1 << 6 | 1 << 7;
	PORTA.OUT = 0;

	PORTD.PIN2CTRL &= ~PORT_ISC_gm;
	PORTD.PIN2CTRL |= PORT_ISC_INPUT_DISABLE_gc;
	PORTD.PIN2CTRL &= ~PORT_PULLUPEN_bm;

	VREF.ACREF = VREF_REFSEL_1V024_gc;

	AC0.DACREF = 0xff;
	AC0.MUXCTRL = AC_MUXPOS_AINP0_gc | AC_MUXNEG_DACREF_gc;
	AC0.INTCTRL = AC_INTMODE_NORMAL_POSEDGE_gc | AC_CMP_bm;
	AC0.CTRLA = AC_OUTEN_bm | AC_HYSMODE_MEDIUM_gc | AC_ENABLE_bm;

	sei();
    /* Replace with your application code */
    while (1)
    {
		PORTA.OUTCLR = 1 << 6;
    }
}

The response is shown below: (It is noted that this is the minimum response) It appears that the interrupt response of AC0 is no more than 4.5us, which means that the maximum theoretical interrupt frequency with a 4MHz main clock is about 222kHz.

Comparator modified output comparison

Last Edited: Sat. Aug 6, 2022 - 12:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The response is shown below: (It is noted that this is the minimum response) It appears that the interrupt response of AC0 is no more than 4.5us, which means that the maximum theoretical interrupt frequency with a 4MHz main clock is about 222kHz.

No, from the graph your comparator generates an IRQ request (red go high), then 4.7us later you begin the IRQ (yellow led go high), then it takes approx 4.5us to finish the irq get back to main(another IRQ could then allow to refire), and the led goes off (yellow low)

 

so approx  9.2us  (108.7 KHz).  The comparator also has some time delay (try ,measuring that too), though for a repetitive case that should just scoot everything over.  However the AC going on/off combo sets a comparator freq limit too (so mease AC going off time too).

 

Did you try cranking up the input AC freq with this new code (until you no longer get a led toggle response)?  

 

 

  

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

Ah I see. So the minimum period the interrupt can handle with the input frequency is measured from the point when the input crosses the voltage reference to the point when ISR finishes and execute the main code. I tried to input a 1MHz signal. The interrupt fired the response with even less frequency (about 45kHz). I kind of expected that as it needs more time to back to the main and execute the output clear action.

 

I did a rough calculation based on the 4MHz main clock: it takes about 37 clock cycles to set up, execute and escape ISR. It means that the comparator interrupt can handle about 652kHz maximum input signal related to 24MHz main clock if not considering the AC spec itself. 

 

I read the datasheet about the comparator. As I am using Power Profile 0 in the configuration, both the rising and falling edge response time are 50ns, which should be capable of 20MHz maximum for single edge detection. The comparator itself is theoretically able to handle higher frequency signals. I will measure that in practice.

Last Edited: Sat. Aug 6, 2022 - 03:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

 

 

One thing we now know

In the original, it looks like the red & yellow are rising together, but now we know (I think!) it takes about 4.7 us to get into the IRQ from AC request...but each square is 2us...so the yellow is actually responding to a prior pulse.

 

We now know it takes roughly 4.5us to get from the AC request to get into the IRQ and about 4.5us to leave the IRQ and get back to main (A below getting back to main) ...then after the next pulse AC request  & time B to get back to the IRQ for toggle 

(There is also some variation due to when the request pulse occurs moving B), so this yellow line (AB) doesn't seem too far-fetched

It is also "interesting" that the yellow hi & lo are both exactly 8 us...probably related to the 4MHz clock quantizing the response time 4 MHz => 0.25 us)

 

 

 

 

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sat. Aug 6, 2022 - 03:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a good conclusion. It took B part to respond to a pulse. I will make the main clock as 24MHz and see whether this response speed is determined by the instruction steps or not. I just have a random variable clock generator on hand. It may not be calibrated and compensated but enough for this rough testing. We would conclude the behaviour of Analog Comparator in AVR128DB28 at least at the end.

By the way, the Event System has not been tested yet, which may have different timing characteristics compared to those two. It is worth checking how that works in comparison to the interrupt. However, the lack of event users and limited functionality makes this not helpful for my usage.

 

Microchip should consider including that information in the datasheet in the next revision. This can be quite helpful to determine whether this chip is suitable for specified usage.

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

You can also look at the lss file (and the optimization levels)..and see how much IRQ code overhead is being put in place. there are some options to tailor IRQs, especially if you don't do a lot in the IRQ (much less needed to save/restore).

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

I do not know if I am doing this right. I set the internal HF oscillator to be 24MHz that is used as the main clock. The code is shown below:

 

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

ISR(AC0_AC_vect)
{
	PORTA.OUTSET = 1 << 6;
	//PORTA.OUTTGL = 1 << 6;
	AC0.STATUS = 1;	// Reset AC0 int flag
}

int main(void)
{
	/* Set OSCHF as main clock source */
	CLKCTRL.MCLKCTRLA = CLKCTRL_CLKSEL_OSCHF_gc;// | CLKCTRL_CLKOUT_bm;
	/* Wait for main clock oscillator changing to finish */
	while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm);
	/* Change OSCHF frequency to 24 MHz */
	CLKCTRL.OSCHFCTRLA = CLKCTRL_FRQSEL_24M_gc | CLKCTRL_RUNSTDBY_bm | CLKCTRL_AUTOTUNE_bm;
	
	PORTA.DIRSET = 1 << 6 | 1 << 7;
	PORTA.OUTSET = 1 << 6;
	
	PORTD.PIN2CTRL &= ~PORT_ISC_gm;
	PORTD.PIN2CTRL |= PORT_ISC_INPUT_DISABLE_gc;
	PORTD.PIN2CTRL &= ~PORT_PULLUPEN_bm;
	
	VREF.ACREF = VREF_REFSEL_1V024_gc;
	
	AC0.DACREF = 0xff;
	AC0.MUXCTRL = AC_MUXPOS_AINP0_gc | AC_MUXNEG_DACREF_gc;
	AC0.INTCTRL = AC_INTMODE_NORMAL_POSEDGE_gc | AC_CMP_bm;
	AC0.CTRLA = AC_HYSMODE_MEDIUM_gc | AC_ENABLE_bm | AC_OUTEN_bm;
	
	sei();
    /* Replace with your application code */
    while (1) 
    {
		PORTA.OUTCLR = 1 << 6;
    }
}

 

The result is as below:

 

24MHz AC output

 

It shows exactly the same result. If I make the input as a 1MHz sine wave, the interrupt response does not change. This does not match the interrupt response time (as cycles) said in the datasheet page 131.

 

I have not looked into the lss file yet. Will have a look at it after I figure out this possible clock issue.

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

Registers MCLKCTRLA  and OSCHFCTRLA are "protected". Your values are not written into them. Use  _PROTECTED_WRITE macro to setup clock settings.

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

Oh thanks. This saves me quite a time. The code used is:

 

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

ISR(AC0_AC_vect)
{
	PORTA.OUTSET = 1 << 6;
	//PORTA.OUTTGL = 1 << 6;
	AC0.STATUS = 1;	// Reset AC0 int flag
}

int main(void)
{
	/* Set OSCHF as main clock source */
	_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
	/* Wait for main clock oscillator changing to finish */
	while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm);
	/* Change OSCHF frequency to 24 MHz */
	_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_RUNSTDBY_bm | CLKCTRL_AUTOTUNE_bm);
	
	PORTA.DIRSET = 1 << 6 | 1 << 7;
	PORTA.OUTSET = 1 << 6;
	
	PORTD.PIN2CTRL &= ~PORT_ISC_gm;
	PORTD.PIN2CTRL |= PORT_ISC_INPUT_DISABLE_gc;
	PORTD.PIN2CTRL &= ~PORT_PULLUPEN_bm;
	
	VREF.ACREF = VREF_REFSEL_1V024_gc;
	
	AC0.DACREF = 0xff;
	AC0.MUXCTRL = AC_MUXPOS_AINP0_gc | AC_MUXNEG_DACREF_gc;
	AC0.INTCTRL = AC_INTMODE_NORMAL_POSEDGE_gc | AC_CMP_bm;
	AC0.CTRLA = AC_HYSMODE_MEDIUM_gc | AC_ENABLE_bm | AC_OUTEN_bm;
	
	sei();
    /* Replace with your application code */
    while (1) 
    {
		PORTA.OUTCLR = 1 << 6;
    }
}

I tested various input signal frequencies, and found 600kHz is the maximum without interfering the next signal trigger on the comparator. The result is shown below:

 

24MHz Comparator comparison

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

If you need low latency or high frequency, use hardware (peripherals) to manage comparator output. For example route comparator output to TCB in single shot mode etc. If you want to react faster, you can continuously poll comparator status register in main while (SW does not need to manage IRQ overhead). That method has lower latency then IRQ routine... and is practicaly useless.