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; }
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; }
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; }
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; }
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; }