Best config prescaller and etc. for ADC in Tiny, need solution

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

Hi!

This code ADC reading and averaging, and you tell whether it done color marking,  if want to delay,

how to choose the frequency prescaller and how this affects the frequency measurement accuracy and a more correct version of the code.

Require stable performance ADC.
Code will work, but not stable read data for period 1 sec.

CPU Tiny45 8MHz or 6.4 MHz, which is better?
5V or 3.3V power supply

unsigned int adc_read(void)                          
{

        ADMUX  &= (~((1<<REFS0) | (1<<ADLAR) | (1<<MUX3)  | (1<< MUX2) | (1<< MUX1)));    // ADC input to PB2/ADC1
        ADMUX  |=    (1<<REFS1) | (1<<REFS2) | (1<<MUX0);                                 //  ADC Left Adjust Result & Internal Voltage Reference 2.56V without C, can 1.1V better?

        ADCSRA |=    (1<<ADEN)  | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);                   //  prescaler clock/128 & enable ADC
        ADCSRA &= (~((1<<ADPS1) | (1<<ADPS0)));                                                                 //

        ADCSRB &= 0;                                                                      // ADC Control and Status Register B; (0) = Free Running mode
                                                                                          // If you are in free running mode, then that line won't work 
                                                                                          // (ADSC never goes low). In single conversion mode it should work fine. ????
        _delay_us(10);                                              // Delay                                                                            ???
        
        unsigned int adc = {0};                                     // tmp data
        unsigned int a;
        for (a=8; a>0; a--)                                         // read 8 times
                {
                ADCSRA |= (1 << ADSC);                              // Start the conversion (set to 1 bit 6)
                _delay_us(10);                                      // Delay needed for the stabilization of the ADC input voltage        ????
                        while  (ADCSRA & (1 << ADSC));              // Wait for it to finish (wait for bit 6 set to 0)           ????
                        while ((ADCSRA & (1 << ADIF))== 0);         // Wait ADIF                                                        ????
                adc = (ADCL|ADCH << 8);                             // Read ADC
                adc = ADCW;
                }                                                   // End 8 reading
        adc /= 8;                                                  // average value of ADC from 8 times
        adc = adc & 0x3F;
        ADCSRA &=    (1<<ADEN);                               // set to 0 (disable ADC)  ?????
        return adc;
}

 

AvrStudio 7
AVR ISP MkII Clone
Core I3-4330
Kingston HyperX Savage SSD

Last Edited: Fri. Feb 13, 2015 - 05:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

As you appear to be hoping for a 10bit result the datasheet is fairly clear - the ADC must not be clocked at more than 200kHz.

 

As such 6.4MHz is better than 8MHz.

 

At 8MHz your choices for the prescaler are:

 

8MHz / 2 = 4MHz

8MHz / 4 = 2MHz

8MHz / 8 = 1MHz

8MHz / 16 = 0.5MHz

8MHz / 32 = 0.25MHz

8MHz / 64 = 0.125MHz = 125kHz

8MHz / 128 = 0.0625MHz

 

Of those only the last two are within the 200kHz range and I guess you'd always want to pick the fastest. So you would use /64 and get 125kHz. As it then takes 13 ADC clocks to get a conversion your sample rate would be 125kHz / 13 = 9.62 kHz

 

Now consider 6.4MHz...

 

6.4MHz / 2 = 3.2MHz

6.4MHz / 4 = 1.6MHz

6.4MHz / 8 = 0.8MHz

6.4MHz / 16 = 0.4MHz

6.4MHz / 32 = 0.2MHz

6.4MHz / 64 = 0.1MHz

6.4MHz / 128 = 0.05MHz

 

So now you can use /32, get the very fastest possible 200kHz and hence a sample rate of 200kHz/13 = 15.3kHz which is the fastest rate possible on a non-Xmega AVR8 if you want all 10 bits of accuracy.

 

At the end of the day you want any crystal that is some binary multiple of 200kHz. So you could even use 0.8MHz and a /4 prescaler etc. It doesn't have to be a particularly fast crystal just one that is 2^N*200kHz

Last Edited: Fri. Feb 13, 2015 - 05:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Where high frequency prescaler operates on exactly ADC conversion?
You should always choose the highest possible frequency presсaler for free-run adc?

AvrStudio 7
AVR ISP MkII Clone
Core I3-4330
Kingston HyperX Savage SSD

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

All that said, 250kHz, one setting "too high", 8MHz / 32 = 0.25MHz isn't going to make a difference in all but the most discerning situations.  Surely not for a "getting going" app.

 

Post the "real" complete test program.  Tell your signal level.  Is there noise on it?  What is the drive of that signal?  Tell what results you expect, and what results you are getting.

 

(A)Vcc must be rock solid for rock solid results.  Same with reference, and the signal, and (A)Gnd.

 

That ADC read routine is a mess.  Compare with the CodeVision Wizard's routine:

// Voltage Reference: AVCC pin
#define ADC_VREF_TYPE ((0<<REFS1) | (0<<REFS0) | (0<<REFS2) | (0<<ADLAR))

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=(adc_input & 0x0f) | ADC_VREF_TYPE;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=(1<<ADSC);
// Wait for the AD conversion to complete
while ((ADCSRA & (1<<ADIF))==0);
ADCSRA|=(1<<ADIF);
return ADCW;
}

Now, most here, including me, would use ADSC for the completion flag:

// Voltage Reference: AVCC pin
#define ADC_VREF_TYPE ((0<<REFS1) | (0<<REFS0) | (0<<REFS2) | (0<<ADLAR))

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=(adc_input & 0x0f) | ADC_VREF_TYPE;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=(1<<ADSC);
// Wait for the AD conversion to complete
while (ADCSRA & (1<<ADSC));
return ADCW;
}

Setup block...of course, your setup may vary:

// ADC initialization
// ADC Clock frequency: 250.000 kHz
// ADC Voltage Reference: 2.56V, AREF discon.
// ADC Bipolar Input Mode: Off
// ADC Reverse Input Polarity: Off
// ADC Auto Trigger Source: ADC Stopped
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
DIDR0|=(0<<ADC0D) | (0<<ADC2D) | (0<<ADC3D) | (0<<ADC1D);
ADMUX=ADC_VREF_TYPE;
ADCSRA=(1<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (0<<ADPS1) | (1<<ADPS0);
ADCSRB=(0<<BIN) | (0<<IPR) | (0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);

Read up on DIDR for best results.

 

Don't do your repeated reads and averaging in the channel read routine.  Call the adc_read routine from the main loop, and do what you want with the results.

 

 

 

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
                        while  (ADCSRA & (1 << ADSC));              // Wait for it to finish
                        while ((ADCSRA & (1 << ADIF))== 0);         // Wait ADIF

Which a better wait ADSC or ADIF?

 

AvrStudio 7
AVR ISP MkII Clone
Core I3-4330
Kingston HyperX Savage SSD

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

In datasheet Tiny45 wrote \>>

 

Table 17-3. Voltage Reference Selections for ADC

Internal 2.56V Voltage Reference without external bypass capacitor, disconnected from PB0 (AREF) (1)

Note: 1. The device requries a supply voltage of 3V in order to generate 2.56V reference voltage.
 

My sch 5 volt and no have capacitor
It should be exactly 3 volts or 3 volts and more up to 5 volts?

AvrStudio 7
AVR ISP MkII Clone
Core I3-4330
Kingston HyperX Savage SSD

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

Which a better wait ADSC or ADIF?

Define "better". However ADSC is self clearing while ADIF requires you to write 1 to it to clear it (yes 1 not 0). So if you wait on ADIF you also need to clear it while ADSC is as simple as:

ADCSRA |= (1 << ADSC);
while (ADCSRA & (1 << ADSC));

and nothing more is required. I personally would call that "better".

 

As for the reference. If it says it is 2.56V then it probably is 2.56V. Their point is simply that to get 2.56V you need Vcc >= 3V. But as you are likely going to use 3.3V or 5.0V it should be good for both.

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

okay, i now use 6.4 mhz compatible tiny15 mode (fusebit) and recompile project for this frequency

_delay_ms() very slowly, real delay time not correct sad

 

AvrStudio 7
AVR ISP MkII Clone
Core I3-4330
Kingston HyperX Savage SSD

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

mixer188 wrote:

_delay_ms() very slowly, real delay time not correct sad

 

Is the CKDIV8 fuse programmed?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

yes, 8 mhz & diveder 8 work ok
6.4 mhz i do not used

AvrStudio 7
AVR ISP MkII Clone
Core I3-4330
Kingston HyperX Savage SSD

Last Edited: Sat. Feb 14, 2015 - 05:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Right, but:

_delay_ms() very slowly, real delay time not correct

Post:

1) your code

2) your fuses

3) what you're expecting to see

4) what you do see.
 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Which take time after power on to the ADC was ready to give stable data from resistor attenuator?
I did this delay
Its true?

 

unsigned int delay_adc(void)						// Delay for ready voltage from ADC
{
        unsigned int adc1 = {0};
        unsigned int adc2 = {0};

        do 
                {
                _delay_ms(2000);
                adc1 = adc_read();
                _delay_ms(2000);
                adc2 = adc_read();
                }		
        while (adc1 != adc2);						// Wait cycle for stable ADC1 = ADC2
        return 1;
}
unsigned int adc_read(void)						// Read voltage
{				
        unsigned int adc_tmp = {0};					// tmp data 
        ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);			// prescaler clock/128 & enable ADC At 8 MHz/128 = 62500 Hz.
	
        ADCSRA |= (1<<ADEN);
        ADCSRA |= (1 << ADSC);          				// Start the conversion (set to 1 bit 6)
        _delay_us(10);							// Delay needed for the stabilization of the ADC read data (1 is few, 10 OK)	
                while  (ADCSRA & (1 << ADSC));  			// Wait for it to finish (wait for bit 6 set to 0)
        adc_tmp = (ADCL | (ADCH << 8));					// Read ADC, ONLY 2 register read!!!
        ADCSRA &= (~(1<<ADEN));
        return adc_tmp;
}

 

AvrStudio 7
AVR ISP MkII Clone
Core I3-4330
Kingston HyperX Savage SSD

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

mixer188 wrote:
_delay_ms() very slowly, real delay time not correct sad

 

Are you running this on real hardware or in the simulator?

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
adc_tmp = (ADCL | (ADCH << 8));					// Read ADC, ONLY 2 register read!!!

ADCL must be read before ADCH, but the compiler doesn't guarantee order of evaluation in an expression so you shouldn't read it like this.  The device header includes the macro ADC to ensure correct order of access:

adc_tmp = ADC;

However you still haven't answered several of my previous questions:

Post:

1) your code <-- (you didn't post the whole program)

2) your fuses

3) what you're expecting to see

4) what you do see.

Most importantly, what do you mean by "real delay time not correct"?  What are you expecting?  What do you see?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

larryvc wrote:

mixer188 wrote:

_delay_ms() very slowly, real delay time not correct sad

Are you running this on real hardware or in the simulator?

programmed chip

AvrStudio 7
AVR ISP MkII Clone
Core I3-4330
Kingston HyperX Savage SSD