cancel
Showing results for 
Search instead for 
Did you mean: 

Inaccurate STM32F769i-disco ADC

lyuIvanov
Associate II

I want to read data from PT1000 thermistor. After succeeding in communicating with the TouchGFX model and displaying the content I wanted, I now want to be able to read real time temp. For this job I have PT1000 sensor. I have made the ADC to work, but the problem I'm experiencing, is, that the values I get are very inaccurate. I'm getting every second different values in the range from 17 to 24 degrees, which is pretty bad. I aim for accuracy of +- 1 degree or even 0.1. Now it is quite miserable. I have placed 10uF capacitor to filter out noise, coded to get average of 10 convertions (excluding the lowest and highest values), but nothing helped, I mean, they have improoved the amplitudes, but not with the margin I expected. Before it was worse than 17-25. I really don't know what the reason could be. I have read a lot and watched and everyone has steady reading (for example 1723-1727 (12bit value straight from ADC)), I get fluctuations like 1723-2023. Maybe there is something wrong with my code, maybe there is problem with my channel, maybe it is EMI, but God this is one pretty big amplitude.

Please, help me with this problem, any suggestions are highly appreciated. This is my first contact with MCUs.

Here is my code. It is pretty dirty, in the end I was just hard trying stuff... :D

#define ADCx                            ADC1
#define ADCx_CLK_ENABLE()               __HAL_RCC_ADC1_CLK_ENABLE()
#define ADCx_CHANNEL_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOA_CLK_ENABLE()
 
#define ADCx_FORCE_RESET()              __HAL_RCC_ADC_FORCE_RESET()
#define ADCx_RELEASE_RESET()            __HAL_RCC_ADC_RELEASE_RESET()
 
/* Definition for ADCx Channel Pin */
#define ADCx_CHANNEL_PIN                GPIO_PIN_6
#define ADCx_CHANNEL_GPIO_PORT          GPIOA
 
/* Definition for ADCx's Channel */
#define ADCx_CHANNEL                    ADC_CHANNEL_6
#define SAMPLINGTIME                    ADC_SAMPLETIME_480CYCLES
 
xQueueHandle msgQueueUI;
 
static void ADCTask(void* params)
{
    ADC_HandleTypeDef AdcHandle;
    
    /*
     * Initialize ADC
     */
    AdcHandle.Instance = ADCx;
    if (HAL_ADC_DeInit(&AdcHandle) != HAL_OK)
    {
        /* ADC de-initialization Error */
        while (1) {};
    }
 
    AdcHandle.Init.ClockPrescaler        = ADC_CLOCKPRESCALER_PCLK_DIV4;  
    AdcHandle.Init.Resolution            = ADC_RESOLUTION_12B;    
    AdcHandle.Init.DataAlign             = ADC_DATAALIGN_RIGHT;    
    AdcHandle.Init.ScanConvMode          = DISABLE;                 
    AdcHandle.Init.EOCSelection          = DISABLE;                     
    AdcHandle.Init.ContinuousConvMode    = DISABLE;                  
    AdcHandle.Init.NbrOfConversion       = 1;                             
    AdcHandle.Init.DiscontinuousConvMode = DISABLE;                    
    AdcHandle.Init.NbrOfDiscConversion   = 0;                             
    AdcHandle.Init.ExternalTrigConv      = ADC_EXTERNALTRIGCONV_T1_CC1;  
    AdcHandle.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE; 
    AdcHandle.Init.DMAContinuousRequests = DISABLE;   
    
    if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
    {
        /* ADC initialization Error */
        while (1) {};
    }    
    
    GPIO_InitTypeDef GPIO_InitStruct;
    /*##-1- Enable peripherals and GPIO Clocks #################################*/
    /* ADC Periph clock enable */
    ADCx_CLK_ENABLE();
    /* Enable GPIO clock ****************************************/
    ADCx_CHANNEL_GPIO_CLK_ENABLE();
    
    /*##-2- Configure peripheral GPIO ##########################################*/
    /* ADC Channel GPIO pin configuration */
    GPIO_InitStruct.Pin = ADCx_CHANNEL_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(ADCx_CHANNEL_GPIO_PORT, &GPIO_InitStruct);
    
    ADC_ChannelConfTypeDef sConfig;
    sConfig.Channel      = ADCx_CHANNEL;                /* Sampled channel number */
    sConfig.Rank         = 1;          /* Rank of sampled channel number ADCx_CHANNEL */
    sConfig.SamplingTime = SAMPLINGTIME;    /* Sampling time (number of clock cycles unit) */
    sConfig.Offset = 0;                                 /* Parameter discarded because offset correction is disabled */
 
    if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
    {
        /* Channel Configuration Error */
        while (1) {};
    }
		float A=3.9083E-3; /* PT1000 consts */
		float B=-5.775E-7; /* PT1000 consts */
		float R = 1000; /* PT1000 consts */
		float averageRead[10]; /* hard trying to improve accuracy */
    while (1)
    {
        vTaskDelay(1000); //Approx 10 Hz
        // Start Conversation Error
			
				HAL_ADC_Start(&AdcHandle);
			
			        for(int i =0; i<10; i++){
				
				HAL_ADC_PollForConversion(&AdcHandle, 10);
                                averageRead[i] = HAL_ADC_GetValue(&AdcHandle);
				}
				float maxValue = averageRead[0]; 
				for(int i=1;i < 10;i++){ 
					if(averageRead[i] > maxValue){ 
						maxValue = averageRead[i]; 
					}
				} 
				float minValue = averageRead[0]; 
				for(int i=1;i < 10;i++){ 
					if(averageRead[i] > minValue){ 
						minValue = averageRead[i]; 
					}
				} 
				float sum = 0;
				for (int i=0;i<10;i++){
					sum += averageRead[i];
				}
				float adcValue = (sum - minValue - maxValue)/8;
 
        // Get the converted value of regular channel
			  float adcVoltage = adcValue*(3.3/4096);
			  float adcResistance = ((3.3*2200)-(adcVoltage * 2200)) / adcVoltage;
				 
			  float adcTemp = ((R * A * (-1)) + sqrt((R * R * A * A) - (4 * R * B * (R - adcResistance))))/(2 * R * B); /* PT1000 formula */
				
				xQueueSendToBack(msgQueueUI, &adcTemp, 0); /* sending value to model in TouchGFX */
    }
}

P.s my question was posted empty at first, so I had to rewrite it, sorry

P.s. Degrees are in Celsius 🙂

P.s. Sorry for bad English

1 ACCEPTED SOLUTION

Accepted Solutions
S.Ma
Principal
  1. Get an oscilloscope to probe the analog channel and check if you have noise or voltage droops by ADC sipping current during the sample and hold time. Signal should be low input impedence, for example using an external op-amp follower buffer.
  2. ADC also have calibration function before doing conversion
  3. Is the chosen channel not used on the disco for something else? Check schematics
  4. Remove the thermistor and place a fixed voltage on the ADC input to monitor the result
  5. How frequent do you convert the thermistor?

View solution in original post

5 REPLIES 5
MikeDB
Lead

I don't use HAL but usually random values from an ADC means you are reading the ADC value before conversion is complete.

Does HAL_ADC_PollForConversion(...) simply not return until conversion is done, or are you supposed to check it repeatedly for being true before using HAL_ADC_GetValue(...) ??

AvaTar
Lead

> I want to read data from PT1000 thermistor.

How do you do it, exactly ?

You can't measure resistance directly with an ADC, perhaps you review your analog circuitry to interface the PT1000.

The ADC needs a low-impedance input for proper conversion, and a high enough voltage for proper accuracy.

The sensor needs a minimal transverse current, or else it will self-heat and distort the measurement.

Verify a proper function of your analog circuitry before attaching the ADC.

S.Ma
Principal
  1. Get an oscilloscope to probe the analog channel and check if you have noise or voltage droops by ADC sipping current during the sample and hold time. Signal should be low input impedence, for example using an external op-amp follower buffer.
  2. ADC also have calibration function before doing conversion
  3. Is the chosen channel not used on the disco for something else? Check schematics
  4. Remove the thermistor and place a fixed voltage on the ADC input to monitor the result
  5. How frequent do you convert the thermistor?

  1. Unfortunately, I don't have one :( should order
  2. I was unable to find a function that does it. However I watched how to do it in CR with ADC_CR_ADCAL, but the problem is that TouchGFX shows compilation error while using registers.
  3. I have checked and it seems that the pins to the Arduino looking rail are only connected to the rail itself.
  4. I have tried connecting 1.5V battery, but still flickering a lot. When wire going to ADC is removed, it continues to show values. When wire is connected directly to ground receive fluctoations between 0-45, maybe a bit more. When connect directly to ref voltage (IOREF5) shows 4040-4095. When it is wired all as the pic I'm posting in next comment, it shows 2680-2750 at room temp.
  5. For the testing In order to write this response I have setted the Delay at 100, which is 10 times a second. I'm using ADC_CLOCKPRESCALER_PCLK_DIV4 and sampling time of 480.

In the end I see, that the error has become smaller, but still bigger than desired. Maybe I can shorten somehow the range, since I'm not going to read temps below -10 and above 180 degrees. So I will have 4095 across 190 points, instead of 600 or more hundreds. The problem though is that I have no idea how to do it and if it will improve accuracy. It is logically to do so, but who knows...

P.s I don't think that current is high, since overnight it showed the same values in the morning as midnight. I have measured it with multimeter, it showed 1000uA, but I don't know if it is that accurate and thrustful.

0690X0000088Gz3QAE.jpg1. White wire is Vref (3.3V)

2 Red wire is one end of thermistor (connected to white wire)

3 Blue wire is other end of thermistor

4 Resistor going to ground is 2k2Ohm (connected to blue)

5 Resistor going to brown is 10kOhm (connected to blue)

6 Brown wire is going to ADC

7 Capacitor is 150nF ceramic going to ground as well (connected to brown)

8 Black wire is connected to ground pin