Low Power User Interface


As you may have noticed I’m quite busy working on the MPPT Solar Charger project. The latest version uses a 4 lines x 20 characters LCD that connects via I2C as well as a rotary encoder with a push button.


While the display got its own little board, the encoder connected directly with the solar charger where its signals aredebounced in hardware and then routed to the PIC.


After a few little fixes (see my last post) that worked but I had to use the signal intended for controlling the  backlight brightness for the display’s reset signal. I don’t want to run any more wires to the display and there are no spare pins on the PIC anyway so I had to come up with another solution.


And it was not very elegant that the display was powered off by just cutting the entire power supply. Having a digital enable/disable signal would be preferable


Design a universal User Interface

I then decided to design an new board that also includes the rotary encoder with all the necessary debouncing. That way I get a quite universal, easy to use user interface that I can use for other projects as well. That eliminates the need to design the same functionality (think debouncing) again and again. The size of the board is mainly given by the size of the display so there is plenty of board space.


So far so good but that doesn’t solve the actual problems yet. I still need a way to control both the backight as well as the reset signal without needing any more singnals. Since the display connects via I2C it was quite straight forward to use I2C communication for those purposes as well. My first thought was to add a I2C port expander just like I’ve done on the solar charger board. Those chips aren’t expensive but they typically provide 8 or 16 extra GPIO pins which seemed a bit wasteful. And PWM control of the backlight would require a great deal of I2C communication which puts a burdon on the microcontroller.


I also considered adding a sub-dollar PIC16 which could be programmed as an I2C slave and control both the backlight and the reset signal (as well as giving the option of getting the encoder input via I2C). But I wasn’t eager to write any software for this thing.


Requirement: Ultra Low Power State

Another design requirement was to keep this a very low-power design. To be sure: when the display and especially the backlight are on it will consume several milliamps to several dozen milliamps. Illumination doesn’t work without power, such is life. But when the user interface is not in use, we need a way to put it in a very low power state where the display as well as the rotary encoder is off but the push button still works in order to wake up the microcontroller. In that state the user interface must not use more than a few microamps. Furthermore the encoder signals must assume a high impedance state when the user interface is disabled.


My final solution was as follows:

  • Use the previous (backlight) PWM signal as an enable signal. Power can now always stay on. When the enable signal is high, the display is on, when enable is low, the user interface goes into its low-power state.
  • Add a dual I2C digipot to control both the reset signal as well as the backlight.

The reset signal is connected directly to the wiper of one of the two digipots. Of course any intermediate digipot values don’t make sense. The digipot should always be either at its minimum or its maximum.

The backlight brightness is controlled by the other digipot via an op-amp and a n-channel mosfet.

The debouncing is basically unchanged. Like in the solar charger design, a 74HC126 quad tri-state buffer is used together with some resistors and capacitors.

Since there are 4 gates on the 74HC126 and I only need to debounce 3 signals, there is still one gate left. I used that gate to power the display as well as the encoder and the encoder’s gates(without the push button which is always powered on). So the enable signal only controls the input of that gate. I thought that’s a nice and elegant solution. Well, if you think so too, think again. More on that later.



First of all nothing worked at all. I asserted the enable signal and nothing happened. Nothing was powered on. The error was soon found. I made a design error with the result that the respective gate was permanently in a high-impedance state. Somehow I had tied the gate’s enable input to ground instead of VCC. The mistake was corrected by cutting the ground connection and conecting the respective pin to the enable singal itself which was available from the pin right next to it. Not pretty (see below) but problem solved.


Then ok, power was there but when I tried to turn off the reset singal (i.e. pulling the reset signal high) nothing happened – again. Again, the reason was simple. The digipot’s upper terminal was floating instead of being connected to VCC. On the schematic the wire touched the respective pin but there was no connection. While that was really hard to notice on the schematic I should have noticed the problem when I laid out the board. There was obviously no connection to that pin.


This was a bit harder to fix than the previous error. There were no signals to cut but the digipot’s pins are much more closely spaced and the right signal was not to be found nearby. I ended up soldering a thin wire accross the digipot to a resistor that is connected to VCC on the upper end.


Even less pretty but problem solved anyway. Turning on the backlight basically worked as intended but the load was a bit much for the 74HC126. While it can supply up to 35mA according to the data sheet, its output voltage is nowhere near its positive supply rail when it supplies that much current. Even with a more modest 5mA load the gate’s output voltage was about half a volt below the input voltage. As a result, the display as well as all the other components only get to see about 2.8 volts instead of 3.3. This didn’t pose any problems so far but it’s not nice.

Another issue I noticed was that the LM321 op amp I had chosen is not a rail-to-rail op amp. The LM321 is inexpensive and I had quite a few left from another project so I used it without giving it much thought. I measured that the output voltage doesn’t get closer than about 1.4 volts of the positive supply rail. Since the n-mosfet used to control the backlight has a very low threshold voltage that didn’t pose a problem but the LM321 is not really a good choice here. While it does work from as little as 3 volts it’s made for split supply and higher voltages, say plus/minus 12 volts. I’ll use a low-voltage rail-to-rail type next time.


Getting any MIDAS I2C display to work is a nightmare. They make nice, pretty and affordable displays. That’s why I buy them. And once you’ve managed to properly initialize them they are easy to work with. But getting them initialized with the right settings is always a lengthy trial-and-error process. I’ve ranted about that before but I feel the need to do it once again.

The entire initialization sequence needs to be written in one single I2C transmission. At least for me it didn’t work otherwise. The data sheet says absolutely nothing about that.


The data sheet doesn’t even mention the initialization sequence. Nor the timing of the reset singnal. The reset signal needs to be pulled low for 10ms. One then needs to wait for 5ms before the initialization sequence is sent. There is not one word about that it in the current datasheet. There is an older version in the net somewhere that mentions those timing issues and at least gives a sample initialization sequence.


There are various contrast settings that must be set properly via I2C commands but there is very little information on those commands in the data sheet. I wrote an email to their customer support asking if there is a list of commands the display supports. That was more than a month ago and I still didn’t get any answer. As so often, google was my friend and others have faced similar problems before so I managed to find some commands that make the display work properly. I’m sending 10 or so bytes to the display but for most of them I have not a clue what they actually mean or what they are supposed to do. And the commands for this black-on-white display are different to the (otherwise identical) white-on-blue display. Have fun…


I’ve devoted one of my very first posts to the much-neglected issue of debouncing. The logic is pretty much the same here except that I use different (non-inverting) gates here. The reason for that is the need for 3-state outputs as mentioned before.


Unfortunately the 74HC126 doesn’t have schmitt-triggered inputs so I need to implement the necessary feedback myself via the 680k resistors.

Debouncing something like a pushbutton is quite easy. Just use a relatively long time constant (i.e. large resistors and capacitors) and all will be fine. That will introduce some delay in the output signal but as a rule of thumb anything below 50ms is not noticable. And a time constant of a few milliseconds is totally sufficient so you might end up with something like 10ms of delay. No human user will ever notice it and it’s more than enough to perfectly debounce any switch that I’ve seen.


With rotary encoders things get much trickier. The basic circuit is exactly the same but choosing the right component values is more difficult. You can’t press a button more than a few times a second but a rotary encoder might produce pulses just milliseconds or even less apart.


So you face the challenge of debouncing the signal while still letting relatively fast transitions pass. If you use a time constant of a few milliseconds like with the push button you will not be able to detect when the encoder is turned quickly.


The data sheet of the Burns encoder I’m using here recommends using two 10k resistors together with a 10nF cap. I’ve increased the value of one resistor to 22k but have otherwise followed that recommendation.  So the time constant is now a few hunderd microseconds.


Toghether with the positive feedback via the 680k resistors that works very well. I expected to tweak those values a bit but found that they work so well that I just leave them as they are.


I’ve inserted plenty of scope screenshots here to give you an idea of what the undebounced and debounced signals look like. Even with the same encoder there’s plenty of variation as you can see. But with the hardware debouncing applied here we get a clean, digital output singal nevertheless.


Power consumption

Very low standby power consumption was one of the key design goals. When in low-power mode only the push button pull-up and the 74HC126 is supplied with power. Everything else, the display, the op-amp, the digipot and the pull-up for the rotary encoder are all completely powered off.

As long as the push button is not pressed, no power flows there so the only power consuming device is the 74HC126. Its datasheet specifies a maximum static current consumption of 8 microamps (worst) at room temperature.  There’s no typical figure so that’s all the information I had. When I measured it, this is what I got.


That’s 4 nanoamps  at 3.3 volts which is nothing really. Actually the measurement fluctuated between about 0 and 15 nanoamps. I thought something is not hooked up correctly but when I pushed the button the current jumped to 326 microamps which is just what I expected since there is a 10k pull-up resistor conected to that button.


So the measurement works and it seems that the 8 microamps given in the data sheet are just a very conservative worst case. I mean CMOS is close to zero-power when static and only a single tri-state gate is active so essentially no current flows. Cool.

Next steps

After the two hardware fixes this user interface works quite as intended. Using the spare gate to supply the rest of the circuit with power was not as good an idea than I thought. On the positive side the debouncing works just perfect with the chosen component values. And as mentioned, the op-amp was not a great choice for the job at hand.

But I like the look and feel of this universal user interface and think the overall concept is good. So there will be a Rev B of this board with those issues solved.

Here you find the eagle files as well as PDFs of the schematic and board. The two errors are already corrected but I haven’t actually built them so check carefully yourself. I’ve also re-exported the gerbers so they, too, already include the fix.

MPPT Solar Charger Testing


In a previous post I have presented a design for an MPPT Solar Charger. In the mean time I have built a prototype and also wrote some software for it. So today I’ll go through my findings of what works well and what needs to be improved. And yes, there are some flaws in the design…

The software is far from final but with the notable exception of USB all the basic functionality has been implemented.

Power Supply


One of my main goals with this design is to archieve very low standby current, somewhere in the tens of microamps. The basis for this is a low-power buck on the basis of a Texas TPS62120 where the microcontroller can switch the output voltage between 2.2 and 3.3 volts nominally. This works as intended. With no load and the output voltage low, the supply consumes 12.9 microamps at 12V input voltage. With the high output voltage the idle current goes up to 14.3uA. Quite a bit of that current is due to the voltage divider that sets the output voltage. The regulator itself consumes about 9uA in both cases.



The PIC18F26J50 starts up using the primary oscillator’s 8MHz crystal with the internal PLL disabled. It can then switch to 48MHz operation by enabling the PLL or to the secondary oscillator running at 32.768kHz. The latter is always running since it also serves as the clock source to the real-time clock and calender (RTCC). Switching between clock sources as well as the RTCC have been implemented in software and work fine.

I2C Multiplexer and Port Expander


The microcontroller doesn’t have enough GPIO pins so a I2C port expander (Microchip MCP23008) is used to give us another 8 pins. The display is connected via I2C as well but since the display is entirely powered off when not in use, the display cannot be on the same bus. Otherwise it will pull the SCL and SDA lines low and block the bus. The NXP PCA9546 multiplexer takes care of that. Both devices, the mux as well as the port expander work as they should.

Voltage Reference, Temperature Sensors and Fan


There is a total of 3 temperature sensors, one on the board and 2 external ones. The temperature is measured by the PIC directly so it has a 2.5V voltage reference in order to get meaningful results. At room temperature all three temperature sensors deliver very similar results, typically within a few tenth of a degree. Better than expected. The fan output can also be enabled if the on-board temperature gets too high.

Voltage and Current Measurements


The more important measuements, namely the input and output voltages and currents are performed by a MCP3424 4-channel 18-bit ADC. I was already familiar with that type so I quickly got it to work. In this application I don’t use its internal PGA (programmable gain amplifier) or rather I leave the gain at 1. All the measurements are done with 14bit accuracy which is reasonably fast (23ms worst case) and sufficient here.

User Interface


The debouncing of the rotary encoder works ok but I’ll tweak the resistor and capacitor values a bit when I get time. The push button is uncritical but there is a bit too much debouncing for the rotary encoder itself making it miss some very fast turns. But it already performs reasonably well as it is.

The display module is the first real flaw in my design. It has 5 wire connections: GND, VCC, SDA, SCL and Backlight. The idea was to turn the display off by simply cutting off VCC when the display is not needed. When in use, the brightness of the backlight is then controlled by the Backlight PWM signal.


Since the display needs quite a few supporting components (mainly 1uF capacitors) and has no mounting holes I made a little one-sided PCB for it. When I first tried it nothing worked. A ground connection was missing and I didn’t notice that in Eagle because in Eagle it was a double-sided board. That was easily fixed by a short piece of blank wire soldered in place. So far so good.

Unfortunately the display (a Midas MCCOG42005A6W-BNMLWI) still didn’t work. Besides the data sheet being a nightmare it needs to be reset after having powered up. So you need to power it up, wait for a while and then do a reset by pulling its reset pin low. So just pulling the reset pin high with a resistor like I have done won’t work. My solution for now was to connect the backlight signal to the reset pin. So I can now use the display but the backlight brightness is permanently  at it’s maximum.


I already have a new and hopefully better version of this display unit in the making and there will be a separate post on that. My idea is to have a rather universal module that I can use in other projects as well.

USB Charging


The USB charging module works reasonably well. When pulling the full rated current of 2A it gets rather warm but doesn’t overheat. I was able to pull 2.5 amps for a prolonged period of time without any issues. I only had a Samsung A5 to try but at least that phone charged perfectly fast pulling around 1A of current. With that load the module only gets slightly warm.


Turning the USB charger on and off in software also works as planned. This can now even be done via the user interface – see above.

Power Outputs


The 4 power outputs can be controlled in software. In order to save power, the mosfet drivers can be powered off if none of the outputs is on . All that is already implemented in software and the outputs can be turned on and off individually via the user interface.


I plan to implement a low-frequency (say, 100Hz) PWM functionality for these outputs in order to e.g. control some LED lighting but that has not been done yet.



I haven’t implemented any data logging functionality yet but I have written a few library functions for the EEPROM. When the date and time is set via the user interface those values are saved to EEPROM and restored after a reset. Reading from and writing to the EEPROM therefore works.


Solar Charger

Yes, I’ve left the main thing for last. Don’t know why.


When I first assembled the board I noticed that I had ordered the wrong mosfet driver – a MIC4605-2 instead of a MIC4605-1. They are near-identical except the fact that the -1 has two independant inputs while the -2only has one PWM input plus an enable signal. That also works but doesn’t give us the option to run the converter in asynchronous mode. So I’ve unsoldered the chip again and replaced it with the MIC4605-1 that I had in mind when I designed this thing.


As you can see on the photos above, I’m now using a 22uH coil, not a 68uH coil as shown in the schematic. The reason for that is that I’m using a relatively high switching frequency of 48MHz / 256 or 187.5kHz. That high switching frequency enables me to use a lower value inductor which massively increases its current rating while pyhsically being the same size. Since the inductor was the limiting element in this design before this significantly increases the power rating of this solar charger. The previous version was (very conservatively) rated at 30 watts only. With the new 22uH inductor this very similar design can handle something like 75 watts. I need a more powerful power supply to do some serious testing but at 35 watts it’s getting slightly warm at the most. I’ve only done some quick and dirty testing but efficiency at 35 watts is around 97%. That means we are only losing about 1 watt which is the reason the charger barely gets warm.


There will likely be another post focussing only on the charger itself so I won’t go into more details here. The code regarding the buck is extremely basic and potentially dangerous at this point. I’ve killed the bottom mosfet twice due to the not very graceful way the buck turns off. If it turns off while the bottom fet is on, that fet will stay on, effectively shorting the battery to ground. At least that’s my explanation at the moment.


Oh yes, there’s another issue with the buck as well. With the battery at its output there will always be the battery voltage minus a diode drop at its input where the panel is connected. So when there is no sun, the battery is powering the panel. I’ve tried that with a small 30W panel and the panel draws 8mA at 12 volts which several magnitudes more than we are willing to use when the charger is sitting idle. So the next version will have to disconnect the panel when the charger is off. And we will also need to disconnect the voltage divider at the charger’s input when we’re not measuring the voltage, just like we’re doing at the battery.


There are a lot of features on this board and getting them all to work properly requires quite a bit of work. But most of the heavy lifting has been done so I can now focus on improving the software.


First and foremost I need to work on the way the buck is controlled. First there needs to be a strict and safe procedure how this thing is turned on and off. I’m confident that there won’t be any blown-up mosfets once that’s done. Then I also need to improve the algorithm of how the maximum point of power is tracked. And I also want to implement asynchronous operation at low loads in order to improve efficiency. I’ll spend some time on all these issues next, looking at the signals on a scope and trying to improve things.

But all-in-all I’m quite happy with how how this design has performed so far. Yes, there are some issues but nothing that can’t be fixed with relative ease.

For those of you interested, the code can be found under downloads on the overview page. In my next post we will take a closer look at the display unit / user interface.

Ultrasonic Anemometer Part 28: New hardware tested


I last time proudly presented the new RevB board and got a lot of feedback from people who want one, too. As mentioned I have all the components here to ship up to 10 kits but I was reluctant to send anything until I had the chance to do some hardware testing. Not much had changed since the last revision but I don’t like taking chances on things like this.


In the mean time I managed to do some rudimentary testing and now feel confident to take orders. These tests concern the hardware only. What I said last time about the state of the software still applies. But let me tell you what I’ve been able to test so far.


Tests performed so far

  • The PIC32 can be programmed from a PICKit3 via the ICSP header without any issues.
  • Power consumption is as expected. Like the previous version it draws 45mA@12V (programmed) and the other two rails come up with +3.310 and -3.279V, respectively. Also as expected. Regulator stays cool.
  • With the PIC controlling the AXIS, DIRECTION and SIGNAL pins, the transducers receive the 12V signal from the mosfet drivers. HOWEVER: the signals AXIS and DIRECTION are incorrectly labeled both in Eagle as well as on the silk screen. Electrically everything is fine but the names have been confused.
  • The signal from the transducers is properly received (Rec pin on the board) and amplified by a factor of 11 by the first stage of the amplifier (S1 pin on the board).
  • The PIC is able to control the digipot over the internal I2C bus and the second amplifier stage also performs as expected.
  • The zero-crossing detector (ZCD) works.
  • The input to the PIC’s ADC (ADC+ and ADC-) look fine, too. HOWEVER: the labeling on the silk screen is wrong. Eagle is correct, it’s just the silk screen. Plus should be minus and vice-versa. Again, electrically everything is fine.
  • The PIC can communicate (as a slave) with an Arduino UNO connected to the external I2C bus.
  • Communication over USB to a YAT-terminal under Win 7 works.



The following has not been tested so far

  • For my tests I still used the transducers already used previously. I believe the ones I ordered last week are of the same type but I haven’t tested them.
  • EEPROM. I haven’t tried the newly added memory yet. I have confirmed that it has power and is connected to the same bus as the digipot so I have no reasons to assume there are issues with it. But testing it would require some software first.
  • The external SPI bus has never been tested, neither on the Rev A board nor with the new one. I don’t expect any problems but I haven’t done any testing so far.


Is there anything important that I forgot to mention? In that case just ask.  A lot still needs to be done but at this point I’m confident that the board has no major flaws and performs much like the prototype.  Want to give it a try? I have some kits left for you.


Ultrasonic Anemometer Part 27: Ready to take pre-orders

20160903_StandaloneAnemometer_001Good news: the boards from dirtypcbs.com have arrived and look great. I also got all the components for the 11 boards. Why 11? I ordered about 10 (they call it a protopack) and was lucky enough to get 11. Thats dirtypcbs.

Last week I also upgraded my hobbyist Eagle license to a proper Premium LS license which means I can now legally start selling stuff. So I’m basically ready to ship the first kits.


Today I assembled one of the boards and it at least looks great. All the footprints are correct and it was a pleasure to solder. Now what I want to do is to run some tests with it just to make sure it works as intended. I didn’t change much since the last version but I want to be sure first.


About the kit

There’s one thing I want to be absolutely clear about. At this stage of development the wind meter is not yet ready to be deployed. While I think the hardware is final now, a lot more work is needed to get the software ready. So for the time being this kit is intended for people who want to join the development and testing. I’ve done most of the low-level, register-fiddling stuff but much remains to be done at a higher level. I know there are a lot of people out there with much more experience in signal processing than me and I’m looking forward to work on this challenge together. And a challenge it is. But the PIC32 still has plenty of RAM, Flash and CPU time left to try out new ideas and approaches until we find one that works well.


The kit contains the board and all the necessary components. Details can be found in the BOM linked on the overview page. Once assembled it should look precisely like on the photos on this page. But as the name suggests, it comes as a kit, i.e. as components that you have to solder yourself. Most components come in relatively large SOIC packages but there are a few smaller MSOP and SOT-23 packages as well. They can all be soldered with a conventional soldering iron and strain solder just like I’ve done today.


The microcontroller is not yet programmed so you will need a suitable programmer. Microchip’s PICKit3 (USD47.95) is the obvious choice here. This is also what I’m using and matches the board’s pinout. All the software (MPLAB X IDE and XC32 compiler) are available for download from Microchip free of charge.

Taking pre-orders now

I’ll start taking pre-orders now but as mentioned I won’t ship the kits until I’ve done some tests with my own board. Once that’s done I’ll let you know and if you’re still interested by then I’ll give you my PayPal details and ship the kits.

Some have mentioned that they already have some ultrasonic tranducers and/or want to try some specific model so you are free to order your kit with or without the transducers.


There’s no online shop or anything like that so just use the contact form on the about me page.


Now it starts getting interesting. I’ll quote all prices in USD, EUR and CHF.  Choose what’s cheapest or most convenient for you.

  • Kit without transducers: USD 70 / EUR 63 / CHF 69
  • Kit with transducers: USD 95 / EUR 85 / CHF 93

The prices above include worldwide shipping. The kits ship by Swiss Post Priority Mail in a padded envelope.  I’ve used this service before to locations like Brazil or India and never had problems. However, there are no tracking numbers.

Any other questions? Just ask.



MPPT Solar Charger Design

I’m currently waiting for the boards for my Ultrasonic Anemometer Rev B to arrive from Hong Kong and this gives me some time to write about the MPPT Solar Charger design that I did quite some time ago. I published a series of posts on a Arduino MPPT Solar Charger Shield and got a lot of encouraging feedback. But that shield was more of a proof-of-concept than a finished product.  While it generally performed well it drew way too much current when idle to actually be deployed unless you can count on plenty of sunshine every day.


Aiming for very low power consumption

While I like the Arduino platform I had to admit that it’s probably not ideal for a low-power design. Yes there are some things you can do to reduce the 50mA or the Arduino draws but it will never be truely low power. So I designed a stand alone version with plenty of extra features that I hope to draw only a small fraction of the current. I particularly care about the idle current, i.e. the current it pulls when the solar panel is not producing any energy. In winter, the panel might be covered by snow for weeks and you don’t want your charger to drain the battery during that time. With this new design I’m aiming for an idle current in the tens of microamps. Even if it ends up being 100 microamps that is still 500 times less than an Arduino uses just by itself. And that means it draws less than 1Ah (ampere-hour) per year so you will never drain the battery no matter how little sunshine there is.


PIC18 series microcontroller

At the core of the design is a PIC18F26J50 in a 28 pin SOIC package. It’s capable of running at down to 2.15 volts and consumes extremely little power when running at lower clock speeds. And apart from that it features USB so we can have all the benefits of USB without any external components except, of course, a USB socket.

The PIC has two crystals at its disposal. A 8MHz crystal which will be boosted up to 32MHz by its internal PLL. That’s what the PIC will run on when there is work to do. And then there is a 32.768kHz crystal that will be used to run its real-time clock (RTC). When there is little to no work to do this low-frequency clock will also be used to run the CPU which will greatly reduce power consumption. Power consumption is approximately linear in frequency so this should cut power consumption by a factor of about 1000 compared to full-speed operation.


Switch mode power supply

Now we can run the microcontroller at only a few volts but our power supply is a 12 volt battery. So one of the most straight forward things to do in order to save power was to use a switch mode step-down regulator aka buck.

I looked around and found the Texas TPS62120. It’s only capable of providing 75mA but that’s more than enough for us in this case. It works at a switching frequency of 800kHz and only consumes a bit more than 10 microamps with no load at its output.

It needs a 18uH inductor as well as some ceramic capacitors to work. The output voltage is set via a pair of resistors acting as a voltage divider. I’ve added a n-channel mosfet that allows the PIC to increase the output voltage from 2.2 volts to 3.3 volts when needed. Because while the PIC can run on down to 2.15 volts the display can’t. And even the PIC needs 3.0 to 3.6 volts for USB operation.

Synchronous / asynchronous operation

The actual MPPT converter has changed only little. I’ve changed the mosfet driver to a MIC4605.  Unlike the IR2104 used last time, this model has adaptive dead-time (as opposed to the longish 540ns fixed) and separate inputs for each mosfet. This will allow us to either operate in synchronous (using both mosfets) or asynchronous (only using the upper fet and relying on the diode) mode. Asynchronous operation has a certain efficiency advantage at low power levels so this might come in handy.

The MIC4605 consumes quite little quiescent current for a mosfet driver, only 100uA typical. But that’s still too much for our purpose. So the PIC can power the whole thing off via a NPN transistor and a p-channel mosfet. That BUCK_ON signal also serves as the supply voltage for the INA213 current sensors already used in the last version. So the entire converter can be powered off and should consume precisely zero current when not in use.

What about the voltage divider necessary to measure the battery voltage? That’s been taken care of, too. That divider is interrupted by a (low threshold voltage) n-channel mosfet unless a signal from the PIC turns on the mosfet and closes the circuit.


Port expansion

I soon ran out of GPIO pins with that PIC so I had to add an I2C port expander (MCP23008) to gain another 8 I/O pins. I’ve also added a PCA9546 I2C switch in order to translate between different voltage levels.

It’s probably not the most elegant solution and a future version might trade these 3 chips for a higher pin-count PIC. But I had all components here already so that’s what I’ll use for now.

Precise measurements

In order to precisely measure input and output voltages and currents there is now a MCP3424 4-channel 18-bit ADC. To be sure, we don’t need 18 bits of precision here but we’ll trade some of that precision for speed and work with 14 or 16 bits.

The ADC has its on-board voltage reference and PGA with gains up to 8.  Since it only consumes a maximum of 1uA in standby mode it is always powered on.

There are also a total of 3  LMT86 temperature sensors, one on the board and 2 external ones. The external ones are intended to measure the temperature of the panel and battery, respectively. The maximum voltage for a battery is quite dependent on temperature so that’s a useful information to have. The inputs from the temperature sensors are measured directly by the PIC.  For that purpose there’s also a ADR361 2.5V voltage reference.

Measuring temperatures requires the board voltage to be high, 3.3 volts nominally. So both the voltage reference and the temperature sensors are only powered on when then VCC_HIGH signal is set.

User interface

To communicate with a human user there is a 4×20 LCD display that is controlled via I2C in order to save some I/O pins. There are quite a few external components needed to run it at 3.3 volts so it has its own PCB and connects via a 5-pole wire. There is 3.3 volts and ground for power, SCL and SCD for I2C communication and a PWM singal in order to control the display brightness. Because that’s a rather universal board I will document that as a separate post.

As an input device there’s a rotary encoder with push button. Together with the display (and some decent software) that should allow for a pleasant user experience.

The inputs from the encoder are debounced in hardware via a 74HC126 that serves a double purpose. With its 3-state outputs it allows us to use the pins that are otherwise used for in-circuit programming of the PIC.

Both the rotary encoder (except the push button) and the entire display unit can be powered off when not in use. The push button is always powered on so the user can wake up the user interface at any time by pressing the button. When the user interface is not actively powered on the 74HC126’s outputs are in high-impedance mode and the PIC can be programmed without being affected by the rotary encoder.


Data logging

One might be interested how much energy has been harvested by the solar charger over the last hours, days, weeks or months. So there’s some non-volatile storage as well. The 24FC256 connects via I2C and offers 256kBit of memory. It consumes only 100nA in standby so it can stay powered on at all times.

Fan control

As mentioned, there’s a temperature sensor on the board. If it gets too hot, a fan can be powered on via the FAN_ON signal controlling an n-channel mosfet.


There are 4 power outputs, each controlled by a separate signal from the PIC. There should be some PWM modules left on the PIC so some (two I think) can be PWM controlled. A typical application would be LED lighting which can be controlled and dimmed directly from the solar charger via the rotary encoder. Each output channel has a beefy  mosfet of the same type as the MPPT switcher (IPB136N08N3).

Each has its own FAN3111E mosfet driver. They have a separate input for the reference voltage so the PIC can easily control them when running at only 2.2 volts. The FAN3111 should only draw 5uA (10uA max) when idle but there are 4 of them so they can be powered off (all togeher, not individually) when not in use.


USB charging ports

One of the first thing one wants to do when there is power is to charge one’s cell phone or similar device. So there are two USB charging ports capable of delivering some 2 amps of current at 5 volts in total.

They are powered from the 12V batter via a TPS54231 buck converter. So there are a total of 3 buck converters on this board… It is always connected to the 12V rail but the PIC can turn it off when not in use. The regulator’s shutdown current consumption is only 1uA typical (4uA max) so that should be adequate.

Manufacturers of mobile devices have all come up with nasty ways of making their devices incompatible with other manufacturer’s chargers. They basically abuse the otherwise unused (for charging purposes) data lines to recognize their own chargers and discriminate against any others. That might mean they won’t charge at all or only at a slow rate.  So there are two charging ports on this board, one emulating an iPad charger and the other one a popular Samsung scheme. So pretty much any device should be able to charge on at least one of these ports at a reasonable speed.


As you can see, there’s a lot of functionality in this new design just waiting to be unlocked by some clever software.  I’ve already milled a board and I’m looking forward to populating it and bringing it to life. I guess that will be quite a bit of work but I think its well worth it. Thanks to all of you who have kept asking about this project – I very much appreciate all your feedback.

There are only Eagle files (including PDFs of the layout and schematics) at this point. They can be downloaded on the overview page. There’s now also a prototype. First test results are presented here.

Ultrasonic Anemometer Part 26: Rev B Board ordered

I recently ordered my first PCB at dirtypcbs.com and the result was promising. So there was nothing stopping me from finalizing the Rev B of my standalone Ultrasonic Anemometer and ordering a protopack. I’ve placed the order a few days ago and expect the boards to arrive here in 2 to 3 weeks. This should be good news for all those of you who have been asking for kits and want to contribute to the further developement of this project. I’ll build up one or two boards as soon as they get here and do some testing. If everything works as planned I can order some more components and ship some kits soon after that.


So today I’ll go through the changes I’ve made compared to the previous version. All in all the changes are quite minor and only require minimal changes in software. But let’s go through them one by one.

Non-volatile memory

This is the biggest change from a functional point of view. The PIC32MX250 doesn’t have any EEPROM memory of its own. So in order to be able to save some settings an the like I’ve added a Microchip 24AA16 I2C EEPROM providing 16kbit (2kB) of non-volatile memory. That should be more than enough to store any settings and calibrations one might want to make. For example, this gives the user the possibility to calibrate the filter kernels to the transducers used. Of course, the software first needs to make use of that memory but I think it’s great to have the possibility to durably  store a reasonably large amount of data.


Support for 5V I2C communication

I’ve hinted at this in a previous post. On the Rev A board the I2C signals were pulled up to the 3.3 volt rail. This was great as long as one didn’t want to interface to a 5V device such as an Arduino. The microcontroller pins are 5V compatible so you want to be able to pull those lines up to 5V whenever you interface to a 5V device. So I’ve added a diode to allow the SDA and SCL lines to be pulled higher than 3.3 volts. The I2C reference voltage of 3.3 volts minus a schottky diode drop or about 3.1 volts is accessible from the I2C header at the bottom. So just connect that to the external device’s 5V operating voltage and you have a fully compliant 5V I2C bus.


Physical layout and connectors

There was a rather large 8-pin connector on the last version to connect to the transducers. Now all the connectors along the edges of the board are standard 100-mil headers. This also allowed me to slightly shrink the physical size of the board to 60x70mm.

The pinout has also slightly changed. The board is now powered from a header on the right-upper side and all three voltage rails are now externally accessible from a newly added header on the right side. The pin order on the I2C and SPI headers on the bottom side of the board has changed, mainly to accomodate an exteral I2C reference voltage.


Power supply

The tiny (SOT23-5) 3.3 volt linear regulator on the last version worked well but got rather hot when providing close to 50mA from a 12V input voltage. I never had any issues with it at room temperature but decided to be cautious and upgrade to a LD1117 regulator in a much larger SOT223 package. This should be more than sufficient any reasonable ambient temperature..


Miscellaneous changes

I changed the digipot used to set the amplifier gain to a Microchip MCP4531. This model only has 128 steps but this is still more than sufficient for its task and it’s quite a bit cheaper than the 256-step version.

I also had to change the crystal because the model previously used became unavailable.


That’s it for now. I’ll let you know as soon as the boards get here.

Bi-Directional Voltage Level Translator – Board House Test


While most of my microcontroller designs run on 3.3 volts there is still the ocasional 5 volt design. Or I do something with an Arduino. So the need may arise to interface between logic working at different voltage levels. There are several ways of doing this, depending on your needs. Things are relatively simple as long as you know in advance which side is transmitting and which side is receiving. It gets more difficult if the communication is bi-directional or with busses such as I2C that are bi-directional by nature. I did a search on farnell.com and identified two chips that can translate between almost any two voltage levels bi-directionally. The Texas Instruments TXB0106 works with up to 6 CMOS (i.e. actively driven high or low) signals for protocols such as SPI. The PCA9306 (also from TI) is intended for protocols such as I2C that rely on pull-up resistors and where a line must never be actively driven high.


I ordered a few of these chips and laid out a simple board that contains the two chips together with the pull-up resistors and some decoupling caps. I also added two larger 10uF ceramic capacitors for a generous amount of bulk capacitance. The result is a tiny little board (45x30mm) that can universally be used to translate between almost any two logic voltages for almost any protocol.

Giving dirtypcbs.com a try

I can think of a lot of situations where it could be useful. But the main reason for this project was to gain some experience with getting a PCB professionally manufactured by a board house. For several years I have done my own designs but I always milled and drilled them myself. This had pros and cons. I never had to worry about silk screens or solder masks because my boards never had any. On the other hand I suffered from the lack of plated-through holes. Vias were always a pain in the arse because I had to manually solder in pieces of wire to connect the two sides. And it was very difficult if not impossible to put a via below a component which made the layout challenging when working with ICs with many and/or tightly spaced pins.


So this simple project seemed perfect to gain some experience in getting a design made by a board house. I chose dirtypcbs.com for their unbeatable prices and read their requirements and restrictions.


Here are some things to watch out for:

  • If you’re working with Eagle you can download a design rule file to automatically check if your design fulfills their requirements. This is great for checking things like minimum via size or trace width/spacing.
  • Make your own gerber files. Yes, you can just send dirtypcbs.com your Eagle files and they will take care of it. But I highly recommend you do it yourself so you know what you’re getting. It’s not difficult. Just download their .cam file and run it. I modified it somewhat so the file names reflect what the file contains. The file types themselves are rather cryptic.
  • View the gerbers online: There are several online gerber viewers available for free. I particularly like the online viewer at mayhewlabs.com. Just drag and drop the gerber files produced in Eagle and get a beautiful 3D view of your design. Check it carefully to be sure the gerbers represent what you are after. My workflow was rather iterative: I produced the gerbers, looked at them online, changed something in Eagle, produced some new gerbers… Again and again until I was happy.
  • Control what’s on your silk screen. A lot of the silk screen comes directly from the component libraries. Typically, the libraries print the outline, orientation, part name and part value on the silk screen. Unless your layout has a loooot of space between components the silk screen will soon be cluttered with all that information. I recommend you make your own libraries. You can then change the components  to only contain the information you want and how you want it. I ended up only putting the outline and orientation of the components on the silk screen.
  • Be aware that the design rule check will not look at your silk screen. You need to make sure your silk screen meets the minimum width of 0.15mm. If you’re using vector fonts (as you should) the math is simple. Just multiply the font size by the font ratio to calculate the line width. Example: A 70mils font size with a 10% ratio gives a line width of 7mils or 0.178mm.
  • Make sure your silk screen doesn’t overlap any of the pads. Again, he design rule check will not check for this. The board house might avoid printing the silk screen over an exposed pad but I wouldn’t bet on it.
  • Eagle seems to do quite a good job with the solder mask without any manual intervention but check the result carefully using the gerber viewer. Pay particular attention to the vias. You generally want your vias to be covered with solder stop – there’s no reason to have them exposed. But you might have some vias that you use as pads to access some signal for testing and debugging. Make sure they are not covered by the solder mask. An easy way to distinguish by the two types of vias is by drill size. You can set this parameter under DRC -> Mask -> Limit.


It took me quite some time until I had my files ready for manufacturing. Especially given the simple nature of this project. I then ordered a proto-pack from dirtypcbs.com. I went for a industry-standard 1.6mm (they default to 1.2mm) FR4 with a cool-looking (and non-standard) blue solder mask at no extra cost. Some 3 weeks later I found 10 of those nice little boards in my mailbox. They are quite precisely how I expected from the gerber viewer. When you look at them close enough you’ll notice that the solder mask and silk screen are not perfectly aligned. The silk screen could also be somewhat cleaner. But don’t get me wrong – I’m not complaining. The quality is absolutely ok, these are nice little boards. And at this price – I paid 14$ including everything – they are simply amazing. Thank you, dirtypcb.


So the board house test was a success but how about the rest? So far I’ve only populated a single board. And while I haven’t actually used it yet I have performed some tests with a signal generator and a scope.

PCA9306 for I2C

So let’s look at the PCA9306′ performance in some more detail.

I2C: 5V to 1.8V at 1MHz

The chip performs excellently when translating from a high voltage to a lower voltage. In the  example above it is translating from 5 volts to 1.8 volts at a very high 1MHz frequency and the wave forms still look nice.

I2C: 1.8V to 5.0V at 100kHz

Translating in the opposite direction (1.8 to 5 volts) everything is fine at 100kHz.

I2C: 1.8V to 5.0V at 400kHz

At 400kHz the output waveform starts to look very jagged, however.

I2C: 3.3V to 5V at 400kHz

But of course, translating from 1.8 to 5 volts is a rather extreme example. In the much more likely scenario of translating from 3.3 to 5 volts the chip performs reasonably well, even at 400kHz. And I2C doesn’t usually happen at frequencies higher than that. An Arduino, for example, will usually work at 100kHz. So I’m very happy with the performance so far.

TXB0106 for SPI and the like

Now let’s look at the TXB0106.

5V to 1.8V at 100kHz

Translating from 5V to 1.8V at a modest 100kHz is rather undemanding and the waveforms look nothing but perfect.

5V to 1.8V at 1MHz

Even up at 1MHz this translation works totally fine.

1.8V to 5V at 100kHz

Translating the opposite way, from 1.8V to 5V is more demanding but works very well at 100kHz.

1.8V to 5V at 1MHz

However, at 1Mhz the wave forms start to look pretty uggly. And with a protocol like SPI it is much more likely to actually operate at 1MHz. Note that the glitches might be an artefact of my primitive test setup.

3.3V to 5V at 1MHz

As with the other chip, the output signal starts to better when only translating from 3.3 volts to 5 volts. As mentioned above this is a much more likely application and the chip does a decent job even at 1Mhz.

Support this blog – Buy one

By the way: If you need one of these universal voltage level translators you can support this blog by ordering one (fully assembled) for USD 20, including worldwide shipping. Just use the contact form on the about me page.


With the following link you can download the Eagle files as well as the gerbers. Just click here.

Ultrasonic Anemometer Part 25: I2C Interfacing and more


It’s been a long six weeks since my last post but that doesn’t mean that I haven’t done anything since. Among other things, I wrote some code to get the I2C interface working and hooked the anemometer up to an Arduino Uno with an LCD display attached. Apart from demonstrating the I2C interface this also nice for testing. For the first time I can see what this thing is measuring in real time without hooking it up to a PC over USB.


I2C Interfacing

But let’s look at the setup in some more detail. The PIC has a total of two I2C interfaces and I’ve made both of them accessible via the 100mil headers along the edges of the board. One of them is primarily intended for internal purposes like controlling the gain via the I2C digipot. The other one can then be used to interface to some external logic without having to worry about any internal communication. This external I2C interface also comes with 5V compatible pins which means we can interface to 5V devices like an Arduino without any further logic level translation. All we need is a pair of pull-up resistors pulling the SDA and SCL lines up to 5 volts. The Arduino’s Atmega328 already has built-in (weak) pull-up resistors so that’s not a problem. I didn’t think of interfacing to a 5V device when I designed the board and pulled the I2C signals to the anemometer’s 3.3V supply. So for proper 5V operation I’d have to unsolder the two 10k resistors. Luckily, 3.3 volts is enough to almost certainly be recognized as a logic high by the Arduino so the setup works anyway. But I will think about how to improve this in the next version. I might add a diode to allow the lines to be pulled higher than 3.3 volts.

The I2C interface can be configured to act as a master or as a slave device. For now I’ve only implemented slave mode so the wind meter behaves just like a I2C temperature sensor or external ADC. The Arduino acts as a master and asks the slave for its latest measurement every 250ms. The anemometer then returns 8 bytes of data consisting of 2 status bytes, north-south wind speed, east-west wind speed (both in mm/s as signed 16-bit integers) and temperature (0.01 degrees centigrade as signed 16-bit integer). It’s also possible to send data to the anemometer. That data is then saved to a buffer is otherwise ignored.  In a future version of the software one might use this functionality to set the data format to wind speed and wind direction or to change the temperature unit to kelvin or fahrenheit.


It would not be difficult to implement master mode as well but so far I haven’t done it yet. A lot of code could be copied from the module communicating with the digipot where the PIC acts as a master. The anemometer could then push data to an external device whenever a new measurement becomes available. Definitely something I’d like to implement at some point but no priority right now.

Bug fixes

I’ve found (and fixed) a number of bugs while testing. Among other things, the axis and direction signals were not always properly set and so the measurements did not always correspond to the direction they should. So take with a grain of salt some of the test results reported earlier. Some of them were almost a bit too good to be true and this bug might have been the cause. I suspect I might have compared two successive measurements in the same direction when I actually wanted to compare measurements taken in opposite directions. But I’ve fixed the code and I’m confident that now all the directions are set and reported correctly.

Individual filter kernels


As can easily be seen from the scope screenshots above, the shape of the received signal varies quite a bit from transducer to transducer. Note that the amplifier gain is dynamically adjusted to make sure the peak amplitude is the same for all of them but the shape still differs quite substantially. So the kernel for the matched filter has to be some compromise to suit them all. I have now modified the software to use four individual kernels, one for each direction. This gives us the flexibility to calibrate the kernel to each transducer and so get more reliable results for the absolute phase.

Revised board


My main priority at the moment is to complete the revised version of the board and to order a small series of boards. Until recently I never ordered a board from a professional board house so there are quite a few things for me to learn. For the first time I have to worry about silk screen, for example. Or solder mask. On the other hand, a board house can do a lot of things I can’t. Plated-through holes for example. Or smaller vias. Or place vias under an IC. This means a lot more flexibility in my layout that I first have to get used to. But I’m making progress. I got a simple design of mine produced by dirtypcbs.com and got a batch of very usable boards. More on that in a future post.

Wind tunnel

If you’ve been following this project for a long time already you might remember my simplistic wind tunnel made of a 120mm brushless fan and a cardboard tube. I got a number of suggestions from you guys on how to build something better than that and I also found some useful material online. So I’ve started to build a much improved wind tunnel that will hopefully allow me to perform more meaningful tests. That’s also for one or more future posts.


Software ideas

I’ve also played around with some software ideas that I believe to have potential. One is dynamically adjusting the frequency. I’m now only working at the transducer’s nominal frequency of 40kHz. But the individual transducer’s resonance frequency might be somewhat different and might change with temperature or age. So I might try to adjust the frequency dynamically using some perturbation and observation algorithm.

I’m also thinking about measuring at two slightly different frequencies (say, 39.5kHz and 40.5kHz) and using the two phase shifts to figure out the absolute time-of-flight. I’ve given it a try and was not very successful but I haven’t given up on that idea yet.

So that’s it for now. The code for the Ultrasonic Anemometer as well as the Arduino are available for download. See the overview page for the respective links.

Ultrasonic Anemometer Part 24: New Microcontroller and Software Controlled Gain

It’s been almost three weeks since my last post and some further progress has been made. I’ve upgraded the microcontroller and can now control the gain of the second amplifier stage in software. But let’s look at the changes in some more detail.


New microcontroller: PIC32MX250

I mentioned last time that I was running out of code space, i.e. flash memory on the PIC32MC220. That particular model has only 32k of flash and I’m using the free version of the XC32 compiler. That free version only performs limited amounts of optimization and therefore produces rather large and slow code compared to the standard and professional version. But the other two are rather costly (around USD 500 and 1000, respectively) and are not really an option here.  And at least so far I’ve always had all the speed I needed so the only issue was flash memory.

So the straight forward solution was to upgrade the microcontroller to an otherwise identical model with more memory. The 250 I’m using now has four times more of both flash (now 128k) and ram (now 32k). I unsoldered the old chip using a hot air gun and soldered in a PIC32MX250 in its place. Now we have all the flash we need to continue our journey.


Getting I2C to work

My design uses a dual op amp for the necessary amplification of the received signal. The first stage is ground-referenced and uses a simple resistive divider to set the gain (currently set at 11).

The second stage is biased to 1.65V (i.e. half way between ground and 3.3 volts) and has its gain controlled by a I2C digipot. The idea is to have the PIC control the digipot so it can adjust the gain as needed to compensate for any effect that might change the amplitude of the received signal.

So in order to control our digipot we first need to get the I2C interface working on the PIC. There are two (identical) I2C peripherals on the PIC32MX2xx and this design uses one of them (#2) exclusively to communicate to the digipot. The other one (#1) is then available to interface to the outside world.

I’ve written a set of simple functions to use the I2C interface. So far I’ve only implemented  master transmit mode since that’s the only thing we need here.

  • void app_i2c_internal_init(void);
  • bool app_i2c_internal_write(uint8_t address, uint8_t *data, uint8_t length);
  • void app_i2c_internal_writeDigipot(uint8_t value);

The functions are entirely non-blocking so they can be called from within the interrupt service routines that do the measurement.

Fixing a design bug

Unfortunately, I made a mistake in the schematic when I referenced the feedback loop of the second op amp stage to ground instead of the mentioned 1.65 volts. Now let’s look at what that did to the signal. First, below is the signal with the digipot at 0 (of 256). The gain is set to one and all is well.


But at a setting of 64, some clipping starts to occur as shown below.


With the gain turned up to 4 with a digipot setting of 192 things get really uggly with a completely unrecognizable output signal.


I was extremely lucky that the correct signal was available right next to the pin where I needed it so all I had to do was to cut the ground connection with a carving knife and to connect the correct signal using a tiny bit of wire.  The change is hardly visible on the photo below. Can you spot it? It’s almost at the center of the photo at pin 5 (bottom right) of the small 8-pin IC. It now connects to the 10k resistor at the bottom instead of the ground plane on its right.


Controlling the gain in software

With that error fixed we can now set the gain as we please. Here some examples. Yellow is the (unamplified) input signal whereas green is the output of the (fixed) first amplifier stage.  The purple signal is calculated as the difference between the DAC+ and DAC- signals. Those two signals is what we feed into the PIC to be measured.

With the gain at 1 (digipot at 0) we get a about 2.6 volts peak-peak. A bit little but sufficient.


This is probably about what we want. Digipot at 50 resulting in a peak-peak amplitude of a bit above 3 volts.


Needless to say that we can jerk the gain up far more than that if we want.  Below is an example where a gain of 4 results in a seriously clipped signal.


Now let’s look a a situation where such a high gain might actually be useful. In the example below I’ve lowered the input voltage to only 5 volts. As a result the received signal is only 90mV in amplitude instead of the 220mV seen above. That’s easily compensated with a bit of help from our digipot. With a setting of 170 we get a nice, clean 3 volt output signal.


Calculating the necessary gain

For the examples above I’ve explicitly set the gain in the code. But what we really want is to have the software calculate and set the necessary gain automatically.

So I’ve implemented a simple algorithm to do so. I set some target value for the peak-to-peak amplitude of the signal measured by the DAC. Knowing the amplitude and digipot setting of the last measurement I calculate the optimal gain and digipot setting for the next measurement.


Above is the signal without this automatic gain setting in place (gain=1). As you can see, the peak-to-peak amplitudes vary quite a bit between transducer pairs. So the gain calculations, too, work on a transducer pair basis. Each direction gets its own setting to compensate for different transducer sensitivities.

Below is a screenshot of the result. Notice how now all transducer pairs have identical (and somewhat larger) amplitudes.


That’s it for today. Click here for my next post.

Ultrasonic Anemometer Part 23: First successful measurements

In my last post I was happy to report that I managed to get the USB interface to work. This interface has since proved to be extremely valuable in software development and testing. While the device is taking measurements you can look at the results (or intermediate results) at your PC in real time. You can even log large amounts of data to a .csv file and inspect the results in Excel.


But let’s look at the developements in a bit more detail. Last time the device was sending pulses and capturing some of the resulting zero-crossings but not much more than that. And in a not very structured way.

Measuring amplitude

Now it’s not only capturing the times when the zero-crossings occur but also measures the amplitude of the half-waves in between. In order to do that an interrupt is generated at every zero-crossing capture. Inside that interrupt service routine time of the zero-crossing is saved (as previously) and the ADC is started. In order to measure the amplitude at its maximum (or minimum in case of a negative half-wave), the ADC first samples the input for a 6.25 microseconds (which corresponds to a quarter-wave at 40kHz). I’ve chosen the sampling period slightly shorter to compensate for the time from when the zero-crossing occured unil the ADC is started. After the sampling period the internal sample-and-hold amplifier switches from sample to hold and the actual analog-to-digital conversion takes place.

The PIC’s datasheet advertises a maximum sampling rate of 1 million samples per second. Beware, though, that this requires separate Vref+ and Vref- connections and doesn’t work in differential mode anyway. In my configuration without separate analog references and differential measurements the maximum sampling rate drops to 400k samples per second. And the reported conversion time doesn’t include the sampling time yet. I wasn’t aware of that but luckily the PIC’s ADC is still more than fast enough for what I’m doing here.


Finding the absolute phase

Capturing the zero-crossings is relatively easy and the results are very precise. But there’s a challenge: there are hundreds of zero crossings for each burst of pulses sent. How do you know which zero-crossings to use?

The Arduino-based anemometer used an analog envelope detector to solve this problem. After averaging plenty of samples this works most of the time. But even after many attempts to tweek the analog circuit the envelope detector approach was never as reliable as I wanted it to be.

My standalone anemometer has an entirely different approach. Being able to digitally measure the amplitude of each half-wave we can tackle the challenge in software. We have a series of measurements and we have an idea of that the signal we are looking for looks like. Looking the scope screenshot below you could easily and reliably determine where the maximum amplitude occurs. That’s what we need to teach the software to do.


One could, of course, just loop through the all the amplitudes and find the maximum. But there are a lot of similar amplitudes and so any noise would make the result unreliable.

I did a bit of reading on digital signal processing (DSP) and realized that this is a classic DSP problem. The solution is a matched filter. You take the signal you are looking for (also known as kernel or template) and multiply it sample by sample with the captured signal and sum up the results. Do that for every possible (or reasonable) overlap of signal and kernel and find the position where the result reaches its maximum.

If you’re new to the subject (like I am), Steven W. Smith’s Digital Signal Processing is a great place to start. It’s even available online for free at dspguide.com. The method is also referred as convolution or correlation depending on who you ask. This wikipedia article gives a nice introduction to the subject.

Implementing the matched filter

I’ve parameterized the software to capture 34 zero crossings as well as the n=33 amplitudes in between them. The kernel consists of k=17 data points with a peak in the middle.

There are n-k+1=17 possibilities to entirely overlap the kernel with the signal. We can skip all the odd numbers where a negative kernel value would be multiplied with a positive sample value and vice versa. This leaves us with 9 possible positions to chose from.

For each position we need to do 17 multiplications and 16 additions. And we need to do that for every single measurement, i.e. 512 times per second. That sounds like a lot of work and it probably is. Luckily, since this is a very common DSP task, microcontrollers like the PIC32 have a special instruction for this. It’s called MAC – Multiply Accumulate and executes in a single clock cycle. The result is just amazing. The corresponding ISR takes less than 30 microseconds, including some housekeeping tasks as can be seen in the screenshot below.

Once the maximum amplitude is found, the 16 zero-crossings around it (i.e. the 8 before and the 8 after) are summed up and the sum is saved as the result of that measurement.


Averaging measurements

The goal is to report wind speed and temperature four times per second. Since there are 512 measurements per second we can use up to 128 individual measurements  (32 in each direction) to do our calculations.

So we have plenty of data to identify and exclude outliers and do some averaging of the remaining samples. Robust statistics is the key word here, click here for the corresponding wikipedia article.

For now I’m doing something reasonably simple: First the 32 results per direction are sorted. The 12 lowest and 12 highest results are ignored and only the 8 results in the middle are summed up.

This might seem wasteful but it makes the average very robust against outliers and still results in 16 x 8 = 128 zero-crossings being averaged. The resolution of each zero-crossing is equal to 1 / 48MHz or about 20.83 nanoseconds. Summing up 128 of them gives us a resolution of far below a nanosecond. Beware however that resolution doesn not imply accuracy.

As a last step, the resulting sum is multiplied with 125 and then divided by 768 to make the unit 1 nanosecond. So every 250 milliseconds we finally have 4 time-of-flight measurements with a resolution of 1 nanosecond. That’s what we will use to calculate the winds speed as well as wind direction and temperature.

This sorting and averaging step is a bit more costly in terms of computation time. It takes around 600 microseconds to complete (see below). But unlike the convolution, it only has to be performed 4 times per second so this is more than fine.


Calculating wind speed

We are finally in a position to calculate the actual wind speed. There are various ways of doing this. For now I’ve just done the simple approach of taking the difference in time-of-flight, assuming room temperature and solving for wind speed. This means solving a quadratic equation for which I have resorted to floating point math and using <math.h> for the square root function.

I don’t have my wind tunnel any more so doing any testing was difficult. But one thing was soon obvious: at zero wind speed, the time-of-flight measurements match extremely well and are extrordinary stable from measurement to measurement. Also, looking at the intermediate results (i.e. the 128 single measurements before averaging) shows that there are basically no outliers present. I could randomly pick a measurement and still get a very reasonable value.

Something seems to be systematically wrong with the first of the 128 measurements but I haven’t had time to look into this. Otherwise, the results are impressively stable. And I’m only using a relatively primitive kernel for the matched filter.

USB data logging

As I’ve mentioned at the beginning, the USB interface lets me do some serious data logging even at this early stage of development. Here’s a list of what I can do by sending a character to the device from a USB terminal.

  • ‘Z’: Get all the 34 zero-crossings of a single measurement
  • ‘A’: Get all 33 amplitudes of a single measurement
  • ‘F’: Get a full single measurement, i.e. 34 zero-crossings plus 33 amplitudes
  • ‘T’: Get all the 4 x 32 = 128 time-of-flights for a measurement series
  • ‘R’: Get the 4 averaged time-of-flights as well as wind speed and temperature

Some versions of these commands also let you specify the direction you’re interested in as well as how many sets of data you want to receive. This makes it easy to log large amounts of data that you can use to test possible algorithms on your PC before you implement them on the PIC.


Next steps

The next step is to get the I2C digipot working so I can control the amplification in software. My idea is to aim for a maximum amplitude of around 3 volts independent of wind speed and so on.

There’s also plenty of work to do to improve the algorithm that calculates wind speed and temperature. And then I also have to implement the I2C and SPI interfaces that let the anemometer communicate to other embedded devices like an Arduino or Raspberry Pi.

Having used floating point math and <math.h> I’m also running out of flash memory. I’m currently using 93% of flash (32kB total) and 52% of ram (8kB total). There will be a slightly revised board (Rev B) that uses a PIC32MX250 which is identical to the MX220 used here but has four times as much flash and ram.

That’s it for today. On the overview page you find the software at the stage of developement just described as well as some examples of logged data (all at zero wind speed) as .csv files.

The next post on this project is here: Part 24.

DIY Electronics