cancel
Showing results for 
Search instead for 
Did you mean: 

Skipped codes in BlueNRG-LP ADC

JWhong
Associate

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.

0 REPLIES 0