AVR Noise reduction mode not cooperating

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

Hi everyone,
I am working with an mega128 and wish use the ADC in ADC noise reduction mode. So I set up the ADC and write the appropriate bits to the MCUCR register and...nothing happens. I am almost certain, at least, that the ADC conversion never starts.

If have looked through previous posts and although others have had similar problems, I have not been able to find a solution.

I have stripped down my program to the code below. It basically turns on two LEDs at the start and if a conversion complete flag is set, one of the LED turns off. Note that if I start the conversion the normal way: ADCSRA |=(1<<ADSC); then the ADIF is set and the LED does switch off.

What have I missed? How do I make the the ADC noide reduction mode switch off the CPU, start the ADC and wake up again?

Grateful for any assistance!

Nick

#include 		
#include 	

uint16_t ADCOutput;

int main(void)
{
	sei();
	
	DDRA|=(1<<7)|(1<<6);    //Ports are outputs
	PORTA|=(1<<7)|(1<<6);	//LEDs are on
		
	ADMUX = 0b01000001;		
//Single ended input at PF1 with ref to VCC
	ADCSRA=0b10011111;		
//Bit 7: ADC on.					//Bit 6: Conversion NOT started					//Bit 5: Not free running mode
//Bit 4: Clear ADC complete flag
//Bit 3: ADC interrupt enabled
//Bits 2:0 ADC prescaler 128 (16MHz CPU)
while (1)
{	
 if (ADCSRA & (1<<ADIF)) PORTA&=(1<<7); 
 //If a conversion is ever completed
// and flag not cleared in interrupt
// this LED will turn off.
		
//ADCSRA |=(1<<ADSC);	 
//If I start the conversion like this, the LED turns	
							//off, indicating ADC complete flag has been set. 
//MCUCR = 0x00;
MCUCR |= (1<<SE);		//Sleep mode enable
MCUCR|=(1<<SM0);		//Enter ADC noise reduction mode (supposedly)
MCUCR&=~(1<<SM1);
MCUCR&=~(1<<SM2);
//(I have tried these in various combinations)		
		
//As far as I understand it, the AVR should now enter //ADC noise reduction
//mode and the ADC conversion should start.

ADCOutput = (ADCL);
ADCOutput +=(ADCH<<8);		
//Add the high ADC byte to output result
	
}
	return 0;
}


ISR(ADC_vect)
{
//MCUCR &=~(1<<SE);	//Sleep disable
PORTA&=~(1<<6); //If the ADC complete interrupt is ever executed, 
// this LED will turn off.
}

[/code]

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

You only select a sleep mode, the MCU enters sleep mode after the SLEEP instruction is executed. Try

asm volatile ("sleep"::);

after setting MCUCR.

However, the avr-libc contains some macros for selecting and entering any sleep mode. The macros are well tested and ready to use.

Regards
Sebastian

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

Vielen Dank!

I wasn't aware that I had to write the SLEEP instruction. I thought it just magically appeared when I wrote to the MCUCR register. Explains a lot really.

Anyway, now I can get the processor to sleep, but not wake up. i.e. The AD interrupt flag is not being set.

When I look more closely, I find that the ADSC bit is not enabled during sleep. In other words, the SLEEP instruction does not appear to start the AD conversion like it is supposed to.

Any ideas?

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

Quote:

if (ADCSRA & (1<<ADIF)) PORTA&=(1<<7);

This doesn't work. The ADIF bit is cleared by hardware when the ADC ISR is executed. Thus the condition ADCSRA & (1<<ADIF) is always false and the LED is never turned off.

EDIT:
A bit is not cleared by
PORTA &= (1 << 7);
but by
PORTA &= ~(1 << 7);

Regards
Sebastian

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

I just found another typo that was setting ADCSRA being set correctly. Indeed, the

asm volatile ("sleep"::); 

line was all that was missing to make the above code work.
Danke fuer deine Hilfe Sebastian!