cancel
Showing results for 
Search instead for 
Did you mean: 

ADC sequencer on STM32WL33

RenzoPosega
Associate

Hi all, 

I'm setting up a custom board using the STM32WL33 device. 

I'm using four single-ended ADC inputs: ADC_VINM0, ADC_VINP0, ADC_VINM3, ADC_VINP3.

I would like to use DMA and sequencer, adding TEMP and VDD as 5th and 6th conversions. 

I managed to got the above up and running, but

a) appears that ALL conversion is done on 3.6V conversion range, regardless of software setup and subsequent SWITCH register settings (which appears correctly set: 0x8282); using the below macro gives correct ADC_value => mV conversion: 

__HAL_ADC_CALC_DATA_TO_VOLTAGE(ADC_VIN_RANGE_3V6, adc[2], ADC_DS_DATA_WIDTH_12_BIT);

b) TEMP reading appears totally wrong. At ambient temp (30°C), ADC readings is around 726 (over 12 bits). If I readback calibration registers: 

uint32_t Calib_c30 = (int32_t)*TEMPSENSOR_C30_ADDR; // =2556

uint32_t TCK_c30 = (int32_t)*TEMPSENSOR_TCK_ADDR; // =300

and use RM0511 - chpt 12.2.1 formula, I get T[°C] = -153°C (!!!)

 

ADC register settings:

RenzoPosega_0-1755249872170.png

Finally, note that COMP_x registers are at default values.

And indeed, I didn't find any documentation about estimating COMP fields: OFFSET and GAIN;

it would be possible having a GND and VREF input capability, which I didn't find, either.

 

1 ACCEPTED SOLUTION

Accepted Solutions

Thank you for your prompt reply. 

Nevertheless, the documentation I have (RM0511 and STM32WL33 datasheet) does not reference VREF+. 

I just found in a design example the correct usage of the calibration points (code snippet here below for anyone having the same issue), which acting on gain, must be set accordingly to full scale range (1.2V, 2.4V or 3.6V) for each input.

Please note, however, that the definition of ADC_CALIB_NONE is wrong in stm32wl3x_hal_adc.h file generated by STMCubeMX, preventing the use of ADC_CALIB_POINT_4:

 

#define ADC_CALIB_POINT_1 (LL_ADC_CALIB_POINT_1) /*!< ADC calibration point 1 */

#define ADC_CALIB_POINT_2 (LL_ADC_CALIB_POINT_2) /*!< ADC calibration point 2 */

#define ADC_CALIB_POINT_3 (LL_ADC_CALIB_POINT_3) /*!< ADC calibration point 3 */

#define ADC_CALIB_POINT_4 (LL_ADC_CALIB_POINT_4) /*!< ADC calibration point 4 */

//#define ADC_CALIB_NONE (LL_ADC_CALIB_POINT_1 \

// | LL_ADC_CALIB_POINT_2 \

// | LL_ADC_CALIB_POINT_3 \

// | LL_ADC_CALIB_POINT_4) /*!< ADC calibration point disabled: correction are left untouched

// for the selected channel */

 

// RPO: above definition is wrong, being equal to ADC_CALIB_POINT_4

#define ADC_CALIB_NONE 4

 

Complete ADC init code (under beerware license):

 

static void MX_ADC1_Init(void)

{

 

/* USER CODE BEGIN ADC1_Init 0 */

uint32_t uADCxCalibrationPoint1_Gain;

uint32_t uADCxCalibrationPoint1_Offset;

uint32_t uADCxCalibrationPoint2_Gain;

uint32_t uADCxCalibrationPoint2_Offset;

 

uint32_t uADCxCalibrationPoint4_Gain;

uint32_t uADCxCalibrationPoint4_Offset;

/* USER CODE END ADC1_Init 0 */

 

ADC_ChannelConfTypeDef ConfigChannel = {0};

 

/* USER CODE BEGIN ADC1_Init 1 */

uADCxCalibrationPoint1_Gain = LL_ADC_GET_CALIB_GAIN_FOR_VINMX_2V4(); // 0x828

uADCxCalibrationPoint1_Offset = LL_ADC_GET_CALIB_OFFSET_FOR_VINMX_2V4(); // 0x23

if(uADCxCalibrationPoint1_Gain == 0xFFF)

{

uADCxCalibrationPoint1_Gain = LL_ADC_DEFAULT_RANGE_VALUE_2V4;

uADCxCalibrationPoint1_Offset = 0UL;

}

uADCxCalibrationPoint2_Gain = LL_ADC_GET_CALIB_GAIN_FOR_VINPX_2V4(); // 0x826

uADCxCalibrationPoint2_Offset = LL_ADC_GET_CALIB_OFFSET_FOR_VINPX_2V4(); // 0xFDB

if(uADCxCalibrationPoint2_Gain == 0xFFF)

{

uADCxCalibrationPoint2_Gain = LL_ADC_DEFAULT_RANGE_VALUE_2V4;

uADCxCalibrationPoint2_Offset = 0UL;

}

 

uADCxCalibrationPoint4_Gain = LL_ADC_GET_CALIB_GAIN_FOR_VINPX_3V6(); // 0x56E

uADCxCalibrationPoint4_Offset = LL_ADC_GET_CALIB_OFFSET_FOR_VINPX_3V6(); // 0xFD7

if(uADCxCalibrationPoint4_Gain == 0xFFF)

{

uADCxCalibrationPoint4_Gain = LL_ADC_DEFAULT_RANGE_VALUE_3V6;

uADCxCalibrationPoint4_Offset = 0UL;

}

/* USER CODE END ADC1_Init 1 */

 

/** Common config

*/

hadc1.Instance = ADC1;

hadc1.Init.SequenceLength = ADC_SEQ_LENGTH;

hadc1.Init.SamplingMode = ADC_SAMPLING_AT_START;

hadc1.Init.SampleRate = ADC_SAMPLE_RATE_64;

hadc1.Init.InvertOutputMode = ADC_DATA_INVERT_SING;

hadc1.Init.Overrun = ADC_NEW_DATA_IS_LOST;

hadc1.Init.ContinuousConvMode = DISABLE;

hadc1.Init.DownSamplerConfig.DataWidth = ADC_DS_DATA_WIDTH_16_BIT;

hadc1.Init.DownSamplerConfig.DataRatio = ADC_DS_RATIO_16;

if (HAL_ADC_Init(&hadc1) != HAL_OK)

{

Error_Handler();

}

 

/** Configure Regular Channel

*/

ConfigChannel.Channel = ADC_CHANNEL_VINM0; // LOAD_CURR

ConfigChannel.Rank = ADC_RANK_1;

ConfigChannel.VoltRange = ADC_VIN_RANGE_2V4; // <= inputs can rise up to 2.18V [RPO]

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_1;

ConfigChannel.CalibrationPoint.Gain = uADCxCalibrationPoint1_Gain;

ConfigChannel.CalibrationPoint.Offset = uADCxCalibrationPoint1_Offset;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

/* USER CODE BEGIN ADC1_Init 2 */

 

 

ConfigChannel.Channel = ADC_CHANNEL_VINP3; // VDC_IN_SENSE

ConfigChannel.Rank = ADC_RANK_2;

ConfigChannel.VoltRange = ADC_VIN_RANGE_2V4; // <= inputs can rise up to 2.18V [RPO]

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_2;

ConfigChannel.CalibrationPoint.Gain = uADCxCalibrationPoint2_Gain;

ConfigChannel.CalibrationPoint.Offset = uADCxCalibrationPoint2_Offset;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

 

ConfigChannel.Channel = ADC_CHANNEL_VINM3; // VBATT_SENSE

ConfigChannel.Rank = ADC_RANK_3;

ConfigChannel.VoltRange = ADC_VIN_RANGE_2V4; // <= inputs can rise up to 2.18V [RPO]

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_1;

ConfigChannel.CalibrationPoint.Gain = uADCxCalibrationPoint1_Gain;

ConfigChannel.CalibrationPoint.Offset = uADCxCalibrationPoint1_Offset;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

 

ConfigChannel.Channel = ADC_CHANNEL_VINP0; // USB_SENSE

ConfigChannel.Rank = ADC_RANK_4;

ConfigChannel.VoltRange = ADC_VIN_RANGE_2V4; // <= inputs can rise up to 2.18V [RPO]

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_2;

ConfigChannel.CalibrationPoint.Gain = uADCxCalibrationPoint2_Gain;

ConfigChannel.CalibrationPoint.Offset = uADCxCalibrationPoint2_Offset;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

 

ConfigChannel.Channel = ADC_CHANNEL_TEMPSENSOR; // TEMP

ConfigChannel.Rank = ADC_RANK_5;

ConfigChannel.VoltRange = ADC_VIN_RANGE_1V2; // it should be set to 1.2V

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_3;

ConfigChannel.CalibrationPoint.Gain = 0; // = default (0xFFF)

ConfigChannel.CalibrationPoint.Offset = 0;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

 

ConfigChannel.Channel = ADC_CHANNEL_VBAT; // VCC

ConfigChannel.Rank = ADC_RANK_6;

ConfigChannel.VoltRange = ADC_VIN_RANGE_3V6; // up to 3.6V

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_4;

ConfigChannel.CalibrationPoint.Gain = uADCxCalibrationPoint4_Gain;

ConfigChannel.CalibrationPoint.Offset = uADCxCalibrationPoint4_Offset;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

 

/* USER CODE END ADC1_Init 2 */

 

}

 

View solution in original post

2 REPLIES 2
TDK
Super User

a) Conversion is done based on VREF+. It's a custom board, so you'll have to set this up correctly if you want a particular voltage.

b) Increase your sampling time to max. There is a minimum sampling duration on the temperature sensor which can be found in the datasheet.

 

Edit: Oh, the ADC on here is completely different from other STM32 chips. Sorry for the noise. Possibly still something to the second point.

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

Thank you for your prompt reply. 

Nevertheless, the documentation I have (RM0511 and STM32WL33 datasheet) does not reference VREF+. 

I just found in a design example the correct usage of the calibration points (code snippet here below for anyone having the same issue), which acting on gain, must be set accordingly to full scale range (1.2V, 2.4V or 3.6V) for each input.

Please note, however, that the definition of ADC_CALIB_NONE is wrong in stm32wl3x_hal_adc.h file generated by STMCubeMX, preventing the use of ADC_CALIB_POINT_4:

 

#define ADC_CALIB_POINT_1 (LL_ADC_CALIB_POINT_1) /*!< ADC calibration point 1 */

#define ADC_CALIB_POINT_2 (LL_ADC_CALIB_POINT_2) /*!< ADC calibration point 2 */

#define ADC_CALIB_POINT_3 (LL_ADC_CALIB_POINT_3) /*!< ADC calibration point 3 */

#define ADC_CALIB_POINT_4 (LL_ADC_CALIB_POINT_4) /*!< ADC calibration point 4 */

//#define ADC_CALIB_NONE (LL_ADC_CALIB_POINT_1 \

// | LL_ADC_CALIB_POINT_2 \

// | LL_ADC_CALIB_POINT_3 \

// | LL_ADC_CALIB_POINT_4) /*!< ADC calibration point disabled: correction are left untouched

// for the selected channel */

 

// RPO: above definition is wrong, being equal to ADC_CALIB_POINT_4

#define ADC_CALIB_NONE 4

 

Complete ADC init code (under beerware license):

 

static void MX_ADC1_Init(void)

{

 

/* USER CODE BEGIN ADC1_Init 0 */

uint32_t uADCxCalibrationPoint1_Gain;

uint32_t uADCxCalibrationPoint1_Offset;

uint32_t uADCxCalibrationPoint2_Gain;

uint32_t uADCxCalibrationPoint2_Offset;

 

uint32_t uADCxCalibrationPoint4_Gain;

uint32_t uADCxCalibrationPoint4_Offset;

/* USER CODE END ADC1_Init 0 */

 

ADC_ChannelConfTypeDef ConfigChannel = {0};

 

/* USER CODE BEGIN ADC1_Init 1 */

uADCxCalibrationPoint1_Gain = LL_ADC_GET_CALIB_GAIN_FOR_VINMX_2V4(); // 0x828

uADCxCalibrationPoint1_Offset = LL_ADC_GET_CALIB_OFFSET_FOR_VINMX_2V4(); // 0x23

if(uADCxCalibrationPoint1_Gain == 0xFFF)

{

uADCxCalibrationPoint1_Gain = LL_ADC_DEFAULT_RANGE_VALUE_2V4;

uADCxCalibrationPoint1_Offset = 0UL;

}

uADCxCalibrationPoint2_Gain = LL_ADC_GET_CALIB_GAIN_FOR_VINPX_2V4(); // 0x826

uADCxCalibrationPoint2_Offset = LL_ADC_GET_CALIB_OFFSET_FOR_VINPX_2V4(); // 0xFDB

if(uADCxCalibrationPoint2_Gain == 0xFFF)

{

uADCxCalibrationPoint2_Gain = LL_ADC_DEFAULT_RANGE_VALUE_2V4;

uADCxCalibrationPoint2_Offset = 0UL;

}

 

uADCxCalibrationPoint4_Gain = LL_ADC_GET_CALIB_GAIN_FOR_VINPX_3V6(); // 0x56E

uADCxCalibrationPoint4_Offset = LL_ADC_GET_CALIB_OFFSET_FOR_VINPX_3V6(); // 0xFD7

if(uADCxCalibrationPoint4_Gain == 0xFFF)

{

uADCxCalibrationPoint4_Gain = LL_ADC_DEFAULT_RANGE_VALUE_3V6;

uADCxCalibrationPoint4_Offset = 0UL;

}

/* USER CODE END ADC1_Init 1 */

 

/** Common config

*/

hadc1.Instance = ADC1;

hadc1.Init.SequenceLength = ADC_SEQ_LENGTH;

hadc1.Init.SamplingMode = ADC_SAMPLING_AT_START;

hadc1.Init.SampleRate = ADC_SAMPLE_RATE_64;

hadc1.Init.InvertOutputMode = ADC_DATA_INVERT_SING;

hadc1.Init.Overrun = ADC_NEW_DATA_IS_LOST;

hadc1.Init.ContinuousConvMode = DISABLE;

hadc1.Init.DownSamplerConfig.DataWidth = ADC_DS_DATA_WIDTH_16_BIT;

hadc1.Init.DownSamplerConfig.DataRatio = ADC_DS_RATIO_16;

if (HAL_ADC_Init(&hadc1) != HAL_OK)

{

Error_Handler();

}

 

/** Configure Regular Channel

*/

ConfigChannel.Channel = ADC_CHANNEL_VINM0; // LOAD_CURR

ConfigChannel.Rank = ADC_RANK_1;

ConfigChannel.VoltRange = ADC_VIN_RANGE_2V4; // <= inputs can rise up to 2.18V [RPO]

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_1;

ConfigChannel.CalibrationPoint.Gain = uADCxCalibrationPoint1_Gain;

ConfigChannel.CalibrationPoint.Offset = uADCxCalibrationPoint1_Offset;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

/* USER CODE BEGIN ADC1_Init 2 */

 

 

ConfigChannel.Channel = ADC_CHANNEL_VINP3; // VDC_IN_SENSE

ConfigChannel.Rank = ADC_RANK_2;

ConfigChannel.VoltRange = ADC_VIN_RANGE_2V4; // <= inputs can rise up to 2.18V [RPO]

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_2;

ConfigChannel.CalibrationPoint.Gain = uADCxCalibrationPoint2_Gain;

ConfigChannel.CalibrationPoint.Offset = uADCxCalibrationPoint2_Offset;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

 

ConfigChannel.Channel = ADC_CHANNEL_VINM3; // VBATT_SENSE

ConfigChannel.Rank = ADC_RANK_3;

ConfigChannel.VoltRange = ADC_VIN_RANGE_2V4; // <= inputs can rise up to 2.18V [RPO]

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_1;

ConfigChannel.CalibrationPoint.Gain = uADCxCalibrationPoint1_Gain;

ConfigChannel.CalibrationPoint.Offset = uADCxCalibrationPoint1_Offset;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

 

ConfigChannel.Channel = ADC_CHANNEL_VINP0; // USB_SENSE

ConfigChannel.Rank = ADC_RANK_4;

ConfigChannel.VoltRange = ADC_VIN_RANGE_2V4; // <= inputs can rise up to 2.18V [RPO]

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_2;

ConfigChannel.CalibrationPoint.Gain = uADCxCalibrationPoint2_Gain;

ConfigChannel.CalibrationPoint.Offset = uADCxCalibrationPoint2_Offset;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

 

ConfigChannel.Channel = ADC_CHANNEL_TEMPSENSOR; // TEMP

ConfigChannel.Rank = ADC_RANK_5;

ConfigChannel.VoltRange = ADC_VIN_RANGE_1V2; // it should be set to 1.2V

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_3;

ConfigChannel.CalibrationPoint.Gain = 0; // = default (0xFFF)

ConfigChannel.CalibrationPoint.Offset = 0;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

 

ConfigChannel.Channel = ADC_CHANNEL_VBAT; // VCC

ConfigChannel.Rank = ADC_RANK_6;

ConfigChannel.VoltRange = ADC_VIN_RANGE_3V6; // up to 3.6V

ConfigChannel.CalibrationPoint.Number = ADC_CALIB_POINT_4;

ConfigChannel.CalibrationPoint.Gain = uADCxCalibrationPoint4_Gain;

ConfigChannel.CalibrationPoint.Offset = uADCxCalibrationPoint4_Offset;

if (HAL_ADC_ConfigChannel(&hadc1, &ConfigChannel) != HAL_OK)

{

Error_Handler();

}

 

/* USER CODE END ADC1_Init 2 */

 

}