Skip to main content
SFeje
Associate II
August 28, 2019
Question

How to read ADC with Dual Regular + Differential mode?

  • August 28, 2019
  • 1 reply
  • 1422 views

Hello!

I have found a lot of examples about simple ADC reads, with:

-single channel single conversion

-single channel continuous conversion

-multi channel single conversion

-multi channel continuous conversion

And these with polling, interrupt and DMA.

I need to measure singple phase AC voltage and current.

Hardware built up:

-VDDA 3.3V

-VSSA AGND

-Vref 3V

-PA6-PA7 differential pair AC voltage

-PC4-PC5 differential pair AC current

I need Dual Regular mode plus Differential read.

Hardware side without load (0V AC) on both pair I have 1.5V. For example if there is 100V AC then PA6 bigger than 1.5V, PA7 smaller than 1.5V. This differential value I need to measure.

Right now without success.

In stm32cubeL4 examples have found this: Diff conversion result = mid-range + (channel_high-channel_low)/2

In 16bit case this means: (let's say 1.5V = ~33500)

without load: 32768-65536 + (33500 - 33500) / 2 = -32768 ???

with load: 32768-65536 + (33800 - 33200) / 2 = -32468 ???

I need only the difference: 33800 - 33200 = 600

I don't really know how to do it in right way. Not so much useful examples on web.

The questions:

-How to adjust cubeMX for ADC1 differential pair?

-How to adjust cubeMX for ADC1+ADC2 in dual mode + differential pair?

-How to start and get value with HAL from differential pair?

-How to start and get value with HAL from dual mode + differential pair?

It must be possible.

For start no matter is it polling, interrupt, or DMA

Starpoint: https://www.st.com/content/ccc/resource/technical/document/application_note/c4/63/a9/f4/ae/f2/48/5d/CD00258017.pdf/files/CD00258017.pdf/jcr:content/translations/en.CD00258017.pdf

STM32 H743ZI

C

Thanks for every answers

Szilveszter

This topic has been closed for replies.

1 reply

SFeje
SFejeAuthor
Associate II
September 3, 2019

Okey, so I have made it, just not really work how I want it to work. But it works.

The code:

/* 
 * the example code is from dual interleaved mode configuration. But here below is only Dual regular mode
*/
 
 
#define ADCCONVERTEDVALUES_BUFFER_SIZE ((uint32_t) 1) //256 was before	/* Size of array containing ADC converted values */
/**
 * @brief Computation of ADC master conversion result
 * from ADC dual mode conversion result (ADC master and ADC slave
 * results concatenated on data register of ADC master).
 * @param DATA: ADC dual mode conversion result
 * @retval None
 */
#define COMPUTATION_DUALMODEINTERLEAVED_ADCMASTER_RESULT(DATA) \
 ((DATA) & 0x0000FFFF)
 
/**
 * @brief Computation of ADC slave conversion result
 * from ADC dual mode conversion result (ADC master and ADC slave
 * results concatenated on data register of ADC master).
 * @param DATA: ADC dual mode conversion result
 * @retval None
 */
#define COMPUTATION_DUALMODEINTERLEAVED_ADCSLAVE_RESULT(DATA) \
 ((DATA) >> 16)
 
 
ADC_HandleTypeDef hadc1; /* Master */ 
ADC_HandleTypeDef hadc2; /* Slave */
 
ALIGN_32BYTES(__IO uint32_t aADCDualConvertedValues[ADCCONVERTEDVALUES_BUFFER_SIZE]); /* ADC dual mode interleaved conversion results (ADC master and ADC slave results concatenated on data register 32 bits of ADC master). */
ALIGN_32BYTES(__IO uint16_t aADCxConvertedValues[ADCCONVERTEDVALUES_BUFFER_SIZE]); /* For the purpose of this example, dispatch dual conversion values into arrays corresponding to each ADC conversion values. */
ALIGN_32BYTES(__IO uint16_t aADCyConvertedValues[ADCCONVERTEDVALUES_BUFFER_SIZE]); /* For the purpose of this example, dispatch dual conversion values into arrays corresponding to each ADC conversion values. */
uint8_t ubADCDualConversionComplete = RESET; /* Set into ADC conversion complete callback */
 
/* End of conversion interrupt */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc){
 
 uint32_t tmp_index = 0;
 
 /* For the purpose of this example, dispatch dual conversion values */
 /* into 2 arrays corresponding to each ADC conversion values. */
 for (tmp_index = (ADCCONVERTEDVALUES_BUFFER_SIZE/2); tmp_index < ADCCONVERTEDVALUES_BUFFER_SIZE; tmp_index++)
 {
 aADCxConvertedValues[tmp_index] = (uint16_t) COMPUTATION_DUALMODEINTERLEAVED_ADCMASTER_RESULT(aADCDualConvertedValues[tmp_index]);
 aADCyConvertedValues[tmp_index] = (uint16_t) COMPUTATION_DUALMODEINTERLEAVED_ADCSLAVE_RESULT(aADCDualConvertedValues[tmp_index]);
 }
 
	 
 /* ADCCONVERTEDVALUES_BUFFER_SIZE was 256, I have changed it to 1. Right now it's not clear why it was so big buffer */
 float32_t ACCurrent = (((uint16_t)aADCxConvertedValues[0] * 6000) / 0xFFFF) - 3000; /* Result value is the difference between to differential wires in mV. It can be also negative value */
 float32_t ACVoltage = (((uint16_t)aADCyConvertedValues[0] * 6000) / 0xFFFF) - 3000; /* Result value is the difference between to differential wires in mV. It can be also negative value */
 
 ubADCDualConversionComplete = SET;
 HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_11);
}
 
/* Half conversion interrupt */
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc){
 
 uint32_t tmp_index = 0;
 
 /* For the purpose of this example, dispatch dual conversion values */
 /* into 2 arrays corresponding to each ADC conversion values. */
 for (tmp_index = 0; tmp_index < (ADCCONVERTEDVALUES_BUFFER_SIZE/2); tmp_index++)
 {
 aADCxConvertedValues[tmp_index] = (uint16_t) COMPUTATION_DUALMODEINTERLEAVED_ADCMASTER_RESULT(aADCDualConvertedValues[tmp_index]);
 aADCyConvertedValues[tmp_index] = (uint16_t) COMPUTATION_DUALMODEINTERLEAVED_ADCSLAVE_RESULT(aADCDualConvertedValues[tmp_index]);
 }
 
 ubADCDualConversionComplete = RESET;
}
 
 
int main(void)
{
 
 HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_DIFFERENTIAL_ENDED); /* attach differential mode to ADC1 */
 HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_OFFSET, ADC_DIFFERENTIAL_ENDED); /* attach differential mode to ADC2 */
 HAL_ADC_Start(&hadc2); /* start in normal mode ADC2 */
 HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t *)aADCDualConvertedValues, ADCCONVERTEDVALUES_BUFFER_SIZE); /* start in multimode DMA ADC1 as master */
 
 /*
 * these steps are neccessary to start the dual regual adc read in differential mode. ADC1 as master and ADC2 as slave. Internally ADC1 triggering ADC2.
 * here are some things what right now i don't really understand, like line-90, that why need to start ADC2 in normal mode.
 * Don't forget to use always on the read data this calculation: 
 * ((adc_value * 6000) / 0xFFFF) - 3000; 
 * ((adc_value * VrefX2) / resolution in hex) - Vref; 
 */
 
 while (1)
 {
 }
}
 

Values are good. Printf works in interrupt so I have made some output messages.

The problem again, that the while(1) don't get time to run. For example an printf("hello") will not happen.

What should I do?

Szilveszter

PS: https://github.com/STMicroelectronics/STM32CubeH7