cancel
Showing results for 
Search instead for 
Did you mean: 

How to read ADC with Dual Regular + Differential mode?

SFeje
Associate II

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

1 REPLY 1
SFeje
Associate II

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