void AutoCheck(uint8_t test_mode) { /* (test_mode & 0x0f) == 0 , only calibration without T1-T7 */ /* (test_mode & 0x0f) == 1 , calibration and additional T1-T7 */ /* (test_mode & 0xf0) == 0 , check for shorted probes, if unshorted, return */ /* (test_mode & 0xf0) == 0x10 , ask for shorted probes */ uint8_t ww; // counter for repeating the tests int adcmv[7]; #ifdef EXTENDED_TESTS uint16_t u680; // 3 * (Voltage at 680 Ohm) uint8_t taste; // ist key pressed? 0 = no #else #ifndef NO_TEST_T1_T7 #warning "Selftest without extended tests T1 to T7!" #endif #endif #if defined(EXTENDED_TESTS) || defined(WITH_MENU) uint8_t tt; // number of running test #endif #ifdef FREQUENCY_50HZ uint8_t ff50; // loop counter for 2s #endif // define the maximum count of repetitions MAX_REP #define MAX_REP 4 #ifdef AUTO_CAL uint8_t cap_found; // counter for found capacitor #ifdef AUTOSCALE_ADC int8_t udiff; // difference between ADC Voltage with VCC or Bandgap reference int8_t udiff2; #endif #endif PartFound = PART_NONE; // no part found before if ((test_mode & 0xf0) == 0) { // probed should be shorted already to begin selftest if (AllProbesShorted() != 3) return; lcd_clear(); lcd_MEM_string(SELFTEST); // "Selftest mode.." lcd_line2(); lcd_data('?'); // wait for key pressed for confirmation if (wait_for_key_ms(2000) > 10) goto begin_selftest; // key is pressed again #ifdef WITH_MENU } else { // report to user, that probes should be shorted ww = 0; for (tt=0;tt<150;tt++) { /* wait about 30 seconds for shorted probes */ lcd_clear(); lcd_MEM2_string(SHORT_PROBES_str); // message "Short probes!" to LCD if (AllProbesShorted() == 3) { ww++; // all probes now shorted } else { ww = 0; // connection not stable, retry } if (ww > 3) break; // connection seems to be stable lcd_refresh(); // write the pixels to display, ST7920 only wait_about200ms(); // wait 200ms and try again } /* end for (tt...) */ if (tt < 150) goto begin_selftest; // is shorted before time limit goto no_zero_resistance; // skip measuring of the zero resistance #endif } // no key pressed for 2s lcd_clear(); lcd_MEM_string(VERSION_str); //"Version ..." return; begin_selftest: lcd_line2(); lcd_MEM2_string(R0_str); // "R0=" eeprom_write_byte((uint8_t *)(&EE_ESR_ZEROtab[2]), (uint8_t)0); // clear zero offset eeprom_write_byte((uint8_t *)(&EE_ESR_ZEROtab[3]), (uint8_t)0); // clear zero offset eeprom_write_byte((uint8_t *)(&EE_ESR_ZEROtab[1]), (uint8_t)0); // clear zero offset adcmv[0] = GetESR(TP3, TP1); adcmv[1] = GetESR(TP3, TP2); adcmv[2] = GetESR(TP2, TP1); DisplayValue16(adcmv[0],-2,' ',3); DisplayValue16(adcmv[1],-2,' ',3); DisplayValue16(adcmv[2],-2,LCD_CHAR_OMEGA,3); if (adcmv[0] >= 90) { adcmv[0] = ESR_ZERO; // set back to default value } eeprom_write_byte((uint8_t *)(&EE_ESR_ZEROtab[2]), (uint8_t)adcmv[0]); // fix zero offset if (adcmv[1] >= 90) { adcmv[1] = ESR_ZERO; // set back to default value } eeprom_write_byte((uint8_t *)(&EE_ESR_ZEROtab[3]), (uint8_t)adcmv[1]); // fix zero offset if (adcmv[2] >= 90) { adcmv[2] = ESR_ZERO; // set back to default value } eeprom_write_byte((uint8_t *)(&EE_ESR_ZEROtab[1]), (uint8_t)adcmv[2]); // fix zero offset last_line_used = 2; wait_for_key_5s_line2(); // wait up to 5 seconds and clear line 2 #ifdef WITH_MENU no_zero_resistance: #endif #ifdef EXTENDED_TESTS #define TEST_COUNT 8 if((test_mode & 0x0f) == 1) { /* full test requested */ for(tt=1;tt<TEST_COUNT;tt++) { // loop for all Tests for(ww=0;ww<MAX_REP;ww++) { // repeat the test MAX_REP times lcd_clear_line2(); // clear total line 2 lcd_clear_line1(); // clear total line 1 lcd_data('T'); //output the Testmode "T" u2lcd(tt); //lcd_string(utoa(tt, outval, 10)); //output Test number lcd_space(); //############################################ if (tt == 1) { // output of reference voltage and factors for capacity measurement lcd_MEM2_string(URef_str); //"URef=" Calibrate_UR(); // get Reference voltage, Pin resistance Display_mV(ref_mv,4); lcd_line2(); //Cursor to column 1, row 2 lcd_MEM2_string(RHfakt_str); //"RHf=" u2lcd(RHmultip); //lcd_string(utoa(RHmultip, outval, 10)); ADCconfig.Samples = R_ANZ_MESS; // set number of ADC reads near to maximum } //############################################ if (tt == 2) { // how equal are the RL resistors? u680 = ((long)ADCconfig.U_AVCC * (PIN_RM + R_L_VAL) / (PIN_RM + R_L_VAL + R_L_VAL + PIN_RP)); R_PORT = 1<<PIN_RL1; //RL1 to VCC R_DDR = (1<<PIN_RL1) | (1<<PIN_RL2); //RL2 to - adcmv[0] = W20msReadADC(TP1); adcmv[0] -= u680; R_DDR = (1<<PIN_RL1) | (1<<PIN_RL3); //RL3 to - adcmv[1] = W20msReadADC(TP1); adcmv[1] -= u680; R_PORT = 1<<PIN_RL2; //RL2 to VCC R_DDR = (1<<PIN_RL2) | (1<<PIN_RL3); //RL3 to - adcmv[2] = W20msReadADC(TP2); adcmv[2] -= u680; lcd_MEM_string(RLRL_str); // "RLRL" } //############################################ if (tt == 3) { // how equal are the RH resistors R_PORT = 1<<PIN_RH1; //RH1 to VCC R_DDR = (1<<PIN_RH1) | (1<<PIN_RH2); //RH2 to - adcmv[0] = W20msReadADC(TP1); adcmv[3] = ADCconfig.U_AVCC / 2; adcmv[0] -= adcmv[3]; R_DDR = (1<<PIN_RH1) | (1<<PIN_RH3); //RH3 to - adcmv[1] = W20msReadADC(TP1); adcmv[1] -= adcmv[3]; R_PORT = 1<<PIN_RH2; //RH2 to VCC R_DDR = (1<<PIN_RH2) | (1<<PIN_RH3); //RH3 to - adcmv[2] = W20msReadADC(TP2); adcmv[2] -= adcmv[3]; lcd_MEM_string(RHRH_str); // "RHRH" } //############################################ if (tt == 4) { // Text release probes lcd_MEM_string(RELPROBE); // "Release Probes" if (AllProbesShorted() != 0) ww = MAX_REP-2; } //############################################ if (tt == 5) { // can we switch the ADC pins to GND across R_H resistor? R_PORT = 0; R_DDR = 1<<PIN_RH1; //Pin 1 over R_H to GND adcmv[0] = W20msReadADC(TP1); R_DDR = 1<<PIN_RH2; //Pin 2 over R_H to GND adcmv[1] = W20msReadADC(TP2); R_DDR = 1<<PIN_RH3; //Pin 3 over R_H to GND adcmv[2] = W20msReadADC(TP3); lcd_MEM_string(RH1L_str); // "RH_Lo=" } //############################################ if (tt == 6) { // can we switch the ADC pins to VCC across the R_H resistor? R_DDR = 1<<PIN_RH1; //Pin 1 over R_H to VCC R_PORT = 1<<PIN_RH1; adcmv[0] = W20msReadADC(TP1) - ADCconfig.U_AVCC; R_DDR = 1<<PIN_RH2; //Pin 2 over R_H to VCC R_PORT = 1<<PIN_RH2; adcmv[1] = W20msReadADC(TP2) - ADCconfig.U_AVCC; R_DDR = 1<<PIN_RH3; //Pin 3 over R_H to VCC R_PORT = 1<<PIN_RH3; adcmv[2] = W20msReadADC(TP3) - ADCconfig.U_AVCC; lcd_MEM_string(RH1H_str); // "RH_Hi=" } if (tt == 7) { // is the voltage of all R_H / R_L dividers correct? u680 = ((long)ADCconfig.U_AVCC * (PIN_RM + R_L_VAL) / (PIN_RM + R_L_VAL + (unsigned long)R_H_VAL*100)); R_PORT = 1<<PIN_RH1; //RH1 to VCC R_DDR = (1<<PIN_RH1) | (1<<PIN_RL1); //RH1 to +, RL1 to - adcmv[0] = W20msReadADC(TP1); adcmv[0] -= u680; R_PORT = 1<<PIN_RH2; //RH2 to VCC R_DDR = (1<<PIN_RH2) | (1<<PIN_RL2); //RH2 to +, RL2 to - adcmv[1] = W20msReadADC(TP2); adcmv[1] -= u680; R_PORT = 1<<PIN_RH3; //RH3 to VCC R_DDR = (1<<PIN_RH3) | (1<<PIN_RL3); //RH3 to +, RL3 to - adcmv[2] = W20msReadADC(TP3); adcmv[2] -= u680; lcd_MEM_string(RHRL_str); // "RH/RL" } //############################################ if (tt > 1) { // output 3 voltages lcd_line2(); //Cursor to column 1, row 2 i2lcd(adcmv[0]); // lcd_string(itoa(adcmv[0], outval, 10)); //output voltage 1 lcd_space(); i2lcd(adcmv[1]); // lcd_string(itoa(adcmv[1], outval, 10)); //output voltage 2 lcd_space(); i2lcd(adcmv[2]); // lcd_string(itoa(adcmv[2], outval, 10)); //output voltage 3 } ADC_DDR = TXD_MSK; // all-Pins to Input ADC_PORT = TXD_VAL; // all ADC-Ports to GND R_DDR = 0; // all R-Ports to Input R_PORT = 0; taste = wait_for_key_ms(1000); // wait up to 1 second or key is pressed if ((tt != 4) && (taste > 10)) { // don't finish repetition for T4 with pressed key break; // if key is pressed, don't repeat } } //end for ww wait_for_key_ms(1000); // wait up to 1 second or key is pressed } //end for tt #if PROCESSOR_TYP == 1280 lcd_clear(); lcd_testpin(TP1); lcd_data('L'); lcd_equal(); // lcd_data('='); ADC_PORT = TXD_VAL; ADC_DDR = (1<<TP1) | TXD_MSK; R_PORT = (1<<PIN_RL1); R_DDR = (1<<PIN_RL1); adcmv[0] = W5msReadADC(TP1); ADCSRB = (1<<MUX5); // switch to upper 8 MUX inputs adcmv[1] = ReadADC(PIN_RL1); ADCSRB = 0; // switch back to lower 8 MUX inputs ResistorVal[0] = (adcmv[0] * (unsigned long)R_L_VAL) / (adcmv[1] - adcmv[0]); DisplayValue(ResistorVal[0],-1,LCD_CHAR_OMEGA,3); lcd_space(); lcd_data('H'); lcd_equal(); // lcd_data('='); ResistorVal[1] = ((ADCconfig.U_AVCC - adcmv[1]) * (unsigned long)R_L_VAL) / (adcmv[1] - adcmv[0]); DisplayValue(ResistorVal[1],-1,LCD_CHAR_OMEGA,3); lcd_line2(); lcd_testpin(TP1); lcd_space(); lcd_data('H'); lcd_equal(); // lcd_data('='); ADC_PORT = (1<<TP1) | TXD_VAL; R_PORT = 0; adcmv[0] = W5msReadADC(TP1); ADCSRB = (1<<MUX5); // switch to upper 8 MUX inputs adcmv[1] = ReadADC(PIN_RL1); ADCSRB = 0; // switch back to lower 8 MUX inputs ResistorVal[1] = ((ADCconfig.U_AVCC - adcmv[0]) * (unsigned long)R_L_VAL) / (adcmv[0] - adcmv[1]); DisplayValue(ResistorVal[1],-1,LCD_CHAR_OMEGA,3); lcd_space(); lcd_data('L'); lcd_equal(); // lcd_data('='); ResistorVal[0] = (adcmv[1] * (unsigned long)R_L_VAL) / (adcmv[0] - adcmv[1]); DisplayValue(ResistorVal[0],-1,LCD_CHAR_OMEGA,3); wait_about1s(); // only for mega1280 last_line_used = 2; wait_for_key_5s_line2(); // wait up to 5 seconds and clear line 2 // lcd_clear(); lcd_testpin(TP2); lcd_data('L'); lcd_equal(); // lcd_data('='); ADC_PORT = TXD_VAL; ADC_DDR = (1<<TP2) | TXD_MSK; R_PORT = (1<<PIN_RL2); R_DDR = (1<<PIN_RL2); adcmv[0] = W5msReadADC(TP2); ADCSRB = (1<<MUX5); // switch to upper 8 MUX inputs adcmv[1] = ReadADC(PIN_RL2); ADCSRB = 0; // switch back to lower 8 MUX inputs ResistorVal[0] = (adcmv[0] * (unsigned long)R_L_VAL) / (adcmv[1] - adcmv[0]); DisplayValue(ResistorVal[0],-1,LCD_CHAR_OMEGA,3); lcd_space(); lcd_data('H'); lcd_equal(); // lcd_data('='); ResistorVal[1] = ((ADCconfig.U_AVCC - adcmv[1]) * (unsigned long)R_L_VAL) / (adcmv[1] - adcmv[0]); DisplayValue(ResistorVal[1],-1,LCD_CHAR_OMEGA,3); lcd_line2(); lcd_testpin(TP2); lcd_data('H'); lcd_equal(); // lcd_data('='); ADC_PORT = (1<<TP2) | TXD_VAL; R_PORT = 0; adcmv[0] = W5msReadADC(TP2); ADCSRB = (1<<MUX5); // switch to upper 8 MUX inputs adcmv[1] = ReadADC(PIN_RL2); ADCSRB = 0; // switch back to lower 8 MUX inputs ResistorVal[1] = ((ADCconfig.U_AVCC - adcmv[0]) * (unsigned long)R_L_VAL) / (adcmv[0] - adcmv[1]); DisplayValue(ResistorVal[1],-1,LCD_CHAR_OMEGA,3); lcd_space(); lcd_data('L'); lcd_equal(); // lcd_data('='); ResistorVal[0] = (adcmv[1] * (unsigned long)R_L_VAL) / (adcmv[0] - adcmv[1]); DisplayValue(ResistorVal[0],-1,LCD_CHAR_OMEGA,3); wait_about1s(); // only for mega1280 last_line_used = 2; wait_for_key_5s_line2(); // wait up to 5 seconds and clear line 2 // lcd_clear(); lcd_testpin(TP3); lcd_data('L'); lcd_equal(); // lcd_data('='); ADC_DDR = (1<<TP3) | TXD_MSK; R_PORT = (1<<PIN_RL3); R_DDR = (1<<PIN_RL3); adcmv[0] = W5msReadADC(TP3); ADCSRB = (1<<MUX5); // switch to upper 8 MUX inputs adcmv[1] = ReadADC(PIN_RL3); ADCSRB = 0; ResistorVal[0] = (adcmv[0] * (unsigned long)R_L_VAL) / (adcmv[1] - adcmv[0]); DisplayValue(ResistorVal[0],-1,LCD_CHAR_OMEGA,3); lcd_space(); lcd_data('H'); lcd_equal(); // lcd_data('='); ResistorVal[1] = ((ADCconfig.U_AVCC - adcmv[1]) * (unsigned long)R_L_VAL) / (adcmv[1] - adcmv[0]); DisplayValue(ResistorVal[1],-1,LCD_CHAR_OMEGA,3); lcd_line2(); lcd_testpin(TP3); lcd_data('H'); lcd_equal(); // lcd_data('='); ADC_PORT = (1<<TP3) | TXD_VAL; R_PORT = 0; adcmv[0] = W5msReadADC(TP3); ADCSRB = (1<<MUX5); // switch to upper 8 MUX inputs adcmv[1] = ReadADC(PIN_RL3); ADCSRB = 0; // switch back to lower 8 MUX inputs ResistorVal[1] = ((ADCconfig.U_AVCC - adcmv[0]) * (unsigned long)R_L_VAL) / (adcmv[0] - adcmv[1]); DisplayValue(ResistorVal[1],-1,LCD_CHAR_OMEGA,3); lcd_space(); lcd_data('L'); lcd_equal(); // lcd_data('='); ResistorVal[0] = (adcmv[1] * (unsigned long)R_L_VAL) / (adcmv[0] - adcmv[1]); DisplayValue(ResistorVal[0],-1,LCD_CHAR_OMEGA,3); wait_about1s(); // only for mega1280 last_line_used = 2; wait_for_key_5s_line2(); // wait up to 5 seconds and clear line 2 #endif /* PROCESSOR_TYP == 1280 */ } /* end if((test_mode & 0x0f) == 1) */ #endif /* end EXTENDED_TESTS */ for (ww=0;ww<120;ww++) { // wait up to 1 minute for releasing the probes if (AllProbesShorted() == 0) break; lcd_clear_line2(); // clear total line2 lcd_MEM_string(RELPROBE); // "Release Probes" lcd_refresh(); // write the pixels to display, ST7920 only wait_about500ms(); } lcd_clear(); lcd_MEM_string(RIHI_str); // "RiHi=" DisplayValue16(RRpinPL,-1,LCD_CHAR_OMEGA,3); lcd_line2(); lcd_MEM_string(RILO_str); // "RiLo=" DisplayValue16(RRpinMI,-1,LCD_CHAR_OMEGA,3); last_line_used = 2; wait_for_key_5s_line2(); // wait up to 5 seconds and clear line 2 //measure Zero offset for Capacity measurement PartFound = PART_NONE; lcd_clear(); lcd_MEM_string(C0_str); //output "C0 " ReadCapacity(TP3, TP1); adcmv[5] = (unsigned int) cap.cval_uncorrected.dw; //save capacity value of empty Pin 1:3 ReadCapacity(TP3, TP2); adcmv[6] = (unsigned int) cap.cval_uncorrected.dw; //save capacity value of empty Pin 2:3 ReadCapacity(TP2, TP1); adcmv[2] = (unsigned int) cap.cval_uncorrected.dw; //save capacity value of empty Pin 1:2 ReadCapacity(TP1, TP3); adcmv[1] = (unsigned int) cap.cval_uncorrected.dw; //save capacity value of empty Pin 3:1 ReadCapacity(TP2, TP3); adcmv[4] = (unsigned int) cap.cval_uncorrected.dw; //save capacity value of empty Pin 3:2 ReadCapacity(TP1, TP2); adcmv[0] = (unsigned int) cap.cval_uncorrected.dw; //save capacity value of empty Pin 2:1 #ifdef WITH_MENU if (((test_mode & 0x0f) == 1) || (UnCalibrated == 2)) #else if (UnCalibrated == 2) #endif { adcmv[3] = adcmv[0] + 2; // mark as uncalibrated until Cap > 100nF has success } else { adcmv[3] = adcmv[0]; // mark as calibrated, short calibration is finished UnCalibrated = 0; // clear the UnCalibrated Flag lcd_cursor_off(); // switch cursor off } u2lcd_space(adcmv[5]); //DisplayValue(adcmv[5],0,' ',3); //output cap0 1:3 u2lcd_space(adcmv[6]); //DisplayValue(adcmv[6],0,' ',3); //output cap0 2:3 DisplayValue(adcmv[2],-12,'F',3); //output cap0 1:2 #ifdef AUTO_CAL for (ww=0;ww<7;ww++) { //checking loop if ((adcmv[ww] > 190) || (adcmv[ww] < 10)) goto no_c0save; } for (ww=0;ww<7;ww++) { // write all zero offsets to the EEprom (void) eeprom_write_byte((uint8_t *)(&c_zero_tab[ww]),adcmv[ww]+(COMP_SLEW1 / (CC0 + CABLE_CAP + COMP_SLEW2))); } lcd_line2(); lcd_MEM_string(OK_str); // output "OK" no_c0save: #endif last_line_used = 2; wait_for_key_5s_line2(); // wait up to 5 seconds and clear line 2 #ifdef SamplingADC sampling_cap_calibrate(); // measure zero capacity for samplingADC #endif #ifdef AUTO_CAL #ifdef WITH_MENU if (((test_mode & 0x0f) == 1) || (UnCalibrated == 2)) #endif // without menu function the capacitor is requested every time, // because there is no way to request recaltbration again // With menu function the capacitor is only requested for first time // calibration (UnCalibrated = 2) or for the full selftest call (test_mode = 1) // of the menu function, not with the automatically call (test_mode = 1). { // for full test or first time calibration, use external capacitor // Message C > 100nF at TP1 and TP3 cap_found = 0; for (ww=0;ww<64;ww++) { init_parts(); #if (TPCAP >= 0) CalibrationCap(); // measure with internal calibration capacitor #else lcd_clear(); lcd_testpin(TP1); lcd_MEM_string(CapZeich); // "-||-" lcd_testpin(TP3); lcd_MEM2_string(MinCap_str); // " >100nF!" PartFound = PART_NONE; ReadCapacity(TP3, TP1); // look for capacitor > 100nF #endif while (cap.cpre < -9) { cap.cpre++; cap.cval /= 10; } if ((cap.cpre == -9) && (cap.cval > 95) && (cap.cval < 22000) && (load_diff > -150) && (load_diff < 150)) { cap_found++; } else { cap_found = 0; // wait for stable connection } if (cap_found > 4) { // value of capacitor is correct (void) eeprom_write_word((uint16_t *)(&ref_offset), load_diff); // hold zero offset + slew rate dependend offset lcd_clear(); lcd_MEM2_string(REF_C_str); // "REF_C=" i2lcd(load_diff); // lcd_string(itoa(load_diff, outval, 10)); //output REF_C_KORR RefVoltage(); // new ref_mv_offs and RHmultip #if 0 //####################################### // Test for switching level of the digital input of port TP3 for (tt=0;tt<8;tt++) { ADC_PORT = TXD_VAL; //ADC-Port 1 to GND ADC_DDR = 1<<TP1 | TXD_MSK; //ADC-Pin 1 to output 0V R_PORT = 1<<PIN_RH3; //Pin 3 over R_H to VCC R_DDR = 1<<PIN_RH3; //Pin 3 over R_H to VCC while (1) { wdt_reset(); if ((ADC_PIN&(1<<TP3)) == (1<<TP3)) break; } R_DDR = 0; //Pin 3 without current R_PORT = 0; adcmv[0] = ReadADC(TP3); lcd_line3(); Display_mV(adcmv[0],4); R_DDR = 1<<PIN_RH3; //Pin 3 over R_H to GND while (1) { wdt_reset(); if ((ADC_PIN&(1<<TP3)) != (1<<TP3)) break; } R_DDR = 0; //Pin 3 without current lcd_line4(); adcmv[0] = ReadADC(TP3); Display_mV(adcmv[0],4); last_line_used = 2; wait_for_key_5s_line2(); // wait up to 5 seconds and clear line 2 } //####################################### #endif #ifdef AUTOSCALE_ADC #if (TPCAP >= 0) #define CAP_ADC TPCAP /* Cap >100nF is integrated at TPCAP */ TCAP_PORT &= ~(1<<TCAP_RH); // 470k resistor to GND TCAP_DDR |= (1<<TCAP_RH); // enable output #else #define CAP_ADC TP3 /* Cap >100nF at TP3 */ ADC_PORT = TXD_VAL; //ADC-Port 1 to GND ADC_DDR = 1<<TP1 | TXD_MSK; //ADC-Pin 1 to output 0V R_DDR = 1<<PIN_RH3; //Pin 3 over R_H to GND #endif do { adcmv[0] = ReadADC(CAP_ADC); } while (adcmv[0] > 980); #if (TPCAP >= 0) TCAP_DDR &= ~(1<<TCAP_RH); // 470k resistor port to input mode #else R_DDR = 0; //all Pins to input #endif ADCconfig.U_Bandgap = 0; // do not use internal Ref adcmv[0] = ReadADC(CAP_ADC); // get cap voltage with VCC reference ADCconfig.U_Bandgap = adc_internal_reference; adcmv[1] = ReadADC(CAP_ADC); // get cap voltage with internal reference adcmv[1] += adcmv[1]; // double the value ADCconfig.U_Bandgap = 0; // do not use internal Ref adcmv[2] = ReadADC(CAP_ADC); // get cap voltage with VCC reference ADCconfig.U_Bandgap = adc_internal_reference; udiff = (int8_t)(((signed long)(adcmv[0] + adcmv[2] - adcmv[1])) * adc_internal_reference / adcmv[1])+REF_R_KORR; lcd_line2(); lcd_MEM2_string(REF_R_str); // "REF_R=" udiff2 = udiff + (int8_t)eeprom_read_byte((uint8_t *)(&RefDiff)); (void) eeprom_write_byte((uint8_t *)(&RefDiff), (uint8_t)udiff2); // hold offset for true reference Voltage i2lcd(udiff2); // output correction voltage RefVoltage(); // set new ADCconfig.U_Bandgap #endif /* end AUTOSCALE_ADC */ last_line_used = 2; wait_for_key_5s_line2(); // wait up to 5 seconds and clear line 2 UnCalibrated = 0; // clear the UnCalibrated Flag lcd_cursor_off(); // switch cursor off cap_found = eeprom_read_byte((uint8_t *)&c_zero_tab[0]); // read first capacity zero offset eeprom_write_byte((uint8_t *)&c_zero_tab[3], cap_found); // mark as calibrated permanent break; // leave the ww for loop } /* end if (cap_found > 4) */ lcd_line2(); DisplayValue(cap.cval,cap.cpre,'F',4); lcd_refresh(); // write the pixels to display, ST7920 only wait_about200ms(); // wait additional time } // end for ww } /* end if((test_mode & 0x0f) == 1) */ #endif /* end AUTO_CAL */ ADCconfig.Samples = ANZ_MESS; // set to configured number of ADC samples #ifdef SamplingADC sampling_lc_calibrate(); // Cap for L-meas #endif #ifdef FREQUENCY_50HZ //#define TEST_SLEEP_MODE /* only select for checking the sleep delay */ lcd_clear(); lcd_MEM_string(T50HZ); //" 50Hz" lcd_refresh(); // write the pixels to display, ST7920 only ADC_PORT = TXD_VAL; ADC_DDR = 1<<TP1 | TXD_MSK; // Pin 1 to GND R_DDR = (1<<PIN_RL3) | (1<<PIN_RL2); for(ww=0;ww<30;ww++) { // repeat the signal up to 30 times (1 minute) for (ff50=0;ff50<100;ff50++) { // for 2 s generate 50 Hz R_PORT = (1<<PIN_RL2); // Pin 2 over R_L to VCC, Pin 3 over R_L to GND #ifdef TEST_SLEEP_MODE sleep_5ms(2); // test of timing of sleep mode call #else wait10ms(); // normal delay #endif R_PORT = (1<<PIN_RL3); // Pin 3 over R_L to VCC, Pin 2 over R_L to GND #ifdef TEST_SLEEP_MODE sleep_5ms(2); // test of timing of sleep mode call #else wait10ms(); // normal delay #endif wdt_reset(); } /* end for ff50 */ if (!(RST_PIN_REG & (1<<RST_PIN))) { // if key is pressed, don't repeat break; } } /* end for ww */ #endif /* end FREQUENCY_50HZ */ lcd_clear(); lcd_MEM_string(VERSION_str); //"Version ..." lcd_line2(); lcd_MEM_string(ATE); //"Selftest End" PartFound = PART_NONE; last_line_used = 2; wait_for_key_5s_line2(); // wait up to 5 seconds and clear line 2 } /* end AutoCheck */
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 }