%(qi-html-head)s %(qi-html-body-top)s

Anelok: keeping the time during battery swaps (2/2)

Werner Almesberger werner at almesberger.net
Sun Mar 27 22:47:52 UTC 2016

The timekeeping gets an unplanned second part, for a fifth variant.
Fifth time is lucky, right ? :-)


All the circuits presented so far have the issue that a voltage
above Vcc is present at the MCU's GPIO(s) when Vc1 > Vcc. This
is outside the chip's specification and may or may not cause

Joerg suggested another variant, on page 5: the diode is now at
the MCU and thus clamps Vadc to Vcc. A standard diode with Vf
around 0.3 V at 1 uA (e.g., Panasonic DA2J10100L) should work
nicely for this.

One issue with the circuit is that the leakage current of the
ADC pin flows through the 3.3 MOhm resistor, which may cause a
voltage offset that is as large as the whole measurement range.
The magnitude of the leakage should depend largely on the chip

Joerg suggested an algorithm that may help there, too. To take
a sample of the unknown Vc1, we would do something like this:

static void pulse(float duty)
	sleep(INTERVAL * duty);
	sleep(INTERVAL * (1 - duty));

float measure_vc1(void)
	unsigned s0;	// initial ADC reading, in ADC counts
	unsigned st;	// further ADC readings
	float duty;	// duty cycle, 0 <= duty <= 1
	unsigned i;	// change detection timeout

	s0 = adc();			// sample Vadc = Vc1 + Ileak(t0) * R1,
					// in ADC counts
	duty = s0 / ADC_RANGE;		// fraction of Vcc

	while (1) {

		// PWM at "duty" * 100%

		i = SAMPLES;
		do {
			pulse(duty);	// emit pulse
			st = adc();
			if (!i--)	// Vc1 is stable
				return duty * 3.3;
		} while (abs(st - s0) <= NOISE);

		// correct Vc1

		if (st > s0) {	// we were too high - pull down
			do pulse(0);
			while (adc() > s0);
			duty -= INCREMENT;
		} else {	// we were too low - pull up
			do pulse(1);
			while (adc() < s0);
			duty += INCREMENT;

This basically implements a PWM with variable duty cycle. We start
with a first guess based on the ADC value we obtain. Then the PWM
pulls Vc1 towards 3.3 V * duty. This voltage is not affected by
GPIO leakage.

During all this, we read back Vc1 with the ADC (which is affected
by leakage). If the values read back stay long enough within the
expected noise bounds, our duty cycle matches the correct Vc1

If our measurements indicate that Vc1 drifts away, we emit 0% or
100% pulses until it goes back to the original value, and we adjust
the duty cycle up or down, accordingly.

For faster convergence, INCREMENT should be a function of the time it
took to pull Vc1 back to the original value.

This seems to look pretty decent, and is easy on the hardware.
Thanks a lot, Joerg !

- Werner

More information about the discussion mailing list