I'm writing a new TFT driver and I want to test it out by drawing an oscilloscope style wave form to get a benchmark on line drawing; I'm just struggling with the ADC functionality. I found many good articles for setting it up on a smaller mcu ( 168/328 ) however the 2560 data sheet is quite involved.
What I'm after is a ADC set to free running mode using an ISR to capture the readings. I have only a need for 8-bit resolution at a pre-scale value of 32 for 500khz sampling.
I used the example code below in an attempt to get something running, however an error reports ADFR as not being declared.
ADCSRA |= ( 1 << ADPS2 ) | ( 1 << ADPS1 ) | ( 1 << ADPS0 ); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz
ADMUX |= ( 1 << REFS0 ); // Set ADC reference to AVCC
ADMUX |= ( 1 << ADLAR ); // Left adjust ADC result to allow easy 8 bit reading
ADCSRA |= ( 1 << ADFR ); // Set ADC to Free-Running Mode
ADCSRA |= ( 1 << ADEN ); // Enable ADC
ADCSRA |= ( 1 << ADIE );
ADCSRA |= ( 1 << ADSC );
I also haven't seen much use of the DIDR register(s) is this important/beneficial?
I'll keep searching, however any ideas/useful links would be great. 8)
I'm writing a new TFT driver and I want to test it out by drawing an oscilloscope style wave form to get a benchmark on line drawing; I'm just struggling with the ADC functionality. I found many good articles for setting it up on a smaller mcu ( 168/328 ) however the 2560 data sheet is quite involved.
What I'm after is a ADC set to free running mode using an ISR to capture the readings. I have only a need for 8-bit resolution at a pre-scale value of 32 for 500khz sampling.
I used the example code below in an attempt to get something running, however an error reports ADFR as not being declared.
ADMUX |= ( 1 << REFS0 ); // Set ADC reference to AVCC
ADMUX |= ( 1 << ADLAR ); // Left adjust ADC result to allow easy 8 bit reading
ADCSRA |= ( 1 << ADFR ); // Set ADC to Free-Running Mode
ADCSRA |= ( 1 << ADEN ); // Enable ADC
ADCSRA |= ( 1 << ADIE );
ADCSRA |= ( 1 << ADSC );
I also haven't seen much use of the DIDR register(s) is this important/beneficial?
I'll keep searching, however any ideas/useful links would be great. 8)
According to the databook, to setup free running mode, you set bits 0, 1 and 2 of the ADCSRB register to 0. You also need to set bit 6 (ACME) to a 1 to enable single ended mode.
Also, strangely, the ADMUX bits 0 through 4 are in the ADMUX register, but ADMUX bit 5 is bit 3 of ADCSRB.
A classic example of "Plan Ahea
d"
There is no ADFR register. ADFR is in internal processor signal.
Thanks for the reply, I got it working eventually and it performs well, cheers.
I didn't notice any change from setting the ACME, maybe this is a default value or gets set by Arduino's init() function.
pYro_65:
Thanks for the reply, I got it working eventually and it performs well, cheers.
I didn't notice any change from setting the ACME, maybe this is a default value or gets set by Arduino's init() function.
I also found that slowing the A/D clock seems to give much cleaner readings. Here's some code that I use (on a 328P) but it should translate easily to the Mega:
/*** this part in main() or setup()
ADCSRA |= (_BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0) | _BV(ADEN)); // a/d prescaler = sysclk/128, a/d enable
ADMUX = (_BV(7) | _BV(6)); // use internal 1.1v ref & clear channel bits
***/
uint16_t readAnalog(uint8_t port)
{
uint8_t hi;
uint8_t lo;
ADMUX |= port; // OR in desired channel
ADCSRA |= _BV(ADSC); // Start ADC conversion
while(ADCSRA & _BV(ADSC)) { ; } // wait for a/d complete
lo = ADCL; // must read ADCL first
hi = ADCH;
return (hi << 8) | lo;
}
The first line of code (the "// a/d prescaler = sysclk/128, a/d enable" part) is what sets the A/D converter clock.