Friday, May 18, 2012

BevSense v4 -- Getting it right this time

Version 3 was supposed to be definitive. But it turned out to be a bit of a facepalm. Although it achieved the goal of power reduction and using the slowest clock available, the drawback--and it's a major one--is that the output of the piezo transducer was severely compromised. It's volume is more than just noticeably softer. And I found this out only after uploading v3 to the pcb (not the breadboard version I was using for firmware testing). You see, connecting the PICkit2 causes RA1 (ICSPCLK) pin to drop well below VDD causing the circuit to think that the low probe has detected liquid and so turns on the appropriate audible alert. The sound level I heard was with firmware version 2. Once I had uploaded v3 and before I could remove the PICkit, the circuit again sounded the same alert. But now the transducer output volume was markedly lower. In fact it was too low even as the PWM duty cycle is the same for both v2 and v3. At that moment my heart sank.

The reason, I believe, is the PWM frequency. With v2 it was ~2.1kHz. In v3 it's ~1.9kHz. As I had discussed before, the highest dB output of the transducer was determined to be around 2.15kHz. But because the PWM resolution is extremely coarse when using 31kHz, the closest frequency that could be obtained was 1.9kHz. (Decreasing PR2 by just one shifts the frequency to 2.58kHz).

Increasing the duty cycle would of course increase the volume, but that method is just out of the question since it eye-poppingly and unacceptably raises the current draw. So I decided it would be best to switch to the 500kHz clock whenever the transducer is on, and use the 31kHz clock at all other times. And so v4 was born.

Incidentally, I bench-tested another transducer--the same model--and to my ear its
highest sound level output is at 2kHz. So I've taken the average of 2.15
and 2kHz and set the PWM to 2.083kHz in the firmware below.

As you can see in the program listing below OSCCON is configured to use the 500kHz MFINTOSC in the function BuzzOn() and to use the 31kHz LFINTOSC in BuzzOff(). In all STATEs other than _standby, timer 0 is used to set the cycle time--the time interval between probes readings. But remember the clock frequency is continually being switched back and forth (when liquid has been detected or when a probe error has occurred). In order to have a more or less equal cycle time when using either clock frequencies, I've pegged the value that TMR0 is initialized to as a constant and varied the timer0 prescale value. Since 500kHz / 31kHz = approx 16, the prescale value when in 500kHz mode must be 16x that of the value when using the low frequency clock. I've set TMR0 = 256 - 66 giving a theoretical cycle time of ~17ms. Number of stored probe readings has been reduced from 8 to 6. The 17ms cycle was chosen so that 17ms x 6 readings = ~100ms. Using the Saleae Logic, measured cycle time is ~18.6ms @31kHz and ~17.0ms @500kHz (see the screenshots below)

For timer1 I took the opposite tact. I kept the prescale value constant (for each STATE) and varied the initial value of TMR1H since TMR1H initial value is different for transducer on-time and off-time anyway. Up to v3 transducer on-time and off-time during liquid detection was equal. In v4 I've decreased the on-time slightly to reduce current draw just a tad.

The transducer on-times during probe error have been limited to a couple of 100ms pulses every 8.5 seconds.

In the following screenshots firmware was in STATE = _plophi_immersed (both probes immersed in liquid). Bear in mind in this mode/state, transducer is designed to be on ~100ms and off ~125ms. Channel 7 is hooked up to RA5 pin; Ch6 to RA0.

Length of time that transducer is on is ~103ms (see value for "Period" in the screenshot)

Time that transducer is off is ~124ms.

With clock = 500kHz (transducer is sounding), out of the ~17.0ms cycle time the firmware is spending 16.35ms doing nothing but waiting for timer0 interrupt flag to get set.

With clock = 31kHz (transducer off), cycle time ~18.5ms and "dead time" ~8ms. That's still a fair amount of idle time even with the LFINTOSC.