I am running code on the M4 core of the VF61 to read the ADC. I am getting very noisy readings.
First I have a question about the ADC reference voltage. I am setting REFSEL to 00 to use an external reference voltage. This seems to give me a full scale reading of about 3.31V. The reference can also be set to an alternate external reference voltage, or to an internal bandgap reference. Please explain exactly what is being used as the reference voltage with each of these settings, and what the full scale input voltage would be.
I am setting my other parameters as follows:
Clock = IPG, clock divisor = 8, mode = 12 bit, sample time = 8 clocks, no averaging.
When I set my input voltage to 1.65V (using a well regulated low noise DC power supply) I get readings around 2032. However, the readings are not very stable. I have seen readings as high as 2054, and as low as 1990. That amounts to a spread of 64 LSBs, or +22 to -42 LSB from the average reading of 2032. That means I am losing about 5 bits worth of precision, and am only getting about 7 bits worth of accuracy.
When I input 0 volts (by using a jumper between the analog input pin and the adjacent GND pin on the evaluation board) the reading jumps around from 0 to 7, so I am still losing 3 bits of precision.
My code for initializing and reading the ADC is as follows:
uint32_t init_adc(void)
{
// set ADC_CFG, ADC_GC, ADC_HC0
ADC0_CFG = ADC_CFG_ADICLK(0) | ADC_CFG_MODE(2) | ADC_CFG_ADIV(2) // clock=IPG, 12 bit, clock/4
| ADC_CFG_ADSTS(3) | ADC_CFG_REFSEL(0) | ADC_CFG_AVGS(0); // sample 8 clocks, external ref, averaging not used
ADC0_GC = 0; // no cal, continuous, averaging, dma or adacken
ADC0_HC0 = 31; // disable conversion
ADC0_GC |= ADC_GC_CAL_MASK; // start the calibration
while ((ADC0_HS & ADC_HS_COCO0_MASK) == 0); // wait for calibration done
return ADC0_R0; // this forces a read of the result register, but the returned data is meaningless
}
uint32_t read_adc(int channel)
{
ADC0_HC0 = channel; // start conversion
while ((ADC0_HS & ADC_HS_COCO0_MASK) == 0); // wait for conversion done
return ADC0_R0; // return result register
}
Is there anything I am doing wrong? How can I get better accuracy out of the ADC? Averaging multiple reading is not an option because I am sampling an AC signal and doing RMS conversion in software. Should I be using a different ADC clock or a different clock rate? Any suggestions would be appreciated. Right now the readings are so noisy as to be pretty much useless.