Wednesday, October 28, 2015

Daylight Logger for Gardening Part 3

Now that we've covered the function and design of the logger device, let's look at a few of the obstacles.

Unexpected Data:
One of the functions that needed to be coded and tested early on was dumping the light data to a PC.  I used a C# program that I wrote for doing two way serial communication and added features to have to send and show data in either ASCII or hex.

So the issue I ran into was that data seemed to be getting distorted, specifically for sunny conditions.  I wasn't seeing any values greater than 0x7F, which is the maximum ASCII value (7 bits).  However this wasn't immediately noticeable as most of the values I was receiving were 0x3F.  It almost looked like maybe there was a memory issue and that was a default value of some sort.  My other thought was that maybe there was a baud rate issue and I kept losing that first bit somehow.  I was pulling at straws.  I spent a whole bunch of time looking at scope captures of the data and measuring pulses manually to compute the baud error to no avail.  Then I took note of how the ASCII value of 0x3F is a '?'.  Maybe there was something to that.

So I started poking around in my C# code for a reason that portions of my data was being converted to '?'s.  I was using hte built-in SerialPort object that is part of .NET and upon received data used the "ReadChar()" method because it returned printable characters.  I had added the ability to print hex as an afterthought, and as such, simply formatted the returned value as a hex byte when printing to the window.  Seeing as the "ReadChar" method actually returns an integer value, I assumed I was getting the raw data.

Turns out I was wrong.  The SerialPort object allows for the setting of a text encoder, which I believe by default is ASCII.  And ASCII does not support values over 0x7F.  A little code rewrite using the "ReadByte()" and all was good.  My firmware or circuit were fine from the start.  Admittedly, the PC side of things is usually much easier to develop and debug, which gave me a false sense of security.  I assumed my debug tool worked because it didn't fail catastrophically (as embedded software often can).  But it usually helps to know what goes on under the hood, otherwise some issues are seemingly impossible.

Small Optomizations:
Seeing as the logger was going to run off of batteries, I took some care to reduce power draw.  I only had so many I/O pins which meant I had to be mindful of idle states when combining functions.  So for instance, I used a PNP for both the TX and the power to the ambient light sensor and buffer amp in order that they both share the same off state.  I only turn the sensor and amp on for a very short period of time, which does turn on the TX transistor (Q4), but the TX resistor is sized to reduce current draw.  It's a compromise, but at least they are both off for the vast majority of the time.  The op amp was even chosen amongst the ones I had (and ones I would have preferred to use up) because of its lower supply current.  Fortunately the memory chip only draws a 1uA while idle, leaving it power on all the time is inconsequential.  And the RX transistor is stuck off unless something unless a com port is attached.

But hardware isn't the only place to save on power.  Efficient code and good use of microcontroller features helps a lot.  The most obvious features is the SLEEP function.  In a 24 hour logging period, the device is inactive 99.9945% of the time.  By putting the MCU in a lower power state, the circuit hardly draws any power (my secondary multimeter of suspect accuracy claims around 60uA, which actually seems a little high).  This amounts to about 1.5mA hours spent idling over 24 hours.  Not too bad.

But some code efficiency can also help.  Ideally, you don't want to be waiting for anything if it can be helped.  In my case, it took a certain amount of time for the sensor output and internal voltage reference to settle when the MCU woke up and turned everything on.
Green line shows the sensor being turned on and off once sampled.  Yellow line is the data signal going to the memory (clock signal would have been better, but you get the idea of  the time it takes).  MCU turns on at the start of green signal and off and the end of the yellow signal.
I didn't like the extra waiting and realized I could save a bit of on time by writing the next address to the memory while things settled.  This knocked the system on time from about 10ms to 7ms.  It may not seem like much, but that's a 30% reduction in total awake time for the microcontroller over the whole 24 hour cycle.

Should have captured the same signals as before.... Green line is the clock signal to the memory, and Yellow line is the light sensor output.  The important thing is that the signals overlap instead of happening in sequence.
Another savings in power is running the MCU at a lower frequency.  Nothing going on here is that time critical, and even at my 500KHz clock, the micro is still fast compared to the analog sensor setup time.  But if running slower also means running longer, it may not net you a total power savings, keep that in mind.

Improvements:
There are of course other improvements to be made on this device though I'm not unhappy with its current state.  Larger resistors can be used for both the I2C pull-ups and for the TX and RX bits of the circuit as the data rates for both are rather slow.  Mechanically I can shade the light sensor so that the sense resistor can be made larger reducing its current draw.  It'd also be nice to slap in a bluetooth module making connection to a computer easier.  Maybe some day....