AnsweredAssumed Answered

STM32F303RB Vrefint

Question asked by Mikk Leini on Oct 1, 2015
Latest reply on Oct 28, 2015 by Mikk Leini
Hello,

I'm trying to samples Vrefint with ADC2 in dual ADC configuration but only value i get is 0xFFF. Here's the code:

/**
  ******************************************************************************
  * @file    power.c
  * @author  TUT Robotics Club NPO
  * @version V1.0
  * @date    16.03.2014
  * @brief   This file contains Power control functions.
   * @details Pin mapping:
   *
   *  Pin   Name           OPAMP          ADC         COMP
   *  PA0   VBAT                          ADC1_IN1    COMP7_VINP
   *  PA1   MC_I_U_FILT    OPAMP1_VINP                COMP1_VINP
   *  PA2                  OPAMP1_VOUT    ADC1_IN3
   *  PA3   MC_TEMP                       ADC1_IN4
   *  PA6                  OPAMP2_VOUT    ADC2_IN3
   *  PA7   MC_I_V_FILT    OPAMP2_VINP                COMP2_VINP
   *  PB0   MC_I_W_FILT    OPAMP3_VINP                COMP4_VINP
   *
  ****************************************************************************** 
  */
 
/* Includes ------------------------------------------------------------------*/
#include "stm32f30x.h"
#include "typedefs.h"
#include "power.h"
#include "util.h"
#include "config.h"
 
/* Private define ------------------------------------------------------------*/
 
/* Division by 100k and 4.7k resistors - meaning 22.28 times */
#define VBAT_FORMULA(sample) (((U32)(sample) * 33UL * 2228UL) / 4095UL)
 
/* VBAT reference 1,65V. It means the VBAT value is 1,65 * 22,28 = 36,76V */
#define VBAT_COMP_REF        COMP_InvertingInput_1_2VREFINT
 
/*
 * TODO Define proper equation
 */
#define TEMPERATURE_FORMULA(sample) (sample / 16U)
 
/*
 * TODO Define proper equation
 */
#define PHASE_CURRENT_FORMULA(sample) (sample / 16U)
 
/* Phase overcurrent comparison voltage.
 * Following information comes from LT spice simulation.
 * We want 5A limit.
 * At 5A shunt voltage is 0,25V.
 * Adjusted voltage is 1,109V
 * DAC value is (1,109 / 3,3V) * 4096 = 1376
 */
#define PHASE_SHUNT_VOLTAGE(i)       (((U32)(i) * (U32)RSHUNT) / 1000UL)
#define PHASE_VOLT_DIVISION(u)       (((U32)(u) * (U32)RPULLUP) / ((U32)RPULLUP + (U32)RSERIES))
#define PHASE_VOLT_ADJUSTED(u)       ((U32)VREF - PHASE_VOLT_DIVISION((U32)VREF - (U32)(u)))
#define PHASE_VOLT_ADC(i)            ((PHASE_VOLT_ADJUSTED(PHASE_SHUNT_VOLTAGE(i)) * 4096UL) / (U32)VREF)
#define PHASE_OC_DAC_VALUE           PHASE_VOLT_ADC(MAX_PHASE_CURRENT)
 
 
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static GPIO_InitTypeDef         GPIO_InitStructure;
static COMP_InitTypeDef         COMP_InitStructure;
static OPAMP_InitTypeDef        OPAMP_InitStructure;
static DAC_InitTypeDef          DAC_InitStructure;
static DMA_InitTypeDef          DMA_InitStructure;
static ADC_InitTypeDef          ADC_InitStructure;
static ADC_CommonInitTypeDef    ADC_CommonInitStructure;
 
static __IO U32 ADCConvertedValue[3];
static U32 CalibrationValue1;
static U32 CalibrationValue2;
static U16 VoltageBuffer[4];
static U16 TemperatureBuffer[4];
static U16 PhaseACurrentBuffer[4];
static U16 PhaseBCurrentBuffer[4];
static U16 Voltage;
static U8  Temperature;
static S32 PhaseACurrent;
static S32 PhaseBCurrent;
 
/* Private function prototypes -----------------------------------------------*/
static void ConfigureCOMP(void);
static void ConfigureDAC(void);
static void ConfigureOPAMP(void);
static void ConfigureADC(void);
static U16 RollingAverage(U16 * Buffer, U16 Length, U16 NewValue);
 
/* Private functions ---------------------------------------------------------*/
 
/**
  * @brief   Configuring comparators
   * @details COMP1, COMP2 and COMP4 are phase current comparators.
   *          COMP7 is battery voltage comparator.
  * @retval  None
  */
static void ConfigureCOMP(void)
{
  /*
   * Phase overcurrent detection with comparators.
   * COMP1, COMP2 and COMP4 configured to have a comparison
   * with DAC1 voltage. Output goes to TIM1 break input.
   */
  COMP_InitStructure.COMP_NonInvertingInput = COMP_NonInvertingInput_IO1;
  COMP_InitStructure.COMP_InvertingInput    = COMP_InvertingInput_DAC1OUT1;
  COMP_InitStructure.COMP_Output            = COMP_Output_TIM1BKIN;
  COMP_InitStructure.COMP_OutputPol         = COMP_OutputPol_NonInverted;
  COMP_InitStructure.COMP_BlankingSrce      = COMP_BlankingSrce_None;
  COMP_InitStructure.COMP_Hysteresis        = COMP_Hysteresis_Low;     /* 8 mV at low power mode */
  COMP_InitStructure.COMP_Mode              = COMP_Mode_MediumSpeed;   /* 10 uA consumption, delay 0,3 us */
  COMP_Init(COMP_Selection_COMP1, &COMP_InitStructure);
  COMP_Init(COMP_Selection_COMP2, &COMP_InitStructure);
  COMP_Init(COMP_Selection_COMP4, &COMP_InitStructure);
 
  /*
   * Overvoltage detection with comparator.
   * COMP7 configured to have a comparison with internal reference (set with macro).
   * Output goes to TIM1 break input.
   */
  COMP_InitStructure.COMP_NonInvertingInput = COMP_NonInvertingInput_IO1;
  COMP_InitStructure.COMP_InvertingInput    = VBAT_COMP_REF;
  COMP_InitStructure.COMP_Output            = COMP_Output_TIM1BKIN;
  COMP_InitStructure.COMP_OutputPol         = COMP_OutputPol_NonInverted;
  COMP_InitStructure.COMP_BlankingSrce      = COMP_BlankingSrce_None;
  COMP_InitStructure.COMP_Hysteresis        = COMP_Hysteresis_Low;    /* 8 mV at low power mode */
  COMP_InitStructure.COMP_Mode              = COMP_Mode_MediumSpeed;  /* 10 uA consumption, delay 0,3 us */
  COMP_Init(COMP_Selection_COMP7, &COMP_InitStructure);
 
  /* Enable comparators */
  COMP_Cmd(COMP_Selection_COMP1, ENABLE);
  COMP_Cmd(COMP_Selection_COMP2, ENABLE);
  COMP_Cmd(COMP_Selection_COMP4, ENABLE);
  COMP_Cmd(COMP_Selection_COMP7, ENABLE);
    
  /* Lock comparator configurations */
  COMP_LockConfig(COMP_Selection_COMP1);
  COMP_LockConfig(COMP_Selection_COMP2);
  COMP_LockConfig(COMP_Selection_COMP4);
  COMP_LockConfig(COMP_Selection_COMP7);
}
 
/**
  * @brief   Configuring DAC's
  * @details DAC1 provides negative reference for phase comparators.
  * @retval  None
  */
static void ConfigureDAC(void)
{
  /* DAC1 channel 1 configuration */
  DAC_InitStructure.DAC_Trigger          = DAC_Trigger_None;
  DAC_InitStructure.DAC_WaveGeneration   = DAC_WaveGeneration_None;
  DAC_InitStructure.DAC_Buffer_Switch    = DAC_BufferSwitch_Disable;
  DAC_Init(DAC1, DAC_Channel_1, &DAC_InitStructure);
   
   /* Set DAC1 value */
  DAC_SetChannel1Data(DAC1, DAC_Align_12b_R, PHASE_OC_DAC_VALUE);
    
  /* Enable DAC1 channel 1 */
  DAC_Cmd(DAC1, DAC_Channel_1, ENABLE);
}
 
 
/**
  * @brief   Configuring operational amplifiers
  * @details OPAMP1 is phase U current
  *          OPAMP2 is phase V current
  *          OPMAP3 is phase W current (but it's not used)
  * @retval  None
  */
static void ConfigureOPAMP(void)
{
  /* OPAMP1 and OPAMP2 config */
  OPAMP_InitStructure.OPAMP_NonInvertingInput = OPAMP_NonInvertingInput_IO4;
  OPAMP_InitStructure.OPAMP_InvertingInput    = OPAMP_InvertingInput_PGA;
  OPAMP_Init(OPAMP_Selection_OPAMP1, &OPAMP_InitStructure);
  OPAMP_Init(OPAMP_Selection_OPAMP2, &OPAMP_InitStructure);
 
  /* Configure OPAMP's in PGA mode with gain set to 2 */
  OPAMP_PGAConfig(OPAMP_Selection_OPAMP1, OPAMP_OPAMP_PGAGain_2, OPAMP_PGAConnect_No);
  OPAMP_PGAConfig(OPAMP_Selection_OPAMP2, OPAMP_OPAMP_PGAGain_2, OPAMP_PGAConnect_No);
 
  /* Enable OPAMP's */
  OPAMP_Cmd(OPAMP_Selection_OPAMP1, ENABLE);
  OPAMP_Cmd(OPAMP_Selection_OPAMP2, ENABLE);
}
 
 
/**
  * @brief  Configuring ADC
  * @retval None
  */
static void ConfigureADC(void)
{
  volatile U32 temp;
 
  /*------------------------ DMA configuration ------------------------------*/ 
 
  /* DMA Channel Init */
  DMA_InitStructure.DMA_PeripheralBaseAddr = (U32)&ADC1_2->CDR;
  DMA_InitStructure.DMA_MemoryBaseAddr     = (U32)&ADCConvertedValue;
  DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize         = 3U;
  DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
  DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Word;
  DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority           = DMA_Priority_Medium;
  DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;
 
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);
 
  /*------------------------------ ADC calibration ---------------------------*/
 
  /* ADC Calibration procedure */
  ADC_VoltageRegulatorCmd(ADC1, ENABLE);
  ADC_VoltageRegulatorCmd(ADC2, ENABLE);
 
  /* Insert delay equal to 10 us (more or less...) */
  for (temp = 0U; temp < 100000U; temp++) { ; }
 
  ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
  ADC_StartCalibration(ADC1); 
 
  ADC_SelectCalibrationMode(ADC2, ADC_CalibrationMode_Single);
  ADC_StartCalibration(ADC2);
 
  while (ADC_GetCalibrationStatus(ADC1) != RESET);
  CalibrationValue1 = ADC_GetCalibrationValue(ADC1);
 
  while (ADC_GetCalibrationStatus(ADC2) != RESET);
  CalibrationValue2 = ADC_GetCalibrationValue(ADC2);
 
  UNUSED(CalibrationValue1);
  UNUSED(CalibrationValue2);
 
  /*--------------------------- ADC configuration ----------------------------*/
 
  /* Initialize struct */
  ADC_StructInit(&ADC_InitStructure);
 
  /* Configure ADC dual mode */
  ADC_CommonInitStructure.ADC_Mode             = ADC_Mode_RegSimul;
  ADC_CommonInitStructure.ADC_Clock            = ADC_Clock_AsynClkMode;
  ADC_CommonInitStructure.ADC_DMAAccessMode    = ADC_DMAAccessMode_1;
  ADC_CommonInitStructure.ADC_DMAMode          = ADC_DMAMode_Circular;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = 10U;
  ADC_CommonInit(ADC1, &ADC_CommonInitStructure);
 
  ADC_InitStructure.ADC_ContinuousConvMode    = ADC_ContinuousConvMode_Enable;
  ADC_InitStructure.ADC_Resolution            = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;
  ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;
  ADC_InitStructure.ADC_DataAlign             = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_OverrunMode           = ADC_OverrunMode_Disable;
  ADC_InitStructure.ADC_AutoInjMode           = ADC_AutoInjec_Disable;
  ADC_InitStructure.ADC_NbrOfRegChannel       = 3U;
  ADC_Init(ADC1, &ADC_InitStructure);
  ADC_Init(ADC2, &ADC_InitStructure);
 
  /* Enable Vref for ADC2 */
  ADC_VrefintCmd(ADC2, ENABLE);
 
  /*--------------------------- Channel configuration ------------------------*/
 
  /* It is important that in dual ADC mode both sequences have same length !
   * DMA puts master ADC1 samples to lower 16-bits and slave ADC2 samples to higher 16-bits */
 
  /* ADC regular channel configuration */
  /* Sampling time - 8,4 uS */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_3,          1U, ADC_SampleTime_19Cycles5); /* OPAMP1_OUT */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1,          2U, ADC_SampleTime_19Cycles5); /* VBAT */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_4,          3U, ADC_SampleTime_19Cycles5); /* MC_TEMP */
  ADC_RegularChannelConfig(ADC2, ADC_Channel_3,          1U, ADC_SampleTime_19Cycles5); /* OPAMP2_OUT */
  ADC_RegularChannelConfig(ADC2, ADC_Channel_Vrefint,    2U, ADC_SampleTime_19Cycles5); /* Internal reference voltage */
  ADC_RegularChannelConfig(ADC2, ADC_Channel_Vrefint,    3U, ADC_SampleTime_19Cycles5); /* Internal reference voltage */
 
  /*----------------------- ADC enabling and calibration ---------------------*/
 
  /* Configures the ADC DMA */
  ADC_DMAConfig(ADC1, ADC_DMAMode_Circular);
 
  /* Enable the ADC DMA */
  ADC_DMACmd(ADC1, ENABLE);  
 
  /* Enable ADC */
  ADC_Cmd(ADC1, ENABLE);
  ADC_Cmd(ADC2, ENABLE);
 
  /* Wait for ADC ADRDY */
  while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY));
  while (!ADC_GetFlagStatus(ADC2, ADC_FLAG_RDY));
 
  /* Enable the DMA channel */
  DMA_Cmd(DMA1_Channel1, ENABLE);
 
  /* Start ADC Software Conversion */
  ADC_StartConversion(ADC1);
}
 
/**
  * @brief  Rolling average calculation
  * @param  Buffer: Pointer to values buffer
  * @param  Length: Length of buffer
  * @param  NewValue: Newest value to add to buffer
  * @retval Average value
  */
static U16 RollingAverage(U16 * Buffer, U16 Length, U16 NewValue)
{
  U32 i;
  U32 sum = 0UL;
   
  for (i = (Length - 1U); i > 0UL; i--)
  {
    Buffer[i] = Buffer[i - 1U];
    sum += (U32)Buffer[i];
  }
   
  Buffer[0] = NewValue;
  sum += (U32)Buffer[0];
   
  return (U16)(sum / Length);
}
 
 
/* Public functions ----------------------------------------------------------*/
 
/**
  * @brief  Power control initialization. 
  * @retval None
  */
void Power_Init(void)
{
  /*------------------------ Clocks configuration ----------------------------*/
 
  /* Enable PWR clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); 
   
  /* GPIO clocks enable */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
 
  /* Enable COMP and OPAMP clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
 
  /* Enable DAC clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
 
  /* Enable ADC clocks */
  RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div32);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);
 
  /* Enable DMA clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
 
  /*------------------------ IO configuration --------------------------------*/
 
  /* Configure the input pins as analog inputs */
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
 
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
 
  /* Wait until Vref is stable */
  while (PWR_GetFlagStatus(PWR_FLAG_VREFINTRDY) != SET);
 
  /*------------------- COMP, DAC, OPAMP and ADC configuration --------------*/
 
  ConfigureCOMP();
  ConfigureDAC();
  ConfigureOPAMP();
  ConfigureADC();
}
 
/**
  * @brief  Power periodic task
  * @param  Period: Task execution period in milliseconds 
  */
void Power_Task(U32 Period)
{
  U16 Sample;
 
  /* Read samples.
   * Master samples are lower 16 bits, slave samples are higher 16 bits */
 
  /* Read phase A sample */
  Sample = (ADCConvertedValue[0] & 0xFFFFU);
  Sample = RollingAverage(PhaseACurrentBuffer, COUNT_OF(PhaseACurrentBuffer), Sample);
  PhaseACurrent = PHASE_CURRENT_FORMULA(Sample);
 
  /* Read phase B sample */
  Sample = ((ADCConvertedValue[0] >> 16U) & 0xFFFFU);
  Sample = RollingAverage(PhaseBCurrentBuffer, COUNT_OF(PhaseBCurrentBuffer), Sample);
  PhaseBCurrent = PHASE_CURRENT_FORMULA(Sample);
   
  /* Read voltage sample */
  Sample = (ADCConvertedValue[1] & 0xFFFFU);
  Sample = RollingAverage(VoltageBuffer, COUNT_OF(VoltageBuffer), Sample);
  Voltage = VBAT_FORMULA(Sample);
 
  /* Read temperature sample */
  Sample = (ADCConvertedValue[2] & 0xFFFFU);
  Sample = RollingAverage(TemperatureBuffer, COUNT_OF(TemperatureBuffer), Sample);
  Temperature = TEMPERATURE_FORMULA(Sample);
   
  /* Ignore internal reference voltage samples */
}
 
 
/**
  * @brief  Getting supply voltage
  * @retval Millivolts
  */
U16 Power_GetSupplyVoltage(void)
{
  return Voltage;
}
 
 
/**
  * @brief  Getting driver temperature
  * @retval Celcius degrees
  */
U8 Power_GetDriverTemperature(void)
{
  return Temperature;
}


Actually i'd like to use Vrefint/2 for comparators negative reference voltage also but comparators didn't work as expected. So thats why i started sampling the Vref with ADC2 to see what is it's value. But in MSW of ADCConvertedValue[2]  i see only 0x0FFF (it's 4095 decimal).

It kind of seems that Vref is completely invalid inside the MCU. The factory calibration value exists in Flash (was around 1.23V). VDDA and VREF+ are connected at there is 3,29V.  VDD is 3.3V.

I have tried the slowest ADC clock possible but it didn't help. I also tried sampling with ADC1 and on different sequence ranks. Strangely i also tried to sample Vbat (after enabling it) which also gave 0xFFF.

There's an errata saying that for comparator Vrefint follower has a 1s delay but nothing else about Vrefint.

Anybody has some idea?

Outcomes