Skip to main content
JWhong
Visitor II
September 22, 2022
Question

Skipped codes in BlueNRG-LP ADC

  • September 22, 2022
  • 0 replies
  • 811 views

Hi,

I'm seeing some very strange behavior on the ADC of the BlueNRG-LP. It looks like the ADC is skipping codes near the inversion point of a differential input, with similar behavior in single ended mode near 0.9V (with a 1.2V reference). This is on the STEVAL-IDB011V2 development kit.

High level description of the ADC configuration:

* Differential mode input on PB2/PB3 (differential input 0)

* 1MSPS sample rate

* 16 bit depth

* Downsampler active (ratio varies)

* Input common mode at 0.6V

* 1.2V internal reference voltage

* Analog watchdog off

* DMA active

What I'm seeing is that the ADC skips over a range close to, but not exactly at, the midpoint of the sample range. In 16 bit mode the range is approx 32700-32750 (with 32768 being the midpoint). See attached images (X axis is seconds, Y axis ADC code).

This is with the downsampler active. 

0693W00000Sw21iQAB.png And this is sampling at full 1MSPS, no downsampling. Data is left shifted but you can clearly see that 1 or 2 codes are being skipped. This is a 1kHz sine wave input.0693W00000Sw2hUQAR.pngI see the same behavior in single-ended mode around 0.9V input, which is even further from the midpoint (which is 0.6V with a 1.2V reference). I've seen the same behavior on another analog input as well (PA14/PA15 as differential input).

Here is the code being used to configure the ADC.

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
	/* Parameters for ADC initialization */
	__HAL_RCC_ADCDIG_CLK_ENABLE();
	__HAL_RCC_ADCANA_CLK_ENABLE();
 
 
 
#if USE_PA_FOR_ANALOG
	LL_AHB_EnableClock(LL_AHB_PERIPH_GPIOA);
	GPIO_TypeDef* port_pos = GPIOA;
	uint32_t pin_pos = LL_GPIO_PIN_15;
	GPIO_TypeDef* port_neg = GPIOA;
	uint32_t pin_neg = LL_GPIO_PIN_14;
#else
	LL_AHB_EnableClock(LL_AHB_PERIPH_GPIOB);
	GPIO_TypeDef* port_pos = GPIOB;
	uint32_t pin_pos = LL_GPIO_PIN_3;
	GPIO_TypeDef* port_neg = GPIOB;
	uint32_t pin_neg = LL_GPIO_PIN_2;
#endif
	/* Configure ADC PINs */
	LL_GPIO_SetAFPin_0_7( port_pos, pin_pos, LL_GPIO_AF_0);
	LL_GPIO_SetPinMode( port_pos, pin_pos, LL_GPIO_MODE_ANALOG);
	LL_GPIO_SetPinSpeed( port_pos, pin_pos, LL_GPIO_SPEED_FREQ_LOW);
	LL_GPIO_SetPinOutputType(port_pos, pin_pos, LL_GPIO_OUTPUT_PUSHPULL);
	LL_GPIO_SetPinPull( port_pos, pin_pos, LL_GPIO_PULL_NO);
 
	LL_GPIO_SetAFPin_0_7( port_neg, pin_neg, LL_GPIO_AF_0);
	LL_GPIO_SetPinMode( port_neg, pin_neg, LL_GPIO_MODE_ANALOG);
	LL_GPIO_SetPinSpeed( port_neg, pin_neg, LL_GPIO_SPEED_FREQ_LOW);
	LL_GPIO_SetPinOutputType(port_neg, pin_neg, LL_GPIO_OUTPUT_PUSHPULL);
	LL_GPIO_SetPinPull( port_neg, pin_neg, LL_GPIO_PULL_NO);
}
 
 /* @brief ADC Initialization Function
 * @param None
 * @retval None
 */
static void MX_ADC_Init(uint32_t ds_ratio)
{
 /* Enable the ADC peripheral */
 HAL_ADC_StructInit(&adc_handle);
 adc_handle.Init.DataRatio = ds_ratio;
 adc_handle.Init.DataWidth = USER_DATAWIDTH;
 adc_handle.Init.SampleRate = USER_SAMPLERATE;
#if defined(CONFIG_DEVICE_BLUENRG_LPS)
 adc_handle.Init.SampleRateMsb = USER_SAMPLERATE_MSB;
#endif
 adc_handle.DMA_Handle = &hdma_adc;
 
 if (HAL_ADC_Init(&adc_handle) != HAL_OK) {
 Error_Handler();
 }
 
 
	SYSCFG->GPIO_SWA_CTRL |= 2;
	LL_ADC_ConfigureMicrophonePGA(adc_handle.Instance, LL_ADC_PGA_BIAS_090_BAT, 0);
 
 /* DMA controller clock enable */
 	__HAL_RCC_DMA_CLK_ENABLE();
 
 	hdma_adc.Instance = DMA1_Channel1;
 	hdma_adc.Init.Request = DMA_REQUEST_ADC_DS;
 	hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;
 	hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;
 	hdma_adc.Init.MemInc = DMA_MINC_ENABLE;
 	hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
 	hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
 	hdma_adc.Init.Mode = dma_mode_;
 	hdma_adc.Init.Priority = DMA_PRIORITY_LOW;
 
 	if(HAL_DMA_Init(&hdma_adc) != HAL_OK) {
 		Error_Handler();
 	}
 
 	__HAL_LINKDMA(&adc_handle, DMA_Handle, hdma_adc);
 
 /* Start the sampling at end of previous sample */
 LL_ADC_InputSamplingMode(ADC, LL_ADC_SAMPLING_AT_START);//LL_ADC_SAMPLING_AT_END);
 
 /* Set the input channel */
#if USE_PA_FOR_ANALOG
 xChannel.ChannelType = ADC_CH_VINP2_VINM2_TO_DIFF_INPUT;
#else
 xChannel.ChannelType = ADC_CH_VINP0_VINM0_TO_DIFF_INPUT;
#endif
 //xChannel.ChannelType = ADC_CH_VINP0_TO_SINGLE_POSITIVE_INPUT;
 //xChannel.ChannelType = ADC_CH_VINM0_TO_SINGLE_NEGATIVE_INPUT;
 xChannel.SequenceNumber = ADC_SEQ_POS_01;
#if 1
 xChannel.VoltRange = ADC_VIN_RANGE_1V2;
 //xChannel.VoltRange = ADC_VIN_RANGE_2V4;
 if (HAL_ADC_ConfigChannel(&adc_handle, &xChannel)!= HAL_OK) {
 Error_Handler();
 }
 if(LL_ADC_GET_CALIB_GAIN_FOR_VINDIFF_1V2() != 0xFFF) {
 LL_ADC_SetCalibPoint1Gain(ADC, LL_ADC_GET_CALIB_GAIN_FOR_VINDIFF_1V2() );
 
 offset_vinp0 = LL_ADC_GET_CALIB_OFFSET_FOR_VINDIFF_1V2();
#ifdef CONFIG_DEVICE_BLUENRG_LP
 if(offset_vinp0 < -64 || offset_vinp0 > 63) {
 	// Intrinsic offset too large to compensate!
 	asm("bkpt 0");
 }
#endif
 LL_ADC_SetCalibPoint1Offset(ADC, offset_vinp0);
 offset_vinp0 = 0;
 }
 else {
 LL_ADC_SetCalibPoint1Gain(ADC, LL_ADC_DEFAULT_RANGE_VALUE_1V2);
 }
 LL_ADC_SetCalibPointForDiff1V2(ADC, LL_ADC_CALIB_POINT_1);
#else
 // experimental: Try the 2.4V reference range.
 xChannel.VoltRange = ADC_VIN_RANGE_2V4;
 if (HAL_ADC_ConfigChannel(&adc_handle, &xChannel)!= HAL_OK) {
 Error_Handler();
 }
 if(LL_ADC_GET_CALIB_GAIN_FOR_VINDIFF_2V4() != 0xFFF) {
 LL_ADC_SetCalibPoint1Gain(ADC, LL_ADC_GET_CALIB_GAIN_FOR_VINDIFF_2V4() );
 
 offset_vinp0 = LL_ADC_GET_CALIB_OFFSET_FOR_VINDIFF_2V4();
#ifdef CONFIG_DEVICE_BLUENRG_LP
 if(offset_vinp0 < -64 || offset_vinp0 > 63) {
 	// Intrinsic offset too large to compensate!
 	asm("bkpt 0");
 }
#endif
 LL_ADC_SetCalibPoint1Offset(ADC, offset_vinp0);
 offset_vinp0 = 0;
 }
 else {
 LL_ADC_SetCalibPoint1Gain(ADC, LL_ADC_DEFAULT_RANGE_VALUE_2V4);
 }
 LL_ADC_SetCalibPointForDiff2V4(ADC, LL_ADC_CALIB_POINT_1);
#endif
}

Any ideas? Thank you.

This topic has been closed for replies.