2023-03-05 11:09 PM
Target: STM32L031C6T6
editor: SMT32CubeIDE using HAL
I getting crazy soon. I cannot get this ADC to read correct. I think I missing something important. I googled and googled again and again.
I have two voltage on two separate channels (7 & 8). 6.9V and 14V. Of course, it is led to the pin via a voltage divider. Voltage is around 2.5V messured at the pin.
The function ADC_Read(channel, samples) returns the voltage in mV and I get 6800 for the first one and the 11608 mV for the second. There is the problem. No matter what I'm setting the voltage to (8V or 14.5V) i get around 11600 mV. I can see in the array that it change a few bits here and there but every value has wrong "level" leading to wrong mean. Do I mesure wrong channel?
My code just calls ADC_Init() in the beginning (where CubeIDE place it) and then I do the calls to ADC_Read further below. Forgot, I added a call to calibration in the end of ADC_Init.
I have no more code that I add. STM32CubeIDE adds ADC Init. I don't add no "Clock start" or something else.
The code is below. Please please have a look. Give me a good monday! What you see in ADC_Read is a "lab-code" and written so I can single-step it.
/*
* adc.c
*
* Created on: 25 Jan 2023
*/
#include "adc.h"
#include "main.h"
#include "stm32l0xx_hal_adc.h"
#include <stdint.h>
const ADC_ChannelConfTypeDef sConfigs[] = {
{ ADC_CHANNEL_VREFINT, ADC_RANK_CHANNEL_NUMBER }, // 1 Internal
{ ADC_CHANNEL_TEMPSENSOR, ADC_RANK_CHANNEL_NUMBER }, // 2 Internal
{ ADC_CHANNEL_1, ADC_RANK_CHANNEL_NUMBER },
{ ADC_CHANNEL_2, ADC_RANK_CHANNEL_NUMBER },
{ ADC_CHANNEL_3, ADC_RANK_CHANNEL_NUMBER },
{ ADC_CHANNEL_4, ADC_RANK_CHANNEL_NUMBER },
{ ADC_CHANNEL_7, ADC_RANK_CHANNEL_NUMBER }, //CH_12VSNS
{ ADC_CHANNEL_8, ADC_RANK_CHANNEL_NUMBER } //CH_6V9SNS
};
const uint16_t ADC_factors[] = { 100,100,196,196,196,196,399,224 }; //12 bitars
//************************************************************************************************
uint32_t adc_values[20];
uint16_t ADC_Read(uint32_t ch, uint8_t samples)
{
uint8_t right, i;
uint32_t summa = 0;
if(samples > 20) samples = 20;
for(i=0;i<20;i++)
adc_values[i]=0;
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = sConfigs[ch].Channel;
sConfig.Rank = sConfigs[ch].Rank;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
_NOP; // ADC channel configuration error
return(0xFFFF);
} //End if
right = 0;
for (i = 0; i < samples; i++)
{
if(HAL_ADC_Start(&hadc) == HAL_OK)
{
if(HAL_ADC_PollForConversion(&hadc, 1000) == HAL_OK)
{
short_delay(50);
adc_values[i] = HAL_ADC_GetValue(&hadc);
right = right + 1;
} //End if
} //End if
} //End for
HAL_ADC_Stop(&hadc); //??
summa = 0;
for (i = 0; i < samples; i++)
summa += adc_values[i];
if(right == samples)
{
summa = (summa / (uint32_t)samples) * (uint32_t)ADC_factors[ch] / (uint32_t)100;
} //End if
else
{
summa = (uint16_t)0xFFFF;
} //End else
short_delay(35); //35 us
return (uint16_t)summa; //mV
} //End func
//*************** ADC Init ****************************
static void MX_ADC_Init(void)
{
/* USER CODE BEGIN ADC_Init 0 */
/* USER CODE END ADC_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC_Init 1 */
/* USER CODE END ADC_Init 1 */
/** Configure the global features of the ADC
(Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.OversamplingMode = DISABLE;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV4;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.SamplingTime = ADC_SAMPLETIME_3CYCLES_5;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerFrequencyMode = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
#define XXXXx
#ifdef XXXXx
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_2;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_3;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_4;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_7;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_8;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
#endif
/* USER CODE BEGIN ADC_Init 2 */
HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED);
/* USER CODE END ADC_Init 2 */
}
2023-03-06 09:10 AM
By using a voltage divider it's very easy to introduce a high source impedance, which prevents the sampling capacitor from fully charging.
> hadc.Init.SamplingTime = ADC_SAMPLETIME_3CYCLES_5;
3.5 cycles is pretty short. Data sheet [DS10668 rev 6] Table 58 gives the maximum source impedance for different sampling times -- for 3.5 cycles (at 16MHz) it looks to be about 200 Ohms.
As a quick experiment, try setting SamplingTime to something very large and see if your symptom changes.
2023-03-06 11:20 PM
Thanx for answer. I have eariler used higher sampl.time just for test and it did not help. Same now. Did not help. (I haven't read Table 58. Thanx for letting me know.)
I do not need to use any setup regarding Vref+ or something? I just accept CubeIDEs ADC_Init and then I put together the ADC_Read and start using it.
Why I have a feeling that I read wrong channel is that my code in ADC_Read are exact the same as all others examples. 1) config ch, 2) start, 3) polling, 4) read. 5) start 6) polling read start polling read.
What I have noticed is that I need a short delay (200us) after polling before I read or else ADC_Start fails. Is that a clue?
The MCU using 24 MHz, btw.
2023-03-07 03:23 AM
I made the ADC_Read without HAL. Now it is working. I cannot spend more time on this. Must move on.