Skip to main content
TCash.1
Associate III
March 27, 2021
Question

Stm32H7 DMA ADC Low Bit Resolution

  • March 27, 2021
  • 5 replies
  • 949 views

Hello Everyone,

I am using the stm32h7 to sample 4 channels from adc1 using the DMA.

I am using circular mode with half word size. I start the dma and let it fill up a memory buffer:

volatile uint16_t adcInsDMA[4*ADCBLOCKSIZE] = {0};
 
HAL_StatusTypeDef status = HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&adcInsDMA[0], 4*ADCBLOCKSIZE);
 

This works, however It looks like I am only getting 6bits of resolution. and not 16.

0693W000008y4RNQAY.png 

I consistently get only 63 distinct value no matter when I sample, or what the speed is of the incoming signal etc.

Here are my initialization settings generated by CUBEIDE:

/* ADC1 init function */
void MX_ADC1_Init(void)
{
 ADC_MultiModeTypeDef multimode = {0};
 ADC_ChannelConfTypeDef sConfig = {0};
 
 /** Common config
 */
 hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
 hadc1.Init.Resolution = ADC_RESOLUTION_16B;
 hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
 hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
 hadc1.Init.LowPowerAutoWait = DISABLE;
 hadc1.Init.ContinuousConvMode = ENABLE;
 hadc1.Init.NbrOfConversion = 4;
 hadc1.Init.DiscontinuousConvMode = DISABLE;
 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
 hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
 hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
 hadc1.Init.OversamplingMode = DISABLE;
 if (HAL_ADC_Init(&hadc1) != HAL_OK)
 {
 Error_Handler();
 }
 /** Configure the ADC multi-mode
 */
 multimode.Mode = ADC_MODE_INDEPENDENT;
 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
 {
 Error_Handler();
 }
 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_3;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLETIME_32CYCLES_5;
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 sConfig.OffsetSignedSaturation = DISABLE;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_4;
 sConfig.Rank = ADC_REGULAR_RANK_2;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_7;
 sConfig.Rank = ADC_REGULAR_RANK_3;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_8;
 sConfig.Rank = ADC_REGULAR_RANK_4;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
 
}
 
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
 
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 if(adcHandle->Instance==ADC1)
 {
 /* USER CODE BEGIN ADC1_MspInit 0 */
 
 /* USER CODE END ADC1_MspInit 0 */
 /* ADC1 clock enable */
 __HAL_RCC_ADC12_CLK_ENABLE();
 
 __HAL_RCC_GPIOA_CLK_ENABLE();
 __HAL_RCC_GPIOC_CLK_ENABLE();
 /**ADC1 GPIO Configuration
 PA6 ------> ADC1_INP3
 PA7 ------> ADC1_INN3
 PA7 ------> ADC1_INP7
 PC4 ------> ADC1_INP4
 PC5 ------> ADC1_INN4
 PC5 ------> ADC1_INP8
 */
 GPIO_InitStruct.Pin = IN_SIG_1_ADC_Pin|IN_SIG_2_ADC_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
 GPIO_InitStruct.Pin = IN_SIG_3_ADC_Pin|IN_SIG_4_ADC_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
 /* ADC1 DMA Init */
 /* ADC1 Init */
 hdma_adc1.Instance = DMA1_Stream0;
 hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
 hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
 hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
 hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
 hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
 hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
 hdma_adc1.Init.Mode = DMA_CIRCULAR;
 hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
 hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
 hdma_adc1.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
 hdma_adc1.Init.MemBurst = DMA_MBURST_SINGLE;
 hdma_adc1.Init.PeriphBurst = DMA_PBURST_SINGLE;
 if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
 {
 Error_Handler();
 }
 
 __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
 
 /* USER CODE BEGIN ADC1_MspInit 1 */
 
 /* USER CODE END ADC1_MspInit 1 */
 }
}
 
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
 
 if(adcHandle->Instance==ADC1)
 {
 /* USER CODE BEGIN ADC1_MspDeInit 0 */
 
 /* USER CODE END ADC1_MspDeInit 0 */
 /* Peripheral clock disable */
 __HAL_RCC_ADC12_CLK_DISABLE();
 
 /**ADC1 GPIO Configuration
 PA6 ------> ADC1_INP3
 PA7 ------> ADC1_INN3
 PA7 ------> ADC1_INP7
 PC4 ------> ADC1_INP4
 PC5 ------> ADC1_INN4
 PC5 ------> ADC1_INP8
 */
 HAL_GPIO_DeInit(GPIOA, IN_SIG_1_ADC_Pin|IN_SIG_2_ADC_Pin);
 
 HAL_GPIO_DeInit(GPIOC, IN_SIG_3_ADC_Pin|IN_SIG_4_ADC_Pin);
 
 /* ADC1 DMA DeInit */
 HAL_DMA_DeInit(adcHandle->DMA_Handle);
 /* USER CODE BEGIN ADC1_MspDeInit 1 */
 
 /* USER CODE END ADC1_MspDeInit 1 */
 }
}

Any Ideas on what I could be missing would be appreaciated!

Thanks,

Trevor

This topic has been closed for replies.

5 replies

TCash.1
TCash.1Author
Associate III
April 4, 2021

Even when using a very minimal ADC only program I get the missing LSB bits, oddly, the exact same program works fine on my NUCLEO dev board.

waclawek.jan
Super User
April 4, 2021

My guess is, problematic/unstable VREF+ and/or VREF-/VSSA.

JW

TCash.1
TCash.1Author
Associate III
April 5, 2021

Hi JW,

Thanks for your reply,

I have VREF+ connected to 3.3v, same line as all VDD pins and VDDA.

I have VSSA/VREF- (Pin 31) connected to GND on same line as other VSS pins.

0693W000008yfbUQAQ.png 

I am curious why would an unstable/moving reference would cause a bit precision error? does the hardware have/go into a "safety" mode?

weird thing is, I have seen the ADC work with LSB on a similar previous iteration of my board (with a similar power scheme). I am beginning to think I got a bad batch, I am usually wrong about that though.

Gudgel.boB
Senior
April 5, 2021

You sure this part allows ADC_CLOCK_ASYNC_DIV1 at 16 bit resolution ?

When you apply Vdd to the ADC input(s), which of the 16 bits are zero in the result register or buffer ?

TCash.1
TCash.1Author
Associate III
April 5, 2021

Hi Gudgel,

When I apply Vdd I get 1111 1110 0000 0000 (65024)

When I apply GND I get 0000 0010 0000 0000 (512)

all intermediate value still scale accordingly but with the least significant 9 bits always zero.

I tried increasing the clock prescaler to 4, and I begins to work again. It is odd to me though why clock prescaler = 1 worked on STM32H743ZIT6U . My Part is STM32H743ZIT6. Maybe the missing U is part of it.

In any case I think clock prescaler is the fix I'll go with for now! Thanks!