STM32: weird ADC "noise" - Page 1
Forum section: electronics / general

author: hbozyq
author_rank: Contributor
timestamp: May 05, 2023, 02:21:12 pm
content: Hi all. I'm working on some kind of data collector. For this purpose I‘m using stm32 with ADC triggered by TIM with DMA.For now only one channel is used. Most of the code work well, the only question is there're some 'noise' disturbed the result.As shown in the figure, there are many regular spikes in the sampling results of sinusoidal waves. Since its regularity, I guess it's not really random noise but something I don't know. I wonder where the spikes come from and how to get rid of them.Some of the code I wrote is as follows.Code:/* Private define ------------------------------------------------------------*//* USER CODE BEGIN PD */#define ADCBufSize 10volatile uint16_t ADCBuf;uint8_t UARTTxBuf_ADC[ADCBufSize *2];/* In main func, after MX_*_Init, before while (1) ------------------------------------------------------------*/HAL_ADCEx_Calibration_Start(&hadc1);TIM3->PSC = 64-1;TIM3->ARR = 1000;TIM3->CCR1 = 500;HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADCBuf,ADCBufSize);__HAL_DMA_DISABLE_IT(&hdma_adc1, DMA_IT_HT);/* At the very end of main.c ------------------------------------------------------------*/void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc){uint16_t ADCBufCpy;memcpy(ADCBufCpy, (void*) ADCBuf, ADCBufSize*2);uint16_t a1 = 0;int16_t value ;for(;a1 < ADCBufSize;a1++){value = ADCBufCpy;UARTTxBuf_ADC[2*a1] = value >> 8;UARTTxBuf_ADC[2*a1+1] = value & 0xff;}HAL_UART_Transmit_IT(&huart2,UARTTxBuf_ADC,ADCBufSize *2);}Codes generated by CUBEMX:Code:static void MX_ADC1_Init(void){/* USER CODE BEGIN ADC1_Init 0 *//* USER CODE END ADC1_Init 0 */ADC_ChannelConfTypeDef sConfig = {0};/* USER CODE BEGIN ADC1_Init 1 *//* USER CODE END ADC1_Init 1 *//** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)*/hadc1.Instance = ADC1;hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;hadc1.Init.Resolution = ADC_RESOLUTION_12B;hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;hadc1.Init.LowPowerAutoWait = DISABLE;hadc1.Init.LowPowerAutoPowerOff = DISABLE;hadc1.Init.ContinuousConvMode = DISABLE;hadc1.Init.NbrOfConversion = 1;hadc1.Init.DiscontinuousConvMode = DISABLE;hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T3_TRGO;hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;hadc1.Init.DMAContinuousRequests = ENABLE;hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_19CYCLES_5;hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_1CYCLE_5;hadc1.Init.OversamplingMode = DISABLE;hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;if (HAL_ADC_Init(&hadc1) != HAL_OK){Error_Handler();}/** Configure Regular Channel*/sConfig.Channel = ADC_CHANNEL_1;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}/* USER CODE BEGIN ADC1_Init 2 *//* USER CODE END ADC1_Init 2 */}/*** @brief TIM3 Initialization Function* @param None* @retval None*/static void MX_TIM3_Init(void){/* USER CODE BEGIN TIM3_Init 0 *//* USER CODE END TIM3_Init 0 */TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};/* USER CODE BEGIN TIM3_Init 1 *//* USER CODE END TIM3_Init 1 */htim3.Instance = TIM3;htim3.Init.Prescaler = 0;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = 65535;htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_PWM_Init(&htim3) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK){Error_Handler();}sConfigOC.OCMode = TIM_OCMODE_PWM1;sConfigOC.Pulse = 0;sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM3_Init 2 *//* USER CODE END TIM3_Init 2 */HAL_TIM_MspPostInit(&htim3);}The hardware connection should be fine. The gpio connected directly to a waveform generator.Also, once I managed to get it to output just sine wave without spikes, but then somehow I can't reproduce it.(may be some coding error I don't see it.)Thanks in advance.

author: hbozyq
author_rank: Contributor
timestamp: May 05, 2023, 02:27:01 pm
content: BTW It's a STM32G030C8, I had tried another mcu but same issue.

author: mikerj
author_rank: Super Contributor
timestamp: May 05, 2023, 02:33:03 pm
content: How many samples are there between the spikes? What is your sample rate and your USART bit rate? When you HAL_UART_Transmit_IT are you certain the previous transmission has completed?

author: eTobey
author_rank: Super Contributor
timestamp: May 05, 2023, 02:33:44 pm
content: You should try to change back the code when it worked. Interestingly, there is one spike at the top and bottom of the sine missing. Are you sure the signal is good?

author: jwet
author_rank: Frequent Contributor
timestamp: May 05, 2023, 02:38:23 pm
content: You're using ADC buf with a +1 type error. You're looping through and getting a an old value thrown in ever 10 I think

author: ajb
author_rank: Super Contributor
timestamp: May 05, 2023, 02:45:48 pm
content: Quote from: jwet on May 05, 2023, 02:38:23 pmI suspect something along these lines as well. But the fact that the top of each spike lines up with the bottom of the following one suggest that it's kind of the opposite problem: the last sample getting added to the UART buffer is from the next sample cycle, like the ADC conversion is overrunning the writes to the UART buffer, or the writes to the UART buffer are overrunning the UART transmit. Reducing the sampling frequency without changing anything else would be a useful test. The real fix might be to double-buffer the UART, assuming no deeper issues with the program.

author: hbozyq
author_rank: Contributor
timestamp: May 05, 2023, 02:53:14 pm
content: Sampling freq is 1khz, and baud rate is 2Mbps. I guess uart is fast enough.The frequency of the spike appears to be related to the input signal, with fewer spikes occurring as the input frequency decreases。While I'm playing with codes I modified something and then go to lunch. When I'm back I had forgotten what had been changed.

author: langwadt
author_rank: Super Contributor
timestamp: May 05, 2023, 02:56:51 pm
content: looks to me like a broken bit in the ADC

author: eutectique
author_rank: Frequent Contributor
timestamp: May 05, 2023, 03:07:35 pm
content: Do you see spikes when you ground the input?

author: ajb
author_rank: Super Contributor
timestamp: May 05, 2023, 04:06:35 pm
content: hmm, yeah, seems more like it's related to the specific values rather than timing then. Can you share the list of numeric values? Or at least the value of each spike and the sample immediately before and after?Maybe something to do with the bit resolution and alignment settings of the ADC? Or the DMA is misconfigured and is reading the low byte of one sample and the high byte of another sample from the ADC rather than a single 16-bit read.

author: wek
author_rank: Frequent Contributor
timestamp: May 05, 2023, 10:54:20 pm
content: Circular DMA, am I right?The ISR is not fast enough (yes Cube/HAL bloat) and the first sample is already overwritten at the moment when you copy it into the UART buffer.I also guess you have other interrupts active.Use the half-transfer interrupt to ping-pong between half-buffers (maybe doubling the total buffer size), that will give you the time you need.And, of course, ditch Cube :-) .JW

author: hbozyq
author_rank: Contributor
timestamp: May 06, 2023, 12:38:43 am
content: Spikes are gone while ground the input. Besides, there is no spike at all when the square wave signal is input. Seems like it has to do with the slope.

author: hbozyq
author_rank: Contributor
timestamp: May 06, 2023, 01:54:46 am
content: I finally get it right. After manually check every hex data printed, I found the real issue is the big/little endian setting in SerialPlot. The code just works as expected.In my case I should choose big endian, for my code sending higher byte first. Then (may or may not needed) click skip byte to correct the alignment and spikes gone.Still I wonder why those spikes come from and why it occurs regularly rather than mess up every sample.

author: langwadt
author_rank: Super Contributor
timestamp: May 06, 2023, 01:56:35 am
content: Quote from: hbozyq on May 06, 2023, 12:38:43 amtry masking one bit at a time to see if it is always the same bitedit, I see you found the problemmixing upper and lower bytes from different samples will give you a glitch when the LSB of the up byte changesi.e....0x00ff,0x00ff,0x0100,0x0100.. in bytes BE:...0x00,0xff,0x00,0xff,0x01,0x00,0x01,0x00...if you skip a byte and read it as LE you get..0x00ff,0x01ff,0x100...

author: Doctorandus_P
author_rank: Super Contributor
timestamp: May 06, 2023, 08:32:24 pm
content: What is the difference (in sample resolution) between the "peaks" and "what it's expected to be"?Is that difference an integer multiple of two? (or some other fixed number). That can give you a hint to the cause of the anomaly.