cancel
Showing results for 
Search instead for 
Did you mean: 

Capture peak value through ADC

DSabo
Associate III

I am using the STM IoT Kit Node and have a current sensor (voltage output) connected to the ADC.

I can read the current through the ADC by reading the counts and doing the correct conversion. But I'm trying to read the instantaneous peak current (the sensor is on a line driving a motor).

So the peak current draw when the motor is activated goes high (8-9 amps) for a split second, before settling down to the steady state value of around 4 amps.

I have the ADC set up using DMA and have the HAL_ADC_ConvHalfCpltCallback and HAL_ADC_ConvCpltCallback functions implemented. When they are called they search their respective half of the ADC array to find the max value. As I said though, this seems to be missing the instantaneous peak current.

I'm not sure if the DMA / ADC is missing the value because it isn't sampling fast enough and misses it, or if my processing of the data is taking too long...

Attached is my init code and interrupt code

static void MX_ADC1_Init(void)
{
       ADC_ChannelConfTypeDef sConfig = {0};
 
	/** Common config */
	hadc1.Instance = ADC1;
	hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
	hadc1.Init.Resolution = ADC_RESOLUTION_12B;
	hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
	hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
	hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
	hadc1.Init.LowPowerAutoWait = DISABLE;
	hadc1.Init.ContinuousConvMode = ENABLE;
	hadc1.Init.NbrOfConversion = 3;
	hadc1.Init.DiscontinuousConvMode = DISABLE;
	hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
	hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
	hadc1.Init.DMAContinuousRequests = ENABLE;
	hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
	hadc1.Init.OversamplingMode = DISABLE;
	if (HAL_ADC_Init(&hadc1) != HAL_OK)
	{
	  Error_Handler(__LINE__, __FILE__);
	}
 
	/** Configure Regular Channel */
	sConfig.Channel = ADC_CHANNEL_1;
	sConfig.Rank = ADC_REGULAR_RANK_1;
	sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
	sConfig.SingleDiff = ADC_SINGLE_ENDED;
	sConfig.OffsetNumber = ADC_OFFSET_NONE;
	sConfig.Offset = 0;
	if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	{
	  Error_Handler(__LINE__, __FILE__);
	}
	/** Configure Regular Channel */
	sConfig.Channel = ADC_CHANNEL_2;
	sConfig.Rank = ADC_REGULAR_RANK_2;
	if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	{
	  Error_Handler(__LINE__, __FILE__);
	}
	/** Configure Regular Channel */
	sConfig.Channel = ADC_CHANNEL_3;
	sConfig.Rank = ADC_REGULAR_RANK_3;
	if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	{
	  Error_Handler(__LINE__, __FILE__);
	}
 
	while((HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED)!= HAL_OK))
	{
		vTaskDelay(10);
	}
 
	// -- Enables ADC DMA request
	if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC1ConvertedValues, DMA_BUFFER_SIZE_PER_ADC * NUM_ADC_MEASUREMENTS) != HAL_OK)
	{
		Error_Handler(__LINE__, __FILE__);
	}
 
	HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY, 0);
	HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
 
void MaxAdcVal(int start, int end, int step)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 
	xSemaphoreTakeFromISR(maxCurrentMeasurementSemaphore, &xHigherPriorityTaskWoken);
	for(int i = start; i < end; i += step)
	{
		maxCurrentAdcCount = max_uint32(maxCurrentAdcCount, ADC1ConvertedValues[i]);
	}
 
	xSemaphoreGiveFromISR(maxCurrentMeasurementSemaphore, &xHigherPriorityTaskWoken);
 
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
 
// Called when first half of buffer is filled
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
	MaxAdcVal(CURRENT_SENSOR_ADC_RANK - 1,DMA_BUFFER_SIZE_PER_ADC * NUM_ADC_MEASUREMENTS / 2, NUM_ADC_MEASUREMENTS);
}
 
// Called when buffer is completely filled
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	MaxAdcVal(currentAdcDmaSecondHalfStartIndex,DMA_BUFFER_SIZE_PER_ADC * NUM_ADC_MEASUREMENTS, NUM_ADC_MEASUREMENTS);
}

3 REPLIES 3

Or your analog circuit is not up to the task.

How could we possibly know the answer?

JW

The sensor is directly input to the eval board.. it's certainly possible the eval board can't handle it, but since there is nothing I can do about that, I'm looking at it from a configuration and software side.

> there is nothing I can do about that,

Of course you can. Observe the ADC pin (directly the pin on the mcu) using an oscilloscope.

You most probably will see also spikes from the sampling process, that will give you an idea how long the sampling should last, (so that the level settles), how often you sample; and if you'll toggle a pin at the start and end of processing in ISR and observe it on a second channel of that oscilloscope, that will give you also an idea whether the processing is fast enough.

JW