Interrupt based all channels ADC in Atmega8

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

Hello!

I have a application which reads all ADC channels in (DIP) Atmega8. For one channel it does Goertzel filtering. For some reason goertzel doesn't work as expected. I can't find anything what could cause it. Do you?

volatile uint16_t adc_values[6];
volatile uint8_t adc7samplecount = 0;

....

ISR(ADC_vect)
{
	static uint8_t ch=0;
	uint16_t result;
	result = ADCL;                    // low order
	result += ADCH << 8;              // and high order
	
	if(ch == 5 && adc7ready == 0)
	{
		ProcessSample(result);
		adc7samplecount++;
		
		if(adc7samplecount >= N )
		{	
			adc7samplecount = 0;
			adc7ready = 1;
		}

	}

	adc_values[ch] = result;

	ADCSRA &= ~(1 << ADEN | 1 << ADFR);

	ch++;
	if(ch > 5) ch = 0;

	
	ADMUX = (ADMUX & 0xF0) | ch;
	ADCSRA |= ((1 << ADSC) | (1 << ADEN) | (1 << ADFR));

}

int main(void)
{
....

	init_adc_int();
	InitGoertzel();

....
	sei();
....
	while(1)
	{

...
		if(adc7ready == 1)
		{
			mag = GetMagnitudeSquared();

			GetRealImag(&real, &imag);
			res = real*real + imag*imag;
			
ResetGoertzel();
			adc7ready=0;
		}
....
}
}

void init_adc_int(void)
{
	// Select AVcc as ref and start from ch0
	ADMUX = (1 << REFS0);
	
  	// enable with prescale = 128
  	ADCSRA = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);

	// Enable ADC, enable interrupts, free running mode
	ADCSRA |= (1 << ADEN) | (1 << ADIE) | (1 << ADFR);

	// Start A2D Conversions 
	ADCSRA |= (1 << ADSC);  

}

#define SAMPLING_RATE	(F_CPU / 32 / 13)
#define TARGET_FREQUENCY	1000.0	
#define N	92	//Block size
#define PI 3.141592654
/* Call this routine for every sample. */
void ProcessSample(uint16_t sample)
{
  float Q0;
  Q0 = coeff * Q1 - Q2 + (float) sample;
  Q2 = Q1;
  Q1 = Q0;
}

/* Basic Goertzel */
/* Call this routine after every block to get the complex result. */
void GetRealImag(float *realPart, float *imagPart)
{
  *realPart = (Q1 - Q2 * cosine);
  *imagPart = (Q2 * sine);
}

/* Optimized Goertzel */
/* Call this after every block to get the RELATIVE magnitude squared. */
float GetMagnitudeSquared(void)
{
  float result;

  result = Q1 * Q1 + Q2 * Q2 - Q1 * Q2 * coeff;
  return result;
}


/* Call this routine before every "block" (size=N) of samples. */
void ResetGoertzel(void)
{
  Q2 = 0;
  Q1 = 0;
}

/* Call this once, to precompute the constants. */
void InitGoertzel(void)
{
  int	k;
  float	floatN;
  float	omega;

  floatN = (float) N;
  k = (int) (0.5 + ((floatN * TARGET_FREQUENCY) / SAMPLING_RATE));
  omega = (2.0 * PI * k) / floatN;
  sine = sin(omega);
  cosine = cos(omega);
  /*k= 0.45;
  sine = 0.2;
  cosine = 0.7;
  omega = 0.8;
  coeff = 2.0 * cosine;
*/

  ResetGoertzel();
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you need to be more explicate. What is not working, what is the mode of the failure or error?

having said that... since you are using trig functions, and floating point, make sure you are linking against libm

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Well.. the problem is that goertzel doesn't detect/filter frequency as supposed. Probably algorithm works but ADC reading doesn't?

I'm linking against libm.

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

toglader wrote:

#define SAMPLING_RATE	(F_CPU / 32 / 13)

Atleast this is incorrectly, because I'm sampling every 6 ADC channels which are available in DIP Atmega8. So maybe correct sample rate is: F_CPU/32/(6*13) ?