ADC resolution on Orangutan SVP

Hello all,

I’m beginning a new project and I plan to use an MMA7361L-3-Axis accelerometer with an Orangutan SVP-1824 Robot Controller.
The Orangutan ADC converts 0 – 5 Vcc signals to 0-1023 (10-bit mode), what gives 4.88 mV resolution.

MMA7361L outputs a signal of 1.5 ± 0.8 Vcc for ± 1g, which is small compared with the range of the ADC.

My question is:
¿Is there any way to improve the ADC resolution in this application?
According to the ATmega1284P user’s guide, the voltage range for the ADC can be set using an external reference (i.e: 3.3Vcc at pin AREF) and setting the ADMUX register.
Is this also possible for the Orangutan SVP?
If so, where can I find information about the commands to do that?

Thanks.

Hello.

Yes, you can improve the ADC resolution on the Orangutan SVP by lowering your SVP’s analog reference voltage. Specifically, you can connect the your accelerometer’s Vdd (use the 3.3 V output if you are using the version with an integrated regulator) to the Orangutan SVP’s AREF pin. The AREF pin is labeled on the bottom silkscreen of the SVP.

You can find more information on how to configure the ADC registers to use AREF in the ATmega1284 datasheet, but it’s pretty easy. You just need to clear bits 6 and 7 (REFS0 and REFS1) of the ADMUX register. Note that the Pololu AVR library does not have built-in support for doing this, and the OrangutanAnalog library functions automatically configure the ADMUX register to use the AVcc (5 V) as the analog reference voltage, so you will need to modify the library code or write your own if you want to do this. For example, you could add a parameter to the OrangutanAnalog::startConversion() method that determines whether the analog reference voltage is AREF or AVcc:

void OrangutanAnalog::startConversion(unsigned char channel, unsigned char use_aref)
{
	#ifdef _ORANGUTAN_SVP
	if (channel > 31)
	{
		adc_result_is_in_millivolts = 1;

		if (channel == TRIMPOT){ adc_result_millivolts = OrangutanSVP::getTrimpotMillivolts(); }
		else if (channel == CHANNEL_A){ adc_result_millivolts = OrangutanSVP::getChannelAMillivolts(); }
		else if (channel == CHANNEL_B){ adc_result_millivolts = OrangutanSVP::getChannelBMillivolts(); }
		else if (channel == CHANNEL_C){ adc_result_millivolts = OrangutanSVP::getChannelCMillivolts(); }
		else if (channel == CHANNEL_D){ adc_result_millivolts = OrangutanSVP::getChannelDMillivolts(); }

		return;
	}

	adc_result_is_in_millivolts = 0;

	#else

	// Channel numbers greater than 31 are invalid.
	if (channel > 31)
	{
		return;
	}

	#endif

	ADCSRA = 0x87;		// bit 7 set: ADC enabled
						// bit 6 clear: don't start conversion
						// bit 5 clear: disable autotrigger
						// bit 4: ADC interrupt flag
						// bit 3 clear: disable ADC interrupt
						// bits 0-2 set: ADC clock prescaler is 128
						//  128 prescaler required for 10-bit resolution when FCPU = 20 MHz
						
	// NOTE: it is important to make changes to a temporary variable and then set the ADMUX
	// register in a single atomic operation rather than incrementally changing bits of ADMUX.
	// Specifically, setting the ADC channel by first clearing the channel bits of ADMUX and
	// then setting the ones corresponding to the desired channel briefly connects the ADC
	// to channel 0, which can affect the ADC charge capacitor.  For example, if you have a
	// high output impedance voltage on channel 1 and a low output impedance voltage on channel
	// 0, the voltage on channel 0 be briefly applied to the ADC capacitor before every conversion,
	// which could prevent the capacitor from settling to the voltage on channel 1, even over
	// many reads.
	unsigned char tempADMUX = ADMUX;

	tempADMUX &= ~(1 << 7);
	if(use_aref)
	{
		// use AREF as a reference
		tempADMUX &= ~(1 << 6);
	}
	else
	{
		// use AVCC as a reference
		tempADMUX |= 1 << 6;
	}

	tempADMUX &= ~0x1F;		 // clear channel selection bits of ADMUX
	tempADMUX |= channel;    // we only get this far if channel is less than 32
	ADMUX = tempADMUX;
	ADCSRA |= 1 << ADSC; // start the conversion
}

You would also then need to add the use_aref parameter to any other analog library functions you want to use, or you could just hard-code everything to use AREF as the reference voltage. Does this make sense? Please ask if you have any questions about how to do this.

By the way, please note that it is possible for the accelerometer to output voltages all the way up to its supplied Vdd (i.e. it is not necessarily limited to responses within the ±1g range), and it is dangerous to supply an analog voltage input with voltages exceeding the analog reference voltage. Please be careful not to use analog reference voltages below Vdd, and please do not connect 5 V signals to your analog inputs if you are using something like a 3.3 V AREF as your voltage reference.

- Ben

Thanks Ben,

I’ll follow your advices.