//================================================================= void ReadInductance(void) { #if FLASHEND > 0x1fff // check if inductor and measure the inductance value unsigned int tmpint; unsigned int umax; unsigned int total_r; // total resistance of current loop unsigned int mess_r; // value of resistor used for current measurement unsigned long inductance[4]; // four inductance values for different measurements union t_combi{ unsigned long dw; // time_constant uint16_t w[2]; } timeconstant; uint16_t per_ref1,per_ref2; // percentage uint8_t LoPinR_L; // Mask for switching R_L resistor of low pin uint8_t HiADC; // Mask for switching the high pin direct to VCC uint8_t ii; uint8_t count; // counter for the different measurements uint8_t cnt_diff; // resistance dependent offset uint8_t LowPin; // number of pin with low voltage uint8_t HighPin; // number of pin with high voltage int8_t ukorr; // correction of comparator voltage uint8_t nr_pol1; // number of successfull inductance measurement with polarity 1 uint8_t nr_pol2; // number of successfull inductance measurement with polarity 2 inductor_lpre = 0; // H units, mark inductor as 0 if(PartFound != PART_RESISTOR) { return; //We have found no resistor } if (ResistorsFound != 1) { return; // do not search for inductance, more than 1 resistor } if (resis[0].rx > 21000) return; // we can check for Inductance, if resistance is below 2100 Ohm for (count=0;count<4;count++) { // Try four times (different direction and with delayed counter start) if (count < 2) { // first and second pass, direction 1 LowPin = resis[0].ra; HighPin = resis[0].rb; } else { // third and fourth pass, direction 2 LowPin = resis[0].rb; HighPin = resis[0].ra; } HiADC = pgm_read_byte(&PinADCtab[HighPin]); // Table of ADC Pins including | TXD_VAL LoPinR_L = pgm_read_byte(&PinRLtab[LowPin]); //R_L mask for HighPin R_L load //================================================================================== // Measurement of Inductance values R_PORT = 0; // switch R port to GND ADC_PORT = TXD_VAL; // switch ADC-Port to GND if ((resis[0].rx < 240) && ((count & 0x01) == 0)) { // we can use PinR_L for measurement mess_r = RR680MI - R_L_VAL; // use only pin output resistance ADC_DDR = HiADC | (1<<LowPin) | TXD_MSK; // switch HiADC and Low Pin to GND, } else { R_DDR = LoPinR_L; // switch R_L resistor port for LowPin to output (GND) ADC_DDR = HiADC | TXD_MSK; // switch HiADC Pin to GND mess_r = RR680MI; // use 680 Ohm and PinR_L for current measurement } // Look, if we can detect any current for (ii=0;ii<20;ii++) { // wait for current is near zero umax = W10msReadADC(LowPin); total_r = ReadADC(HighPin); if ((umax < 2) && (total_r < 2)) break; // low current detected } // setup Analog Comparator ADC_COMP_CONTROL = (1<<ACME); //enable Analog Comparator Multiplexer ACSR = (1<<ACBG) | (1<<ACI) | (1<<ACIC); // enable, 1.3V, no Interrupt, Connect to Timer1 ADMUX = (1<<REFS0) | LowPin; // switch Mux to Low-Pin ADCSRA = (1<<ADIF) | AUTO_CLOCK_DIV; //disable ADC // setup Counter1 timeconstant.w[1] = 0; // set ov counter to 0 TCCR1A = 0; // set Counter1 to normal Mode TCNT1 = 0; //set Counter to 0 TI1_INT_FLAGS = (1<<ICF1) | (1<<OCF1B) | (1<<OCF1A) | (1<<TOV1); // reset TIFR or TIFR1 // HiADC |= TXD_VAL; wait200us(); // wait for bandgap to start up if ((count & 0x01) == 0 ) { //first start counter, then start current TCCR1B = (1<<ICNC1) | (0<<ICES1) | (1<<CS10); //start counter 1MHz or 8MHz ADC_PORT = HiADC; // switch ADC-Port to VCC } else { //first start current, then start counter with delay //parasitic capacity of coil can cause high current at the beginning ADC_PORT = HiADC; // switch ADC-Port to VCC #if F_CPU >= 8000000UL wait3us(); // ignore current peak from capacity #else wdt_reset(); // delay wdt_reset(); // delay #endif TI1_INT_FLAGS = (1<<ICF1); // Reset Input Capture TCCR1B = (1<<ICNC1) | (0<<ICES1) | (1<<CS10); //start counter 1MHz or 8MHz } //****************************** while(1) { // Wait, until Input Capture is set ii = TI1_INT_FLAGS; //read Timer flags if (ii & (1<<ICF1)) { break; } if((ii & (1<<TOV1))) { // counter overflow, 65.536 ms @ 1MHz, 8.192ms @ 8MHz TI1_INT_FLAGS = (1<<TOV1); // Reset OV Flag wdt_reset(); timeconstant.w[1]++; // count one OV if(timeconstant.w[1] == (F_CPU/100000UL)) { break; //Timeout for Charging, above 0.13 s } } } TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<CS10); // stop counter TI1_INT_FLAGS = (1<<ICF1); // Reset Input Capture timeconstant.w[0] = ICR1; // get previous Input Capture Counter flag // check actual counter, if an additional overflow must be added if((TCNT1 > timeconstant.w[0]) && (ii & (1<<TOV1))) { // this OV was not counted, but was before the Input Capture TI1_INT_FLAGS = (1<<TOV1); // Reset OV Flag timeconstant.w[1]++; // count one additional OV } ADC_PORT = TXD_VAL; // switch ADC-Port to GND ADCSRA = (1<<ADEN) | (1<<ADIF) | AUTO_CLOCK_DIV; //enable ADC for (ii=0;ii<20;ii++) { // wait for current is near zero umax = W10msReadADC(LowPin); total_r = ReadADC(HighPin); if ((umax < 2) && (total_r < 2)) break; // low current detected } #define CNT_ZERO_42 6 #define CNT_ZERO_720 7 //#if F_CPU == 16000000UL // #undef CNT_ZERO_42 // #undef CNT_ZERO_720 // #define CNT_ZERO_42 7 // #define CNT_ZERO_720 10 //#endif total_r = (mess_r + resis[0].rx + RRpinMI); // cnt_diff = 0; // if (total_r > 7000) cnt_diff = 1; // if (total_r > 14000) cnt_diff = 2; cnt_diff = total_r / ((14000UL * 8) / (F_CPU/1000000UL)); tmpint = ref_mv_offs; // corrected reference voltage (for C) if (mess_r < R_L_VAL) { // measurement without 680 Ohm cnt_diff = CNT_ZERO_42; if (timeconstant.dw < 225) { ukorr = (timeconstant.w[0] / 5) - 20; } else { ukorr = 25; } tmpint -= (((REF_L_KORR * 10) / 10) + ukorr); } else { // measurement with 680 Ohm resistor // if 680 Ohm resistor is used, use REF_L_KORR for correction cnt_diff += CNT_ZERO_720; tmpint += REF_L_KORR; } if (timeconstant.dw > cnt_diff) timeconstant.dw -= cnt_diff; else timeconstant.dw = 0; if ((count&0x01) == 1) { // second pass with delayed counter start timeconstant.dw += (3 * (F_CPU/1000000UL))+10; } if (timeconstant.w[1] >= (F_CPU/100000UL)) timeconstant.dw = 0; // no transition found if (timeconstant.dw > 10) { timeconstant.dw -= 1; } // compute the maximum Voltage umax with the Resistor of the coil umax = ((unsigned long)mess_r * (unsigned long)ADCconfig.U_AVCC) / total_r; per_ref1 = ((unsigned long)tmpint * 1000) / umax; // per_ref2 = (uint8_t)MEM2_read_byte(&LogTab[per_ref1]); // -log(1 - per_ref1/100) per_ref2 = get_log(per_ref1); // -log(1 - per_ref1/1000) /* ********************************************************* */ #if 0 if (count == 0) { lcd_line3(); DisplayValue(count,0,' ',4); DisplayValue(timeconstant.dw,0,'+',4); DisplayValue(cnt_diff,0,' ',4); DisplayValue(total_r,-1,'r',4); lcd_space(); DisplayValue(per_ref1,-1,'%',4); lcd_line4(); DisplayValue(tmpint,-3,'V',4); lcd_space(); DisplayValue(umax,-3,'V',4); lcd_space(); DisplayValue(per_ref2,-1,'%',4); wait_about4s(); wait_about2s(); } #endif /* ********************************************************* */ // inductor_lx in 0.01mH units, L = Tau * R per_ref1 = ((per_ref2 * (F_CPU/1000000UL)) + 5) / 10; inductance[count] = (timeconstant.dw * total_r ) / per_ref1; if (((count&0x01) == 0) && (timeconstant.dw > ((F_CPU/1000000UL)+3))) { // transition is found, measurement with delayed counter start is not necessary inductance[count+1] = inductance[count]; // set delayed measurement to same value count++; // skip the delayed measurement } wdt_reset(); } //end for count ADC_PORT = TXD_VAL; // switch ADC Port to GND wait_about20ms(); nr_pol1 = 0; if (inductance[1] > inductance[0]) { nr_pol1 = 1; } nr_pol2 = 2; if (inductance[3] > inductance[2]) { nr_pol2 = 3; } if (inductance[nr_pol2] < inductance[nr_pol1]) nr_pol1 = nr_pol2; inductor_lx = inductance[nr_pol1]; inductor_lpre = -5; // 10 uH units if (((nr_pol1 & 1) == 1) || (resis[0].rx >= 240)) { // with 680 Ohm resistor total_r is more than 7460 inductor_lpre = -4; // 100 uH units inductor_lx = (inductor_lx + 5) / 10; } if (inductor_lx == 0) inductor_lpre = 0; //mark as zero // switch all ports to input ADC_DDR = TXD_MSK; // switch all ADC ports to input R_DDR = 0; // switch all resistor ports to input #endif return; } // end ReadInductance()
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; }