ADC converted value error: bit truncation when using DMA
- September 11, 2023
- 5 replies
- 2446 views
Hello.
I encountered a truncation error issue while working on a grid-connected converter application with the STM32G474MET6 MCU. To manage multiple ADC channels, I opted for DMA to obtain 12-bit ADC converted values. However, I've noticed a bit truncation error in the converted values, where such LSB of the value remains unchanged even as the analog value varies. Here's an illustrative example:
When Vref = VDDA = 3.3V, and the analog value continuously shifts from 1.65V to 1.68V, the converted values exhibit a step-function behavior. The digital values transition from 2063 (0b 1000 0000 1111) to 2079 (0b 1000 0001 1111), with 'no intermediate values'. Even though the analog value changes, the four LSBs of the converted value persist as 0b1111. I also attached the waveform of bit truncation: the green one is real value and the others are ADC converted values(I apologize for slight difference of scale).
Discovering this error was quite embarrassing, prompting me to explore potential solutions. Initially, I attempted to adjust the ADC module parameters to address the issue. I observed that the truncation error correlates with the ADC's sampling cycle. Increasing the sampling cycle (e.g., from 2.5 cycles to 12.5 cycles) augmented the bit truncation (e.g., from 2 LSBs to 4 LSBs). I also experimented with oversampling to enhance resolution. While the oversampling reduced the bit truncation slightly, a few LSBs remained unchanged, indicating that this may not be a fundamental solution.
The ADC conversion code is currently implemented using HAL functions, as shown below. Additionally, my CUBEMX (.ioc) file can be downloaded at the drive link: https://drive.google.com/file/d/1DkIZht7omcr_Q17ae8uVIGorbue5hK6r/view?usp=sharing
//////////////h file//////////////
#define ADC1CHANNEL 4 // Ia,Ib,Ic,Idc
#define ADC2CHANNEL 2 // N,NTC
#define ADC3CHANNEL 5 // Ea,Eb,Ec,Vdcp,Vdcn
uint16_t ADC1_Result[ADC1CHANNEL], ADC1_Offset[ADC1CHANNEL];
uint16_t ADC2_Result[ADC2CHANNEL], ADC2_Offset[ADC2CHANNEL];
uint16_t ADC3_Result[ADC3CHANNEL], ADC3_Offset[ADC3CHANNEL];
//////////////c file//////////////
void InitADC(void){
// ADC gain calculation
Gain_ACV = RES_DIV_AC*ISO_OP_GAIN*OPAMP_GAIN*ADC3GAIN;
Gain_ACC = -CUR_SEN_GAIN*OPAMP_GAIN*ADC1GAIN;
Gain_DCV = RES_DIV_DC*ISO_OP_GAIN*OPAMP_GAIN*ADC3GAIN;
Gain_DCC = CUR_SEN_GAIN*OPAMP_GAIN*ADC1GAIN;
Gain_PEV = ISO_OP_GAIN*OPAMP_GAIN*ADC4GAIN;
Gain_PEC = LEAK_CUR_SEN_GAIN*LEAK_CUR_OPAMP_GAIN*ADC5GAIN;
Gain_PEVrms = OPAMP_GAIN*ADC2GAIN;
Gain_NTC = NTC_GAIN*ADC2GAIN;
ADC_Enable(&hadc1);
ADC_Enable(&hadc2);
ADC_Enable(&hadc3);
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED);
HAL_ADCEx_Calibration_Start(&hadc3, ADC_SINGLE_ENDED);
HAL_ADC_Start_DMA(&hadc1, (uint32_t *) ADC1_Result, ADC1CHANNEL);
HAL_ADC_Start_DMA(&hadc2, (uint32_t *) ADC2_Result, ADC2CHANNEL);
HAL_ADC_Start_DMA(&hadc3, (uint32_t *) ADC3_Result, ADC3CHANNEL);
}
void ADC(void){
while(adc1wait || adc2wait || adc3wait)
;
Ia = (float)(ADC1_Result[0] - ADC1_Offset[0]) * Gain_ACC;
Ib = (float)(ADC1_Result[1] - ADC1_Offset[1]) * Gain_ACC;
Ic = (float)(ADC1_Result[2] - ADC1_Offset[2]) * Gain_ACC;
Idc = (float)(ADC1_Result[3] - ADC1_Offset[3]) * Gain_DCC;
Ea = (float)(ADC3_Result[0] - ADC3_Offset[0]) * Gain_ACV;
Eb = (float)(ADC3_Result[1] - ADC3_Offset[1]) * Gain_ACV;
Ec = (float)(ADC3_Result[2] - ADC3_Offset[2]) * Gain_ACV;
Vdcp = (float)(ADC3_Result[3] - ADC3_Offset[3]) * Gain_DCV;
Vdcn = (float)(ADC3_Result[4] - ADC3_Offset[4]) * Gain_DCV;
adc1wait = 1; adc2wait = 1; adc3wait = 1; adc4wait = 1; adc5wait = 1;
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
if (hadc == &hadc1) {
if (adc1wait) adc1wait = 0;
}
else if (hadc == &hadc2) {
if (adc2wait) adc2wait = 0;
}
else if (hadc == &hadc3) {
if (adc3wait) adc3wait = 0;
}
else if (hadc == &hadc4) {
if (adc4wait) adc4wait = 0;
}
else if (hadc == &hadc5) {
if (adc5wait) adc5wait = 0;
}
else ;
}
I would greatly appreciate any guidance or suggestions to help resolve the truncation problem.
Best Regards,
Paul
