Beispiel #1
0
//=================================================================
void GetVloss() {
#if FLASHEND > 0x1fff
  // measure voltage drop after load pulse
  unsigned int tmpint;
  unsigned int adcv[4];
  union t_combi{
  unsigned long dw;     // capacity value  in 100nF units
  uint16_t w[2];
  } lval;
  uint8_t ii;
  uint8_t HiPinR_L;
  uint8_t LoADC;

  if (cap.v_loss > 0) {
     return;		// Voltage loss is already known (big Capacitor)
  }
#if (((PIN_RL1 + 1) != PIN_RH1) || ((PIN_RL2 + 1) != PIN_RH2) || ((PIN_RL3 + 1) != PIN_RH3))
  LoADC = pgm_read_byte((&PinRLRHADCtab[6])+cap.ca-TP_MIN) | TXD_MSK;
#else
  LoADC = pgm_read_byte((&PinRLRHADCtab[3])+cap.ca-TP_MIN) | TXD_MSK;
#endif
  HiPinR_L = pgm_read_byte(&PinRLRHADCtab[cap.cb-TP_MIN]);	//R_L mask for HighPin R_L load

  EntladePins();			// discharge capacitor
  ADC_PORT = TXD_VAL;			// switch ADC-Port to GND
  R_PORT = 0;				// switch R-Port to GND
  ADC_DDR = LoADC;			// switch Low-Pin to output (GND)
  R_DDR = HiPinR_L;			// switch R_L port for HighPin to output (GND)
  adcv[0] = ReadADC(cap.cb);		// voltage before any load 
// ******** should adcv[0] be measured without current???
  if ((cap.cpre_max > -9) || (cap.cpre_max < -12)) return;	// too much or too less capacity
  lval.dw = cap.cval_max;
  for (ii=cap.cpre_max+15;ii<7;ii++) {
     lval.dw = (lval.dw + 5) / 10;
  }
  if (lval.dw > 5000) {
     /* capacity more than 50uF, Voltage loss is already measured  */
     return;
  }
  if (lval.w[0] < 5) return;		// Capacity below 5nF
  R_PORT = HiPinR_L;			//R_L to 1 (VCC) 
  R_DDR = HiPinR_L;			//switch Pin to output, across R to GND or VCC
  for (tmpint=0;tmpint<lval.w[0];tmpint+=2) {
//     wait50us();			// wait exactly 50us
     wait5us();			// wait exactly 5us
  }
  R_DDR = 0;				// switch back to input
  R_PORT = 0;			// no Pull up
 // wait10us();			//wait a little time
  wdt_reset();
  // read voltage without current
  ADCconfig.Samples = 5;		// set ADC to only 5 samples
  adcv[2] = ReadADC(cap.cb);
  if (adcv[2] > adcv[0]) {
     adcv[2] -= adcv[0];		//difference to beginning voltage
  } else {
     adcv[2] = 0;			// voltage is lower or same as beginning voltage
  }
  // wait 2x the time which was required for loading
  for (tmpint=0;tmpint<lval.w[0];tmpint++) {
//     wait50us();
     wait5us();
  }
  adcv[3] = ReadADC(cap.cb);	// read voltage again, is discharged only a little bit ?
  ADCconfig.Samples = ANZ_MESS;		// set ADC back to configured No. of samples
  wdt_reset();
  if (adcv[3] > adcv[0]) {
     adcv[3] -= adcv[0];		// difference to beginning voltage
  } else {
     adcv[3] = 0;			// voltage is lower or same as beginning voltage
  }
  if (adcv[2] > adcv[3]) {
     // build difference to load voltage
     adcv[1] = adcv[2] - adcv[3];	// lost voltage during load time wait
  } else {
     adcv[1] = 0;			// no lost voltage
  }
  // compute voltage drop as part from loaded voltage
  if (adcv[1] > 0) {
     // there is any voltage drop (adcv[1]) !
     // adcv[2] is the loaded voltage.
     cap.v_loss = (unsigned long)(adcv[1] * 500UL) / adcv[2];
  }
#if 0
  lcd_line3();
  DisplayValue16(adcv[2],0,' ',4);
  DisplayValue16(adcv[1],0,' ',4);
  lcd_line4();
  DisplayValue16(lval.w[0],0,'x',4);
#endif

  // discharge capacitor again
  EntladePins();		// discharge capacitors
  //ready
  // switch all ports to input
  ADC_DDR =  TXD_MSK;		// switch all ADC ports to input
  ADC_PORT = TXD_VAL;		// switch all ADC outputs to GND, no pull up
  R_DDR = 0;			// switch all resistor ports to input
  R_PORT = 0; 			// switch all resistor outputs to GND, no pull up
#endif
  return;
 } // end GetVloss()
Beispiel #2
0
uint16_t MeasureESR(Capacitor_Type *Cap)
{
  uint16_t          ESR = 0;       /* return value */
  uint16_t          U_1;           /* voltage at probe 1 with pos. pulse unloaded */
  uint16_t          U_2;           /* voltage at probe 2 with pos. pulse loaded */
  uint16_t          U_3;           /* voltage at probe 2 with neg. pulse unloaded */
  uint16_t          U_4;           /* voltage at probe 1 with neg. pulse loaded */
  uint8_t           Probe1;        /* probe #1 */
  uint8_t           Probe2;        /* probe #2 */
  uint8_t           ADC_Mask;      /* bit mask for ADC */
  uint8_t           n;             /* counter */
  uint8_t           muCycles;      /* MCU cycles per µs */
  uint8_t           PulseCycles;   /* MCU cycles for a half pulse */
  uint32_t          Sum_1;         /* sum #1 */
  uint32_t          Sum_2;         /* sum #2 */
  uint32_t          Value;

  #define LOOP_RUNS      255

  /* check for a capacitor >= 0.18µF */
  if ((Cap == NULL) ||
      (CmpValue(Cap->Value, Cap->Scale, 180, -9) < 0)) return ESR;


  /*
   *  init stuff
   */

  DischargeProbes();                    /* try to discharge probes */
  if (Check.Found == COMP_ERROR) return ESR;   /* skip on error */

  Probe1 = Cap->A;       /* probe facing Gnd */
  Probe2 = Cap->B;       /* probe facing Vcc */

  UpdateProbes(Probe1, Probe2, 0);      /* update probes */

  /* init variables */
  Sum_1 = 1;             /* 1 to prevent division by zero */
  Sum_2 = 1;             /* 1 to prevent division by zero */

  Probe1 |= (1 << REFS1) | (1 << REFS0);     /* select bandgap reference */
  Probe2 |= (1 << REFS1) | (1 << REFS0);     /* select bandgap reference */

  /* bitmask to enable and start ADC (ADC clock: 125kHz / 8µs) */
  ADC_Mask = (1 << ADSC) | (1 << ADEN) | (1 << ADIF) | ADC_CLOCK_DIV;

  /* delay for pulse */
  muCycles = (CPU_FREQ / 1000000);      /* MCU cycles per µs */

  /*
   *  We have to create a delay to shift the middle of the puls to the ADC's
   *  S&H. S&H happens at 1.5 ADC clock cycles after starting the conversion.
   *  We synchronize to a dummy conversion done directly before, so we'll got
   *  2.5 ADC clock cycles to S&H. The time between the completed dummy
   *  conversion and S&H of the next conversion is:
   *    2.5 ADC clock cycles (2.5 * 1/125kHz = 20µs)
   *    - MCU cycles for waiting loop for completion of dummy conversion (4)
   *    - MCU cycles for starting next conversion (2)
   *    - 5µs delay
   *    - MCU cycles for enabling pulse (4)
   *
   *  That time is the first half of the puls. So we have to double the time
   *  for a full pulse. Half pulse for 8MHz MCU clock is about 13.5µs.
   */

  PulseCycles = muCycles * 15;          /* MCU cycles for 15µs (20µs S/H - 5µs delay) */
  PulseCycles -= 10;                    /* substract other cycles */

  /* setup delay timer */
  if (SetupDelayTimer(PulseCycles) == 0) return ESR;   /* skip on error */


  /*
   *  charge capacitor with a negative pulse of half length
   *  pulse: GND -- probe 2 / probe 1 -- Rl -- 5V
   */

  ADC_PORT = 0;               /* set ADC port to low */
  ADMUX = Probe1;             /* set input channel to probe 1 & set bandgap ref */
  wait10ms();                 /* time for voltage stabilization */
  ADC_DDR = Probes.ADC_2;     /* pull down probe 2 directly */
  R_PORT = Probes.Rl_1;       /* pull up probe 1 via Rl */
  R_DDR = Probes.Rl_1;        /* enable resistor */
  DelayTimer();               /* wait 1/2 pulse */
  R_PORT = 0;                 /* set resistor port to low */
  R_DDR = 0;                  /* set resistor port to HiZ */


  /*
   *  measurement loop:
   *  - simulate AC by positive and negative pulses
   *  - measure start voltage (no load)
   *  - measure pulse voltage (with load)
   */  

  n = LOOP_RUNS;
  while (n > 0)
  {
    /*
     *  forward mode, probe 1 only (probe 2 in HiZ mode)
     *  get voltage at probe 1 (facing Gnd)
     *  set probes: GND -- probe 1 -- Rl -- 5V / probe 2 -- HiZ
     */

    ADC_DDR = Probes.ADC_1;        /* pull down probe 1 directly to GND */
    R_PORT = Probes.Rl_1;          /* pull up probe 1 via Rl */
    R_DDR = Probes.Rl_1;           /* enable resistor */
    ADMUX = Probe1;                /* set input channel to probe 1 & set bandgap ref */
    wdt_reset();                   /* reset watchdog */
    /* run dummy conversion for ADMUX change */
    ADCSRA = ADC_Mask;             /* start conversion */
    while (ADCSRA & (1 << ADSC));  /* wait until conversion is done */
    /* real conversion */
    ADCSRA = ADC_Mask;             /* start conversion */
    while (ADCSRA & (1 << ADSC));  /* wait until conversion is done */
    U_1 = ADCW;                    /* save ADC value */


    /*
     *  forward mode, positive charging pulse
     *  get voltage at probe 2 (facing Vcc)
     *  set probes: GND -- probe 1 / probe 2 -- Rl -- 5V
     */

    ADMUX = Probe2;                /* set input channel to probe 2 & set bandgap ref */
    /* run dummy conversion for ADMUX change */
    ADCSRA = ADC_Mask;             /* start conversion */
    while (ADCSRA & (1 << ADSC));  /* wait until conversion is done */

    /* read ADC in the mid of a positive charging pulse */
    ADCSRA = ADC_Mask;             /* start conversion with next ADC clock cycle */
    wait5us();
    R_PORT = Probes.Rl_2;          /* pull up probe 2 via Rl */
    R_DDR = Probes.Rl_2;           /* enable resistor */
    DelayTimer();                  /* wait 1/2 pulse */
    DelayTimer();                  /* wait another 1/2 pulse */
    R_PORT = 0;                    /* set resistor port to low */
    R_DDR = 0;                     /* set resistor port to HiZ */
    while (ADCSRA & (1 << ADSC));  /* wait until conversion is done */
    U_2 = ADCW;                    /* save ADC value */


    /*
     *  reverse mode, probe 2 only (probe 1 in HiZ mode)
     *  get voltage at probe 2 (facing Gnd)
     *  set probes: GND -- probe 2 -- Rl -- 5V / probe 1 -- HiZ
     */

    ADC_DDR = Probes.ADC_2;        /* pull down probe 2 directly */
    R_PORT = Probes.Rl_2;          /* pull up probe 2 via Rl */
    R_DDR = Probes.Rl_2;           /* enable resistor */
    ADMUX = Probe2;                /* set input channel to probe 2 & set bandgap ref */
    wdt_reset();                   /* reset watchdog */
    /* run dummy conversion for ADMUX change */
    ADCSRA = ADC_Mask;             /* start conversion */
    while (ADCSRA & (1 << ADSC));  /* wait until conversion is done */
    /* real conversion */
    ADCSRA = ADC_Mask;             /* start conversion */
    while (ADCSRA & (1 << ADSC));  /* wait until conversion is done */
    U_3 = ADCW;                    /* save ADC value */


    /*
     *  reverse mode, negative charging pulse
     *  get voltage at probe 1 (facing Vcc)
     *  set probes: GND -- probe 2 / probe 1 -- Rl -- 5V
     */

    ADMUX = Probe1;                /* set input channel to probe 1 & set bandgap ref */
    /* run dummy conversion for ADMUX change */
    ADCSRA = ADC_Mask;             /* start conversion */
    while (ADCSRA & (1 << ADSC));  /* wait until conversion is done */

    /* read ADC in the mid of a negatve charging pulse */
    ADCSRA = ADC_Mask;             /* start conversion with next ADC clock cycle */
    wait5us();
    R_PORT = Probes.Rl_1;          /* pull up probe 1 via Rl */
    R_DDR = Probes.Rl_1;           /* enable resistor */
    DelayTimer();                  /* wait 1/2 pulse */
    DelayTimer();                  /* wait another 1/2 pulse */
    R_PORT = 0;                    /* set resistor port to low */
    R_DDR = 0;                     /* set resistor port to HiZ */
    while (ADCSRA & (1 << ADSC));  /* wait until conversion is done */
    U_4 = ADCW;                    /* save ADC value */


    /*
     *  manage measured values
     */

    U_1 += U_3;          /* sum of both measurements without pulses/load */
    Sum_1 += U_1;        /* add to total no-load sum */
    U_2 += U_4;          /* sum of both measurements with pulses/load */
    Sum_2 += U_2;        /* add to total with-load sum */


    /*
     *  prevent runaway of cap's charge
     */

    if (U_4 <= 100)           /* <= 107mV */
    {
      /* charge cap a little bit more (negative pulse) */

      /* set probes: GND -- probe 2 / probe 1 -- Rl -- 5V */
      /* probe 2 is still pulled down directly */
      R_PORT = Probes.Rl_1;        /* pull up probe 1 via Rl */
      R_DDR = Probes.Rl_1;         /* enable pull up */
      wait2us();
      R_DDR = 0;                   /* disable any pull up */      
      R_PORT = 0;                  /* reset probe resistors */
    }

    if (U_2 <= 100)
    {
      /* charge cap a little bit more (positive pulse) */

      /* set probes: GND -- probe 1 / probe 2 -- Rl -- 5V */
      ADC_DDR = Probes.ADC_1;      /* pull down probe 1 directly */
      R_PORT = Probes.Rl_2;        /* pull up probe 2 via Rl */
      R_DDR = Probes.Rl_2;         /* enable pull up */
      wait2us();
      DelayTimer();                /* wait 1/2 pulse */
      DelayTimer();                /* wait another 1/2 pulse */
      R_DDR = 0;                   /* disable any pull up */      
      R_PORT = 0;                  /* reset probe resistors */
    }

    n--;                 /* next loop run */
  }


  /*
   *  process measurements
   */

  /* calculate voltage across the DUT */
  if (Sum_2 > Sum_1)               /* valid measurement */
  {
    Sum_2 -= Sum_1;                /* subtract voltage at DUT's low side (RiL) */
  }
  else                             /* invalid measurement */
  {
    Sum_2 = 0;
  }


  /*
   *  calculate ESR
   *  - ESR = U_ESR / I_ESR
   *    with U_ESR = (U2 or U4) and I_ESR = (U1 or U3)/RiL
   *    ESR = (U2 or U4) * RiL / (U1 or U3)
   *  - since we devide (U2 or U4) by (U1 or U3) we don't need to convert
   *    the ADC value into a voltage and desample the sums.
   *  - so ESR = Sum_2 * RiL / Sum_1
   *  - for a resolution of 0.01 Ohms we have to scale RiL to 0.01 Ohms
   */

  Value = (uint32_t)(NV.RiL * 10);      /* RiL in 0.01 Ohms */
  Value *= Sum_2;
  Value /= Sum_1;
  U_1 = (uint16_t)Value;

  /* consider probe resistance */
  if (U_1 > NV.RZero)
  {
    U_1 -= NV.RZero;               /* subtract offset */
    ESR = U_1;                     /* we got a valid result */
  }

  /* update Uref flag for next ADC run */
  Config.RefFlag = (1 << REFS1);        /* set REFS1 bit flag */

  return ESR;

  #undef LOOP_RUNS 
}