Пример #1
0
int main(void)
{
  uint16_t          U_Bat;         /* voltage of power supply */
  uint8_t           Test;          /* test value */

  /*
   *  init
   */

  /* switch on power to keep me alive */
  CONTROL_DDR = (1 << POWER_CTRL);      /* set pin as output */
  CONTROL_PORT = (1 << POWER_CTRL);     /* set pin to drive power management transistor */

  /* setup MCU */
  MCUCR = (1 << PUD);                        /* disable pull-up resistors globally */
  ADCSRA = (1 << ADEN) | ADC_CLOCK_DIV;      /* enable ADC and set clock divider */

  #ifdef HW_RELAY
  /* init relay (safe mode) */
                                      /* ADC_PORT should be 0 */
  ADC_DDR = (1 << TP_REF);            /* short circuit probes */
  #endif

  /* catch watchdog */  
  Test = (MCUSR & (1 << WDRF));         /* save watchdog flag */
  MCUSR &= ~(1 << WDRF);                /* reset watchdog flag */
  wdt_disable();                        /* disable watchdog */

  /* init LCD module */
  LCD_BusSetup();                       /* setup bus */
  LCD_Init();                           /* initialize LCD */
  LCD_NextLine_Mode(MODE_NONE);         /* reset line mode */


  /*
   *  watchdog was triggered (timeout 2s)
   *  - This is after the MCU done a reset driven by the watchdog.
   *  - Does only work if the capacitor at the base of the power management
   *    transistor is large enough to survive a MCU reset. Otherwise the
   *    tester simply loses power.
   */

  if (Test)
  {
    LCD_Clear();                        /* display was initialized before */
    LCD_EEString(Timeout_str);          /* display: timeout */
    LCD_NextLine_EEString(Error_str);   /* display: error */
    MilliSleep(2000);                   /* give user some time to read */
    CONTROL_PORT = 0;                   /* power off myself */
    return 0;                           /* exit program */
  }


  /*
   *  operation mode selection
   */

  Config.SleepMode = SLEEP_MODE_PWR_SAVE;    /* default: power save */
  UI.TesterMode = MODE_CONTINOUS;            /* set default mode: continous */
  Test = 0;                                  /* key press */

  /* catch long key press */
  if (!(CONTROL_PIN & (1 << TEST_BUTTON)))   /* if test button is pressed */
  {
    RunsMissed = 0;

    while (Test == 0)
    {
      MilliSleep(20);
      if (!(CONTROL_PIN & (1 << TEST_BUTTON)))    /* if button is still pressed */
      {
        RunsMissed++;
        if (RunsMissed > 100) Test = 3;      /* >2000ms */
      }
      else                                        /* button released */
      {
        Test = 1;                            /* <300ms */
        if (RunsMissed > 15) Test = 2;       /* >300ms */
      }
    }
  }

  /* key press >300ms sets autohold mode */
  if (Test > 1) UI.TesterMode = MODE_AUTOHOLD;


  /*
   *  load saved offsets and values
   */

  if (Test == 3)              /* key press >2s resets to defaults */
  {
    SetAdjustDefaults();           /* set default values */
  }
  else                        /* normal mode */
  {
    LoadAdjust();                  /* load adjustment values */
  }

  /* set extra stuff */
  #ifdef SW_CONTRAST
    LCD_Contrast(NV.Contrast);          /* set LCD contrast */
  #endif


  /*
   *  welcome user
   */

  LCD_EEString(Tester_str);             /* display: Component Tester */
  LCD_NextLine_EEString_Space(Edition_str);   /* display firmware edition */
  LCD_EEString(Version_str);            /* display firmware version */
  MilliSleep(1500);                     /* let the user read the display */


  /*
   *  init variables
   */

  /* cycling */
  RunsMissed = 0;
  RunsPassed = 0;

  /* default offsets and values */
  Config.Samples = ADC_SAMPLES;         /* number of ADC samples */
  Config.AutoScale = 1;                 /* enable ADC auto scaling */
  Config.RefFlag = 1;                   /* no ADC reference set yet */
  Config.Vcc = UREF_VCC;                /* voltage of Vcc */
  wdt_enable(WDTO_2S);		        /* enable watchdog (timeout 2s) */


  /*
   *  main processing cycle
   */

start:

  /* reset variabels */
  Check.Found = COMP_NONE;
  Check.Type = 0;
  Check.Done = 0;
  Check.Diodes = 0;
  Check.Resistors = 0;
  Semi.U_1 = 0;
  Semi.I_1 = 0;
  Semi.F_1 = 0;

  /* reset hardware */
  ADC_DDR = 0;                     /* set all pins of ADC port as input */
                                   /* also remove short circuit by relay */
  LCD_NextLine_Mode(MODE_KEEP);    /* line mode: keep first line */
  LCD_Clear();                     /* clear LCD */


  /*
   *  voltage reference
   */

  #ifdef HW_REF25
  /* external 2.5V reference */
  Config.Samples = 200;            /* do a lot of samples for high accuracy */
  U_Bat = ReadU(TP_REF);           /* read voltage of reference (mV) */
  Config.Samples = ADC_SAMPLES;    /* set samples back to default */

  if ((U_Bat > 2250) && (U_Bat < 2750))   /* check for valid reference */
  {
    uint32_t        Temp;

    /* adjust Vcc (assuming 2.495V typically) */
    Temp = ((uint32_t)Config.Vcc * UREF_25) / U_Bat;
    Config.Vcc = (uint16_t)Temp;
  }
  #endif

  /* internal bandgap reference */
  Config.Bandgap = ReadU(0x0e);         /* dummy read for bandgap stabilization */
  Config.Samples = 200;                 /* do a lot of samples for high accuracy */
  Config.Bandgap = ReadU(0x0e);         /* get voltage of bandgap reference (mV) */
  Config.Samples = ADC_SAMPLES;         /* set samples back to default */
  Config.Bandgap += NV.RefOffset;       /* add voltage offset */ 


  /*
   *  battery check
   */

  /*
   *  ADC pin is connected to a voltage divider Rh = 10k and Rl = 3k3.
   *  Ul = (Uin / (Rh + Rl)) * Rl  ->  Uin = (Ul * (Rh + Rl)) / Rl
   *  Uin = (Ul * (10k + 3k3)) / 3k3 = 4 * Ul  
   */

  /* get current voltage */
  U_Bat = ReadU(TP_BAT);                /* read voltage (mV) */
  U_Bat *= 4;                           /* calculate U_bat (mV) */
  U_Bat += BAT_OFFSET;                  /* add offset for voltage drop */

  /* display battery voltage */
  LCD_EEString_Space(Battery_str);      /* display: Bat. */
  DisplayValue(U_Bat / 10, -2, 'V');    /* display battery voltage */
  LCD_Space();

  /* check limits */
  if (U_Bat < BAT_POOR)                 /* low level reached */
  {
    LCD_EEString(Low_str);              /* display: low */
    MilliSleep(2000);                   /* let user read info */
    goto power_off;                     /* power off */
  }
  else if (U_Bat < BAT_POOR + 1000)     /* warning level reached */
  {
    LCD_EEString(Weak_str);             /* display: weak */
  }
  else                                  /* ok */
  {
    LCD_EEString(OK_str);               /* display: ok */
  }


  /*
   *  probing
   */

  /* display start of probing */
  LCD_NextLine_EEString(Running_str);   /* display: probing... */

  /* try to discharge any connected component */
  DischargeProbes();
  if (Check.Found == COMP_ERROR)   /* discharge failed */
  {
    goto result;                   /* skip all other checks */
  }

  /* enter main menu if requested by short-circuiting all probes */
  if (AllProbesShorted() == 3)
  {
    MainMenu();                    /* enter mainmenu */;
    goto end;                      /* new cycle after job is is done */
  }

  /* check all 6 combinations of the 3 probes */ 
  CheckProbes(TP1, TP2, TP3);
  CheckProbes(TP2, TP1, TP3);
  CheckProbes(TP1, TP3, TP2);
  CheckProbes(TP3, TP1, TP2);
  CheckProbes(TP2, TP3, TP1);
  CheckProbes(TP3, TP2, TP1);

  /* if component might be a capacitor */
  if ((Check.Found == COMP_NONE) ||
      (Check.Found == COMP_RESISTOR))
  {
    /* tell user to be patient with large caps :-) */
    LCD_Space();
    LCD_Char('C');    

    /* check all possible combinations */
    MeasureCap(TP3, TP1, 0);
    MeasureCap(TP3, TP2, 1);
    MeasureCap(TP2, TP1, 2);
  }


  /*
   *  output test results
   */

result:

  LCD_Clear();                     /* clear LCD */
  LCD_NextLine_Mode(MODE_KEEP | MODE_KEY);

  /* call output function based on component type */
  switch (Check.Found)
  {
    case COMP_ERROR:
      Show_Error();
      goto end;
      break;

    case COMP_DIODE:
      Show_Diode();
      break;

    case COMP_BJT:
      Show_BJT();
      break;

    case COMP_FET:
      Show_FET();
      break;

    case COMP_IGBT:
      Show_IGBT();
      break;

    case COMP_THYRISTOR:
      Show_Special();
      break;

    case COMP_TRIAC:
      Show_Special();
      break;

    case COMP_RESISTOR:
      Show_Resistor();
      break;

    case COMP_CAPACITOR:
      Show_Capacitor();
      break;

    default:                  /* no component found */
      Show_Fail();
      goto end;
  }

  /* component was found */
  RunsMissed = 0;             /* reset counter */
  RunsPassed++;               /* increase counter */


  /*
   *  take care about cycling and power-off
   */

end:

  #ifdef HW_RELAY
  ADC_DDR = (1<<TP_REF);              /* short circuit probes */
  #endif

  LCD_NextLine_Mode(MODE_NONE);       /* reset next line mode */

  /* get key press or timeout */
  Test = TestKey((uint16_t)CYCLE_DELAY, 12);

  if (Test == 0)              /* timeout (no key press) */
  {
    /* check if we reached the maximum number of rounds (continious mode only) */
    if ((RunsMissed >= CYCLE_MAX) || (RunsPassed >= CYCLE_MAX * 2))
    {
      goto power_off;              /* -> power off */
    }
  }
  else if (Test == 1)         /* short key press */
  {
    /* a second key press triggers extra functions */
    MilliSleep(50);
    Test = TestKey(300, 0);

    if (Test > 0)           /* short or long key press */
    {
      #ifdef HW_RELAY
      ADC_DDR = 0;               /* remove short circuit */
      #endif

      MainMenu();                /* enter main menu */
      goto end;                  /* re-run cycle control */
    }
  }
  else if (Test == 2)         /* long key press */
  {
    goto power_off;              /* -> power off */
  }
  #ifdef HW_ENCODER
  else if (Test == 4)         /* rotary encoder: left turn */
  {
    MainMenu();                  /* enter main menu */
    goto end;                    /* re-run cycle control */
  }
  #endif

  /* default action (also for rotary encoder) */
  goto start;                 /* -> next round */


power_off:

  /* display feedback (otherwise the user will wait :-) */
  LCD_Clear();
  LCD_EEString(Bye_str);

  wdt_disable();                        /* disable watchdog */
  CONTROL_PORT &= ~(1 << POWER_CTRL);   /* power off myself */

  return 0;
}
Пример #2
0
void CLispEng::Disassemble(ostream& os, CP p) {
	CClosure *c = ToCClosure(p);
	g_pClos = c;
	os << "Closure " << hex << p << "\n";
	Print(c->NameOrClassVersion);
	os << "\nConsts:";
	if (AsArray(p)->DataLength)
		for (size_t i=0; i<AsArray(p)->DataLength; ++i) {
			os << "\n  CONST[" << i << "] = ";
			Print(c->Consts[i]);
		}
	os << "\n\n";
	int off = c->Flags & FLAG_KEY ? CCV_START_KEY : CCV_START_NONKEY;
	byte *prevPb = CurVMContext->m_pb;
	for (ssize_t i = off; i<AsArray(c->CodeVec)->GetVectorLength();) {
		byte *pb = (byte*)AsArray(c->CodeVec)->m_pData; 
		os << DWORD(i-off) << "\t";
		byte b = pb[i++];
		os << Convert::ToString(b, "X2") << "  " << g_arOpcode[b] << "\t";
		VM_CONTEXT;
		CurVMContext->m_pb = pb+i;
		switch (b) {
		case COD_CALLS1:
		case COD_CALLS2:
		case COD_CALLS1_PUSH:
		case COD_CALLS2_PUSH:
			os << int(ReadB());
			break;
		case COD_CALLSR:
		case COD_CALLSR_PUSH:
			os << ReadU() << " ";
			os << int(ReadB());
			break;
		case COD_CALLS1_JMPIF:
		case COD_CALLS1_JMPIFNOT:
		case COD_CALLS2_JMPIF:
		case COD_CALLS2_JMPIFNOT:
			os << int(ReadB()) << " ";
			ReadPrintLabel(os);
			break;
		case COD_BLOCKOPEN:
		case COD_LOAD_JMPIF:
		case COD_LOAD_JMPIFNOT:
		case COD_CALL1_JMPIF:
		case COD_CALL1_JMPIFNOT:
		case COD_CALL2_JMPIF:
		case COD_CALL2_JMPIFNOT:
		case COD_JMPIFBOUNDP:
		case COD_JMPIFEQTO:
		case COD_JMPIFNOTEQTO:
			os << ReadU() << " ";
			ReadPrintLabel(os);
			break;
		case COD_CALLSR_JMPIF:
		case COD_CALLSR_JMPIFNOT:
			os << ReadU() << " " << ReadU() << " ";
			ReadPrintLabel(os);
			break;
		case COD_CATCHOPEN:
		case COD_UWPOPEN:
		case COD_JSR:
		case COD_JMP:
		case COD_JMPIF:
		case COD_JMPIF1:
		case COD_JMPIFNOT:
		case COD_JMPIFNOT1:
		case COD_JMPIFATOM:
		case COD_JMPIFCONSP:
		case COD_JMPIFEQ:
		case COD_JMPIFNOTEQ:
			ReadPrintLabel(os);
			break;
		case COD_RETURNFROM:
		case COD_JMPHASH:
		case COD_JMPHASHV:
		case COD_APPLY:
		case COD_CALL0:
		case COD_CALL1:
		case COD_CALL2:
		case COD_CALL1_PUSH:
		case COD_CALL2_PUSH:
		case COD_CONST_PUSH:
		case COD_POP_STORE:
		case COD_LOAD:
		case COD_LOAD_PUSH:
		case COD_SETVALUE:
		case COD_LOAD_CAR_PUSH:
		case COD_LOAD_CDR_STORE:
		case COD_LOAD_INC_PUSH:
		case COD_LOAD_DEC_PUSH:
		case COD_LOAD_INC_STORE:
		case COD_LOAD_DEC_STORE:
		case COD_GETVALUE:
		case COD_GETVALUE_PUSH:
		case COD_PUSH_UNBOUND:
		case COD_PUSH_NIL:
		case COD_BIND:
		case COD_UNBIND:
		case COD_UNBOUND_NIL:
		case COD_NVTOSTACK:
		case COD_SKIP:
		case COD_SKIP_RET:
		case COD_SKIP_RETGF:
		case COD_FUNCALL:
		case COD_FUNCALL_PUSH:
		case COD_MAKEVECTOR1_PUSH:
		case COD_CONST:
		case COD_CONST_SYMBOLFUNCTION:
		case COD_CONST_SYMBOLFUNCTION_PUSH:
		case COD_LIST_PUSH:
		case COD_LISTSTERN_PUSH:
		case COD_STACKTOMV:
		case COD_BOUNDP:
		case COD_HANDLEROPEN:
			os << ReadU();
			break;
		case COD_CALL:
		case COD_CALL_PUSH:
		case COD_LOADC:
		case COD_LOADV:
		case COD_LOADV_PUSH:
		case COD_STOREC:
		case COD_STOREV:
		case COD_COPYCLOSURE:
		case COD_COPYCLOSURE_PUSH:
		case COD_FUNCALL_SKIP_RETGF:
		case COD_APPLY_SKIP_RET:
		case COD_UNLISTSTERN:
		case COD_UNLIST:
		case COD_SKIPSP:
			os << ReadU() << " ";
			os << ReadU();
			break;
		case COD_RETURNFROMI:
		case COD_LOADI:
		case COD_LOADI_PUSH:
		case COD_CALLSR_STORE:
			os << ReadU() << " ";
			os << ReadU() << " ";
			os << ReadU();
			break;
		case COD_STOREIC:
			os << ReadU() << " ";
			os << ReadU() << " ";
			os << ReadU() << " ";
			os << ReadU();
			break;
		}
		i = CurVMContext->m_pb-pb;

		os << "\n";
	}
	CurVMContext->m_pb = prevPb;
	os << endl;
}
Пример #3
0
uint8_t LargeCap(Capacitor_Type *Cap)
{
  uint8_t           Flag = 3;      /* return value */
  uint8_t           TempByte;      /* temp. value */
  uint8_t           Mode;          /* measurement mode */
  int8_t            Scale;         /* capacitance scale */
  uint16_t          TempInt;       /* temp. value */
  uint16_t          Pulses;        /* number of charging pulses */
  uint16_t          U_Zero;        /* voltage before charging */
  uint16_t          U_Cap;         /* voltage of DUT */
  uint16_t          U_Drop = 0;    /* voltage drop */
  uint32_t          Raw;           /* raw capacitance value */
  uint32_t          Value;         /* corrected capacitance value */

  /* setup mode */
  Mode = FLAG_10MS | FLAG_PULLUP;       /* start with large caps */


  /*
   *  We charge the DUT with up to 500 pulses each 10ms long until the
   *  DUT reaches 300mV. The charging is done via Rl. This method is
   *  suitable for large capacitances from 47uF up to 100mF. If we find a 
   *  lower capacitance we'll switch to 1ms charging pulses and try again
   *  (4.7µF up to 47µF).
   *
   *  Problem:
   *  ReadADC() needs about 5ms (44 runs). We charge the DUT for 10ms and
   *  measure for 5ms. During that time the voltage will drop due to
   *  resistive losses of the DUT and the measurement itself. So the DUT
   *  seems to need more time to reach 300mV causing a higher capacitance
   *  be calculated.
   *
   *  Remark:
   *  The Analog Input Resistance of the ADC is 100MOhm typically.
   */

large_cap:

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

  /* setup probes: Gnd -- probe 1 / probe 2 -- Rl -- Vcc */
  ADC_PORT = 0;                    /* set ADC port to low */
  ADC_DDR = Probes.ADC_2;          /* pull-down probe 2 directly */
  R_PORT = 0;                      /* set resistor port to low */
  R_DDR = 0;                       /* set resistor port to HiZ */
  U_Zero = ReadU(Probes.Pin_1);    /* get zero voltage (noise) */

  /* charge DUT with up to 500 pulses until it reaches 300mV */
  Pulses = 0;
  TempByte = 1;
  while (TempByte)
  {
    Pulses++;
    PullProbe(Probes.Rl_1, Mode);       /* charging pulse */
    U_Cap = ReadU(Probes.Pin_1);        /* get voltage */

    /* zero offset */
    if (U_Cap > U_Zero)            /* voltage higher than zero offset */
      U_Cap -= U_Zero;                  /* subtract zero offset */
    else                           /* shouldn't happen but you never know */
      U_Cap = 0;                        /* assume 0V */

    /* end loop if charging is too slow */
    if ((Pulses == 126) && (U_Cap < 75)) TempByte = 0;
    
    /* end loop if 300mV are reached */
    if (U_Cap >= 300) TempByte = 0;

    /* end loop if maximum pulses are reached */
    if (Pulses == 500) TempByte = 0;

    wdt_reset();                        /* reset watchdog */
  }

  /* if 300mV are not reached DUT isn't a cap or much too large (>100mF) */
  /* we can ignore that for mid-sized caps */
  if (U_Cap < 300)
  {
    Flag = 1;
  }

  /* if 1300mV are reached with one pulse we got a small cap */
  if ((Pulses == 1) && (U_Cap > 1300))
  {
    if (Mode & FLAG_10MS)                    /* 10ms pulses (>47µF) */
    {
      Mode = FLAG_1MS | FLAG_PULLUP;         /* set mode to 1ms charging pulses (<47µF) */
      goto large_cap;                        /* and re-run */
    }
    else                                     /* 1ms pulses (<47µF) */
    {
      Flag = 2;                              /* signal low capacitance (<4.7µF) */
    }
  }


  /*
   *  check if DUT sustains the charge and get the voltage drop
   *  - run the same time as before minus the 10ms charging time
   *  - this gives us the approximation of the self-discharging
   */

  if (Flag == 3)
  {
    /* check self-discharging */
    TempInt = Pulses;
    while (TempInt > 0)
    {
      TempInt--;                        /* descrease timeout */
      U_Drop = ReadU(Probes.Pin_1);     /* get voltage */
      U_Drop -= U_Zero;                 /* zero offset */
      wdt_reset();                      /* reset watchdog */
    }

    /* calculate voltage drop */
    if (U_Cap > U_Drop) U_Drop = U_Cap - U_Drop;
    else U_Drop = 0;

    /* if voltage drop is too large consider DUT not to be a cap */
    if (U_Drop > 100) Flag = 0;
  }


  /*
   *  calculate capacitance
   *  - use factor from pre-calculated LargeCap_table
   *  - ignore NV.CapZero since it's in the pF range
   */

  if (Flag == 3)
  {
    Scale = -9;                           /* factor is scaled to nF */
    /* get interpolated factor from table */
    Raw = GetFactor(U_Cap + U_Drop, TABLE_LARGE_CAP);
    Raw *= Pulses;                        /* C = pulses * factor */
    if (Mode & FLAG_10MS) Raw *= 10;      /* *10 for 10ms charging pulses */

    if (Raw > (UINT32_MAX / 1000))        /* scale down if C >4.3mF */
    {
      Raw /= 1000;                        /* scale down by 10^3 */
      Scale += 3;                         /* add 3 to the exponent */
    }

    Value = Raw;                          /* copy raw value */

    /* it seems that we got a systematic error */
    Value *= 100;
    if (Mode & FLAG_10MS) Value /= 109;   /* -9% for large cap */
    else Value /= 104;                    /* -4% for mid cap */

    /* copy data */
    Cap->A = Probes.Pin_2;    /* pull-down probe pin */
    Cap->B = Probes.Pin_1;    /* pull-up probe pin */
    Cap->Scale = Scale;       /* -9 or -6 */
    Cap->Raw = Raw;
    Cap->Value = Value;       /* max. 4.3*10^6nF or 100*10^3µF */ 
  }

  return Flag;
}
Пример #4
0
uint8_t SmallCap(Capacitor_Type *Cap)
{
  uint8_t           Flag = 3;      /* return value */
  uint8_t           TempByte;      /* temp. value */
  int8_t            Scale;         /* capacitance scale */
  uint16_t          Ticks;         /* timer counter */
  uint16_t          Ticks2;        /* timer overflow counter */
  uint16_t          U_c;           /* voltage of capacitor */
  uint32_t          Raw;           /* raw capacitance value */
  uint32_t          Value;         /* corrected capacitance value */


  /*
   *  Measurement method used for small caps < 50uF:
   *  We need a much better resolution for the time measurement. Therefore we
   *  use the MCUs internal 16-bit counter and analog comparator. The counter
   *  inceases until the comparator detects that the voltage of the DUT is as
   *  high as the internal bandgap reference. To support the higher time
   *  resolution we use the Rh probe resistor for charging.
   *
   *  Remark:
   *  The analog comparator has an Input Leakage Current of -50nA up to 50nA 
   *  at Vcc/2. The Input Offset is <10mV at Vcc/2.
   */

  Ticks2 = 0;                           /* reset timer overflow counter */

  /*
   *  init hardware
   */

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

  /* set probes: Gnd -- all probes / Gnd -- Rh -- probe-1 */
  R_PORT = 0;                           /* set resistor port to low */
  /* set ADC probe pins to output mode */
  ADC_DDR = (1 << TP1) | (1 << TP2) | (1 << TP3);
  ADC_PORT = 0;                         /* set ADC port to low */
  R_DDR = Probes.Rh_1;                  /* pull-down probe-1 via Rh */

  /* setup analog comparator */
  ADCSRB = (1 << ACME);                 /* use ADC multiplexer as negative input */
  ACSR =  (1 << ACBG) | (1 << ACIC);    /* use bandgap as positive input, trigger timer1 */
  ADMUX = (1 << REFS0) | Probes.Pin_1;  /* switch ADC multiplexer to probe 1 */
                                        /* and set AREF to Vcc */
  ADCSRA = ADC_CLOCK_DIV;               /* disable ADC, but keep clock dividers */
  wait200us();

  /* setup timer */
  TCCR1A = 0;                           /* set default mode */
  TCCR1B = 0;                           /* set more timer modes */
  /* timer stopped, falling edge detection, noise canceler disabled */
  TCNT1 = 0;                            /* set Counter1 to 0 */
  /* clear all flags (input capture, compare A & B, overflow */
  TIFR1 = (1 << ICF1) | (1 << OCF1B) | (1 << OCF1A) | (1 << TOV1);
  R_PORT = Probes.Rh_1;                 /* pull-up probe-1 via Rh */  
                                        
  /* enable timer */
  if (Check.Found == COMP_FET)
  {
    /* keep all probe pins pulled down but probe-1 */
    TempByte = (((1 << TP1) | (1 << TP2) | (1 << TP3)) & ~(1 << Probes.Pin_1));    
  }
  else
  {
    TempByte = Probes.ADC_2;            /* keep just probe-1 pulled down */
  }

  /* start timer by setting clock prescaler (1/1 clock divider) */
  TCCR1B = (1 << CS10);
  ADC_DDR = TempByte;                   /* start charging DUT */


  /*
   *  timer loop
   *  - run until voltage is reached
   *  - detect timer overflows
   */

   while (1)
   {
     TempByte = TIFR1;                  /* get timer1 flags */

     /* end loop if input capture flag is set (= same voltage) */
     if (TempByte & (1 << ICF1)) break;

     /* detect timer overflow by checking the overflow flag */
     if (TempByte & (1 << TOV1))
     {
       /* happens at 65.536ms for 1MHz or 8.192ms for 8MHz */
       TIFR1 = (1 << TOV1);             /* reset flag */
       wdt_reset();                     /* reset watchdog */
       Ticks2++;                        /* increase overflow counter */

       /* end loop if charging takes too long (13.1s) */
       if (Ticks2 == (CPU_FREQ / 5000)) break;
     }
   }

  /* stop counter */
  TCCR1B = 0;                           /* stop timer */
  TIFR1 = (1 << ICF1);                  /* reset Input Capture flag */

  Ticks = ICR1;                         /* get counter value */

  /* disable charging */
  R_DDR = 0;                  /* set resistor port to HiZ mode */

  /* catch missed timer overflow */
  if ((TCNT1 > Ticks) && (TempByte & (1 << TOV1)))
  {
    TIFR1 = (1 << TOV1);                /* reset overflow flag */
    Ticks2++;                           /* increase overflow counter */
  }

  /* enable ADC again */
  ADCSRA = (1 << ADEN) | (1 << ADIF) | ADC_CLOCK_DIV;

  /* get voltage of DUT */
  U_c = ReadU(Probes.Pin_1);       /* get voltage of cap */

  /* start discharging DUT */
  R_PORT = 0;                      /* pull down probe-2 via Rh */
  R_DDR = Probes.Rh_1;             /* enable Rh for probe-1 again */

  /* skip measurement if charging took too long */
  if (Ticks2 >= (CPU_FREQ / 5000)) Flag = 1;


  /*
   *  calculate capacitance (<50uF)
   *  - use factor from pre-calculated SmallCap_table
   */

  if (Flag == 3)
  {
    /*  combine both counter values */
    Raw = (uint32_t)Ticks;                /* set lower 16 bits */
    Raw |= (uint32_t)Ticks2 << 16;        /* set upper 16 bits */
    if (Raw > 2) Raw -= 2;                /* subtract processing time overhead */

    Scale = -12;                          /* default factor is for pF scale */
    if (Raw > (UINT32_MAX / 1000))        /* prevent overflow (4.3*10^6) */
    {
      Raw /= 1000;                        /* scale down by 10^3 */
      Scale += 3;                         /* add 3 to the exponent (nF) */
    }

    /* multiply with factor from table */
    Raw *= GetFactor(Config.Bandgap + NV.CompOffset, TABLE_SMALL_CAP);

    /* divide by CPU frequency to get the time and multiply with table scale */
    Raw /= (CPU_FREQ / 10000);
    Value = Raw;                          /* take raw value */

    /* take care about zero offset if feasable */
    if (Scale == -12)                     /* pF scale */
    {
      if (Value >= NV.CapZero)            /* if value is larger than offset */
      {
        Value -= NV.CapZero;              /* substract offset */
      }
      else                                /* if value is smaller than offset */
      {
        /* we have to prevent a negative value */
        Value = 0;                        /* set value to 0 */
      }
    }

    /* copy data */
    Cap->A = Probes.Pin_2;    /* pull-down probe pin */
    Cap->B = Probes.Pin_1;    /* pull-up probe pin */
    Cap->Scale = Scale;       /* -12 or -9 */
    Cap->Raw = Raw;
    Cap->Value = Value;       /* max. 5.1*10^6pF or 125*10^3nF */


    /*
     *  Self-adjust the voltage offset of the analog comparator and internal
     *  bandgap reference if C is 100nF up to 20µF. The minimum of 100nF
     *  should keep the voltage stable long enough for the measurements. 
     *  Changed offsets will be used in next test run.
     */

    if (((Scale == -12) && (Value >= 100000)) ||
        ((Scale == -9) && (Value <= 20000)))
    {
      int16_t         Offset;
      int32_t         TempLong;

      /*
       *  We can self-adjust the offset of the internal bandgap reference
       *  by measuring a voltage lower than the bandgap reference, one time
       *  with the bandgap as reference and a second time with Vcc as
       *  reference. The common voltage source is the cap we just measured.
       */

       while (ReadU(Probes.Pin_1) > 980)
       {
         /* keep discharging */
       }

       R_DDR = 0;                       /* stop discharging */

       Config.AutoScale = 0;            /* disable auto scaling */
       Ticks = ReadU(Probes.Pin_1);     /* U_c with Vcc reference */
       Config.AutoScale = 1;            /* enable auto scaling again */
       Ticks2 = ReadU(Probes.Pin_1);    /* U_c with bandgap reference */

       R_DDR = Probes.Rh_1;             /* resume discharging */

       Offset = Ticks - Ticks2;
       /* allow some offset caused by the different voltage resolutions
          (4.88 vs. 1.07) */
       if ((Offset < -4) || (Offset > 4))    /* offset too large */
       {
         /*
          *  Calculate total offset:
          *  - first get offset per mV: Offset / U_c
          *  - total offset for U_ref: (Offset / U_c) * U_ref
          */

         TempLong = Offset;
         TempLong *= Config.Bandgap;         /* * U_ref */
         TempLong /= Ticks2;                 /* / U_c */

         NV.RefOffset = (int8_t)TempLong;
       }


      /*
       *  In the cap measurement above the analog comparator compared
       *  the voltages of the cap and the bandgap reference. Since the MCU
       *  has an internal voltage drop for the bandgap reference the
       *  MCU used actually U_bandgap - U_offset. We get that offset by
       *  comparing the bandgap reference with the voltage of the cap:
       *  U_c = U_bandgap - U_offset -> U_offset = U_c - U_bandgap
       */

      Offset = U_c - Config.Bandgap;

      /* limit offset to a valid range of -50mV - 50mV */
      if ((Offset > -50) && (Offset < 50)) NV.CompOffset = Offset;
    }
  }

  return Flag;
}
Пример #5
0
uint8_t SelfTest(void)
{
    uint8_t           Flag = 0;           /* return value */
    uint8_t           Test = 1;           /* test counter */
    uint8_t           Counter;            /* loop counter */
    uint8_t           DisplayFlag;        /* display flag */
    uint16_t          Val0;               /* voltage/value */
    int16_t           Val1 = 0, Val2 = 0, Val3 = 0;   /* voltages/values */

    /* make sure all probes are shorted */
    Counter = ShortCircuit(1);
    if (Counter == 0) Test = 10;     /* skip selftest */

    /* loop through all tests */
    while (Test <= 6)
    {
        Counter = 1;

        /* repeat each test 5 times */
        while (Counter <= 5)
        {
            /* display test number */
            LCD_Clear();
            LCD_Char('T');                    /* display: T */
            LCD_Char('0' + Test);             /* display test number */
            LCD_Space();

            DisplayFlag = 1;                  /* display values by default */

            /*
             *  tests
             */

            switch (Test)
            {
            case 1:     /* reference voltage */
                Val0 = ReadU(0x0e);           /* dummy read for bandgap stabilization */
                Val0 = ReadU(0x0e);           /* read bandgap reference voltage */
                LCD_EEString(URef_str);       /* display: Vref */

                LCD_NextLine();
                DisplayValue(Val0, -3, 'V');       /* display voltage in mV */

                DisplayFlag = 0;                   /* reset flag */
                break;

            case 2:     /* compare Rl resistors (probes still shorted) */
                LCD_EEString_Space(Rl_str);     /* display: +Rl- */
                LCD_EEString(ProbeComb_str);    /* display: 12 13 23 */

                /* set up a voltage divider with the Rl's */
                /* substract theoretical voltage of voltage divider */

                /* TP1: Gnd -- Rl -- probe-2 -- probe-1 -- Rl -- Vcc */
                R_PORT = 1 << (TP1 * 2);
                R_DDR = (1 << (TP1 * 2)) | (1 << (TP2 * 2));
                Val1 = ReadU_20ms(TP3);
                Val1 -= ((int32_t)Config.Vcc * (R_MCU_LOW + R_LOW)) / (R_MCU_LOW + R_LOW + R_LOW + R_MCU_HIGH);

                /* TP1: Gnd -- Rl -- probe-3 -- probe-1 -- Rl -- Vcc */
                R_DDR = (1 << (TP1 * 2)) | (1 << (TP3 * 2));
                Val2 = ReadU_20ms(TP2);
                Val2 -= ((int32_t)Config.Vcc * (R_MCU_LOW + R_LOW)) / (R_MCU_LOW + R_LOW + R_LOW + R_MCU_HIGH);

                /* TP1: Gnd -- Rl -- probe-3 -- probe-2 -- Rl -- Vcc */
                R_PORT = 1 << (TP2 * 2);
                R_DDR = (1 << (TP2 * 2)) | (1 << (TP3 * 2));
                Val3 = ReadU_20ms(TP2);
                Val3 -= ((int32_t)Config.Vcc * (R_MCU_LOW + R_LOW)) / (R_MCU_LOW + R_LOW + R_LOW + R_MCU_HIGH);

                break;

            case 3:     /* compare Rh resistors (probes still shorted) */
                LCD_EEString_Space(Rh_str);     /* display: +Rh- */
                LCD_EEString(ProbeComb_str);    /* display: 12 13 23 */

                /* set up a voltage divider with the Rh's */

                /* TP1: Gnd -- Rh -- probe-2 -- probe-1 -- Rh -- Vcc */
                R_PORT = 2 << (TP1 * 2);
                R_DDR = (2 << (TP1 * 2)) | (2 << (TP2 * 2));
                Val1 = ReadU_20ms(TP3);
                Val1 -= (Config.Vcc / 2);

                /* TP1: Gnd -- Rh -- probe-3 -- probe-1 -- Rh -- Vcc */
                R_DDR = (2 << (TP1 * 2)) | (2 << (TP3 * 2));
                Val2 = ReadU_20ms(TP2);
                Val2 -= (Config.Vcc / 2);

                /* TP1: Gnd -- Rh -- probe-3 -- probe-2 -- Rh -- Vcc */
                R_PORT = 2 << (TP2 * 2);
                R_DDR = (2 << (TP2 * 2)) | (2 << (TP3 * 2));
                Val3 = ReadU_20ms(TP1);
                Val3 -= (Config.Vcc / 2);

                break;

            case 4:     /* un-short probes */
                ShortCircuit(0);         /* make sure probes are not shorted */
                Counter = 100;           /* skip test */
                DisplayFlag = 0;         /* reset flag */
                break;

            case 5:     /* Rh resistors pulled down */
                LCD_EEString(RhLow_str);      /* display: Rh- */

                /* TP1: Gnd -- Rh -- probe */
                R_PORT = 0;
                R_DDR = 2 << (TP1 * 2);
                Val1 = ReadU_20ms(TP1);

                /* TP1: Gnd -- Rh -- probe */
                R_DDR = 2 << (TP2 * 2);
                Val2 = ReadU_20ms(TP2);

                /* TP1: Gnd -- Rh -- probe */
                R_DDR = 2 << (TP3 * 2);
                Val3 = ReadU_20ms(TP3);

                break;

            case 6:     /* Rh resistors pulled up */
                LCD_EEString(RhHigh_str);     /* display: Rh+ */

                /* TP1: probe -- Rh -- Vcc */
                R_DDR = 2 << (TP1 * 2);
                R_PORT = 2 << (TP1 * 2);
                Val1 = ReadU_20ms(TP1);

                /* TP1: probe -- Rh -- Vcc */
                R_DDR = 2 << (TP2 * 2);
                R_PORT = 2 << (TP2 * 2);
                Val2 = ReadU_20ms(TP2);

                /* TP1: probe -- Rh -- Vcc */
                R_DDR = 2 << (TP3 * 2);
                R_PORT = 2 << (TP3 * 2);
                Val3 = ReadU_20ms(TP3);

                break;
            }

            /* reset ports to defaults */
            R_DDR = 0;                             /* input mode */
            R_PORT = 0;                            /* all pins low */

            /* display voltages/values of all probes */
            if (DisplayFlag)
            {
                LCD_NextLine();                      /* move to line #2 */
                DisplaySignedValue(Val1, 0 , 0);     /* display TP1 */
                LCD_Space();
                DisplaySignedValue(Val2, 0 , 0);     /* display TP2 */
                LCD_Space();
                DisplaySignedValue(Val3, 0 , 0);     /* display TP3 */
            }

            /* wait and check test push button */
            if (Counter < 100)                     /* when we don't skip this test */
            {
                DisplayFlag = TestKey(1000, 0);      /* catch key press or timeout */

                /* short press -> next test / long press -> end selftest */
                if (DisplayFlag > 0)
                {
                    Counter = 100;                       /* skip current test anyway */
                    if (DisplayFlag == 2) Test = 100;    /* also skip selftest */
                }
            }

            Counter++;                        /* next run */
        }

        Test++;                             /* next one */
    }

    Flag = 1;         /* signal success */
    return Flag;
}