cancel
Showing results for 
Search instead for 
Did you mean: 

Bad ADC values STM32G0B1

MichaelSweden
Associate III

I have problem with the result from ADC. I divide it into two problems and will try to describe them good below. First some facts about the design, software and ADC configuration.

Device: STM32G0B1CCU6

Software using: STM32CubeG0 MCU Firmware Package V1.5.0

Config: HSE=24MHz SYSCLK=40MHz HCLK=APB=20MHz PLLQ=ToUSB=48MHz

       SYSCLK=40MHz->ToADC(async) ADC=async/2=20MHz tS=3.5 tCONV=tS+12.5=16 fS=1.25MSps

       25000 samples via DMA

PA3 connected to a light sensor, OPT101 via a RC filter (100ohm 1nF).

void HAL_MspInit(void)
{
    __HAL_RCC_SYSCFG_CLK_ENABLE();
    __HAL_RCC_PWR_CLK_ENABLE();
    HAL_SYSCFG_VREFBUF_VoltageScalingConfig(SYSCFG_VREFBUF_VOLTAGE_SCALE1); // Internal voltage reference 2.5V
    HAL_SYSCFG_EnableVREFBUF();
    HAL_SYSCFG_VREFBUF_HighImpedanceConfig(SYSCFG_VREFBUF_HIGH_IMPEDANCE_DISABLE);
    HAL_SYSCFG_StrobeDBattpinsConfig(SYSCFG_CFGR1_UCPD1_STROBE | SYSCFG_CFGR1_UCPD2_STROBE);
}
 
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if (hadc->Instance == ADC1) {
        __HAL_RCC_ADC_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        GPIO_InitStruct.Pin = GPIO_PIN_3; // PA3
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
        hDmaAdc.Instance = DMA1_Channel1;
        hDmaAdc.Init.Request = DMA_REQUEST_ADC1;
        hDmaAdc.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hDmaAdc.Init.PeriphInc = DMA_PINC_DISABLE;
        hDmaAdc.Init.MemInc = DMA_MINC_ENABLE;
        hDmaAdc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
        hDmaAdc.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
        hDmaAdc.Init.Mode = DMA_NORMAL;
        hDmaAdc.Init.Priority = DMA_PRIORITY_HIGH;
        if (HAL_DMA_Init(&hDmaAdc) != HAL_OK) {
            Error_Handler();
        }
        __HAL_LINKDMA(hadc, DMA_Handle, hDmaAdc);
    }
}
 
static void InitAdc(void)
{
    ADC_ChannelConfTypeDef sConfig = {0};
    hAdc.Instance = ADC1;
    hAdc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; // ADC Clock Mux
    hAdc.Init.Resolution = ADC_RESOLUTION_12B;
    hAdc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hAdc.Init.ScanConvMode = ADC_SCAN_SEQ_FIXED;
    hAdc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
    hAdc.Init.LowPowerAutoWait = DISABLE;
    hAdc.Init.LowPowerAutoPowerOff = DISABLE;
    hAdc.Init.ContinuousConvMode = ENABLE;
    hAdc.Init.NbrOfConversion = 1;
    hAdc.Init.DiscontinuousConvMode = DISABLE;
    hAdc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hAdc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    hAdc.Init.DMAContinuousRequests = DISABLE;
    hAdc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
    hAdc.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_3CYCLES_5;
    hAdc.Init.OversamplingMode = DISABLE;
    hAdc.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
    if (HAL_ADC_Init(&hAdc) != HAL_OK) {
        Error_Handler();
    }
    sConfig.Channel = ADC_CHANNEL_3;
    sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
    if (HAL_ADC_ConfigChannel(&hAdc, &sConfig) != HAL_OK) {
        Error_Handler();
    }
}

#1 Slow rising

I early discover that the first sample seems to be lower than the others. However after looking at curves I noted that is was more than the first sample. Signal is slowly rising. I have made a workaround for this, by sample 1000 extra sample and discard them. The picture show with different serie resistor on the analog input. This is from prototype no 1. The second have different DC level (around 200).

0693W00000HpxmxQAB.png 

#2 DC offset

It is some kind of DC offset. DC level measured with oscilloscope isn't that low from the ADC. I think that this mysterious DC offset level keep the ADC from see low level signal and therefor give curves like this:

0693W00000HpxngQAB.pngThe level is different betwen the two prototype boards I have and seems to differ if I change the RC filter in front of ADC input pin.

#3 Overshoot

It will for some level of signals be a heavy overshoot in the curves from the ADC. Note that the 50 Hz square wave signal to the ADC isn't straight square wave. It is bandwidth limited by the light sensor. So the upper corner to the left of the rising signal shouldn't be sharp, it will round off little like the curves down to right in the pictures. However overshoot and ringing as in these curves shouldn't exist. These cuvres are from prototype number 2 and the DC offset differ from previous curves above.

0693W00000HpxnqQAB.png 

What have I done wrong?

//Michael

1 ACCEPTED SOLUTION

Accepted Solutions

The sampling capacitor in AC is charged internally to some level (presumably half of VREF) and then connected to your signal for the sampling period. If your signal is high impedance, you will see this on the scope, and if the sampling period is too short, it will have influence on the output of ADC.

JW

View solution in original post

9 REPLIES 9
MichaelSweden
Associate III

More investigation of the DC offset. I remove the light sensor and instead mounted a resistor of 1kohm from PA3 to GND. This give a level close to zero, as can seen in picture below. I added a resistor to VDD and got a straight line at 2683-2696, which corresponds to 1.64 volt. It seems good, half of 3.3 volt.

0693W00000HpxooQAB.png 

Now I got an idea of measure with an oscilloscope at the analog input (with only a resistor to ground). It looks like this, while the ADC is working:

0693W00000HpxpNQAR.pngWhere does this signal come from? Please note the high level (0.5 volt), at 1kohm load.

Is it this that destroy my measurements. Can it build up a DC level. Let us mount a capacitor over the resistor at PA3. The result can be seen in picture above at the third row of curves. Yes, a DC level is measured by the ADC.

How can I avoid this?

//Michael

TDK
Guru

> hAdc.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_3CYCLES_5;

The sensor you have has a very high output impedance. You should increase the sampling time to improve accuracy.

What is the hardware setup difference between "PA3 - 1kOhm - GND" which gives the expected result and "ULS P1 PA3 - 1kOhm - GND" which does not?

I would imagine most/all of these are artifacts from the sensor and not the ADC.

If you feel a post has answered your question, please click "Accept as Solution".

The sampling capacitor in AC is charged internally to some level (presumably half of VREF) and then connected to your signal for the sampling period. If your signal is high impedance, you will see this on the scope, and if the sampling period is too short, it will have influence on the output of ADC.

JW

Dvorak.Peter
Senior II

Can you switch to a digital light sensor?

The OPT101 light sensor is an old device designed for resistive load to ground.

MichaelSweden
Associate III

Big thanks for all answers.

"The sensor you have has a very high output impedance. You should increase the sampling time to improve accuracy."

I want the selected sample time (1.25MHz), it's a requirement.

Since the sensor includes an OP I did not think it have high output impedance. Now I see in datasheet it actually have problem to sink current. Therefor it also contain a JFET for that purpose. However it require a negative power supply and I don't have that.

"What is the hardware setup difference between "PA3 - 1kOhm - GND" which gives the expected result and "ULS P1 PA3 - 1kOhm - GND" which does not?"

They both have only a resistor to ground at the analog input pin. The difference is that the first is the values from the ADC and the second is a measurement with an oscilloscope.

"The sampling capacitor in ADC is charged internally to some level (presumably half of VREF) and then connected to your signal for the sampling period."

Thank you very much for this information. It explained why it behaves as it does.

"Can you switch to a digital light sensor?"

Yes, if I can find one that is fast enough and pretty cheap. I actually have plan to design an own light sensor. Little bit like the OPT101, but built with separate components. I found the "1 MHz, Single-Supply, Photodiode Amplifier Reference Design" document from Texas Instruments. I would like faster response than OPT101 and better light sensitivity.

"The OPT101 light sensor is an old device designed for resistive load to ground."

I have now read more in the datasheet and realize that OPT101 cannot sink current.

Could one solution be to add an OP between OPT101 and ADC (MCU)?

Should it be a resistor between OP output and the ADC input? That should comply with the Max.RAIN 680 ohm in datasheet. For example 100 ohm, or can the OP output handle the current from the ADC directly connected?

Can you recommend a cheap OP?

//Michael

MichaelSweden
Associate III

I mounted an OP and got better results. Now low levels are visible and no overshoots. It looks like curves I'm used to see from this sensor, then it is connected to an oscilloscope. I connected the OP (MAX44259) as a buffer between the sensor and the ADC. Between OP output and ADC input is a resistor. I believe this resistor is needed to reduce the peak current at sample time. I mounted 470 ohm and think that is good, since datasheet specify max 680 ohm for the configuration I use. I already have 100 ohm resistors in the design and was on the they to select it for this position also. However I think it is better with higher value, to reduce the current. I will experiment with different value to see if it effects the sample values. I will also test to load the OPT101 output. Right now it only goes directly to the OP input.

0693W00000Hq4QFQAZ.png 

THANKS!

//Michael

MichaelSweden
Associate III

I found an application note that describe this and more about ADC:

AN2834 How to get the best ADC accuracy in STM32 microcontrollers

https://www.st.com/resource/en/application_note/cd00211314-how-to-get-the-best-adc-accuracy-in-stm32-microcontrollers-stmicroelectronics.pdf

I recommend it to everyone that shall use the ADC in STM32.

Piranha
Chief II

That MCU has an ADC calibration feature. At least the code shown doesn't show the calibration code. The calibration should remove the DC offset.

MichaelSweden
Associate III

I did a calibration before first measurement, after power up. However have now changed and always do it, before each measurement. The code sequence is like this:

HAL_ADCEx_Calibration_Start()

HAL_ADC_Start_DMA()

Wait for HAL_ADC_ConvCpltCallback()

HAL_ADC_Stop_DMA()

Send data on USB

Regarding the DC offset that can be seen in the curves. In the first picture it was caused by the current spikes from ADC, capacitor on input pin and the lack of sink capacity of the signal source. In the last picture above, the dc offset is actually from the source. The light sensor don't go down to zero. In one curve the sample values are 10 to 18, which correspond to 6.1 - 11 mV. The light sensor is specified to have 5 - 10 mV dc level at dark. So now all looks good to me. However I wan't a faster light sensor, so I will replace OPT101.