Limpkin's blog<div>An electronics geek blog, dedicated to sharing and open source. Check out my stores: <a href="https://lectronz.com/stores/stephanelec" hreflang="en" title="Lectronz store">EU</a> / <a href="https://www.tindie.com/stores/stephanelec" hreflang="en" title="tindie store">EU & US</a>.</div>2024-03-19T09:35:26+00:00Mathieuurn:md5:51de6a3d917257edeff5a252fe925b02DotclearAssembling a 48V 18650 Cell-Based Batteryurn:md5:b46a38f387778837d1bd4f8cbc3971362023-11-26T12:48:00+00:002024-03-08T20:53:32+00:00limpkinMy Projects18650BMS<p><img src="https://www.limpkin.fr/public/48V_battery/.batterys_side_m.jpg" alt="" class="media-center">
... without making any fire!</p> <h2>Project Context<br></h2>
<p>This project isn't really a creation, but more like something I assembled together during the little spare time I could find.<br>
It all started when I found a listing for <strong>100x salvaged 18650 li-ion cells</strong> on a local auction website.<br>
Not having a home to build a powerwall into, I thought of the next best thing to do with them: make <strong>my own 48V backup battery</strong>. Why buy a new (and certified) battery when a geek can make one and potentially burn his/her appartment in the process?<br></p>
<h2>The Battery Kit<br></h2>
<p><a href="https://www.limpkin.fr/public/48V_battery/48V_battery_ebay_listing.PNG"><img src="https://www.limpkin.fr/public/48V_battery/48V_battery_ebay_listing.PNG" alt="" class="media-center"></a>
I then started looking on the interwebs for similar projects... and <strong>videos of lithium fires</strong>.<br>
I was quite surprised when I stumbled upon a (chinese) 48V 30A DYI battery kit on ebay for <strong>less than $40</strong>!<br>
This kit seemed to be made for e-bikes and came with 18650 holders, a Battery Management System (BMS) and the box that goes around them. All that was then needed was the 18650 cells, a spot welder, (very) thick wires and a high current connector.<br></p>
<h2>Cleaning out the Cells<br></h2>
<p><a href="https://www.limpkin.fr/public/48V_battery/battery_grinding.JPG"><img src="https://www.limpkin.fr/public/48V_battery/.battery_grinding_m.jpg" alt="" class="media-center"></a><br>
The salvaged cells I purchased locally still had pieces of nickel strips on them. I therefore used a <strong>dremel and the grinding bit you see above</strong> to clean the 18650s.<br>
I then used lithium cells chargers to measure every 18650 cell capacity. All cells (surprisingly) had a capacity between 2300mAh and 2600mAh, but I found these measurements to <strong>not particularly be repeatable</strong>.<br></p>
<h2>Balancing out the Cells<br></h2>
<p><a href="https://www.limpkin.fr/public/48V_battery/cell_balancer.JPG"><img src="https://www.limpkin.fr/public/48V_battery/cell_balancer.JPG" alt="" class="media-center"></a><br>
The idea of assembling a battery with 78 fully charged lithium cells wasn't particularly appealing to me. I therefore designed the gigantic PCB you see above, which essentially <strong>puts all cells with series resistors in parrallel</strong>.<br>
The goal of this contraption is therefore to <strong>balance all the cells</strong> (so I don't connect a 3.6V cell to a 4.2V one during assembly) and discharge them all to a <strong>safer voltage before assembly</strong> (using an external programmable load).<br>
Here's the thing though: every PCB manufacturer you'll find out there won't (for some reason) sell you a single PCB: <strong>the minimum order quantity is 5</strong>. But <a href="http://www.pcbway.com" hreflang="en" title="pcbway">PCBWay</a> came to the rescue and graciously offered to produce them for me!<br>
I found the 18650 cell holders on aliexpress and soldered them together with the balancing resistors... which took quite a while. Once the board was assembled and the cells balanced, I then took the opportunity to <strong>measure each cell series resistance with an ESR meter</strong>. That was the result:<br><br>
<a href="https://www.limpkin.fr/public/48V_battery/battery_caps.JPG"><img src="https://www.limpkin.fr/public/48V_battery/battery_caps.JPG" alt="" class="media-center"></a><br>
This much more reliable measurement <strong>painted a clearer picture of the cells' states</strong>. Interestingly, it did look like the higher the measured the ESR, the more capacity was remaining. I'm guessing this is due to the fact that for a random cell distribution a battery pack, the cells with the lower ESR would contribute more current than the others. That or something is up with my cell charger.<br></p>
<h2>Soldering the Wires<br></h2>
<p><a href="https://www.limpkin.fr/public/48V_battery/BMS_with_wires.JPG"><img src="https://www.limpkin.fr/public/48V_battery/BMS_with_wires.JPG" alt="" class="media-center"></a><br>
For obvious cost reaons the BMS didn't come with wires, so the first step before spot-welding the cells was to solder some thick gage wires I bought from Digikey. As you can see above, I even added a (very big) <strong>fuse assembly</strong> as an extra precaution.<br></p>
<h2>Assembling the Battery<br></h2>
<p><a href="https://www.limpkin.fr/public/48V_battery/battery_assembly.JPG"><img src="https://www.limpkin.fr/public/48V_battery/.battery_assembly_m.jpg" alt="" class="media-center"></a><br>
This obviously was the <strong>most dangerous part of this adventure</strong> as this pack is composed of <strong>13 times 6 parallel cells in series</strong> (aka 13s/6p). When selecting the groups of 6 parallel cells, I <strong>picked the cells with similar internal resistance</strong> so no cell would work harder than another. I double checked that all cell voltages were equal and then interleaved groups of 6 cells with low and high ESR to make sure that one side of the battery wouldn't get hotter than the other during charge/discharge.<br>
Before spot welding the last group of 6 cells to the BMS most positive tab, <strong>I tested the BMS using a lab power supply to simulate a group of 6 cells' voltage</strong>. When performing a battery discharge using an external programmable load, I set a simulated cell voltage of 2.8V and checked that the BMS would stop the discharge. Similarly, when performing a battery charge I set a simulated cell voltage of 4.2V and checked the BMS would stop the charge.<br>
Finally, <strong>I discovered holes on the BMS to solder a thermistor</strong>. As I had a few in stock, I soldered one and also did check that the BMS <strong>would stop the discharge when the sensed temperature would get above 60degrees</strong>.<br></p>
<h2>A Final Precaution<br></h2>
<p><img src="https://www.limpkin.fr/public/48V_battery/temp_sensor.PNG" alt="" class="media-center"><br>
To really make sure the battery wouldn't overheat, I found a <strong>temperature sensor with an alarm feature</strong>.<br>
I obviously tested it before adding it into the assembly.<br></p>
<h2>The Final Result<br></h2>
<p><a href="https://www.limpkin.fr/public/48V_battery/battery_top.JPG"><img src="https://www.limpkin.fr/public/48V_battery/.battery_top_m.jpg" alt="" class="media-center"></a><br>
Here it is!<br>
I performed a discharge/charge test and measured that the battery had a <strong>570Wh capacity and a 145mR internal resistance</strong>... not bad!</p>https://www.limpkin.fr/index.php?post/2023/04/29/Assembling-a-Custom-48V-18650-Battery#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/218A Board for Current-Based Side Channel Attacksurn:md5:ff9554d786d6edd085d22df7d4c549c12023-11-14T22:15:00+00:002024-01-02T12:42:23+00:00limpkinMy Projectscurrent senseshunt resistorside channel<p><img src="https://www.limpkin.fr/public/sc_ampl_non_isol/.sc_ampl_non_isol_m.jpg" alt="" class="media-center" />
Or how to snoop on targets by looking at their current consumption...</p> <h2>Introduction<br /></h2>
<p>For several months, I had the chance to share an office with a security researcher whose hobby was to <strong>break the ESP32 AES engine by only looking at its current consumption</strong>.<br />
His measurement setup was not ideal: long wires, a noisy current probe that required lots of trace averaging to measure anything... something needed to be done!<br /><br /></p>
<h2>Selected approach<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_non_isol/time_trace.png"><img src="https://www.limpkin.fr/public/sc_ampl_non_isol/.time_trace_m.png" alt="" class="media-center" /></a><br />
Before we begin, it's important to know that the tiny bit of leakage current that gives you tips about what data the AES encryption engine is currently dealing with <strong>is buried inside the overall current measurement</strong>.<br />
This effectively means <strong>that special attention must be paid to noise</strong>, or in other words the measurement setup you use shouldn't introduce (lots of) additional noise before the signal digitization performed by your oscilloscope.<br />
And unfortunately for us, the typical ways to measure current at high frequencies (differential & current probes, LISNs) were indeed found to <strong>add so much noise that a side channel attack wouldn't be feasible</strong>.<br /><br />
<img src="https://www.limpkin.fr/public/sc_ampl_non_isol/shunt_resistor.png" alt="" class="media-center" />
You may now be wondering why I didn't mention the simplest current measurement technique of all: <strong>the shunt resistor</strong> (shown above). Just put a resistor in line with your power supply, put your probe across it and <em>voila</em>, right?<br />
Unfortunately, this measurement technique <strong>doesn't offer enough gain and is prone to ground loops</strong>: to precisely measure low currents, you'd need such a high resistor value that your target <strong>wouldn't boot in the first place</strong>.<br /><br />
<img src="https://www.limpkin.fr/public/sc_ampl_non_isol/.sc_ampl_non_isol_diagram_m.png" alt="" class="media-center" /><br />
So what about a <strong>"standalone" amplified shunt resistor</strong>: a small value resistor, followed by low-noise amplifiers?<br /><br /></p>
<h2>Coming up with requirements<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_non_isol/current_sensors.png"><img src="https://www.limpkin.fr/public/sc_ampl_non_isol/.current_sensors_m.png" alt="" class="media-center" /></a><br />
How to come up with requirements when you don't know what signal you're looking for?<br />
I looked at the different measurement tools above and came up with the following specifications:<br />
- <strong>shunt resistor value</strong>: reasonably low, between 1R and 10R<br />
- <strong>gain</strong>: tough one... around 100x, adjustable?<br />
- <strong>frequency</strong>: let's aim for 1 to 500MHz<br />
- <strong>noise</strong>: as low as possible, obviously!<br />
- <strong>battery powered</strong><br /><br />
I wanted to design something as versatile as possible to increase the odds that I wouldn't need to do a complete redesign.<br />
Why battery powered you may ask? Well, <strong>standalone power supplies are noisy.</strong><br />
As measurement sessions typically last hours, 18650 batteries seemed like the obvious choice.<br /><br /></p>
<h2>Amplification chain schematics<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_non_isol/sc_ampl_non_isol_schematics.png"><img src="https://www.limpkin.fr/public/sc_ampl_non_isol/.sc_ampl_non_isol_schematics_m.png" alt="" class="media-center" /></a><br />
From left to right you can see:<br /><br />
<strong>A 10R potentiometer followed by a high pass filter</strong>: this allows the user to manually adjust the low side shunt resistance. It's important to note that the potentiometer doesn't really behave like a potentiometer above 20MHz or so. Testing revealed this wasn't a big issue as low frequency contents are <strong>way more present</strong> in current measurements, so they're the ones that need to be attenuated the most. The following high pass filter is only here because <strong>leakage information is always above 2-3MHz</strong>.... and if you'd amplify DC then your output would quickly be saturated!<br /><br />
<strong>A first stage amplifier</strong>: the OPA855 was selected for its impressive specs: 8GHz gain-bandwidth product and a <1nV/sq(Hz) input voltage noise rating! By default configured for a x19 gain / 421MHz BW, removing a 50R resistor changes the gain to x10 and allows a 800MHz BW.<br /><br />
<strong>An adjustable 25dB attenuator</strong>: specified from DC to 2.5GHz, it "only" needs a negative input between -3V and GND to vary the applied attenuation.<br /><br />
<strong>A second stage amplifier</strong>, identical to the first stage one.<br /><br />
Just looking at the amplifiers and attenuator, high-Z loaded, the overall amplification chain gain can be set between <strong>6.8 and 120,6</strong>. To get the current to voltage amplification value, you then need to multiply these last 2 values by the set potentiometer value.<br /><br /></p>
<h2>The three drawbacks that don't matter (much)<br /></h2>
<p><strong>First drawback</strong>: the potentiometer and selected attenuator have different characteristics at different frequencies.<br />
This means that the <strong>circuit gain across frequencies won't be flat</strong>... <strong>which is fine!</strong> Side channel measurements are <strong>differential measurements</strong> that look for amplitude variations for different input data.<br /><br />
<strong>Second drawback</strong>: <strong>the output may saturate</strong>.<br />
As previously mentioned we may be looking for small buried signals, so if the gain is set too high then some input signal frequencies may lead to output saturation. Testing revealed that this was also fine as relevant leakage seems to be present during "quiet times". Moreover, the OPA855 has a <5ns recovery time specified.<br /><br />
<strong>Third drawback:</strong> <strong>the target ground isn't your measurement setup ground anymore</strong>.<br />
This is obviously due to the shunt resistor that essentially "lifts" your DUT ground to a couple mVs. This may be something to keep in mind when designing your measurement setup: your oscilloscope input grounds are connected together so if you were to connect another oscilloscope input ground to your DUT ground then your shunt resistor would essentially be shorted. That's the theory though... in practice the ground voltage difference is so low that <strong>I didn't see any impact when doing so</strong>. Moreover, the measurement board does include some solder pads/pins to offer real ground connection.<br /><br /></p>
<h2>The power supplies<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_non_isol/sc_ampl_non_isol_power_diagram.png"><img src="https://www.limpkin.fr/public/sc_ampl_non_isol/.sc_ampl_non_isol_power_diagram_m.png" alt="" class="media-center" /></a><br />
I'm really not a big fan of designing devices that use 18650 li-ion batteries.... but no choice.<br />
This project uses four batteries:<br />
- two to provide the +-2.5V(ish) voltage rails required by the op-amps and attenuator<br />
- two in (kinda) parallel to provide power to an LDO with <strong>three outputs</strong><br /><br />
Why that last LDO? To provide a <strong>clean power supply to the target</strong> as an external one would just add more noise to our measurements. Finally, protection circuits are present on the board to protect the 18650 cells from over charge and over discharge.<br /><br /></p>
<h2>Measuring the transfer function<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_non_isol/transmission_20db_atten_50r_series_whole_range_1-50M.png"><img src="https://www.limpkin.fr/public/sc_ampl_non_isol/.transmission_20db_atten_50r_series_whole_range_1-50M_m.png" alt="" class="media-center" /></a><br />
Using my bode100 with 20dB of external attenuation and a 45R series resistor I then injected current between the DUT ground and the actual ground to measure the above transfer function, for different shunt resistance and different set attenuation values.<br />
It's in my opinion quite impressive to measure such a wide attenuation range of <strong>nearly 50dB</strong>.<br />
In that wiring configuration, assuming 50R is presented to the bode100, we'd expect a theoretical maximum gain of:<br />
20log10( (8.33/50) * 19 * 19) - 6dB - 3.6dB - 6dB - 20dB = <strong>0dB</strong>... <strong>nearly exactly what is measured.</strong><br /><br />
<a href="https://www.limpkin.fr/public/sc_ampl_non_isol/transmission_20db_atten_50r_series_whole_range_1-1000M_atten_then_shunt.png"><img src="https://www.limpkin.fr/public/sc_ampl_non_isol/.transmission_20db_atten_50r_series_whole_range_1-1000M_atten_then_shunt_m.png" alt="" class="media-center" /></a><br />
Measuring between DC and 1GHz, I was quite impressed by seeing such a flat frequency response.<br /><br /></p>
<h2>Does it work? The conclusion<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_non_isol/sc_ampl_non_isol.JPG"><img src="https://www.limpkin.fr/public/sc_ampl_non_isol/.sc_ampl_non_isol_m.jpg" alt="" class="media-center" /></a><br />
<strong>It does,</strong> so well that I actually was invited to hardwear.io to talk about it:<br /></p>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/22qQDQXWq4E" frameborder="0" allowfullscreen></iframe>
</div>
<p>The board is currently being used by several security researchers out there and ICs have already been broken with it!<br />
You may find its source files <a href="https://github.com/limpkin/side_channel_amplifier" hreflang="en" title="side channel amplifier repository">here</a>, the board is available for sale here: <a href="https://lectronz.com/products/side-channel-attack-measurement-platform" hreflang="en" title="EU store">EU store</a> / <a href="https://www.tindie.com/products/stephanelec/side-channel-attack-measurement-platform/" hreflang="en" title="US store">US store</a>.<br /></p>https://www.limpkin.fr/index.php?post/2023/10/19/A-Board-for-Current-Based-Side-Channel-Attacks#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/220Using a Balun for Current-Based Side Channel Attacksurn:md5:f4214001d0fc462bc878ecf62b375fb92023-10-31T17:19:00+00:002024-01-02T12:36:56+00:00limpkinMy Projectscurrent senseshunt resistorside channel<p><img src="https://www.limpkin.fr/public/sc_ampl_isol/.sc_isol_fixed_pcba_m.jpg" alt="" class="media-center" />
Or how to use a common component for a completely different purpose!</p> <h2>Introduction<br /></h2>
<p>For several months, I had the chance to share an office with a security researcher whose hobby was to <strong>break the ESP32 AES engine by only looking at its current consumption</strong>.<br />
His measurement setup was not ideal: long wires, a noisy current probe that required lots of trace averaging to measure anything... something needed to be done!<br /><br /></p>
<h2>Why a Balun?<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_isol/balun.jpg"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.balun_m.jpg" alt="" /></a><br />
There are obviously many different tools to measure the current consumption of a given device: differentials probes, <a href="https://en.wikipedia.org/wiki/Current_clamp" hreflang="en" title="current probe">current probes</a>, <a href="https://en.wikipedia.org/wiki/Shunt_(electrical)" hreflang="en" title="shunt resistor">shunt resistors</a>, <a href="https://en.wikipedia.org/wiki/Line_Impedance_Stabilization_Network" hreflang="en" title="LISNs">LISNs</a>... so why go for a balun?<br />
The answer is fairly long and I actually was <strong>invited to hardwear.io</strong> to talk about this:<br /></p>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/22qQDQXWq4E" frameborder="0" allowfullscreen></iframe>
</div>
<p>... but in short, the "standard tools" made to measure very small currents are either <strong>too noisy</strong> or <strong>don't have enough gain</strong>.<br /><br />
<a href="https://www.limpkin.fr/public/sc_ampl_isol/sc_ampl_isol_diagram.png"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.sc_ampl_isol_diagram_m.png" alt="" class="media-center" /></a><br />
I therefore came up with the above concept which uses a balun to provide <strong>isolated current measurements</strong>: the balun primary/left side is isolated from its secondary/right side!<br />
This effectively means that you can place this device on the Device Under Test (DUT) "high side" (on its power supply rail) or on its "low side" (between the DUT and its ground) as the <strong>amplification output ground is floating</strong>. On top of that, having an isolated output prevents ground loops, which could have introduced noise at our input!<br />
The only downside of baluns is that <strong>they don't handle DC well</strong>, which is actually perfectly fine for me as side channels attacks <strong>only care about frequencies above 2MHz</strong>.<br />
In the above diagram, DC current will go through the shunt resistor while the AC current will go through <strong>both the shunt and the balun</strong>.<br /><br /></p>
<h2>Figuring out the details<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_isol/sc_ampl_isol_diagram_details.png"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.sc_ampl_isol_diagram_details_m.png" alt="" class="media-center" /></a><br />
With the concept locked in, I started looking online for baluns. One important thing to know about baluns is that they <strong>expect a given impedance on both their primary and secondary side</strong>, and that impedance typically is <strong>50 ohms</strong>.<br />
Luckily, <strong>I ended up finding a balun with a 1:8 impedance ratio</strong>, meaning that for a 50 ohms present at its secondary/right side, a <strong>6.25R ohms impedance is shown at its primary/left side</strong>... quite the perfect value for an AC shunt resistance!<br />
And what better component than a <strong>potentiometer</strong> to vary both the DC & AC shunt resistance to adjust the overall current to voltage gain?<br />
But what about that "amplification" box? What should we use to amplify the signal coming out of the balun while presenting a 50R impedance at the same time? Given the balun stated 2-500MHz bandwidth, the answer was fairly obvious: <strong>RF amplifiers</strong>!<br /><br /></p>
<h2>The amplification chain schematics<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_isol/sc_ampl_isol_sch_chain.PNG"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.sc_ampl_isol_sch_chain_m.png" alt="" class="media-center" /></a><br />
How apparently simple are these schematics?<br />
You'll notice that I'm using <strong>two low noise RF amplifiers in series</strong> to get lots of gain... maybe too much actually!<br />
For a 10R potentiometer position, the expected current to voltage gain is <strong>50.5dB or 335x</strong>.<br />
You may also be wondering <strong>why C5 is here</strong>. Well it turns out that during my initial tests <strong>I would get oscillations at around 2.2GHz</strong> because my amplification chain output would wirelessly couple into my input! C5 therefore reduces the balun's bandwidth (yup, it can transmit more than its specified 500MHz, likely due to capacitive coupling).<br /><br /></p>
<h2>What provides power?<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_isol/sc_ampl_isol_power.PNG"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.sc_ampl_isol_power_m.png" alt="" class="media-center" /></a><br />
From the previous paragraph you'll have noticed <strong>that only a single 3V3 rail is needed</strong> to power the two amplifiers.<br />
Using an external power supply was an option but just to be extra careful and not <strong>bring its noise to the board, which could then couple into our signal</strong> I opted for a <strong>lithium ion battery</strong> instead.<br />
U1 takes care of its under/over voltage protection, and its 3,6V-4,2V output then gets passed to a 3v3 LDO.<br /><br /></p>
<h2>The final board<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_isol/sc_isol_fixed_pcba.JPG"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.sc_isol_fixed_pcba_m.jpg" alt="" class="media-center" /></a><br />
It is pretty small! Notice the two holes on the bottom left, to either directly solder wires or a standard 0.1" header.<br /><br /></p>
<h2>Measuring the transfer function<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_non_isol/current_sensor_testing_setup.drawio.png"><img src="https://www.limpkin.fr/public/sc_ampl_non_isol/.current_sensor_testing_setup.drawio_m.png" alt="" class="media-center" /></a><br />
The transfer function was measured using the above test setup.<br /><br />
<a href="https://www.limpkin.fr/public/sc_ampl_isol/bode_transf_40dB_atten_0dBm_power_45r_series.PNG"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.bode_transf_40dB_atten_0dBm_power_45r_series_m.png" alt="" class="media-center" /></a><br />
Looking at the above frequency response for different potentiometer positions, "gain flatness" are the two words that come to mind.<br />
In that DC-50MHz sweep the gain keeps increasing.... <strong>which is actually fine for two reasons</strong>:<br />
- actual wiring setups will heavily attenuate high frequencies<br />
- <strong>side channel attacks don't care about frequency profiles</strong>!<br />
...and that's actually lucky for us, as gain isn't particularly flat above 50MHz either:<br /><br />
<a href="https://www.limpkin.fr/public/sc_ampl_isol/bode_transf_40dB_atten_45r_series.PNG"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.bode_transf_40dB_atten_45r_series_m.png" alt="" class="media-center" /></a><br />
What's cool in the above plot is that <strong>RF transmissions seems to be picked up</strong> at around 780MHz and 915MHz!<br />
Keeping in mind that I'm using 40dB of external attenuation and that my AC shunt resistance is around 6R, for a 10R potentiometer position my expected overall measured gain should be:<br />
20log10( (4/50) * (10/16) * 6) + 23dB + 26dB - 40dB = <strong>-1.45dB</strong>... which is fairly close to what we measure!<br /></p>
<h2>Improving the board by adding variable attenuation<br /></h2>
<p><a href="https://www.limpkin.fr/public/sc_ampl_isol/sc_isol_var_schem.PNG"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.sc_isol_var_schem_m.png" alt="" class="media-center" /></a><br />
Happy with that first board, I then decided to add a feature requested by my office-mate: <strong>variable gain</strong>.<br />
I therefore found a very neat <strong>variable attenuator</strong> that only needs a negative voltage between -3V and 0V to vary its attenuation by up to 25dB!<br />
Unfortunately that meant adding another battery to the board to provide a negative voltage... and a negative LDO so the set gain doesn't change as the battery depletes. As the current needed by the attenuator is extremely low, I'm using a <strong>CR1220</strong> coin cell battery, directly inserted inside a holder located at the back of the PCB.<br />
<a href="https://www.limpkin.fr/public/sc_ampl_isol/sc_ampl_isol_var.JPG"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.sc_ampl_isol_var_m.jpg" alt="" class="media-center" /></a><br />
As you can see, the updated board is fairly similar to its first version!<br /><br />
<a href="https://www.limpkin.fr/public/sc_ampl_isol/bode_transf_40dB_atten_0dBm_power_45r_series_through_var.PNG"><img src="https://www.limpkin.fr/public/sc_ampl_isol/.bode_transf_40dB_atten_0dBm_power_45r_series_through_var_m.png" alt="" class="media-center" /></a><br />
Above is the transfer function for different set shunt resistance values and different attenuations... that's quite the range!<br /></p>
<h2>Does it work? The conclusion<br /></h2>
<p><strong>It does!</strong><br />
The board is currently being used by several security researchers out there and ICs have already been broken with it!<br />
You may find its source files <a href="https://github.com/limpkin/side_channel_amplifier" hreflang="en" title="side channel amplifier repository">here</a>.<br />
The boards are also available for sale:<br />
- the fixed gain version: <a href="https://www.tindie.com/products/stephanelec/isolated-balun-based-current-sensor/" hreflang="en" title=" Isolated Balun-Based Current Sensor - EU & US shop">EU & US shop</a><br />
- the variable gain version: <a href="https://lectronz.com/products/isolated-balun-based-variable-current-sensor" hreflang="en" title="Isolated Balun-Based Variable Current Sensor - US shop">EU shop</a> / <a href="https://www.tindie.com/products/stephanelec/isolated-balun-based-variable-current-sensor/" hreflang="en" title="Isolated Balun-Based Variable Current Sensor - US shop">US shop</a><br /></p>https://www.limpkin.fr/index.php?post/2023/10/26/Using-a-1%3A8-Balun-for-Current-Based-Side-Channel-Attacks#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/221Repairing a Pair of Audioengine A5 Speakersurn:md5:c950534e21db781f026df88f3e043e542023-09-05T20:37:00+01:002023-09-05T20:37:00+01:00limpkinOthersa5audioenginerepairs<p><img src="https://www.limpkin.fr/public/a5_repair/.a5_speakers_m.jpg" alt="" class="media-center" /><br />
I started experiencing an issue with my A5 speakers: <strong>my right speaker was getting quieter than the left one!</strong><br /></p> <p>I don't know about you, but for me this was one of these issues that would constantly annoy me as it progressively got worse.... there's so much an operating system's equalizer could do!<br />
As customer support let me know that <strong>replacement parts weren't made anymore</strong>, I decided to sacrifice a Sunday afternoon to get to the bottom of things.<br />
As you can imagine, the first step was to open the back of the left speaker, which contained all the electronics:<br /><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_opening.jpg"><img src="https://www.limpkin.fr/public/a5_repair/.a5_opening_m.jpg" alt="" class="media-center" /></a><br />
I was pleasantly surprised by the build quality: nearly all cables are surrounded by foam, all heat generating components are mounted to a big heatsink that is thermally connected to the speaker back-plate, and some kind of black silicon is used to make sure that no air can pass through the connectors holes (and dampen vibrations).<br />
As the problem I was experiencing was a balance issue between the left and right channels, I started looking along the amplification chain for a place <strong>where I could probe both signals with my oscilloscope</strong>:<br /><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_lgr.jpg"><img src="https://www.limpkin.fr/public/a5_repair/.a5_lgr_m.jpg" alt="" class="media-center" /></a><br />
I then found this connector on what I called the 'input stage board', at the end of a cable connecting the latter to the 'amplification board'. Looking at the picture above you'll notice <strong>L/G/R markings</strong>, likely for <strong>Left / Ground / Right</strong>.<br />
As to why there were 2 of them... I'm not fully sure but could guess it had something to do with the second input jack on the speaker (<em>edit: they actually were mute & standby signals)</em>.<br /><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_jack.jpg"><img src="https://www.limpkin.fr/public/a5_repair/.a5_jack_m.jpg" alt="" class="media-center" /></a><br />
I then made the above contraption to feed a tone to the A5 input jack and checked for a volume imbalance at that connector's pins:<br /><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_con_probing.jpg"><img src="https://www.limpkin.fr/public/a5_repair/.a5_con_probing_m.jpg" alt="" class="media-center" /></a><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_left_right.png"><img src="https://www.limpkin.fr/public/a5_repair/.a5_left_right_m.png" alt="" class="media-center" /></a><br />
Success! I could definitely see different peak-to-peak amplitudes between the L and R marked pins.<br />
I then disconnected the cable going to the amplification board and checked the resistance between each signal pin and ground:<br /><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_cable_probe.jpg"><img src="https://www.limpkin.fr/public/a5_repair/.a5_cable_probe_m.jpg" alt="" class="media-center" /></a><br />
47k for one pair, <strong>15k for the other!</strong> The problem was on the amplification board... <strong>or so I thought</strong>.<br /><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_amp_board_res.jpg"><img src="https://www.limpkin.fr/public/a5_repair/.a5_amp_board_res_m.jpg" alt="" class="media-center" /></a><br />
Following the L/R signals to the amplification board I was happy to discover the <strong>utter left/right 47k resistors,</strong> connecting each L/R input to ground. I confirmed my 47k & 15k measurement across each resistor, then removed what I thought was the faulty 47k resistor.<br />
I measured the resistances again.... <strong>and discovered in disbelief that my 15k reading had become a 22k reading</strong>, even though the other resistor connected to each L/R input was 740k. How come?<br />
Well.... I'm not 100% sure but my best guess is that a small voltage was still present at each node, which would confuse my multimeter.<br /><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_input_board.jpg"><img src="https://www.limpkin.fr/public/a5_repair/.a5_input_board_m.jpg" alt="" class="media-center" /></a><br />
I then turned my attention to the closest IC next to the connector on the input stage board. A quick google search revealed that the N5532 was a <a href="https://www.ti.com/lit/ds/symlink/ne5532.pdf" hreflang="en" title="low noise amplifier">low noise amplifier</a> and its datasheet let me know what its output pins were.<br /><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_removed_cap.jpg"><img src="https://www.limpkin.fr/public/a5_repair/.a5_removed_cap_m.jpg" alt="" class="media-center" /></a><br />
I confirmed that each of its outputs was connected (through passives) to each L/R connector pin I had previously probed, switched on the amplifier with a tone fed to it, and found that a <strong>capacitor seemed to be blocking one output signal</strong>! That's unfortunately quite typical as electrolytic capacitors age this way. A quick Digikey order and a bad soldering job later, I was ready to confirm my diagnosis:<br /><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_repair.jpg"><img src="https://www.limpkin.fr/public/a5_repair/.a5_repair_m.jpg" alt="" class="media-center" /></a><br />
<strong>The capacitor replacement fixed the issue</strong>! But how to make sure it wasn't all in my head?<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/Omicron_BODE-100.jpg"><img src="https://www.limpkin.fr/public/cdm324_v2/Omicron_BODE-100.jpg" alt="" class="media-center" /></a><br />
Well, why not <strong>check the transfer function</strong> between the jack input and the pads I was probing?<br /><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_transfer_func.PNG"><img src="https://www.limpkin.fr/public/a5_repair/.a5_transfer_func_m.png" alt="" class="media-center" /></a><br />
So it seems I definitely <strong>managed to repair my speakers</strong>! The gain difference between the left and right speaker is around .7dB, which isn't perfect but I'll live with it. You'll notice the large gain difference after 12kHz, but that didn't bother me too much as during testing I couldn't hear it (I'm getting old....).<br /></p>
<h2>An Even Better Conclusion<br /></h2>
<p><a href="https://www.limpkin.fr/public/a5_repair/a5_speakers.jpg"><img src="https://www.limpkin.fr/public/a5_repair/.a5_speakers_m.jpg" alt="" class="media-center" /></a><br />
At the end of my debugging adventures I had a brain wave: if the manufacturer doesn't have the spare parts and doesn't sell this model anymore, <strong>why doesn't he release the source files</strong>?<br />
I continued my support thread and got a nice surprise: <strong>Audioengine sent me the schematics</strong>!<br />
You'll therefore find them below if you ever encounter an issue with Audioengine A5s... <br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_amplifier_board_schematics.pdf">a5_amplifier_board_schematics.pdf</a><br />
<a href="https://www.limpkin.fr/public/a5_repair/a5_input_stage_board_schematics.pdf">a5_input_stage_board_schematics.pdf</a><br /><br />
<strong>Hats off to Audioengine</strong>!</p>https://www.limpkin.fr/index.php?post/2023/09/03/Repairing-a-pair-of-Audioengine-A5-speakers#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/219CDM324 Doppler Speed Sensor, with FFTs!urn:md5:c6c13a8d10a780d3192761eae924d3c32023-08-23T17:14:00+01:002023-12-07T09:28:24+00:00limpkinMy Projectscdm324dopplerfftstm32<p><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_and_exp.JPG" alt="" class="media-center" />
A very small form factor project, not only measuring an object's speed but also displaying it!<br />
With its UART interface, interfacing with Arduino platforms is dead simple too!</p> <h2>Introduction<br /></h2>
<p>If you follow this blog, you may have noticed that this is my third project using doppler sensors, and my second with the <strong>CDM324</strong>. This tiny sensor is just so neat for its price!<br /><br />
<img src="https://www.limpkin.fr/public/HB100/doppler-effect.png" alt="Doppler effect" class="media-center" title="Doppler effect, août 2013" /><br />
A quick refresher on the <strong>Doppler effect</strong>: when sending an RF tone at a given frequency towards a moving target, the <strong>reflected signal's frequency will be shifted</strong>. This is the reason why a fire truck's siren has a <strong>higher pitch</strong> when the truck is going towards you than when it is still.<br /><br />
<img src="https://www.limpkin.fr/public/cdm324_v2/cdm324_zoom.jpg" alt="" class="media-center" /><br />
And what's nice with the CDM324 sensor above is that it actually <strong>outputs that frequency shift</strong>, so you "just" need to measure that frequency to compute the moving object's speed!<br /></p>
<h2>The project in action<br /></h2>
<p>Before I start getting into the technical details of this project, I figured you may want to see it in action:<br /></p>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/76kO2TxzD54" frameborder="0" allowfullscreen></iframe>
</div>
<h2>Why re-do this project? Why is it better now?<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_cool.JPG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_cool.JPG" alt="" class="media-center" /></a><br />
I learned quite a few things about electronics since I first made that amplification circuit for the CDM324 <strong>6 years ago</strong>.<br />
Here are the main changes implemented in this new version:<br />
- <strong>using an FFT to extract the measured speed</strong> from the CDM324 output<br />
- using an <strong>automatic gain circuit</strong> to increase the detection range<br />
- adding an <strong>onboard speed display</strong> for reading convenience<br />
Computing the Fast Fourrier Transform (FFT) of a given signal esssentially <strong>extracts all its frequency contents</strong>.<br />
It is therefore more reliable and sensitive than <a href="https://www.limpkin.fr/index.php?post/2017/02/22/Making-the-Electronics-for-a-24GHz-Doppler-Motion-Sensor">the simple comparator circuit</a> I had previously used, as you effectively <strong>look for a big peak in the FFT output</strong> and divide its X coordinate by a constant to get your detected object speed.<br />
Sure, it required adding a microcontroller to first digitize that analog signal, but the <strong>detected speed can now directly be output through UART.</strong><br />
The previous CDM324 amplification circuit had <strong>84dB</strong> of gain which <strong>in some cases was not enough</strong>. Instead of two fixed gain stages, I'm now using <strong>one fixed gain stage and a variable one</strong> for up to <strong>92dB</strong> of gain (or <strong>40000x</strong> voltage gain!). This second gain stage has <strong>automatic gain control</strong>, automatically varying the overall gain between <strong>72dB and 92dB</strong> to hopefully not saturate the overall amplification circuit output.<br />
Finally, as it didn't really make sense for the previous project to require an extra micro-controller to compute the detected speed, this new CDM324 project <strong>includes a small display</strong> directly displaying the detected object speed to the user.<br /></p>
<h2>Digging into the Analog Circuit<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm324_analog.png"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm324_analog.png" alt="" class="media-center" /></a><br />
Starting from left to right, you'll first see the fixed gain stage of 130 (42.3dB) with a 7.2Hz high pass filter (C2 & R1) and a 6.1kHz low pass filter (R3 & C4). This allows progressively <strong>filtering out speeds not between 0.16km/h and 138km/h</strong>.<br />
This particular op-amp was selected for its <strong>low input noise and high power-supply rejection ratio</strong>.<br />
As it's only powered by 3v3, its positive input is set to a fixed voltage generated by the next amplification IC. This effectively allows us to bias (or center) the op-amp output to a voltage between its two power supply rails (0V and 3.3V).<br />
The second amplification stage... <strong>is a microphone amplifier</strong>!<br />
Thinking about it, it made perfect sense using an amplifier made for the exact same frequencies I was interested in, especially <strong>when it comes with automatic gain circuitry</strong>. It'll therefore automatically amplify less if your speeding object is close to the sensor, and amplify more if the the object is far away. Cherry on top of the cake, its output voltage is already centered around 1.23V so there's no need to re-bias it before feeding it to the microcontroller's Analog to Digital Converter (ADC).<br /></p>
<h2>What About the Digital Circuitry?<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm324_digital.PNG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm324_digital.PNG" alt="" class="media-center" /></a><br />
The digital circuitry is simply composed of an STM32F301 microcontroller and an I2C-controlled LCD segment driver.<br />
The STM32F301 was selected for its <strong>small package, relatively low price and Cortex M4 core</strong> which can easily compute FFTs (more on that later).<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/exp_pinout.png"><img src="https://www.limpkin.fr/public/cdm324_v2/exp_pinout.png" alt="" class="media-center" /></a><br />
As there was still some board space available during the layout stage, I also <strong>broke out a full I2C and SPI bus</strong> to 2 expansion connectors... and that's <strong>on top of the existing UART bus</strong> for MCU flashing and the spare IOs/reset/boot signals!<br />
I therefore fully hope to develop some expansion boards that would plug to that module.<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/tn_display.PNG"><img src="https://www.limpkin.fr/public/cdm324_v2/tn_display.PNG" alt="" class="media-center" /></a><br />
A TN display was selected for its <strong>size and readability</strong>: it's of the same type that the ones used in multimeters.<br />
Reading the measured speed in a bright environment therefore shouldn't be an issue! It's however quite tricky to drive as <strong>it requires some interesting waveforms</strong>, and while I had thought of letting the MCU directly drive it for a moment, the number of resistors required to do so made me go for the embedded controller you see in the above schematics. Interestingly, you'll find online <a href="http://awawa.hariko.com/avr_lcd_drive.html" hreflang="ja">some people who did manage to pull it off!</a><br />
As a side note, I had originally gone for a 7 segments display, but the <strong>current transient when changing digits</strong> was so high that the introduced perturbation on the CDM324 5V rail <strong>would lead to glitches in its output</strong>:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/cdm324_cur_transient_issue.png"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm324_cur_transient_issue.png" alt="" class="media-center" /></a><br /></p>
<h2>Things Worth Mentioning<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/gui_demonstrator.png"><img src="https://www.limpkin.fr/public/cdm324_v2/gui_demonstrator.png" alt="" class="media-center" /></a><br />
I figured I'd make a dedicated paragraph to mention the things I really like about this little board.<br />
<strong>No programmers are required to update the MCU</strong>: the STM32F301 comes with an embedded UART bootloader! By simply connecting a USB-UART adapter to the dedicated connector, tying the BOOT0 pin to 3V3 and then briefly bringing the RESET pin to ground, the STM32F301 will enter bootloader mode.<br />
<strong>The overall circuit is very simple and expandable</strong>: there are only a handful of components and the two expansion connectors with I2C, SPI, UART and IOs will hopefully enable projects from electronics enthusiasts!<br /></p>
<h2>The PCB<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_pcb.JPG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_pcb.JPG" alt="" class="media-center" /></a><br />
The folks at <a href="https://www.pcbway.com/" hreflang="en">PCBWay.com</a> were kind enough to sponsor this project!<br />
As usual, the quality was great, shipping was fast with DHL, PCB assembly was without any issue so the PCB worked right away... these days I always go with them.<br />
I'm pretty sure this is the one of the most compact PCB I've ever laid out. It's only <strong>32 by 32.5mm</strong> and is made to be put behind the CDM324. A general rule when amplifying small signals is to have as short traces as possible!<br /></p>
<h2>Measuring the Transfer Function<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/Omicron_BODE-100.jpg"><img src="https://www.limpkin.fr/public/cdm324_v2/Omicron_BODE-100.jpg" alt="" class="media-center" /></a><br />
To make sure the amplification chain could sense the speeds I was interested in, I needed to measure the circuit amplification across frequency.<br />
To do so, I used my Bode100 but could definitely had manually done it using a signal generator and an oscilloscope (it just would have taken longer). Given the extremely high amplification present in the analog circuitry, I used <strong>many</strong> attenuators (for a <strong>total of 80dB</strong>!) at the Bode100 output to present a -100dBm signal at the amplification chain input (that's <strong>6.3uV peak peak</strong>).<br />
Using a large averaging factor and a 10Hz measurement bandwidth, the following graph was gotten 10 hours later:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/cdm_s21.PNG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_s21.PNG" alt="" class="media-center" /></a><br />
Let's ignore for the moment the overall gain and focus on the <strong>-3dB corner frequencies</strong>, even though it's a bit ironic to do so when dealing with such a high circuit gain. While the measured low pass corner frequency was bang on (6.1kHz), the same couldn't be said of the high pass filter corner frequency. The reason was then found inside the microphone amplifier datasheet:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/max9814_gain.PNG"><img src="https://www.limpkin.fr/public/cdm324_v2/max9814_gain.PNG" alt="" class="media-center" /></a><br />
Even though this is actually fine as a 100Hz frequency corresponds to a <strong>2.3km/h speed</strong>, I still took that opportunity to update my first amplification stage to the following:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/updated_first_stage.PNG"><img src="https://www.limpkin.fr/public/cdm324_v2/updated_first_stage.PNG" alt="" class="media-center" /></a><br />
I then ran another frequency sweep (this time with 70dB of external attenuation) and got this:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/transf_func_cdm324_updated_filter.png"><img src="https://www.limpkin.fr/public/cdm324_v2/transf_func_cdm324_updated_filter.png" alt="" class="media-center" /></a><br />
... and if we zoom in between the -3dB corner frequencies:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/transf_func_cdm324_updated_filter_zoomed_in.png"><img src="https://www.limpkin.fr/public/cdm324_v2/transf_func_cdm324_updated_filter_zoomed_in.png" alt="" class="media-center" /></a><br />
Taking into account the 70dB of external attenuation, the overall amplification gain ended up being <strong>95.4dB</strong>, with 3dB corner frequencies of <strong>150Hz</strong> (3.4km/h) and <strong>~7.9kHz</strong> (180km/h).<br />
Finally, here's a very interesting way to test the microphone amplifier automatic gain control feature: in the below measurement, I not only perform a frequency sweep <strong>but also a power sweep</strong>:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/power_sweep.png"><img src="https://www.limpkin.fr/public/cdm324_v2/power_sweep.png" alt="" class="media-center" /></a><br />
Given that I'm linearly sweeping between -90dBm and -60dBm between 1kHz and 1.3kHz, we can conclude that the AGC starts kicking at an input power of <strong>-89.9dBm</strong> and seems to stop intervening at <strong>-66.3dBm</strong>. This 23.6dB range is however a bit high as the datasheet mentions 20dB.</p>
<h2>Checking for Oscillations<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/output_adc_noise_floor.png"><img src="https://www.limpkin.fr/public/cdm324_v2/output_adc_noise_floor.png" alt="" class="media-center" /></a><br />
An <strong>extremely common issue</strong> when having an amplification chain with such a massive gain is <strong>oscillations</strong>: without any signal present at your device input, when probing your output you'd typically see a rogue sine wave.<br />
This happens when some of your output signal gets coupled into the device input (imagine putting a live microphone in front of speakers).<br />
<em>But how does it get coupled?</em> you may then ask. <br />
In my experience either through <strong>electromagnetic coupling</strong> (output PCB trace close to the input trace) or through <strong>power supplies</strong> (a current draw proportional to the output signal introduces a voltage drop on the first amplifier supply which then gets coupled into the input signal).<br />
While one could typically use an oscilloscope to measure the amplification chain output signal to check for small oscillations, one would be limited by said oscilloscope <strong>input noise level</strong>. One way to get around that could be to use my <a href="https://www.limpkin.fr/index.php?post/2022/09/20/The-Low-Noise-Amplifier-Board">low noise amplifier board</a> but I instead went with my <strong>SA44B spectrum analyzer</strong> and got the following spectrum:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/output_spectrum_with_backpack_50r_vs_sensor.png"><img src="https://www.limpkin.fr/public/cdm324_v2/output_spectrum_with_backpack_50r_vs_sensor.png" alt="" class="media-center" /></a><br />
The black trace is the output spectrum with a CDM324 connected and the blue trace is the output spectrum with a <strong>50 ohms resistor connected to the amplification chain input</strong>.<br />
The blue curve being below the black curve <strong>means that my amplification chain noise floor is below the CDM324 output "noise"!</strong> This means the complete device is "limited" by the CDM324.... which is what I wanted to see.<br />
Also worth mentioning is the relative <strong>lack of pronounced spikes</strong> that could be caused the AC grid frequency, TN display scanning or USB lines: remember that the above measurement was taken with a very sensitive spectrum analyzer while the cdm324 was standing still. What really matters is that the spectrum computed by the STM32 is flat when nothing is moving around.<br />
If we "walk back" the amplification chain we can try to compute our amplification chain input noise rating: -80dB (noise level at 1kHz) + 21dB (500 / 50r resistor divider at the specan input) - 95.4dB (circuit amplification) = -154.4dB/sq(Hz) = <strong>4.26nV RMS/sq(Hz)</strong>.<br />
Comparing that value to the theoretical one can be done using the following formula from <a href="https://www.renesas.com/kr/en/document/apn/r13an0010-noise-calculations-op-amp-circuits" hreflang="en" title="opamp noise calculations">that document</a> (from page 6):<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/inv_opamp_noise_calc.png"><img src="https://www.limpkin.fr/public/cdm324_v2/inv_opamp_noise_calc.png" alt="" class="media-center" /></a><br />
Rather than doing these math however, one may notice that <strong>this 4.26nV/sq(Hz) measurement is already below the 4k7 input resistor johnson noise of 8.7nV/sq(Hz)</strong>... and I'm not even mentioning the LMP7731 input voltage noise (2.7nV/sq(Hz)) and LMP7731 input current noise (1.1pA/sq(Hz)) going to the 4k7//620k.<br />
I wish I had an explanation for that difference... but I repeated that measurement several times, even used a signal generator and a table top multimeter to double check the circuit amplification (I actually measured more than 95.4dB)... but still couldn't find an explanation on that better than expected result. If you're reading this and have an idea, send me a message and <strong>I'll send you a device for free</strong>!<br /></p>
<h2>Mechanical Assembly<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_antenna.JPG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_antenna.JPG" alt="" class="media-center" /></a><br />
Similarly to my previous CDM324 project, I've designed and 3D printed a small support to hold everything together.<br />
The overal assembly <strong>only measures 36x36.5x17.5mm</strong>. Tiny!<br /></p>
<h2>MCU Performance & ADC Sampling Rate<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/stm_adc.png"><img src="https://www.limpkin.fr/public/cdm324_v2/stm_adc.png" alt="" class="media-center" /></a><br />
You may know that FFT computation is quite resource intensive.<br />
In a "release' build configuration, by toggling a MCU pin I measured that <strong>2.4ms</strong> was needed to:<br />
- convert 1024 ADC samples to floats<br />
- compute a 1024 points FFT<br />
- compute the magnitude of the FFT output vector elements<br />
This effectively translates to a maximum of 417 FFTs per second, which is more than enough for our purposes!<br />
I therefore selected an ADC sampling rate of <strong>35.7ks/s</strong>, meaning that for a 1024 samples buffer I should theoretically be able to measure frequencies between 34.9Hz and 17.8KHz (or a <strong>minimum of 0.8km/h</strong>). That also meant an FFT frequency bin width of <strong>0.8km/h (0.5mph)</strong>.<br />
By using double buffering (one buffer filling with data while another is getting processed), 34.9 FFTs per second can be computed. If we want to stream raw ADC values and FFT data through UART, a minimum bit rate of 34.9*(1024*uint16 + 512*float32)*10/8 = <strong>1428kb/s</strong> is required. But because of baud rate incompatibilities between the MCU & possible USB to UART adapters, that actually means a 2Mbit/s minimum baud rate.<br />
However, it turned out that many USB to UART adapters <strong>couldn't handle a continuous 2Mbit/s stream</strong>.<br />
In the scripts located at the end of this page, you'll therefore notice that I actually use <strong>1Mbit/s</strong>, and am only sending the "interesting" part of the FFT data.<br />
One last thing to mention: I did find that the required impedance between signal source and ADC input needed to be small, as otherwise what seems to be a current bias would be introduced during the sampling phase.... odd.<br /></p>
<h2>On the topic of Hardware Abstraction Layers<br /></h2>
<p>When it comes to Hardware Abstraction Layers (HALs) everyone has his/her own opinions.<br />
I personally tried several of them (for different platforms and IDEs) and until now have been quite against using them as it'd always take me as much time learning the HAL as I'd spend reading the datasheet.<br />
With the STM32 environment, things are quite different: you actually get a nice graphical user interface (STM32CubeMX, also embedded in the STM32CubeIDE) that allows you to fully configure your microcontroller and its internal peripherals (think Clocks, SPIs, UARTs, Timers, Interrupts, DMA transfers...). Once you save your .ioc file, the IDE will automatically generate the HAL initialization code and interrupt routines in 3 files (main.c, stm32f3xx_hal_msp.c, stm32f3xx_it.c) and you'll be more or less good to go.<br />
Why more or less? Well in the case of configured timers, it'll still be up to you to call the actual HAL start routines depending on your use case (HAL_TIM_Base_Start, HAL_TIM_Base_Start_IT, HAL_TIM_Base_Start_DMA...). Luckily, given the STM32 platform is used all over the globe, the time between realizing something doesn't work and the time you find a solution online will be less than a few minutes. Getting something up and running is therefore extremely quick.<br />
However... there are times where the code generation tool messes with your complete software solution. It happened to me once that when changing an SPI baud rate in STM32CubeMX and saving the changes my platform wouldn't boot anymore. After comparing my main.c with a previous version (don't forget to use code versioning!) I discovered that the generated code initializing the external crystal driver had simply disappeared!<br />
Moreover, while relying on this code generation tool is great when wanting to rapidly tweak a few settings... it actually prevents you from compartimentalizing your code in different files. Even though I managed to do so, identifying all the functions and global variables that are required for a given feature rapidly gets annoying (think interrupt routines for peripherals and DMA transfers, end of transfer HAL callbacks, HAL descriptor objects...).<br />
You also obviously get a performance hit as the HAL performs a few checks before letting you do what you'd like to. For a simple 24bits SPI TX transfer I actually measured a performance penalty factor of 9 between using the HAL and directly writing the registers myself. STM however does also provide a Low Layer API (LL), with "better optimization but less portability, requiring deep knowledge of the MCU and peripheral specifications."... but at this point you may as well go bare-metal :).<br /></p>
<h2>Writing a Debug GUI<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/debug_tool.png"><img src="https://www.limpkin.fr/public/cdm324_v2/debug_tool.png" alt="" class="media-center" /></a><br />
Can you guess the cars passing me by and the ones stopping next to me?<br />
As previously mentioned, the onboard MCU can use its UART peripheral to output data to the outside world.<br />
For debugging purposes (and nice demo effect), I therefore wrote a python GUI that leverages the Enthought Chaco framework (itself <strong>based on qt4</strong>) to display live data on your computer screen.<br />
Depending on your computer configuration, it can (surprisingly) handle a 1600*1200 pixels window at a refresh rate of 34 frames per second to show <strong>raw ADC samples, computed FFT data and detected peaks over time</strong>.<br /></p>
<h2>So sensitive that it can debug your computer<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/disappearing_noise.jpg"><img src="https://www.limpkin.fr/public/cdm324_v2/disappearing_noise.jpg" alt="" class="media-center" /></a><br />
Remember when I mentioned that I switched from a 7 segment display to a TN display because of voltage transients?<br />
In the picture above you can see the output spectrogram when no movement is happening in front of the sensor. At that moment, the AGC is not kicking in and <strong>the gain is at its maximum</strong> (94dB). That means the board amplifies.... <strong>everything</strong>, and that includes potential noise present on your USB power supply!<br />
So what happened at the end of that green arrow? I'm pretty sure it has something to do with either my trackpad or power saving features as this transition <strong>only happens when not touching my laptop for 30 seconds</strong>. I'm assuming the noise is picked up through the USB +5V power line, but it could also also be picked up through RF.... fun, right?<br />
<a href="https://www.limpkin.fr/public/cdm324_v2/usb_isolator.png"><img src="https://www.limpkin.fr/public/cdm324_v2/usb_isolator.png" alt="" class="media-center" /></a><br />
A way to improve things is to use a <strong>USB isolator</strong> as the one pictured above though!<br /></p>
<h2>Making a Companion Board<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_exp.JPG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_exp.JPG" alt="" class="media-center" /></a><br />
As it seems I was particularly motivated by this project, I then took some additional time to make a breakout board.<br />
It offers the following features:<br />
- a <strong>USB to UART converter</strong>, connected to the RESET & BOOT0 lines<br />
- a <strong>jack connector</strong> so you can listen to the doppler noise<br />
- a switch to toggle between MPH and KM/H display<br />
- a <strong>uSD card connector</strong> to log speeds<br />
That 1.6mm PCB with its two 8pins connectors means that it's firmly attached to the CDM324 module!<br />
Something great that is now enabled is <strong>one click firmware updates</strong> using the RTS & DTS lines of the USB-UART converter and the <a href="https://pypi.org/project/stm32loader/" hreflang="en" title="stm32loader">stm32loader project</a>... how awesome is that? All you need to type is:<br />
<a href="https://www.limpkin.fr/public/cdm324_v2/stm32loader.png"><img src="https://www.limpkin.fr/public/cdm324_v2/stm32loader.png" alt="" class="media-center" /></a><br /></p>
<h2>Tying it all together: making a Control GUI<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_tool.png"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_tool.png" alt="" class="media-center" /></a><br />
Rather than having a collection of scripts, I decided to make a single python tool that:<br />
- automatically fetches and displays the detected object's speed<br />
- launches the speed debug tool I previously mentioned<br />
- allows you to <strong>flash the device</strong><br />
This is just the beginning, pull requests are strongly welcome!<br /></p>
<h2>Project source files<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_and_exp.JPG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_and_exp.JPG" alt="" class="media-center" /></a><br />
As with all my other projects, you'll find all source files made for this project <a href="https://github.com/limpkin/cdm324_fft" hreflang="en" title="cdm324 project sources">here</a>!<br />
Want to buy the complete assembled device? Have a look at my <a href="https://www.tindie.com/products/stephanelec/cdm324-doppler-speed-sensor/" hreflang="en" title="US shop">US shop</a> or <a href="https://lectronz.com/products/cdm324-doppler-speed-sensor" hreflang="en" title="CDM324 shop for EU">EU shop</a>!<br />
Want to interface that sensor to an Arduino? Have a look at the <a href="https://github.com/limpkin/cdm324_fft" hreflang="en" title="cdm324 project sources">getting started instructions.</a><br />
Thanks a lot for reading!</p>https://www.limpkin.fr/index.php?post/2022/03/31/CDM324-Doppler-Motion-Sensor-Backpack%2C-now-with-FFTs%21#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/215A DC Block to Measure Low Frequenciesurn:md5:996339ffc328557301fea289b03bb2852023-04-25T20:16:00+01:002023-08-23T11:28:21+01:00limpkinMy Projectsdc-blockinput filter<p><img src="https://www.limpkin.fr/public/dc_block/dc_block.JPG" alt="" class="media-center" />
A <strong>7Hz High Pass Filter</strong> to measure voltage ripple on power supply rails.</p> <h2>Project Context<br /></h2>
<p>Following the making of my DC-coupled <a href="https://www.limpkin.fr/index.php?post/2022/09/20/The-Low-Noise-Amplifier-Board">low frequency, low noise amplifier board</a> I discovered that a crucial piece of equipment was missing from my toolkit if I wanted to measure voltage ripple on power supply rails: a <strong>low corner frequency high pass filter</strong>, or <strong>DC-block</strong>.<br />
Such device allows you to remove the DC component of any signal to only look at "high" frequencies... in short, <strong>it's a capacitor</strong>. But surely you must now be wondering the same thing I wondered when I embarked on this project: why doesn't this exist? Surely people must have had this need before, right?<br />
I wish I had an answer, as when scouting the web I wasn't able to find any commercially-available DC-block with a corner frequency <strong>lower than 100kHz</strong>... which while it may be enough for many applications, wasn't low enough for mines (see a <strong>typical lab power supply output noise measurement</strong> below).<br /><br /></p>
<h2>Just a Capacitor, Really?<br /></h2>
<p><img src="https://www.limpkin.fr/public/dc_block/R_S_schematics.png" alt="" class="media-center" /><br />
Skeptical that a DC-block only was a capacitor, I searched online and found <a href="https://www.rohde-schwarz.com/au/faq/measure-low-frequency-signals-with-dc-offset-faq_78704-29478.html" hreflang="en">this page from Rohde & Schwarz</a> with the above schematics in it.<br />
Looking at the above picture we can see:<br />
- 1 <strong>non polarized</strong> series capacitor<br />
- 2 <strong>PIN diodes</strong> at the output<br />
These 2 diodes effectively limit the maximum voltage that can be output by the filter, as when applying a high voltage at the filter input the very same voltage would be seen at the filter output (due to the high capacitor value)... which your measurement instrument might <strong>not particularly appreciate</strong>.<br />
But why PIN diodes, and what are they?<br />
To make it simple, PIN diodes essentially are resistors whose value decrease with the current going through them:<br />
<a href="https://www.limpkin.fr/public/dc_block/pin_diode_current.jpg"><img src="https://www.limpkin.fr/public/dc_block/pin_diode_current.jpg" alt="" class="media-center" /></a><br />
This characteristic is particularly appreciated to <strong>reduce distortion added</strong> to your signal, as you may remember that standard diodes have a very different V/I curve.<br /><br /></p>
<h2>The Actual Schematics<br /></h2>
<p><a href="https://www.limpkin.fr/public/dc_block/dc_block_schematics.PNG"><img src="https://www.limpkin.fr/public/dc_block/dc_block_schematics.PNG" alt="" class="media-center" /></a><br />
In the end, my DC-block schematics are relatively similar to the ones from R&S:<br />
- 1x <a href="https://www.digikey.com/en/products/detail/panasonic-electronic-components/ECE-A1HN471U/228310" hreflang="en">bi-polar 50V 470uF electrolytic capacitor</a> (yes, that's a thing!)<br />
- 2x <strong>13 Watts</strong> (!) <a href="https://www.digikey.com/en/products/detail/skyworks-solutions-inc/CLA4607-085LF/7806955" hreflang="en">RF PIN diodes</a><br />
- 1x 10k input bleed resistor<br />
I initially went for different PIN diodes.... but they <strong>exploded when I first applied 50V at the DC-block input</strong>! Thinking about it, 470uF at 50V is around <strong>0.5 Joules</strong> so that energy needed to be dissipated somewhere.<br />
And as you will see later, lots of testing was then performed to make sure the final diodes were up to the task.<br /><br /></p>
<h2>Layout<br /></h2>
<p><img src="https://www.limpkin.fr/public/dc_block/dc_block_layout.PNG" alt="" class="media-center" /><br />
It doesn't get as simple as this!<br />
2 layers, silkscreen to specify the IN & OUT ports and that's pretty much it.<br /><br /></p>
<h2>Measuring the Transfer Function<br /></h2>
<p><a href="https://www.limpkin.fr/public/dc_block/filter_s21.png"><img src="https://www.limpkin.fr/public/dc_block/filter_s21.png" alt="" class="media-center" /></a><br />
I was once again lucky enough to get access to a Bode 100 to measure my DC-block transfer function.<br />
<strong>Keeping in mind this filter is meant to be used in 50R systems</strong>, you can see above that the <strong>6.31Hz 3dB corner frequency</strong> ended up being very close to the expected 6.37Hz (470uF with 50R).<br />
And even though it doesn't make a lot of sense using that DC-block for very high frequencies, I used a SA44B + TG44 combo to measure the transfer function at high frequencies:<br /><br />
<a href="https://www.limpkin.fr/public/dc_block/high_freq_s21.PNG"><img src="https://www.limpkin.fr/public/dc_block/high_freq_s21.PNG" alt="" class="media-center" /></a><br />
<strong>1GHz -3dB corner</strong>... not too bad for such a big capacitor!<br /><br /></p>
<h2>Device Testing<br /></h2>
<h3>Maximum Transient Test - Pulse<br /></h3>
<p><em>Any explosion if I directly feed 50V to that DC-block?</em><br />
<strong>Setup</strong>: capacitor discharged, we suddenly feed 50V through a 50R resistor to the input for a short duration.<br />
<strong>Result</strong>: the output voltage is truncated to 1.34V.<br /><br />
<a href="https://www.limpkin.fr/public/dc_block/48V_pulse_terminated.png"><img src="https://www.limpkin.fr/public/dc_block/48V_pulse_terminated.png" alt="" class="media-center" /></a><br />
- Yellow: device input signal<br />
- Cyan: device output signal<br /><br /></p>
<h3>Maximum Transient Test - Step<br /></h3>
<p><em>How long does it take to reach back 200mV?</em><br />
<strong>Setup</strong>: capacitor discharged, we suddenly feed 50V through a 50R resistor to the input.<br />
<strong>Result</strong>: after ~500ms, the voltage gets back to 200mV.<br /><br />
<a href="https://www.limpkin.fr/public/dc_block/48V_transient_terminated_long.png"><img src="https://www.limpkin.fr/public/dc_block/48V_transient_terminated_long.png" alt="" class="media-center" /></a><br />
- Yellow: device input signal<br />
- Cyan: device output signal<br /><br /></p>
<h3>Maximum Transient Test - Zoomed In<br /></h3>
<p><em>What happens when the high voltage input gets applied?</em><br />
<strong>Setup</strong>: capacitor discharged, we suddenly feed 50V through a 50R resistor to the input.<br />
<strong>Result</strong>: very little output ripple.<br /><br />
<a href="https://www.limpkin.fr/public/dc_block/48V_transient_terminated.png"><img src="https://www.limpkin.fr/public/dc_block/48V_transient_terminated.png" alt="" class="media-center" /></a><br />
- Yellow: device input signal<br />
- Cyan: device output signal<br />
Guess where the ripple comes from? From <strong>reflections</strong>!<br /><br /></p>
<h3>Picked Up Noise<br /></h3>
<p><em>Does this filter pickup any environmental noise?</em><br />
<strong>Setup</strong>: we place our DC-block at our <a href="https://www.limpkin.fr/index.php?post/2022/09/20/The-Low-Noise-Amplifier-Board">low frequency, low noise amplifier board</a> input and compare the amplifier output spectrums for different input configurations (50R at the amplifier input, 50R + DC block at the amplifier input, 9V battery + 50R + DC block at the amplifier input)..<br />
<strong>Result</strong>: Environmental noise is indeed picked up by the filter and by the wires going to the DC block.<br />
<a href="https://www.limpkin.fr/public/dc_block/dc_block_noise_spectrum.PNG"><img src="https://www.limpkin.fr/public/dc_block/dc_block_noise_spectrum.PNG" alt="" class="media-center" /></a>
The above measurement <strong>may actually be the reason why you don't see many low frequency DC-blocks in the market</strong>: adding shielding to such a big filter would end up adding quite some cost! If you look at the above spectrums, you basically see that <strong>the more non-shielded area you have, the more noise you pickup</strong>. It's also quite interesting to confirm that 9V batteries basically don't generate noise.<br />
To confirm the noise pickup assumption, I then added some EMI tape around the filter....<br />
<a href="https://www.limpkin.fr/public/dc_block/dc_block_shielded.JPG"><img src="https://www.limpkin.fr/public/dc_block/dc_block_shielded.JPG" alt="" class="media-center" /></a>
...and got my confirmation with this noise measurement:<br />
<a href="https://www.limpkin.fr/public/dc_block/dc_block_spectrum_shielded_vs_non_shielded.PNG"><img src="https://www.limpkin.fr/public/dc_block/dc_block_spectrum_shielded_vs_non_shielded.PNG" alt="" class="media-center" /></a><br /></p>
<h2>So what can actually be seen?<br /></h2>
<p><a href="https://www.limpkin.fr/public/dc_block/psu_noise_test_setup.png"><img src="https://www.limpkin.fr/public/dc_block/psu_noise_test_setup.png" alt="" class="media-center" /></a><br />
At the beginning of this article I mentioned that even lab power supplies have noisy outputs. I therefore implemented the above test setup to get the following scope capture:<br /><br />
<a href="https://www.limpkin.fr/public/dc_block/lab_psu_before_after_ampl.png"><img src="https://www.limpkin.fr/public/dc_block/lab_psu_before_after_ampl.png" alt="" class="media-center" /></a><br />
If you look at the above scope capture (taken on my Rigol DP821A power supply), you'll indeed see that the DC block and the <a href="https://www.limpkin.fr/index.php?post/2022/09/20/The-Low-Noise-Amplifier-Board">low frequency, low noise amplifier board</a> together allows you to see the <strong>PSU switching ripple that you wouldn't be able to see otherwise</strong>.<br /><br /></p>
<h2>Conclusion<br /></h2>
<p><a href="https://www.limpkin.fr/public/dc_block/dc_block.JPG"><img src="https://www.limpkin.fr/public/dc_block/dc_block.JPG" alt="" class="media-center" /></a>
That DC-block ended up being a little more complex than I thought, but it was quite the interesting learning experience!<br />
As usual you can find the source files <a href="https://github.com/limpkin/dc_block" hreflang="en">here</a> and may buy it on <a href="https://www.tindie.com/products/stephanelec/7hz-50v-dc-block/" hreflang="en">my tindie store</a> if you need one right away.</p>https://www.limpkin.fr/index.php?post/2023/03/28/The-DC-Block-For-Low-Frequencies#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/217The Low Frequency, Low Noise Amplifier Boardurn:md5:961a3fb98eb556b29e09d9a71cb47a3d2023-04-03T10:48:00+01:002024-03-09T11:21:49+00:00limpkinMy Projectslow noiseSA44Bspectrum analyzerthermal noise<p><img src="https://www.limpkin.fr/public/sa_ampl/sa_amp_angle_1200.JPG" alt="" class="media-center"><br>
Sometimes one may want to measure <strong>tiny signals</strong>’ frequency contents at frequencies <strong>just above DC</strong>.</p> <p>How tiny you may ask!<br>
Well, my arbitrary goal for this project was <strong>to clearly measure the <a href="https://en.wikipedia.org/wiki/Johnson%E2%80%93Nyquist_noise" hreflang="en">thermal noise</a> of a 50 ohms resistor</strong> (around <strong>0.9nV RMS</strong> for a 1Hz measurement bandwidth at room temperature) to be sure to be able to measure any device output I may encounter in the future (maybe audio amplifiers?).<br>
You may not know this, but using a spectrum analyzer to directly measure that 50 ohms thermal noise isn't really doable as even top of the line Rohde & Schwarz FSWs state a Displayed Averaged Noise Level (in short, an instrument's <strong>noise floor</strong>) between <strong>71nV and 224nV RMS</strong> (-130dBm & -120dBm) at a 1Hz resolution bandwidth around kHz frequencies.<br>
Moreoever, every spectrum analyzer out there that is rated from a few Hz up also comes with a <strong>no DC input requirement!</strong> While the easiest solution to get around this issue usually is to use <strong>inline DC-blocking pass-through adapters</strong>, they however typically come with a low-pass filter corner frequency of a <strong>few hundred Hz</strong>... so what's the solution?<br>
My take on it: a simple <strong>amplification circuit</strong> based on a <strong>low-input noise operational amplifier</strong>, with a <strong>clipper circuit</strong> at its output.<br><br></p>
<h2>The Design Requirements<br></h2>
<p><img src="https://www.limpkin.fr/public/sa_ampl/requirements.png" alt="" class="media-center"><br>
One may argue that a <strong>clipper circuit doesn’t remove the DC component</strong> of an amplifier’s output.<br>
While this obviously true, a quick email exchange with the engineers who designed the Signal Hound SA44B spectrum analyzer (that I'm using) let me know that a <strong>DC component of up to 200mV is actually alright</strong>.<br>
The amplifier requirements therefore became:<br>
- DC to <1MHz bandwidth<br>
- (adjustable) output clipping<br>
- as low as possible input noise<br>
- enough gain so that the output spectrum noise level is above the SA44B DANL<br>
To my biggest surprise my SA44B calibration certificate mentioned a <strong>-139.3dBm/Hz</strong> DANL level at 60Hz!<br><br>
<a href="https://www.limpkin.fr/public/sa_ampl/SA44B_calib.jpg"><img src="https://www.limpkin.fr/public/sa_ampl/SA44B_calib.jpg" alt="" class="media-center"></a><br></p>
<h2>The Design<br></h2>
<p><a href="https://www.limpkin.fr/public/sa_ampl/schematics.png"><img src="https://www.limpkin.fr/public/sa_ampl/schematics.png" alt="" class="media-center"></a><br>
The designed circuit is fairly straight-forward:<br>
- an op-amp based circuit with a <strong>voltage gain of 101</strong><br>
- a high-fidelity, low-noise audio operational amplifier used as a <strong>voltage buffer</strong><br>
- two open-drain output comparators comparing the amplified voltage to a set threshold<br>
- … to then control the enable input of a SPST switch<br>
To keep the generated noise to a minimum, the above circuit is <strong>powered by two 9V batteries</strong> and a DPDT switch takes care of enabling/disabling the board power supply.<br>
It’s important to note that as <strong>we’re designing for 50R systems</strong>, the x101 voltage gain <strong>actually means a x50.5 gain (34dB)</strong> as the final output buffer has an equivalent 50R resistor at its output.<br><br></p>
<h2>Selected Operational Amplifier<br></h2>
<p><img src="https://www.limpkin.fr/public/sa_ampl/lt1028_noise_lowf.PNG" alt="" class="media-center"><br>
The <strong>LT1028</strong> from Analog devices was selected for its great specifications:<br>
- typical <strong>1nV/sq(Hz) input noise</strong> voltage<br>
- typical 1pA/sq(Hz) input noise current<br>
- 50MHz gain-bandwidth product<br>
Doing the math, the LT1028's 1nV/sq(Hz) input noise with a 50.5x gain effectively means a 50.5nV/sq(Hz) output noise, or <strong>-133dBm</strong>.... therefore <strong>above our -139.3dBm SA44B noise floor</strong>. You'll notice here that I'm neglecting the (comparatively low) noise contribution from the voltage buffer at the LT1028's ouput.<br>
The <strong>ADA4898</strong> was also considered during the op-amp choice phase, and as its footprint is (quite) the same as the LT1028's I may try swapping during final testing.<br>
Finally, it is worth mentioning that it is possible to find op-amps with lower input noise specs... <strong>but not at <kHz frequencies</strong> (see <a href="https://www.ti.com/lit/ds/symlink/lmh6629.pdf" hreflang="en">here</a>). Anecdotally they also have higher Gain BandWidth products than the LT1028... but also quite a large <strong>input offset voltage</strong>, which gets amplified by the set voltage gain (which we really don't want).<br><br></p>
<h2>Voltage Buffer - High Fidelity Operational Amplifier<br></h2>
<p><a href="https://www.limpkin.fr/public/sa_ampl/opa1622_noise.png"><img src="https://www.limpkin.fr/public/sa_ampl/opa1622_noise.png" alt="" class="media-center"></a><br>
The <strong>OPA1622 from Texas Instruments</strong> was selected so that the device may be able to drive a 50R + 50R load at its output. It only has a <strong>3nV/sq(Hz) input voltage noise density</strong> at 1kHz and can output more than 100mA. <br>
The initial plan was to use its enable input to implement the clipper feature, but a <a href="https://e2e.ti.com/support/audio-group/audio/f/audio-forum/1164178/opa1622-enable-feature-not-behaving-as-expected" hreflang="en">long exchange with the guys at TI</a> concluded that this wasn’t really possible.<br><br></p>
<h2>Clipper Circuit<br></h2>
<p><a href="https://www.limpkin.fr/public/sa_ampl/clipper.png"><img src="https://www.limpkin.fr/public/sa_ampl/clipper.png" alt="" class="media-center"></a><br>
Perhaps the part of the design that took the longest time to come up with.<br>
To keep it simple, if the LT1028 output voltage is higher or lower than the voltages set by the 2 potentiometers, then the comparator output gets tied to -9V and the <strong>ADG1401 will disconnect the OPA1622 output from the device output</strong>.<br>
R9 & C6 are there to prolong the disabling duration, D3 prevents the ADG1401 enable input from going below 0V and <strong>D1 is there to indicate when clipping is occurring</strong>. <br>
The circuit composed of R8, R10 and Q1 makes sure that the device output is disabled when only the positive supply rail is present, as U3 doesn’t perform well when its negative rail is absent.<br>
Finally, please note that with this design the comparison voltage set using the potentiometers is <strong>twice the output clipping voltage when 50R termination is used</strong>.<br><br></p>
<h2>Layout<br></h2>
<p><a href="https://www.limpkin.fr/public/sa_ampl/sa_amp_layout.PNG"><img src="https://www.limpkin.fr/public/sa_ampl/sa_amp_layout.PNG" alt="" class="media-center"></a><br>
As you can see, the 4 layers board is pretty packed.... and quite small: <strong>60*20mm</strong>.<br>
Even though the device won't deal with high frequencies, it's still good practice to keep transmission lines short. You'll notice test pads at the bottom of the board, meant to offer a place to probe the current positive and negative comparison voltages.<br><br></p>
<h2>The Case<br></h2>
<p><a href="https://www.limpkin.fr/public/sa_ampl/sa_amp_case_1200.JPG"><img src="https://www.limpkin.fr/public/sa_ampl/sa_amp_case_1200.JPG" alt="" class="media-center"></a><br>
For this project I designed an (expensive) aluminum case (machined at PCBWay) through which the SMA connectors can be screwed and the toggle switch can poke. As you can see in the above picture, I'm even using <strong>thermal interface material</strong> to provide thermal contact between the TI voltage buffer and the case.<br>
A healthy dose of solder connects the SMA connectors to the PCB while the 9V batteries fit nicely inside their respective slots. A top cover made of <strong>Trotec laminate</strong> and machined by yours truly provides the curious person some information about what that device is.<br>
Finally, <strong>light pipes</strong> allow the green power LED and clipping red LED's light to easily be seen.<br><br></p>
<h2>Side Note - Reasoning Shortcuts Taken, Quick Tips<br></h2>
<p>When talking about noise, one needs to be particularly careful with the terms used.<br>
I therefore want to add a few notes here for the sake of completeness (consider it a brain dump):<br>
- adding unrelated (thermal) noise is not as easy as adding both RMS values as <strong>power</strong> gets added. You may use <a href="http://www.sengpielaudio.com/calculator-spl.htm" hreflang="en">that calculator</a> for laziness.<br>
- all 50R systems are... 50R input terminated. "Measuring a 50R resistor thermal noise" effectively means making two measurements: one with the spec-an input shorted to ground, one with the input left open (provided the amplifier input current noise is tiny enough).<br>
- a spec-an with a -130dBm noise floor could theoretically see a 50R thermal noise contribution but you won't be likely to see it as -130dBm would become... pretty much -130dBm.<br>
- to not confuse the reader a 1Hz measurement bandwidth was used in all above paragraphs, as when using more a <a href="https://web.archive.org/web/20231210173058/https://analog.intgckts.com/noise/thermal-noise-of-a-resistor/" hreflang="en">square root gets involved</a>...<br>
- one needs to be <strong>careful when using the averaging feature of a spectrum analyzer</strong>, as when "log power averaging" is used, the displayed noise actually gets lowered by 2.51dB. No need to worry if the averaging technique is RMS. Have a look at this <a href="https://reeve.com/Documents/Noise/Reeve_Noise_6_NFMeasSpecAnalyz.pdf" hreflang="en">great document</a>.<br><br></p>
<h2>Testing<br></h2>
<p><em>Lets check that the circuit behaves as expected...</em><br></p>
<h3>Idle Power Consumption<br></h3>
<p><em>How much current does the device actually consume?</em><br>
<strong>Setup</strong>: Using a dual-channel power supply directly feeding the two 9v inputs, we note the current draw on the power supply.<br>
<strong>Result</strong>: 15mA for the positive rail, 16mA for the negative rail<br>
<strong>Note</strong>: This reading doesn't really need to be precise <strong>as power consumption will mainly be dictated by device usage</strong>. It however allows us to know how long the batteries would last if we'd forget to power off the amplifier: in the case of the Energizer Ultimate Lithium I'm using, that would be <strong>47 hours</strong>.<br><br></p>
<h3>Output Offset Voltage<br></h3>
<p><em>With nothing at the input, what DC component do I get at the output?</em><br>
<strong>Setup</strong>: With nothing connected to our device input (remember that a 50R is present internally), we use a multimeter to measure the output voltage.<br>
<strong>Result</strong>: <strong>0mV</strong> at the output, which is quite impressive!<br><br></p>
<h3>Power-Up Clipping Test<br></h3>
<p><em>Any funky things happening when the device turns on?</em><br>
<strong>Setup</strong>: output clipping voltages set to +-500mV (+-1V on the trim-pot), we switch off the device, apply a safe +-20mV DC voltage at the input (+-1V hypothetical output at 50R) and enable positive/negative supply voltages in different sequences to look for funky glitches. Oscilloscope triggering is set on a positive and then on a negative voltage.<br></p>
<h4>with a +20mV input<br></h4>
<p><strong>Scenario 1: device off, enabling positive rail to +9V</strong>: no change at the output, 21mA consumed at +9V, 0mA consumed at 20mV<br>
<strong>Scenario 2: device off, enabling negative rail to -9V</strong>: no change at the output, 26mA consumed at -9V, 9mA consumed at 20mV<br>
<strong>Scenario 3: negative rail at -9V, enabling positive rail to +9V</strong>: 20mV pulse seen at the output<br>
<a href="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_scenario_3.png"><img src="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_scenario_3.png" alt="" class="media-center"></a>
<strong>Scenario 4: positive rail at +9V, enabling negative rail to -9V</strong>: no change at the output<br>
<strong>Scenario 5: randomly toggling the switch</strong>: 800ns 4V pulse seen at the output<br>
<a href="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_scenario_5.png"><img src="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_scenario_5.png" alt="" class="media-center"></a><br></p>
<h4>with a -20mV input<br></h4>
<p><strong>Scenario 1: device off, enabling positive rail to +9V</strong>: no change at the output, 21mA consumed at +9V, 0mA consumed at 20mV<br>
<strong>Scenario 2: device off, enabling negative rail to -9V</strong>: no change at the output, 28mA consumed at -9V, -20mV becomes -0.17V<br>
<strong>Scenario 3: negative rail at -9V, enabling positive rail to +9V</strong>: -900mV pulse seen at the output<br>
<a href="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_neg_scenario_3.png"><img src="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_neg_scenario_3.png" alt="" class="media-center"></a><br>
Zooming on the transients:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_neg_scenario_3_trans0.png"><img src="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_neg_scenario_3_trans0.png" alt="" class="media-center"></a><br>
<a href="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_neg_scenario_3_trans1.png"><img src="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_neg_scenario_3_trans1.png" alt="" class="media-center"></a>
<strong>Scenario 4: positive rail at +9V, enabling negative rail to -9V</strong>: no change at the output<br>
<strong>Scenario 5: randomly toggling the switch</strong>: 800ns 3.5V pulse seen at the output<br>
<a href="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_neg_scenario_5.png"><img src="https://www.limpkin.fr/public/sa_ampl/powerup_clipping_neg_scenario_5.png" alt="" class="media-center"></a><br></p>
<h3>Power-Down Clipping Test<br></h3>
<p><em>Any funky things happening when the device turns off?</em><br>
<strong>Setup</strong>: output clipping voltages set to +-500mV (+-1V on the trimpot), +-20mV DC voltage at the input (+-1V hypothetical output at 50R) we disable positive/negative supply voltages in different sequences. Oscilloscope triggering is set on a positive and then negative voltage.<br>
<strong>Scenario 1: device on, disabling positive rail</strong>: no change at the output<br>
<strong>Scenario 2: device on, disabling negative rail</strong>: no change at the output<br>
<strong>Scenario 3: negative rail disabled, positive rail at +9V, disabling positive rail</strong>: no change at the output<br>
<strong>Scenario 4: positive rail disabled, negative rail at -9V, disabling negative rail</strong>: no change at the output<br>
<strong>Scenario 5: using the switch</strong>: no change at the output<br>
The same tests were then repeated for a -20mV input:<br>
<strong>Scenario 1: device on, disabling positive rail</strong>: no change at the output<br>
<strong>Scenario 2: device on, disabling negative rail</strong>: no change at the output<br>
<strong>Scenario 3: negative rail disabled, positive rail at +9V, disabling positive rail</strong>: no change at the output<br>
<strong>Scenario 4: positive rail disabled, negative rail at -9V, disabling negative rail</strong>: no change at the output<br>
<strong>Scenario 5: using the switch</strong>: no change at the output<br><br></p>
<h3>Clipping Speed Test<br></h3>
<p><em>How long does the clipping circuit take to act?</em><br>
<strong>Setup</strong>: output clipping voltages set to +-500mV (+-1V on the trim-pot), we use a signal generator to create a 0->+-60mV pulse which would generate a 0->+-3V output if there was no clipping.<br>
<strong>Result</strong>: a positive pulse approximately lasting 900ns can be seen at the output, which as long as its maximum amplitude (~+-4V) is below your instrument maximum AC rating, won't be an issue.<br>
Clipping output on a positive pulse:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/clipping_speed_test_pos.png"><img src="https://www.limpkin.fr/public/sa_ampl/clipping_speed_test_pos.png" alt="" class="media-center"></a>
- Blue: device input signal<br>
- Yellow: device output signal<br>
- Cyan: LM293 (U3) output<br>
- Magenta: ADG1401 switching input<br></p>
<p>Zooming on the final disabling transition:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/clipping_speed_test_pos_zoomed.png"><img src="https://www.limpkin.fr/public/sa_ampl/clipping_speed_test_pos_zoomed.png" alt="" class="media-center"></a><br>
Clipping output on a negative pulse:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/clipping_speed_test_neg.png"><img src="https://www.limpkin.fr/public/sa_ampl/clipping_speed_test_neg.png" alt="" class="media-center"></a>
- Blue: device input signal<br>
- Yellow: device output signal<br>
- Cyan: LM293 (U3) output<br>
- Magenta: ADG1401 switching input<br></p>
<p>Zooming on the final disabling transition:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/clipping_speed_test_neg_zoomed.png"><img src="https://www.limpkin.fr/public/sa_ampl/clipping_speed_test_neg_zoomed.png" alt="" class="media-center"></a><br></p>
<h3>Clipping Test at Different Thresholds<br></h3>
<p><em>Does it take longer to cut the output when increasing the clipping voltage?</em><br>
<strong>Setup</strong>: output clipping voltages set to different voltages, we use a signal generator to create a 0->+-80mV pulse which would generate a 0->+-4V output if there was no clipping.<br>
<strong>Result</strong>: positive pulses of different lengths (0.8us to 2us) can be seen at the output, which as long as their maximum amplitude (~+-4V) is below your instrument maximum AC rating, won't be an issue.<br>
<a href="https://www.limpkin.fr/public/sa_ampl/pulses_at_thresholds.png"><img src="https://www.limpkin.fr/public/sa_ampl/pulses_at_thresholds.png" alt="" class="media-center"></a>
- Blue: device input signal<br>
- Yellow: device output signal<br></p>
<h3>Triangular Waveform Clipping Test<br></h3>
<p><em>How does the clipping look like when feeding a triangle signal?</em><br>
<strong>Setup</strong>: output clipping voltages set to +-1.5V (+-3V on the trim-pot), we use a signal generator to create a 70mVpp triangle waveform which would generate a +-3.5V output if there was no clipping.<br>
<strong>Result</strong>: the output is indeed clipped at the expected voltages, and includes the pulse shown in the previous tests<br>
- Cyan: device input signal<br>
- Yellow: device output signal<br><br>
For a 10Hz input signal:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/triangle_clipping_test_10hz.png"><img src="https://www.limpkin.fr/public/sa_ampl/triangle_clipping_test_10hz.png" alt="" class="media-center"></a><br>
For a 100Hz input signal:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/triangle_clipping_test_100hz.png"><img src="https://www.limpkin.fr/public/sa_ampl/triangle_clipping_test_100hz.png" alt="" class="media-center"></a><br>
For a 1kHz input signal:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/triangle_clipping_test_1khz.png"><img src="https://www.limpkin.fr/public/sa_ampl/triangle_clipping_test_1khz.png" alt="" class="media-center"></a><br>
For a 10kHz input signal:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/triangle_clipping_test_10khz.png"><img src="https://www.limpkin.fr/public/sa_ampl/triangle_clipping_test_10khz.png" alt="" class="media-center"></a>
You can see in the above screen captures the impact of the RC circuit, <strong>effectively increasing the clipping time.</strong><br><br></p>
<h3>Clipping Circuit RC Test<br></h3>
<p><em>Testing the disabling time prolongation circuit</em><br>
As was previously seen, a small pulse is always present at the device output when the clipping circuit triggers. Because of that pulse, one may wonder if it could be possible to generate a DC value at the device output higher than the set clipping voltage. This is however impossible as an RC circuit is present at the comparator's output. To demonstrate its effect, we input a square wave whose low level is close to the set clipper voltage and notice the output duty cycles changes the higher we go in frequency.<br>
<strong>Setup</strong>: output clipping voltage set to +-2V (+-4V on the trim-pot), we use a signal generator to create a 40mVpp square waveform offset by 60mV.<br>
- Cyan: device input signal<br>
- Yellow: device output signal<br><br>
For a 10Hz input signal:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/rc_circuit_test_10hz.png"><img src="https://www.limpkin.fr/public/sa_ampl/rc_circuit_test_10hz.png" alt="" class="media-center"></a><br>
For a 100Hz input signal:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/rc_circuit_test_100hz.png"><img src="https://www.limpkin.fr/public/sa_ampl/rc_circuit_test_100hz.png" alt="" class="media-center"></a><br>
For a 500Hz input signal:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/rc_circuit_test_500hz.png"><img src="https://www.limpkin.fr/public/sa_ampl/rc_circuit_test_500hz.png" alt="" class="media-center"></a><br>
At 700Hz, the output is fully disabled, which seems to indicate that the "disabling circuit" time constant is 1/700/2 = 0.7ms.<br><br>
Wanting to look into details on how it behaved, the following capture was then taken:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/rc_circuit_test_details.png"><img src="https://www.limpkin.fr/public/sa_ampl/rc_circuit_test_details.png" alt="" class="media-center"></a>
- Cyan: device input signal<br>
- Yellow: device output signal<br>
- Blue: LM293 (U3) output<br>
- Magenta: ADG1401 switching input<br><br>
Here you can see two interesting things:<br>
- <strong>between the two vertical cursors</strong>: the D3 diode preventing the ADG1401 input from going negative<br>
- <strong>between the last vertical cursor and the output enabling</strong>: time it takes for the ADG1401 input to reach Vih + ADG1401 enable delay<br><br></p>
<h3>Real Use Case Test<br></h3>
<p><em>Making sure we can respect the SA44B max 200mV input spec</em><br>
This amplifier-clipper circuit was made to protect the input stage of the SA44B spectrum analyzer. While its input has a 0V DC max rating, a quick email exchange with the Signal Hound engineering team let us know that up to 200mV DC is actually alright. The test below is therefore meant to represent a real use case.<br>
<strong>Setup</strong>: output clipping voltage set to +-100mV (+-200mV on the trim-pot), we use a signal generator to create an 80mVpp triangle waveform with a 26dB attenuator at its output: 80mVpp = -18dBm, -18-26 = 4mVpp, 4mVpp*50 = 200mVpp.<br>
<strong>Result:</strong><br>
<a href="https://www.limpkin.fr/public/sa_ampl/100mV_clipping_test.png"><img src="https://www.limpkin.fr/public/sa_ampl/100mV_clipping_test.png" alt="" class="media-center"></a>
As can be seen above, the clipper is still behaving as expected! <br><br></p>
<h3>1kHz Sine Test<br></h3>
<p><em>If I'm feeding it a sine, do I get an amplified sine?</em><br>
<strong>Setup</strong>: We configure a signal generator to output a 60mVpp (-20.45dBm) peak-to-peak sine wave signal, then attenuated by 26dB. We connect the amplifier output to my spectrum analyzer, expecting a -20.45-26+34 = -12.45dBm tone.<br>
<strong>Result</strong>: The following spectrum was obtained. We notice a 1dB difference, which is likely caused by the imprecision of the 20 years old signal generator used (Stanford DS335).<br>
<a href="https://www.limpkin.fr/public/sa_ampl/1kHz_60mvpp_sine_1hz_rbw.PNG"><img src="https://www.limpkin.fr/public/sa_ampl/1kHz_60mvpp_sine_1hz_rbw.PNG" alt="" class="media-center"></a><br><br></p>
<h3>Gain and Noise Spectrum Measurement<br></h3>
<p><em>Can we actually measure thermal noise?</em><br>
The whole point of this amplifier is to amplify tiny signals while adding the least amount of noise. We therefore want to measure the noise spectrum at the amplifier output when its input is either shorted, 50R-shorted or left open, and finally compare that with the spectrum analyzer input noise.<br>
<strong>Setup</strong>: the trusted amplifier, powered by batteries, directly connected to the Signal Hound SA44B and then to a Bode 100. <strong>Spur rejection mechanism is disabled (required to get precise measurements at low input power).</strong><br>
<strong>Result</strong>:
<a href="https://www.limpkin.fr/public/sa_ampl/noise_spectrum_gain.PNG"><img src="https://www.limpkin.fr/public/sa_ampl/noise_spectrum_gain.PNG" alt="" class="media-center"></a><br>
The trusted bode 100 reports 34dB of gain, which is 50.12x ! The 3dB point is around <strong>600kHz</strong>.<br>
At the 0R input case, the noise power at 1kHz for a 1Hz RBW is <strong>-134.3dBm</strong> (which is lower than the DANL of these fancy R&S FSWs!), which is <strong>43nV RMS.</strong> Dividing the latter by 50.12x, that’s a <strong>0.86nV input referred noise,</strong> actually lower than the LT1028 specified input noise!<br><br></p>
<h3>Noise Increase at 400kHz<br></h3>
<p>One may wonder why the noise increases at 400kHz in the above spectrum… the answer is in the LT1028 datasheet:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/lt1028_noise_spec.PNG"><img src="https://www.limpkin.fr/public/sa_ampl/lt1028_noise_spec.PNG" alt="" class="media-center"></a><br></p>
<h3>Checking the 25R Noise Contribution<br></h3>
<p>I find this one <strong>extremely neat</strong>: between the 0R/50R/open test cases you actually see an increase in the measured noise spectrum due to the resistance increase at the input! Keeping in mind that the op-amp input is 50R terminated, the difference in input resistance between the 0R/50R/open cases actually is <strong>25R</strong>.<br>
The RMS voltage noise of a 25R resistor at 23 degrees is 0.000639275uV. If you multiply this value by the effective gain of 50.5, that leads to 0.0323uV RMS or <strong>-136.81dBm.</strong><br>
At the 0R input case, the noise power at 1kHz for a 1Hz RBW is <strong>-134.3dBm</strong> and if you add the 25R thermal noise of <strong>-136.81dBm</strong>, that leads to <strong>-132.4dBm</strong>, pretty close to the <strong>-132.8dBm</strong> measured for the 50R input case! It’s also funny to note that with another SMA 50R terminator I did measure <strong>-133dBm</strong>…<br>
Similarly, adding -136.81dBm to that 50R reading -132.8dBm leads to <strong>-131.35dBm</strong>, also pretty close to the <strong>-131.65dBm</strong> reading in the open test case! Keep in mind that -131.65dBm is <strong>58nV RMS…</strong><br><br></p>
<h3>Comparison with the ADA4898<br></h3>
<p>Another measurement was also made, replacing the LT1028 with the ADA4898 to compare both IC noise and gain performances:<br>
<a href="https://www.limpkin.fr/public/sa_ampl/noise_spectrum_gain_compared_to_ada4898.PNG"><img src="https://www.limpkin.fr/public/sa_ampl/noise_spectrum_gain_compared_to_ada4898.PNG" alt="" class="media-center"></a><br>
I’ll let you make your own conclusion on the ADA4898 vs LT1028 topic.<br>
They both have similar levels of input noise until 50kHz where the LT1028 increases its input noise but keeps its gain while the ADA4898 starts to decrease its gain. These tests were done using a single sample for each op-amp, so for all I know we could get different results for other samples.<br><br></p>
<h2>What can actually be seen?<br></h2>
<p><a href="https://www.limpkin.fr/public/dc_block/lab_psu_before_after_ampl.png"><img src="https://www.limpkin.fr/public/dc_block/lab_psu_before_after_ampl.png" alt="" class="media-center"></a>
Even lab power supplies have noisy outputs!<br>
If you look at the above scope capture (taken on my Rigol DP821A power supply), you'll indeed see that using a DC block and the amplifier allows you to see the PSU switching ripple that you wouldn't be able to see otherwise.<br><br></p>
<h2>Testing Conclusion<br></h2>
<p><a href="https://www.limpkin.fr/public/sa_ampl/sa_amp_front_1200.JPG"><img src="https://www.limpkin.fr/public/sa_ampl/sa_amp_front_1200.JPG" alt="" class="media-center"></a><br>
That was quite a lot of tests, but <strong>in my opinion required</strong> as any mistake can lead to a blown-up spectrum analyzer. For me, the main take-aways are:<br>
- the clipper circuit <strong>does function as intended</strong>, but does generate a short pulse at the output when triggering. When feeding the amplifier output to a SA44B, it may be good practice to add a 3dB attenuator so that <strong>3.8V pulse (<22dBm) doesn’t go above the maximum 20dBm input rating</strong>.<br>
- the device gain is <strong>34dB</strong>, its -0.1dB point is <strong>375kHz</strong> and -3dB point <strong>600kHz</strong>.<br><br>
I'm now ready to measure any low frequency signal that comes my way, with a home-made & well characterized device! In case you'd like to make your own one, I've uploaded the KiCad solution <a href="https://github.com/limpkin/sa_amp" hreflang="en">here</a>. Alternatively, you can also purchase it on my <a href="https://www.tindie.com/products/stephanelec/extremely-low-noise-dc-to-600khz-34db-amplifier/" hreflang="en">tindie store</a>.</p>https://www.limpkin.fr/index.php?post/2022/09/20/The-Low-Noise-Amplifier-Board#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/216The IN-9 Nixie Clockurn:md5:f0d84ad7590e6e6143b18b3c0c90b58a2021-11-01T20:43:00+00:002023-08-12T13:08:14+01:00limpkinMy ProjectsESP8266FPGANixie<p><img src="https://www.limpkin.fr/public/nixie_clock/spiral_loop.gif" alt="" style="display:table; margin:0 auto;" /><br />
A 60 Nixie tubes contraption that I postponed for 5 years...</p> <h2>Introduction<br /></h2>
<p>It has been <strong>three years</strong> since my last blog post, and <strong>four years</strong> since my last published project.... time flies!<br />
As you may have guessed, most of this time went into my family and the <a href="https://www.themooltipass.com" hreflang="en">Mooltipass project</a>, with its <strong>third device successfully funded</strong> through Kickstarter!<br />
It's quite hard to find the time for the funky side projects that randomly pops into my mind when so many people like our offline password keeper. But I hope to make some time in the future for one off projects as they are <strong>free of constraints</strong> and allow their creators to truly go crazy!<br />
Speaking about crazy.... this is the story of a PCB I made and assembled <strong>5 years ago</strong>, but never got to put into its housing until now as I realized the original design <strong>wouldn't be pretty</strong>. Some of you may actually remember <a href="https://www.limpkin.fr/index.php?post/2016/02/18/High-Voltage-Power-Supply-for-Nixie-Tubes" hreflang="en">the high voltage power supply</a> I made and wrote about, in which I had mentioned my intentions to drive <strong>many</strong> IN-9 Nixie tubes:<br /><br />
<img src="https://www.limpkin.fr/public/nixie/.in9_tube_m.jpg" alt="in9_tube.JPG" style="display:table; margin:0 auto;" title="in9_tube.JPG, fév. 2016" /><br />
So... how many Nixie tubes was I talking about? <strong>Sixty of them</strong>, so I could <strong>make a clock</strong>!<br />
With Nixie tubes now <strong>ten times more expensive than when I bought them</strong>, it seems I did well to purchase them back then (100pcs for $110!).<br /><br /></p>
<h2>Only Nixie Tubes?<br /></h2>
<p><a href="https://www.limpkin.fr/public/nixie_clock/7_segments.JPG"><img src="https://www.limpkin.fr/public/nixie_clock/7_segments.JPG" alt="" style="display:table; margin:0 auto;" /></a><br />
<strong>Nope</strong>! As my idea was to layout the tubes around a disc, I bought <strong>2.3"</strong> 7 segment displays to put in the center.<br />
I therefore wanted to display the time using both tubes and 7 segment displays. To drive the latter, I just used some I2C PCA9624 LED drivers:<br />
<a href="https://www.limpkin.fr/public/nixie_clock/led_drivers.png"><img src="https://www.limpkin.fr/public/nixie_clock/led_drivers.png" alt="" style="display:table; margin:0 auto;" /></a><br /></p>
<h2>How to Drive That Many Tubes?<br /></h2>
<p><img src="https://www.limpkin.fr/public/nixie/.in9_cur_length_m.png" alt="in9_cur_length.png" style="display:table; margin:0 auto;" title="in9_cur_length.png, fév. 2016" /><br />
IN-9 Nixie tubes are <strong>current driven</strong>, which means the length of the glowing segment will be proportional to the current fed to it.<br />
What's the simplest way to current drive something? By using a <strong>transistor driven by a filtered PWM signal</strong>:<br />
<a href="https://www.limpkin.fr/public/nixie_clock/nixie_current_driving.PNG"><img src="https://www.limpkin.fr/public/nixie_clock/nixie_current_driving.PNG" alt="" style="display:table; margin:0 auto;" /></a><br />
In the above circuit, a PWM signal is filtered using a RC low pass circuit, which is then fed to the transistor base. The transistor acts as a follower, setting the same voltage (minus ~0.7V) at its emitter.<br />
As a resistor is present between its emitter and the circuit's ground, changing the PWM signal duty cycle will linearly change the current going into the resistor and therefore the current going through the Nixie tube.<br />
But you may then wonder.... <strong>how to generate 60 PWM signals</strong>?<br /><br />
<a href="https://www.limpkin.fr/public/nixie_clock/spartan_3.JPG"><img src="https://www.limpkin.fr/public/nixie_clock/spartan_3.JPG" alt="" style="display:table; margin:0 auto;" /></a><br />
Yup... with an FPGA! I therefore wrote some VHDL to implement a <strong>60 channels 14bits PWM controller</strong>.<br />
I remember it being easier than expected, and using a Spartan 3 with its embedded programming flash made the schematics very easy:<br /><br />
<a href="https://www.limpkin.fr/public/nixie_clock/spartan_schematics.png"><img src="https://www.limpkin.fr/public/nixie_clock/spartan_schematics.png" alt="" style="display:table; margin:0 auto;" /></a><br />
One 1.2V LDO, a 10MHz oscillator, lots of decoupling capacitors (not shown) and a few pull-ups & pull-downs... that's all it took! Finally, I also coded an SPI slave controller so the FPGA could be told how to drive each Nixie tube.<br /><br /></p>
<h2>Which Microcontroller to Use?<br /></h2>
<p>Five years ago the ESP8266 was all the rage:<br />
<a href="https://www.limpkin.fr/public/bus_timer/esp8266.jpg" title="esp8266.jpg"><img src="https://www.limpkin.fr/public/bus_timer/esp8266.jpg" alt="esp8266.jpg" style="display:table; margin:0 auto;" title="esp8266.jpg, juil. 2017" /></a><br />
I programmed it in <strong>Lua, running on NodeMCU</strong> as with only ~250 lines of code I could:<br />
- connect to my home Wifi<br />
- fetch the time from an NTP server<br />
- configure the 7 segment display drivers using I²C<br />
- .... and tell the FPGA how to drive each Nixie tube using SPI<br />
The schematics for this part were also extremely straight forward:<br /><br />
<a href="https://www.limpkin.fr/public/nixie_clock/esp8266.PNG"><img src="https://www.limpkin.fr/public/nixie_clock/esp8266.PNG" alt="" style="display:table; margin:0 auto;" /></a><br /><br /></p>
<h2>Putting It All Together<br /></h2>
<p>So I had designed the schematics and layout, assembled the PCB, written the VHDL & LUA, made sure it worked.... <strong>and waited five years to come up with a prettier housing</strong>.<br /><br />
<a href="https://www.limpkin.fr/public/nixie_clock/smooth_integration.JPG"><img src="https://www.limpkin.fr/public/nixie_clock/smooth_integration.JPG" alt="" style="display:table; margin:0 auto;" /></a><br />
You see, originally I had the stupid idea to have the Nixie tubes stick out of a central piece as spikes (<a href="https://www.custommade.com/analog-nixie-clock-nixie-radian/by/tungstencustoms/" hreflang="en">like that</a>).... but the prototype <strong>was truly awful</strong>.<br />
I then realized it would look prettier to integrate the tubes directly into a wooden part.<br /><br />
<a href="https://www.limpkin.fr/public/nixie_clock/cnc_machining.JPG"><img src="https://www.limpkin.fr/public/nixie_clock/cnc_machining.JPG" alt="" style="display:table; margin:0 auto;" /></a><br />
Designing the part, generating the G-Code that would be run on my father's <strong>CNC machine</strong> sure was fun.<br />
As you can see above and below, the 7 segment displays are put in the machined pocket so their light can shine through the thin wood.<br /><br />
<a href="https://www.limpkin.fr/public/nixie_clock/pcb_on_wood.JPG"><img src="https://www.limpkin.fr/public/nixie_clock/pcb_on_wood.JPG" alt="" style="display:table; margin:0 auto;" /></a><br />
... while the nixie tubes rest inside their dedicated groves:<br /><br />
<a href="https://www.limpkin.fr/public/nixie_clock/nixie_in_slot.JPG"><img src="https://www.limpkin.fr/public/nixie_clock/nixie_in_slot.JPG" alt="" style="display:table; margin:0 auto;" /></a><br /><br /></p>
<h2>Layout and Safety<br /></h2>
<p><a href="https://www.limpkin.fr/public/nixie_clock/layout.PNG"><img src="https://www.limpkin.fr/public/nixie_clock/layout.PNG" alt="" style="display:table; margin:0 auto;" /></a><br />
Ever wondered if Kicad's polar coordinate system actually is useful? I don't anymore, as it was extremely convenient to evenly space the high voltage transistor circuits.<br />
Speaking about high voltage, <strong>140V is no joke</strong>. Remember the fuses at the FPGA's and transistors' outputs? I blew several of them due to stupid mistakes, the highlight being: high voltage capacitors still charged, USB to UART adapter connected to my computer (therefore connecting earth to GND), soldering iron (connected to earth) soldering a nixie tube: nice spark, USB to UART adapter and ESP8266 fried. This actually happened <strong>twice</strong>....<br />
Conclusion: do not forget <strong>bleeder resistors</strong> at high voltage power supply outputs.<br />
In any case, these NPN transistors can fail in interesting ways, so the 50mA fuses you saw above will protect both Nixie tubes and FPGA (tested and approved).<br /><br /></p>
<h2>IN9 Burn-in Procedure & Bring-up<br /></h2>
<p><img src="https://www.limpkin.fr/public/nixie_clock/cathode_poisoning.PNG" alt="" style="display:table; margin:0 auto;" /><br />
Oh the nightmares, time spent and number of visited message boards...<br />
Oddly enough, when trying to use something that hasn't been used for the last <strong>30-40 years</strong> you may or may not get lucky. In my case I encountered <strong>two main things</strong>:<br />
1) At first power-up, the light segment wouldn't go all the way to the top: this is normally fixed by a so called '<strong>burn-in procedure</strong>' which seems to consist in powering a given tube at twice its rated current for a couple of hours. I instead simply left each tube running at max current (12mA) for around 10 hours.<br />
2) Either at first light-up or during fast current changes the light segment would get unstuck from the bottom of the tube. Following some online posts, to get rid of that effect I setup a 1/20 duty cycle at a 50Hz frequency and let that running for 10 hours. However, in my experience it seems that IN9 tubes <strong>do not like sudden current decrease</strong>, which can severely limit what you can do with them.<br />
This <a href="https://surfncircuits.com/2019/04/06/eliminating-nixie-tube-cathode-poisoning-bi-quinary-digit-ghosting-and-heavily-oxidized-leads/" hreflang="en">particular page</a> was the most informative one on how to 'initialize' Nixie tubes, I highly recommend the read.<br />
Finally, a <strong>given Nixie tube may simply be not good enough</strong>. I actually ended up replacing around 25% of the tubes I had first soldered.<br /><br /></p>
<h2>Final Words, Pictures and Videos<br /></h2>
<p>Here are the tubes in action:<br /></p>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/4m_zUL-QL6I" frameborder="0" allowfullscreen></iframe>
</div>
<p>In the video above my nearby computer is actually running a <a href="https://github.com/limpkin/nixie_clock/blob/main/python/fft.py" hreflang="en">python script</a> which computes the FFT of my microphone output and then streams it to the nixie clock over Wifi!<br />
Below you can see the 7 segment displays in action... taking that picture was quite tricky as their brightness level is quite different than the tubes'.<br /><br />
<a href="https://www.limpkin.fr/public/nixie_clock/displays_and_tubes.JPG"><img src="https://www.limpkin.fr/public/nixie_clock/displays_and_tubes.JPG" alt="" style="display:table; margin:0 auto;" /></a><br />
You'll find all the source files made for that project on this <a href="https://github.com/limpkin/nixie_clock" hreflang="en">GitHub repository</a>. I'm still planning on improving the clock by adding some numbering on the central part and making some nice animations :).<br /><br /></p>
<h2>Bringing Back Nixie Tubes to Life<br /></h2>
<p>While browsing around I stumbled on a video of someone who by himself brought back Nixie tubes from the dead and made a company out of it. Watch the video below.... it's <strong>mesmerizing</strong>.<br /></p>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/wxL4ElboiuA" frameborder="0" allowfullscreen></iframe>
</div>
https://www.limpkin.fr/index.php?post/2021/05/24/The-IN-9-Nixie-Clock#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/214Radiation Pattern Measurements in an RF Chamberurn:md5:dd5a30803c4599bd8ef2cc29afe533342018-10-15T16:30:00+01:002023-08-20T14:54:08+01:00limpkinMy Projectsanechoic chamberblack magicradiation patternRFVNA<p><img src="https://www.limpkin.fr/public/anechoic/chamber_entrance.JPG" alt="" class="media-center" /><br />
Very few are lucky enough to use such a piece of equipment... so I figured I'd share this experience with you!</p> <p>Let me first start this write-up by apologizing for the lack of recent articles. As you can imagine, I've been fairly busy working on the <a href="https://www.themooltipass.com" hreflang="en">Mooltipass ecosystem</a>, and more recently on an upcoming wireless device!<br />
Unfortunately this article is not going to be about its antenna (we're not there yet), but about ways to characterize antennas in general. Most (if not all) of the information below is over-simplified as my aim is just to give everyone a peek into the RF world.<br /><br /></p>
<h3>What's an Antenna?<br /></h3>
<p><a href="https://www.limpkin.fr/public/anechoic/antenna.jpg"><img src="https://www.limpkin.fr/public/anechoic/antenna.jpg" alt="" class="media-center" /></a><br />
Let's take as an example the above standard Wi-Fi antenna. To make things simpler, we'll assume in the rest of this write-up that it is only used for transmitting RF. This antenna (and any <strong>passive</strong> antenna in general):<br />
- <strong>converts</strong> an input power (fed though the SMA connector) into electro-magnetic waves (its main purpose)<br />
- <strong>reflects</strong> some of the input power back to its sender: an unwanted effect caused by <a href="https://en.wikipedia.org/wiki/Mismatch_loss" hreflang="en">impedance mismatch</a><br />
- <strong>absorbs</strong> part of the input power, due to internal losses<br /><br />
Let's imagine that you want to know how well an antenna is radiating. The very first step is to find out the frequencies for which this antenna is used so you can setup your measurement equipment.<br />
In the case of Wi-Fi, this is fairly simple: a quick look on wikipedia tells you that there are 14 bands are located between <strong>2.4GHz and 2.5GHz</strong>.<br />
You can then measure how well the antenna is 'accepting' the power you're sending by using fairly expensive tools such as <a href="https://en.wikipedia.org/wiki/Network_analyzer_(electrical)" hreflang="en">(Vector) Network Analyzers</a>. It would typically show you something like that:<br /><br />
<a href="https://www.limpkin.fr/public/anechoic/impedance-bandwidth-measurement.png"><img src="https://www.limpkin.fr/public/anechoic/impedance-bandwidth-measurement.png" alt="" class="media-center" /></a><br />
You can see that the amount of reflected power is at its minimum at the middle of the band of interest (2450MHz).<br />
This is a <strong>good thing</strong>, as less signal is reflected more signal is likely to be transmitted over the air.<br /><br /></p>
<h3>Vector Network Analyzers<br /></h3>
<p><a href="https://www.limpkin.fr/public/anechoic/vna.jpg"><img src="https://www.limpkin.fr/public/anechoic/vna.jpg" alt="" class="media-center" /></a><br />
VNAs are cool devices. In short, they allow you to see the quantity of signal going out and back their 2 ports.<br />
To characterize a passive transmit antenna you would therefore connect port 1 of the VNA to the input (RP) SMA connector and connect port 2 to a reference receive antenna. The VNA would then tell you (among <strong>many</strong> other things):<br />
- the <strong>power reflection</strong> at the input, by measuring the amount of power leaving port 1 and the amount of power coming back into the same port<br />
- <strong>how much power is transferred</strong> into the receiving antenna, by measuring the amount of power leaving port 1 and entering port 2<br />
That last point is <strong>key</strong> as it gives you a feel of how well your transmit (TX) antenna can talk to the reference receive (RX) antenna. It is however affected by <strong>many things</strong> that can be 'calibrated out' except one: <strong>the environment you're doing your tests in</strong>.<br />
In a standard environment, when the TX antenna is transmitting, the RF signal is being <strong>bounced</strong> and/or <strong>absorbed</strong> by tables, walls and any other thing in its way. It may also happen that something else in the room may be transmitting at the frequency of interest, making you believe that you're receiving more signal than you actually are. All in all that means <strong>you aren't able to know how well your antenna is radiating in a particular direction</strong>.<br />
This is where anechoic chambers come in.<br /><br /></p>
<h3>The Pyramids Room<br /></h3>
<p><a href="https://www.limpkin.fr/public/anechoic/anechoic_chamber_back.JPG"><img src="https://www.limpkin.fr/public/anechoic/anechoic_chamber_back.JPG" alt="" class="media-center" /></a><br />
It does look that way doesn't it?<br />
RF anechoic chambers have the following characteristics that <strong>solve all our problems</strong>:<br />
- emitted RF signals don't bounce off the walls, all the cones absorb them<br />
- RF signals from the outside don't come in: the chamber is a faraday cage<br />
- these chambes are very silent (but that's just for me)<br /><br />
RF anechoic chambers are (really, really really) <strong>not cheap to rent</strong>. The one you see above is a chamber I had the occasion to do measurements in, located in Erlangen (Germany) at the Fraunhofer Institute.<br />
In it, you simply mount your TX antenna (green in the picture below) several meters away from a receiving probe (the assembly on the right) and you'll then have the guarantee that <strong>the power received at the probe is the one sent by the TX antenna through a direct path</strong>:<br /><br />
<a href="https://www.limpkin.fr/public/anechoic/direct_path.JPG" title="Antenna (green circle) at a 90degrees with the probe (right)"><img src="https://www.limpkin.fr/public/anechoic/direct_path.JPG" alt="Antenna (green circle) at a 90degrees with the probe (right)" class="media-center" /></a><br />
Obivously no devices except the Antenna Under Test (AUT) are allowed inside the anechoic chamber.<br />
That means very long RF cables connect the antenna & probe to the VNA placed outside the chamber. In the picture above, the VNA was therefore measuring the amount of power transmitted by a test antenna when rotated at 90 degrees angle.<br />
What's next? Well now that you can accurately know how much power your AUT is transmitting in a particular direction, you simply need rotate it on its Y & Z axis:<br /></p>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/giwDKEiCaX0" frameborder="0" allowfullscreen></iframe>
</div>
<p>... in order to get recreate your radiation pattern:<br />
<a href="https://www.limpkin.fr/public/anechoic/rad_pattern.jpg"><img src="https://www.limpkin.fr/public/anechoic/rad_pattern.jpg" alt="" class="media-center" /></a><br />
<br /><br /></p>
<h3>Footnotes<br /></h3>
<p>I took <strong>a lot</strong> of shortcuts when writing the above paragraphs.<br />
1) You may replace "TX" with "RX" and vice versa to change the characterization process for a receive antenna.<br />
2) VNAs only output the power ratio between their port inputs/outputs, not the absolute power values.<br />
3) <a href="https://en.wikipedia.org/wiki/Scattering_parameters" hreflang="en">Scattering parameters</a> are therefore never explicitly mentioned. The "amount of reflected power" is indeed S11 and the "amount of transmitted power" is S21 using the setup described above.<br />
4) the importance of dB scale instead of linear scale is left out, as it is a measurement 'technicality'.<br />
5) the difference between <a href="https://en.wikipedia.org/wiki/Near_and_far_field" hreflang="en">near and far field measurements</a> is not mentioned.<br />
6) the complex calibration process and parameters setup of VNAs is skipped.<br />
7) <a href="https://en.wikipedia.org/wiki/Polarization_(waves)" hreflang="en">polarisation types</a> are not mentioned.<br />
8) the video above is sped up 10 times<br />
9) the radiation pattern shown is one found on the internet<br />
10) for obvious reasons, the antenna I used in fraunhofer is hidden.<br /></p>Project In A Day: When Is My Next Bus?urn:md5:8b5f029e7b7ec04017d2d7d84a3c5b782017-07-23T20:36:00+01:002024-03-09T11:00:08+00:00limpkinMy Projectsesp8266<p><img src="https://www.limpkin.fr/public/bus_timer/.platform_m.jpg" alt="platform.JPG" class="media-center" title="platform.JPG, juil. 2017"><br>
Made using only components from my stock !</p> <h2>Why This Project?<br></h2>
<p>For once, this project was not for me... it was <strong>for my wife</strong> !<br>
Every morning she takes the bus then train to go to work. If she misses her train, she has to <strong>wait for more than 30 minutes</strong> for the next one. Not missing her bus is therefore quite important.<br>
Where we live every bus station has a display letting you know in real time when the next bus will be there. My first thought was to reverse engineer its RF signal but something <strong>easier</strong> then came to mind.<br>
In the very same bus stations, a small QR code brings you to a web page displaying the very same "minutes before bus arrival"... <strong>HTML parsing</strong> therefore made more sense given that I was fairly busy with <a href="https://github.com/limpkin/mooltipass" hreflang="en">other projects</a>.<br><br></p>
<h2>What Did I Have In Stock?<br></h2>
<p><a href="https://www.limpkin.fr/public/bus_timer/layettes.JPG" title="layettes.JPG"><img src="https://www.limpkin.fr/public/bus_timer/.layettes_m.jpg" alt="layettes.JPG" class="media-center" title="layettes.JPG, juil. 2017"></a><br>
Every time I design a platform for a client or for my own projects, I order extra components (who doesn't, right?).<br>
To display the number of minutes before bus arrival, I used a big <a href="http://www.ebay.com/itm/5-Red-7-Segment-2-3-LED-Display-Digital-Tube-Common-Anode-1-Bit-Digitron-/141008250355" hreflang="en" title="7 segment 2.3" display :">2.3" common anode 7 segment display:</a><br><br>
<a href="https://www.limpkin.fr/public/bus_timer/7segmentdisp.JPG" title="7segmentdisp.JPG"><img src="https://www.limpkin.fr/public/bus_timer/.7segmentdisp_m.jpg" alt="7segmentdisp.JPG" class="media-center" title="7segmentdisp.JPG, juil. 2017"></a><br>
As you can guess, it doesn't use 2.5V per segment... but something around <strong>7.5V</strong>.<br>
I therefore needed a voltage step-up: the <a href="http://www.ti.com/product/LM4510" hreflang="en" title="LM4510">LM4510</a> was therefore found in my inventory.<br>
Next thing: the power source. I really didn't want to have a power supply plugged 24/7 for this platform.<br>
What I did have laying around was a ~<strong>5600mAh battery</strong> from a USB power bank whose charging IC had burned:<br><br>
<a href="https://www.limpkin.fr/public/bus_timer/burnt_charger.jpg" title="burnt_charger.jpg"><img src="https://www.limpkin.fr/public/bus_timer/.burnt_charger_m.jpg" alt="burnt_charger.jpg" class="media-center" title="burnt_charger.jpg, juil. 2017"></a><br>
Yes, cheap USB power banks from China are a big no-no.<br><br>
<a href="https://www.limpkin.fr/public/bus_timer/esp8266.jpg" title="esp8266.jpg"><img src="https://www.limpkin.fr/public/bus_timer/esp8266.jpg" alt="esp8266.jpg" class="media-center" title="esp8266.jpg, juil. 2017"></a><br>
Finally, as the brain of this platform, to connect to my Wifi and fetch the bus time of arrival web page: the very well known <strong>ESP8266</strong> was chosen, running NodeMCU.<br><br></p>
<h2>The Schematics<br></h2>
<p><a href="https://www.limpkin.fr/public/bus_timer/schematics.png" title="schematics.png"><img src="https://www.limpkin.fr/public/bus_timer/.schematics_m.png" alt="schematics.png" class="media-center" title="schematics.png, juil. 2017"></a><br>
As previously mentioned, the LM4510 generates the 12V (I could have used a lower voltage) required by the common anode of the 7 segment display.<br>
The <a href="http://www.nxp.com/products/interfaces/ic-bus-portfolio/ic-led-controllers/8-bit-fm-plus-ic-bus-100-ma-40-v-led-driver:PCA9624" hreflang="en" title="PCA9624">PCA9624</a> then drives each segment cathode, and is connected to the ESP8266 through an I2C bus. Interestingly enough, it also has an enable input which can be used for blinking or even dimming.<br>
A micro-USB connector (scrapped from a Mooltipass prototype) is used together with the <a href="https://www.maximintegrated.com/en/products/power/battery-management/MAX1551.html" hreflang="en" title="MAX1551">MAX1551</a> to charge the Li-Ion battery. As the charge current is limited to 280mA... <strong>charging takes a while</strong>.<br>
Finally, the <a href="http://www.ti.com/product/LP38693" hreflang="en" title="LP38693">LP38693</a> LDO generates the 3V3 required by the ESP8266.<br><br></p>
<h2>The Board<br></h2>
<p><a href="https://www.limpkin.fr/public/bus_timer/board.JPG" title="board.JPG"><img src="https://www.limpkin.fr/public/bus_timer/.board_m.jpg" alt="board.JPG" class="media-center" title="board.JPG, juil. 2017"></a><br>
You can easily guess what each component does from this picture. The PCB has the exact same size as the 7 segments display.<br>
The two buttons are used to start the <a href="https://github.com/espressif/esptool/wiki/ESP8266-Boot-Mode-Selection" hreflang="en" title="bootloader esp8266">ESP8266 bootloader</a> while the 4 pins connector brings out its UART.<br><br>
<a href="https://www.limpkin.fr/public/bus_timer/platform.JPG" title="platform.JPG"><img src="https://www.limpkin.fr/public/bus_timer/.platform_m.jpg" alt="platform.JPG" class="media-center" title="platform.JPG, juil. 2017"></a><br>
On the display side, you can notice that I 3D printed a "button extension". A simple press on it will wake up the ESP8266 from its deep sleep state to start displaying the time. As the LDO required a minimum 100uA load current, I actually had to add a load resistor!<br><br></p>
<h2>The Source Code<br></h2>
<p>As I said, designing the complete board and making its source code took me less than 10 hours.<br>
NodeMCU definitely made things easy:</p>
<pre>
--bus_timer.lua-- Below: for each number (0->9) a boolean array specifying if we should set a non zero value into the pwm register, following the PCA9624 pwm register order
number_to_reg_val = {{1,1,1,0,1,0,1,1},{1,0,0,0,0,0,0,1},{0,1,1,1,0,0,1,1},{1,1,0,1,0,0,1,1},{1,0,0,1,1,0,0,1},{1,1,0,1,1,0,1,0},{1,1,1,1,1,0,1,0},{1,0,0,0,0,0,1,1},{1,1,1,1,1,0,1,1},{1,1,0,1,1,0,1,1}}
dash_reg_val = {0,0,0,1,0,0,0,0}
displayed_digits = {0, 0, 0, 0}
start_digit_reg_addr = 2
digit_address = 0x08
dot_shown = false
sda, scl = 1, 2
led_noe = 4
led_hv_en = 8
-- Below: time fetching logic
time_until_other_bus = 10
time_until_first_bus = 10
fetching_first_bus = true
fetching_done = true
displaying_first_bus = true
sleep_counter = 0
-- check for led controller
function check_led_controller()
result = true
i2c.start(0) -- start i2c
c = i2c.address(0, digit_address, i2c.TRANSMITTER) -- see if something answers
i2c.stop(0) -- stop i2c
if c == false then
result = false
end
return result
end
-- write a register contents in a PCA
function write_reg_PCA(digit_addr, reg, val)
i2c.start(0)
i2c.address(0, digit_addr, i2c.TRANSMITTER)
i2c.write(0, reg)
i2c.write(0, val)
i2c.stop(0)
end
-- update all segment registers inside a pca
function update_segment_registers(digit_addr, reg_bool_array, pwm_value)
i2c.start(0)
i2c.address(0, digit_addr, i2c.TRANSMITTER)
i2c.write(0, start_digit_reg_addr + 128)
for i=1,8 do
if reg_bool_array[i] == 0 then
i2c.write(0, 0)
else
i2c.write(0, pwm_value)
end
end
i2c.stop(0)
end
-- display the number
function display_number(number)
if number < 10 then
-- display dot or not
if dot_shown == true then
number_to_reg_val[number+1][6] = 1
end
update_segment_registers(digit_address, number_to_reg_val[number+1], 0x10)
number_to_reg_val[number+1][6] = 0
else
update_segment_registers(digit_address, dash_reg_val, 0x10)
end
end
-- IO INIT
gpio.mode(led_noe, gpio.OUTPUT) -- Led output enable GPIO2
gpio.write(led_noe, gpio.LOW) -- Enable output
gpio.mode(led_hv_en, gpio.OUTPUT) -- Led high voltage enable GPIO15
gpio.write(led_hv_en, gpio.HIGH) -- Enable output
i2c.setup(0, sda, scl, i2c.SLOW) -- init i2c
-- CHECK LED CONTROLLER
res = check_led_controller()
if res == true then
print("LED controller here!")
else
print("LED controller not found !!")
end
-- INIT LED CONTROLLER SETTINGS
-- Register auto-increment, normal mode, responds to all call
write_reg_PCA(digit_address, 0x00, 0x81)
-- LED driver 0->7 individual brightness and group dimming/blinking can be controlled through its PWMx register and the GRPPWM registers.
write_reg_PCA(digit_address, 0x0C, 0xFF)
write_reg_PCA(digit_address, 0x0D, 0xFF)
-- TIME FETCHING, every 5secs
tmr.alarm(0,5000,tmr.ALARM_AUTO,
function()
sleep_counter = sleep_counter + 1
if sleep_counter == 240 then -- 20 minutes of activity
write_reg_PCA(digit_address, 0x00, 0x91) -- pca9624 sleep
write_reg_PCA(digit_address, 0x00, 0x91) -- pca9624 sleep
gpio.write(led_hv_en, gpio.LOW) -- Disable output
gpio.write(led_noe, gpio.HIGH) -- Disable output
node.dsleep(0)
sleep_counter = 0
end
if fetching_done == true then
if fetching_first_bus == false then
http.get("VERYLONGURLHERE", nil, function(code, data)
if (code < 0) then
time_until_first_bus = 10
print("HTTP request failed")
else
matches = string.match(data, '"time">(%d*)\'')
if matches ~= nil then
time_until_first_bus = tonumber(matches)
print(string.format("Next bus #1 in %d minutes", time_until_first_bus))
else
time_until_first_bus = 10
end
end
fetching_done = true
end)
fetching_first_bus = true
else
http.get("ANOTHERLONGURLTHERE", nil, function(code, data)
if (code < 0) then
time_until_other_bus = 10
print("HTTP request failed")
else
matches = string.match(data, '"time">(%d*)\'')
if matches ~= nil then
time_until_other_bus = tonumber(matches)
print(string.format("Next bus #2 in %d minutes", time_until_other_bus))
else
time_until_other_bus = 10
end
end
fetching_done = true
end)
fetching_first_bus = false
end
fetching_done = false
end
end)
-- TIME DISPLAY, every 2 secs
tmr.alarm(1,2000,tmr.ALARM_AUTO,
function()
if displaying_first_bus == false then
display_number(time_until_first_bus)
displaying_first_bus = true
else
display_number(time_until_other_bus)
displaying_first_bus = false
end
end)
</pre>
<p>A <strong>regular expression</strong> was used to extract the number of minutes from the web page, and if you look into the source code above you'll notice that I'm displaying 2 different times of arrival as my wife can use 2 buses to go to the train station.<br><br></p>
<h2>The Source Files<br></h2>
<p>This project was <strong>quickly done</strong> so I do apologize for the lack of documentation!<br>
The kicad source files can be downloaded <a href="https://www.limpkin.fr/public/bus_timer/kicad.rar">here</a>.<br>
Cheers!</p>Making the Electronics for a 24GHz Doppler Sensorurn:md5:0e5a89133911f8f8a16bf796d6000a292017-02-22T08:52:00+00:002024-03-09T11:09:53+00:00limpkinMy Projectscdm324doppler<p><img src="https://www.limpkin.fr/public/cdm324/.cdm324_assembled_quarter_m.jpg" alt="cdm324_assembled_quarter.JPG" class="media-center" title="cdm324_assembled_quarter.JPG, mar. 2017">
I couldn't believe my eyes when I saw how tiny that sensor is !</p> <h2>2023 Edit - New Project Version!<br></h2>
<p>I just made an improved version of this project, <a href="https://www.limpkin.fr/index.php?post/2022/03/31/CDM324-Doppler-Motion-Sensor-Backpack%2C-now-with-FFTs%21" hreflang="en">check it out here</a>!<br>
Otherwise, feel free to read about the non-MCU based version below:<br><br></p>
<h2>The Doppler Effect<br></h2>
<p><img src="https://www.limpkin.fr/public/HB100/doppler-effect.png" alt="Doppler effect" class="media-center" title="Doppler effect, août 2013"><br>
I'm sure you're quite familiar with the Doppler effect: you send an RF signal at a given frequency to a target, and if this object/person is moving the <strong>reflected signal's frequency will be shifted</strong>. This is the reason why a fire truck's siren has a <strong>higher pitch</strong> when the truck is going towards you than when it is going away.<br><br></p>
<h2>The CDM324 / IPM165 Motion Sensor<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_size.JPG" title="cdm324_size.JPG"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_size_m.jpg" alt="cdm324_size.JPG" class="media-center" title="cdm324_size.JPG, mar. 2017"></a><br>
You may recall <a href="https://www.limpkin.fr/index.php?post/2013/08/09/Making-the-electronics-for-a-%247-USD-doppler-motion-sensor">the article I wrote a couple of years ago</a> about a nearly identical Doppler sensor, <strong>the HB100</strong>.<br>
While the HB100 is using a 10.525GHz frequency, this new module uses <strong>24.125GHz</strong>! This has the main advantage of being compatible with European regulations (ETSI #300 400) and having good penetration in dry materials. Moreover, as the main frequency is higher the patch antennas are smaller, hence the tiny 25x25x6mm module.<br>
This motion sensor can easily be purchased on eBay under the name <strong>CDM324</strong>. Oddly enough, looking for "cdm324" on your favorite search engine won't bring any interesting results.<br>
I therefore spent several hours tracing the origins of this tiny sensor. I finally arrived to the conclusion that it likely is a clone of the <a href="https://www.digikey.com/en/products/detail/innosent-gmbh/80-00000062/10482982" hreflang="en">InnoSenT IPM 165</a>, which is itself very similar to the <a href="http://agilsense.com" hreflang="en">AP96 from Agilsense</a>.<br>
Specification-wise, the CDM324 antenna pattern is slightly narrower than the HB100's: 80° azimuth and 32° elevation versus 80° azimuth and 40° elevation. The Radiated Power (EIRP) is more or less the same: 16dBm vs 15dBm. Finally, the advertised power consumption is identical to the HB100's: up to <strong>40mA @ 5V</strong>.<br><br></p>
<h2>Finding the Right Amplification Circuit<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_ampl_innosent.png" title="cdm324_ampl_innosent.png"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_ampl_innosent_m.png" alt="cdm324_ampl_innosent.png" class="media-center" title="cdm324_ampl_innosent.png, fév. 2017"></a><br>
Now that I had traced the origins of this CDM324, I could find its recommended amplifier schematics.<br>
The one you see above comes from InnoSenT. It consists in 2 cascaded inverting band pass filter circuits:<br>
<a href="https://www.limpkin.fr/public/cdm324/pass_band_amplifier.png" title="pass_band_amplifier.png"><img src="https://www.limpkin.fr/public/cdm324/.pass_band_amplifier_m.png" alt="pass_band_amplifier.png" class="media-center" title="pass_band_amplifier.png, fév. 2017"></a><br>
You'll however notice that the op-amp positive input in our suggested schematics is tied to vcc/2, allowing us to have a <strong>centered amplification output</strong> as well.<br>
From the formulas above, we can compute the circuit <strong>total gain</strong> and <strong>cutoff frequencies</strong>. I'll spare you the maths, the suggested amplification is <strong>1018 (60dB)</strong> and a band pass filter from <strong>3.4Hz to 1.06kHz</strong>.<br>
The InnoSenT application note allows us to put these frequencies in context:<br>
<a href="https://www.limpkin.fr/public/cdm324/Innosent_app_note_doppler.png" title="Innosent_app_note_doppler.png"><img src="https://www.limpkin.fr/public/cdm324/.Innosent_app_note_doppler_m.png" alt="Innosent_app_note_doppler.png" class="media-center" title="Innosent_app_note_doppler.png, fév. 2017"></a><br>
The high cutoff frequency is therefore set for a <strong>24km/h or 15.4m/h speed</strong>. However, this isn't exactly true as the filter cutoff slope isn't vertical. Here's the simulated amplification output generated using LTspice:<br><br>
<a href="https://www.limpkin.fr/public/cdm324/simul_seller.png" title="simul_seller.png"><img src="https://www.limpkin.fr/public/cdm324/.simul_seller_m.png" alt="simul_seller.png" class="media-center" title="simul_seller.png, fév. 2017"></a><br>
You may therefore be able to measure much higher speeds if the moving object is <strong>close to the sensor</strong>.<br><br></p>
<h2>Amplification Circuit from Chinese Sellers<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_ampl_ebay.jpg" title="cdm324_ampl_ebay.jpg"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_ampl_ebay_m.jpg" alt="cdm324_ampl_ebay.jpg" class="media-center" title="cdm324_ampl_ebay.jpg, fév. 2017"></a><br>
This is the (very low resolution) recommended amplification circuit that you will find online.<br>
Simulating it leads to raising eyebrows:<br><br>
<a href="https://www.limpkin.fr/public/cdm324/simul_ebay.png" title="simul_ebay.png"><img src="https://www.limpkin.fr/public/cdm324/.simul_ebay_m.png" alt="simul_ebay.png" class="media-center" title="simul_ebay.png, fév. 2017"></a><br><br>
Many many things are odd with this recommended amplification circuit:<br>
- <strong>No high pass filter</strong> on the second amplifier (remember, the cutoff slope in the first amplifier stage isn't vertical)<br>
- I don't see any reason for that 1nF capacitor when the high pass filter is done using the first op-amp<br>
- Amplification on the first stage is <strong>510</strong> while the amplification on the second stage is <strong>100</strong><br>
- Which leads to a total gain of <strong>51000 (94dB)</strong><br>
- ... while the LM258 has a <strong>gain bandwidth product of 1MHz</strong>!<br>
The last point is crucial. Given the first amplification stage has a gain of 510, this means there's only 1.96kHz of bandwith "left" inside the LM258. As the cutoff slope isn't vertical, this means that the LM258 isn't the right op-amp for the job! For example, at 10kHz the amplification is 3162, which is a GBW product of <strong>31.6MHz</strong>!<br><br></p>
<h2>Chosen Amplification Circuit<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_ampl_limpkin.png" title="cdm324_ampl_limpkin.png"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_ampl_limpkin_m.png" alt="cdm324_ampl_limpkin.png" class="media-center" title="cdm324_ampl_limpkin.png, mar. 2017"></a><br>
After lots of experimentation and performance comparisons with my previous HB100 module, you can see above the final amplification circuit I chose.<br>
- As you can imagine, it is based on the manufacturer's<br>
- Each amplification stage has a gain of <strong>125.5</strong><br>
- Total gain is therefore <strong>15758 (84dB)</strong><br>
- Cutoff frequencies are <strong>3.4Hz and 999Hz</strong> (< 1 km/h or m/h and 22.7km/h / 14.5m/h respectively)<br>
Not so surprisingly the total gain is quite close to the one I had set on the HB100 (12100) and I'm fairly sure I could have set the same one. It was simply more convenient to choose the same resistors & capacitors values in my circuit.<br><br>
<a href="https://www.limpkin.fr/public/cdm324/simul_limpkin.png" title="simul_limpkin.png"><img src="https://www.limpkin.fr/public/cdm324/.simul_limpkin_m.png" alt="simul_limpkin.png" class="media-center" title="simul_limpkin.png, mar. 2017"></a><br>
As with my previous HB100 amplification circuit, I chose the <a href="http://www.ti.com/product/OPA2365" hreflang="en" title="OPA2365">OPA2365</a> operational amplifier. It has a 50MHz Gain Bandwidth product, which is more than the 15758*(84dB-3dB) = <strong>11.2MHz</strong> product at the high cutoff frequency point.<br><br></p>
<h2>Final Schematics<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_backpack_schematics.png" title="cdm324_backpack_schematics.png"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_backpack_schematics_m.png" alt="cdm324_backpack_schematics.png" class="media-center" title="cdm324_backpack_schematics.png, mar. 2017"></a><br>
You can see above the final schematics:<br>
- FB1 is here to <strong>filter</strong> the power supply noise<br>
- the voltage at the C10/R11 node is proportional to the amount of reflected RF energy<br>
- Q1 allows <strong>pulse mode operation</strong>: you may power on/off the CDM324 using the module nEN pin<br>
- U2 is a simple comparator that will transform our amplified output to a neat <strong>square wave</strong>:<br><br>
<a href="https://www.limpkin.fr/public/cdm324/cdm324_print.png" title="cdm324_print.png"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_print_m.png" alt="cdm324_print.png" class="media-center" title="cdm324_print.png, mar. 2017"></a><br>
In the scope capture above the yellow trace is the amplified output while the pink one is the comparator's output.<br>
Using a comparator is a simple way to 'extract' the amplified output main frequency but I'm quite sure running an FFT on that signal would be quite interesting!<br><br></p>
<h2>Assembled PCB<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_pcb2.JPG" title="cdm324_pcb2.JPG"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_pcb2_m.jpg" alt="cdm324_pcb2.JPG" class="media-center" title="cdm324_pcb2.JPG, mar. 2017"></a><br>
Here's what the assembled PCB looks like! It has the same size as the CDM324 (<strong>25x25mm</strong>) and uses a 3pins header to connect with the sensor. <strong>0805 passive components</strong> were chosen to make the soldering job easier.<br>
Please do not pay attention to the silkscreen as some values have changed since then: have a look at the end of this article to <strong>download all the source files</strong>.<br><br></p>
<h2>3D Printed Holder<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_assembled.JPG" title="cdm324_assembled.JPG"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_assembled_m.jpg" alt="cdm324_assembled.JPG" class="media-center" title="cdm324_assembled.JPG, mar. 2017"></a><br>
The HB100 doppler module had 4 connectors at each corner to solder my 'backpack PCB' to.<br>
Unfortunately the CDM324 only offers a single 3 pins connection, which is why I designed and <strong>3D printed</strong> a neat assembly holder: the CDM324 with its amplification circuit simply slide in it!<br><br></p>
<h2>The Sensors in Action & Sample Code<br></h2>
<p>Here's the video of the HB100 and CDM324 working side by side!<br></p>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/PCI9bbN7HsE" frameborder="0" allowfullscreen></iframe>
</div>
<p>I'm guessing that if you were to use such a module you'd definitely like some <strong>sample code</strong>.<br>
Below is some arduino code that will <strong>output the detected speed in your favorite terminal</strong>:<br></p>
<pre>
// Below: pin number for FOUT
#define PIN_NUMBER 4
// Below: number of samples for averaging
#define AVERAGE 4
// Below: define to use serial output with python script
//#define PYTHON_OUTPUT
unsigned int doppler_div = 44;
unsigned int samples[AVERAGE];
unsigned int x;
void setup() {
Serial.begin(115200);
pinMode(PIN_NUMBER, INPUT);
}
void loop() {
noInterrupts();
pulseIn(PIN_NUMBER, HIGH);
unsigned int pulse_length = 0;
for (x = 0; x < AVERAGE; x++)
{
pulse_length = pulseIn(PIN_NUMBER, HIGH);
pulse_length += pulseIn(PIN_NUMBER, LOW);
samples[x] = pulse_length;
}
interrupts();
// Check for consistency
bool samples_ok = true;
unsigned int nbPulsesTime = samples[0];
for (x = 1; x < AVERAGE; x++)
{
nbPulsesTime += samples[x];
if ((samples[x] > samples[0] * 2) || (samples[x] < samples[0] / 2))
{
samples_ok = false;
}
}
if (samples_ok)
{
unsigned int Ttime = nbPulsesTime / AVERAGE;
unsigned int Freq = 1000000 / Ttime;
#ifdef PYTHON_OUTPUT
Serial.write(Freq/doppler_div);
#else
//Serial.print(Ttime);
Serial.print("\r\n");
Serial.print(Freq);
Serial.print("Hz : ");
Serial.print(Freq/doppler_div);
Serial.print("km/h\r\n");
#endif
}
else
{
#ifndef PYTHON_OUTPUT
Serial.print(".");
#endif
}
}
</pre>
<p><br>
Text written in serial terminals is so small though... why not print it bigger using ASCII art?<br><br>
<img src="https://www.limpkin.fr/public/cdm324/python_script.png" alt="python_script.png" class="media-center" title="python_script.png, mar. 2017"><br>
Simply define PYTHON_OUTPUT in the script above, install python on your computer, run "pip install pyfiglet pyserial" and use that awesome little python script (don't forget to replace COM3 with your COM port):<br></p>
<pre>
from pyfiglet import *
import serial
import os
ser = serial.Serial('COM3', 115200)
while True:
speed = ord(ser.read())
os.system('cls||clear')
print(figlet_format(" ",font="clb8x10"))
print(figlet_format(" ",font="clb8x10"))
print(figlet_format(str(speed)+" km/h",font="clb8x10"))
print(figlet_format(" ",font="clb8x10"))
</pre>
<p><br></p>
<h2>Want to Make or Buy One?<br></h2>
<p>Here's the GitHub repository I made for this project: <a href="https://github.com/limpkin/cdm324_backpack" hreflang="en" title="cdm324 repository">https://github.com/limpkin/cdm324_backpack</a>.<br>
If you're interested by this module and don't want to produce it by yourself, you may buy it from <a href="https://www.tindie.com/products/stephanelec/cdm324-doppler-speed-sensor-arduino-compatible/" hreflang="en" title="Buy Your CDM324 Module">my store here</a>.<br>
You may also purchase my <strong>cheaper</strong> HB100 module <a href="https://www.tindie.com/products/limpkin/hb100-doppler-speed-sensor-arduino-compatible/" hreflang="en" title="HB100 store">there</a>.<br></p>https://www.limpkin.fr/index.php?post/2017/02/22/Making-the-Electronics-for-a-24GHz-Doppler-Motion-Sensor#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/211A Mass Programming Bench for ATMega32u4 MCUsurn:md5:00ec31a19a34f4cab769cd5e4a8801d32017-01-13T14:54:00+00:002023-04-14T13:47:26+01:00limpkinMy ProjectsAVRmass programmingRaspberry<p>Or how to try to spend as little time as possible programming <strong>several thousands MCUs</strong>....<br /></p>
<p><img src="https://www.limpkin.fr/public/massprog_bench/.prog_bench_close_m.jpg" alt="prog_bench_close.JPG" style="display:table; margin:0 auto;" title="prog_bench_close.JPG, janv. 2017" /></p> <h2>Why.... Just Why?<br /></h2>
<p><a href="https://www.limpkin.fr/public/massprog_bench/mini_in_box.JPG" title="mini_in_box.JPG"><img src="https://www.limpkin.fr/public/massprog_bench/.mini_in_box_m.jpg" alt="mini_in_box.JPG" style="display:table; margin:0 auto;" title="mini_in_box.JPG, janv. 2017" /></a><br />
As you may know I started the Mooltipass offline password keeper project more than 2 years ago. Together with a team of volunteers from all over the globe I created two Mooltipass devices which were successfully crowdfunded through <a href="https://www.indiegogo.com/projects/mooltipass-open-source-offline-password-keeper" hreflang="en">Indiegogo</a> and <a href="https://www.kickstarter.com/projects/limpkin/mooltipass-mini-your-passwords-on-the-go" hreflang="en">Kickstarter</a>, raising a total of around <strong>$290k</strong>.<br />
Through a secure mechanism it is possible to upgrade the firmware running on the Mooltipass units. On our latest device, the <strong>Mooltipass Mini</strong>, we implemented <strong>signed firmware updates</strong>, which involved storing inside the microcontrollers' memory some cryptographic keys.<br />
Here's the thing: instead of opting for a unique signing key for all our devices and have a single point of failure, we decided to assign a <strong>unique signing key per device</strong>. As you can guess, that meant <strong>unique Flash and EEPROM memory contents</strong> for every Mooltipass Mini out there. Moreover, it was anyway required as we also needed to store other unique information such as <strong>serial numbers</strong> and <strong>identifiers</strong>.<br />
For the original Mooltipass, all unique information were programmed into the device using <strong>USB commands</strong> during the device functional test. That required trusting the product assembler and trusting that the machine running the functional test hadn't been tampered with during shipping.<br />
For the Mooltipass Mini we are doing things differently: we (or to be more precise, I) am <strong>programming the microcontrollers before our assembler solders them</strong>. Hence the 60x11cm PCB you see in the above picture: you can't do more than 60cm with 4 layers!<br /><br /></p>
<h2>The Schematics<br /></h2>
<p><a href="https://www.limpkin.fr/public/massprog_bench/socket_single_sheet.png" title="socket_single_sheet.png"><img src="https://www.limpkin.fr/public/massprog_bench/.socket_single_sheet_m.png" alt="socket_single_sheet.png" style="display:table; margin:0 auto;" title="socket_single_sheet.png, janv. 2017" /></a><br />
All the electronics revolve around the <strong>9 programming sockets</strong> on the board. Why 9?<br />
Because the required I2C GPIO expanders have a maximum of 8 configurable addresses and I still had standard GPIOs to use. Moreover, by orienting the sockets the way I did, 2 persons on one side of the board and 1 person on the other side can have easy access to <strong>3 programming sockets each</strong>.<br />
Each programming tile is therefore composed of :<br />
- one 6 pin ISP connector<br />
- one current-limited power switch<br />
- one QFN44 programming socket<br />
- one 16MHz crystal and its 2 load capacitors<br />
- one button used by the user to start the programming process<br />
- 3 LEDs rows: green / orange / red displaying the <strong>programming status</strong><br />
- one I2C GPIO expander to control these LEDs, power switch, button<br />
Kicad hierarchical sheets were <strong>very convenient</strong> when designing the schematics: I only had to make a single sheet and duplicate it 7 times! Here is the top sheet:<br /><br />
<a href="https://www.limpkin.fr/public/massprog_bench/massprog_top_sheet.png" title="massprog_top_sheet.png"><img src="https://www.limpkin.fr/public/massprog_bench/.massprog_top_sheet_m.png" alt="massprog_top_sheet.png" style="display:table; margin:0 auto;" title="massprog_top_sheet.png, janv. 2017" /></a><br />
The very same microcontroller present in the Mooltipass Mini is controlling all the sockets. This allowed me to reuse most of the Mooltipass code, most importantly its <strong>USB stack and OLED display driver</strong>.<br /><br /></p>
<h2>Bench Architecture<br /></h2>
<p><a href="https://www.limpkin.fr/public/massprog_bench/mass_prog_bench_principle.png" title="mass_prog_bench_principle.png"><img src="https://www.limpkin.fr/public/massprog_bench/.mass_prog_bench_principle_m.png" alt="mass_prog_bench_principle.png" style="display:table; margin:0 auto;" title="mass_prog_bench_principle.png, janv. 2017" /></a><br />
This brings us to the description of the complete programming bench architecture.<br />
As shown in the above picture, an <strong>offline Raspberry Pi 3</strong> is the brain of the complete system.<br />
Using a <strong>USB hub</strong>, 9 ISP programmers (one for each socket) are connected to it, together with the USB enabled microcontroller controlling the LEDs, power switches, etc...<br />
The program flow in the Raspberry Pi is <strong>fairly simple</strong>:<br />
- through a USB command, query the main board MCU for pushed buttons<br />
If a button is pushed<br />
- <strong>generate a unique Flash and EEPROM file</strong><br />
- send a text to be displayed on the bench screen ("programming socket X with id Y")<br />
- spawn a new thread containing a sequence of avrdude programming commands that will use these files<br />
When programming is done<br />
- display the result on the bench screen<br />
- tell the bench MCU to light up the red or green LED row<br />
- encrypt and store the unit signing keys in an external media<br />
Everything was coded in <a href="https://github.com/limpkin/mooltipass/blob/master/tools/_python_framework/mooltipass_mass_prog.py" hreflang="en"><strong>Python</strong></a>, which allowed me to use threads, hex parsing libraries, encryption and data import/export functions. Yet it still took me several days to code as <strong>there was no room for mistakes</strong>.<br />
Creating the bench MCU firmware was fairly quick as all that was added to the official Mooltipass firmware were the string display/button query/LED set USB commands. The cryptographic keys were generated using the <strong>random number generator</strong> running inside the bench MCU. It uses the jitter between the watch dog timer and the crystal as a source of randomness. This makes it a true random number generator.<br /><br /></p>
<h2>Assembled Bench<br /></h2>
<p><a href="https://www.limpkin.fr/public/massprog_bench/prog_bench.JPG" title="prog_bench.JPG"><img src="https://www.limpkin.fr/public/massprog_bench/.prog_bench_m.jpg" alt="prog_bench.JPG" style="display:table; margin:0 auto;" title="prog_bench.JPG, janv. 2017" /></a><br />
Making the box was fairly straight forward, as several holes were added to the PCB to screw it into place. The assembly <strong>made it in one piece</strong> to China!<br />
As you can imagine all the programmers and the USB hub are under the PCB. If I had to do it again, I would add <strong>a second ISP connector under the PCB</strong>, though I'm not sure to have the space nor do I know if two programmers could coexist (as sometimes I directly plugged another programmer to it).<br />
Choosing a programmer that could perform quick programming and be uniquely identified through a serial number turned out to be a pain as the <strong>Atmel AVRISP MKII isn't made anymore</strong>. I however found the <strong>Diamex ALL-AVR ISP Programmer</strong> which comes with a <a href="http://www.diamex.de/dxshop/mediafiles//Sonstiges/ErfosIspUp_1.9.0.zip" hreflang="en">small tool</a> allowing you to update it and <strong>program its serial number</strong>.<br /><br /></p>
<h2>Adding the Costs<br /></h2>
<p><img src="https://www.limpkin.fr/public/massprog_bench/.mini_alum_final_small_cropped_m.jpg" alt="mini_alum_final_small_cropped.JPG" style="display:table; margin:0 auto;" title="mini_alum_final_small_cropped.JPG, janv. 2017" /><br />
I hope that this article will give you some inspiration if you are to create your own mass programming bench.<br />
This however won't be cheap, though still cheaper than professional ones:<br />
- Board: <strong>$250</strong><br />
- USB hub: <strong>$20</strong><br />
- Programmers: ~<strong>$250</strong><br />
- Programming sockets: <strong>$90*9</strong><br />
- Raspberry Pi 3 with uSD: ~<strong>$50</strong><br />
- Electronic components : ~<strong>$100</strong><br />
- Helping wife when mass programming: several dinners<br /><br />
Excluding the dinners, this adds up to a total of <strong>$1500</strong>! You may find all the files for this project in this <a href="https://github.com/limpkin/mini_mass_prog_bench" hreflang="en">repository</a>.<br />
Cheers!</p>A Small Collection of NodeMCU Lua Scriptsurn:md5:c17a834bde77ee7e923c988b05fc11512016-04-17T14:51:00+01:002024-03-09T10:52:28+00:00limpkinMy Projects<p>I usually never use libraries... but made an exception for these quick projects !<br></p>
<p><img src="https://www.limpkin.fr/public/NodeMCU/.REM_Cycles_m.png" alt="REM_Cycles.png" class="media-center" title="REM_Cycles.png, avr. 2016"></p> <p>I'm pretty sure that most people reading this very article know about the (very) cheap <strong>ESP8266 Wifi module</strong>.<br>
A bit more than a year ago, I actually made a <a href="https://www.limpkin.fr/index.php?post/2014/11/27/A-Development-Board-for-the-ESP8266-03">small development board</a> for it, which was recently used in the <a href="https://www.limpkin.fr/index.php?post/2015/08/30/A-Connected-Clock-to-Wake-Me-Up">connected lamp</a> that wakes me up. While what follows pales in comparison to what cnlohr <a href="http://hackaday.com/author/cnlohr/" hreflang="en" title="Cnlohr on Hackaday">has implemented on this chip</a> over the last months, sometimes you <strong>just have small projects that you don't want to spent days on</strong>.<br>
Anyway, the 'standard' way of compiling programs for this neat little chip involves installing a cross-compiling toolchain on a Linux computer (or VM), and then using a dedicated tool to flash your program to the ESP8266.<br>
As you can guess, this can quickly get tiring if all you want to do is blink an LED... but then I stumbled upon <a href="http://www.nodemcu.com/index_en.html" hreflang="en" title="NodeMCU">NodeMCU</a> and <a href="https://domoticz.com/" hreflang="en" title="Domoticz">Domoticz</a>.<br><br></p>
<h2>Getting Started with NodeMCU<br></h2>
<p><a href="https://www.limpkin.fr/public/NodeMCU/nodemcu_programmer.png" title="nodemcu_programmer.png"><img src="https://www.limpkin.fr/public/NodeMCU/nodemcu_programmer.png" alt="nodemcu_programmer.png" class="media-center" title="nodemcu_programmer.png, avr. 2016"></a><br>
NodeMCU is an open-source firmware and development kit that helps electronics enthusiasts to prototype IoT products <strong>within a few Lua script lines</strong>. Concretely, it is a firmware you can flash to any ESP8266 board, which will then interpret a text file which contains your commands. And while you won't find many websites detailing nodeMCU based projects, it is very convenient when the program you want to make only contains a few actions.<br>
So let's imagine you have one <a href="https://www.tindie.com/products/limpkin/esp8266-wifi-module-breakout/" hreflang="en" title="ESP8266 dev board">ESP8266 development board</a> laying around to which you want to connect a sensor. Let's also imagine you don't want to use any Linux tool and want to have everything working <strong>as soon as possible</strong>. Getting NodeMCU on your board is as simple as:<br>
- <a href="http://nodemcu-build.com/" hreflang="en" title="NodeMCU Build">Generating your own NodeMCU build</a> and selecting the libraries you want included in it<br>
- <a href="https://github.com/nodemcu/nodemcu-flasher" hreflang="en" title="NodeMCU Flasher">Downloading NodeMCU Flasher</a> and using it to flash the firmware you received in the previous step<br>
- <a href="http://benlo.com/esp8266/" hreflang="en" title="ESP8266 Lua Loader">Downloading ESP8266 Lua Loader</a> and using it to send your future Lua Scripts<br><br></p>
<h2>What you need to know about NodeMCU<br></h2>
<p>As previously mentioned, the NodeMCU firmware running on your ESP8266 will simply <strong>run Lua scripts stored in the ESP8266 Flash</strong>. The NodeMCU libraries documentation may be found <a href="http://nodemcu.readthedocs.org/en/dev/" hreflang="en" title="NodeMCU libraries">here</a>.<br>
When the platform first boots, it will try to start a file named <strong>init.lua</strong> which in our case will contain the commands to connect to our wifi network and start our main script:</p>
<pre>
--init.lua
wifi.setmode(wifi.STATION)
wifi.sta.config("mywifinetworkname","mywifinetworkpassword")
wifi.sta.connect()
tmr.alarm(1, 1000, 1, function()
if wifi.sta.getip() == nil then
print("IP unavaiable, Waiting...")
else
tmr.stop(1)
print("ESP8266 mode is: " .. wifi.getmode())
print("The module MAC address is: " .. wifi.ap.getmac())
print("Config done, IP is "..wifi.sta.getip())
dofile ("domoticz.lua")
end
end)
</pre>
<p><br></p>
<h2>The Domoticz Platform<br></h2>
<p><a href="https://www.limpkin.fr/public/NodeMCU/domoticz.png" title="domoticz.png"><img src="https://www.limpkin.fr/public/NodeMCU/.domoticz_m.png" alt="domoticz.png" class="media-center" title="domoticz.png, avr. 2016"></a><br>
Getting data isn't particularly useful if it can't correctly be stored and displayed to the user.<br>
Domoticz is a Home Automation System that lets anyone <strong>monitor and configure various devices</strong> like lights, switches, various sensors/meters like temperature, rain, wind, UV and much more. It is open source, can be installed on Linux, Windows and embedded devices.<br>
In my case I had it installed on my <a href="https://inversepath.com/usbarmory" hreflang="en" title="USBArmory">usbarmory</a> and could access it in my browser <strong>in less than 10 minutes</strong>. You'll find Domoticz main user manual <a href="http://www.domoticz.com/DomoticzManual.pdf" hreflang="en" title="Domoticz User Manual">here</a>.<br>
As a side note, I was very impressed to see how many devices Domoticz supports, while not neglecting the security aspects that comes with connecting sensors and lights to your local network.<br><br></p>
<h2>First Small Project: PIR Sensor<br></h2>
<p>In the Domoticz interface, simply add a virtual device of "light/switch" type and use this domoticz.lua script:</p>
<pre>
--domoticz.lua
pin = PIRSENSOR_PIN
last_state = 1
gpio.mode(pin, gpio.INPUT)
tmr.alarm(0,100, 1, function()
if gpio.read(pin) ~= last_state then
last_state = gpio.read(pin)
conn = net.createConnection(net.TCP, 0)
conn:connect(8080,"YOURSERVERIP")
conn:on("receive", function(conn, payload) end)
conn:on("connection", function(conn, payload)
if last_state == 1 then
conn:send("GET /json.htm?type=command&param=switchlight&idx=YOURSENSORIDX&switchcmd=Set%20Level&level=10"
.." HTTP/1.1\r\n"
.."Host: 127.0.0.1:8080\r\n"
.."Connection: close\r\n"
.."Accept: */*\r\n"
.."User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n"
.."\r\n")
print("ON")
else
conn:send("GET /json.htm?type=command&param=switchlight&idx=YOURSENSORIDX&switchcmd=Set%20Level&level=0"
.." HTTP/1.1\r\n"
.."Host: 127.0.0.1:8080\r\n"
.."Connection: close\r\n"
.."Accept: */*\r\n"
.."User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n"
.."\r\n")
print("OFF")
end
end)
conn:on("disconnection", function(conn, payload) end)
end
end)
</pre>
<p>I won't explain the electrical wiring part of things as I'm fairly sure you can figure that out ;-) .<br>
You'll however need and find the ESP8266 pin number to nodemcu pin number look up table <a href="https://learn.adafruit.com/adafruit-huzzah-esp8266-breakout/using-nodemcu-lua#hello-world" hreflang="en" title="nodemcu adafruit">here</a>.<br><br></p>
<h2>Second Small Project: DHT22 Temp & Humidity Sensor<br></h2>
<p><a href="https://www.limpkin.fr/public/NodeMCU/dht22.png" title="dht22.png"><img src="https://www.limpkin.fr/public/NodeMCU/.dht22_m.png" alt="dht22.png" class="media-center" title="dht22.png, avr. 2016"></a><br>
The days are getting warmer and you can notice it indoors!<br>
By connecting a DHT22 to your ESP8266 and strategically placing your platform (not like me) you can get the kind of graph above. Here's the Lua script:</p>
<pre>
--domoticz.lua
pin = 5
temp_to_send = 0
hum_to_send = 0
aggregate_hum = 0
aggregate_temp = 0
aggregate_counter = 0
status, temp, humi, temp_dec, humi_dec = dht.read(pin)
if status == dht.OK then
tmr.alarm(0,500, 1, function()
status, temp, humi, temp_dec, humi_dec = dht.read(5)
if status == dht.OK then
aggregate_counter = aggregate_counter + 1
aggregate_hum = aggregate_hum + ((math.floor(humi)*1000) + humi_dec)
aggregate_temp = aggregate_temp + ((math.floor(temp)*1000) + temp_dec)
if aggregate_counter == 20 then
temp_to_send = aggregate_temp/20
hum_to_send = aggregate_hum/20
aggregate_hum = 0
aggregate_temp = 0
aggregate_counter = 0
conn=net.createConnection(net.TCP, 0)
conn:connect(8080,"YOURSERVERIP")
conn:on("receive", function(conn, payload) end)
conn:on("connection", function(conn, payload)
conn:send("GET /json.htm?type=command&param=udevice&idx=YOURSENSORIDX&nvalue=0&svalue=" .. string.format("%d.%d;%d.%d;0", temp_to_send/1000, temp_to_send%1000, hum_to_send/1000, hum_to_send%1000)
.." HTTP/1.1\r\n"
.."Host: 127.0.0.1:8080\r\n"
.."Connection: close\r\n"
.."Accept: */*\r\n"
.."User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n"
.."\r\n")
--print("http://YOURSERVERIP:8080/json.htm?type=command&param=udevice&idx=YOURSENSORIDX&nvalue=0&svalue=" .. string.format("%d.%03d;%d.%03d;0", math.floor(temp), temp_dec, math.floor(humi), humi_dec))
print(string.format("DHT Temperature:%d.%d Humidity:%d.%d\r\n", temp_to_send/1000, temp_to_send%1000, hum_to_send/1000, hum_to_send%1000))
end)
conn:on("disconnection", function(conn, payload) end)
end
end
end)
elseif status == dht.ERROR_CHECKSUM then
print( "DHT Checksum error." )
elseif status == dht.ERROR_TIMEOUT then
print( "DHT timed out." )
end
</pre>
<p>A few things to note here:<br>
- some averaging was required to get consistent readings with the DHT22<br>
- this particular LUA script uses an <strong>integer</strong> NodeMCU build<br><br></p>
<h2>Third Small Project: Sleep Cycle Monitor<br></h2>
<p><a href="https://www.limpkin.fr/public/NodeMCU/REM_Cycles.png" title="REM_Cycles.png"><img src="https://www.limpkin.fr/public/NodeMCU/.REM_Cycles_m.png" alt="REM_Cycles.png" class="media-center" title="REM_Cycles.png, avr. 2016"></a><br>
Unfortunately Domoticz doesn't have a vibration sensor type, but can you still notice the <strong>REM cycles</strong>?<br>
This graph can simply be generated by connecting an <a href="http://www.ebay.com/itm/NEW-MPU-6050-Module-3-Axis-Gyroscope-Accelerometer-Module-for-Arduino-MPU-6050-/170881535422" hreflang="en" title="mpu6050">MPU6050 3 axis gyroscope + accelerometer</a> to the ESP8266 and using that (big) script:</p>
<pre>
--domoticz.lua
sda, scl = 5, 7
avg_x = 0
avg_y = 0
avg_z = 0
report_data = 0
aggregate_counter = 0
bigger_aggregate_counter = 0
aggregate_ax_val = 0
aggregate_ay_val = 0
aggregate_az_val = 0
bigger_aggregate_ax_val = 0
bigger_aggregate_ay_val = 0
bigger_aggregate_az_val = 0
aggregate_abs_ax_val = 0
aggregate_abs_ay_val = 0
aggregate_abs_az_val = 0
function write_reg_MPU(reg,val)
i2c.start(0)
i2c.address(0, 0x68, i2c.TRANSMITTER)
i2c.write(0, reg)
i2c.write(0, val)
i2c.stop(0)
end
function read_reg_MPU(reg)
i2c.start(0)
i2c.address(0, 0x68, i2c.TRANSMITTER)
i2c.write(0, reg)
i2c.stop(0)
i2c.start(0)
i2c.address(0, 0x68, i2c.RECEIVER)
c=i2c.read(0, 1)
i2c.stop(0)
--print(string.byte(c, 1))
return c
end
function new_data_interrupt()
-- clear interrupt
read_reg_MPU(58)
-- read acceleration data
i2c.start(0)
i2c.address(0, 0x68, i2c.TRANSMITTER)
i2c.write(0, 59)
i2c.stop(0)
i2c.start(0)
i2c.address(0, 0x68, i2c.RECEIVER)
c=i2c.read(0, 8)
i2c.stop(0)
Ax=bit.lshift(string.byte(c, 1), 8) + string.byte(c, 2)
Ay=bit.lshift(string.byte(c, 3), 8) + string.byte(c, 4)
Az=bit.lshift(string.byte(c, 5), 8) + string.byte(c, 6)
temperature=bit.lshift(string.byte(c, 7), 8) + string.byte(c, 8)
if (Ax > 0x7FFF) then
Ax = Ax - 0x10000;
end
if (Ay > 0x7FFF) then
Ay = Ay - 0x10000;
end
if (Az > 0x7FFF) then
Az = Az - 0x10000;
end
if (temperature > 0x7FFF) then
temperature = temperature - 0x10000;
end
temperature = (temperature*100 / 340) + 3653 -- /100
-- data aggregation
aggregate_ax_val = aggregate_ax_val + Ax
aggregate_ay_val = aggregate_ay_val + Ay
aggregate_az_val = aggregate_az_val + Az
aggregate_counter = aggregate_counter + 1
if (Az - avg_z) < 0 then
aggregate_abs_az_val = aggregate_abs_az_val - Az + avg_z
else
aggregate_abs_az_val = aggregate_abs_az_val + Az - avg_z
end
if (Ay - avg_y) < 0 then
aggregate_abs_ay_val = aggregate_abs_ay_val - Ay + avg_y
else
aggregate_abs_ay_val = aggregate_abs_ay_val + Ay - avg_y
end
if (Ax - avg_x) < 0 then
aggregate_abs_ax_val = aggregate_abs_ax_val - Ax + avg_x
else
aggregate_abs_ax_val = aggregate_abs_ax_val + Ax - avg_x
end
end
function second_timer()
if aggregate_counter > 20 then
report_data = (aggregate_abs_ax_val+aggregate_abs_ay_val+aggregate_abs_az_val)/(aggregate_counter)
bigger_aggregate_az_val = bigger_aggregate_az_val + (aggregate_az_val/aggregate_counter)
bigger_aggregate_ay_val = bigger_aggregate_ay_val + (aggregate_ay_val/aggregate_counter)
bigger_aggregate_ax_val = bigger_aggregate_ax_val + (aggregate_ax_val/aggregate_counter)
bigger_aggregate_counter = bigger_aggregate_counter + 1
if avg_z ~= 0 then
conn=net.createConnection(net.TCP, 0)
conn:connect(8080,"YOURSERVERIP")
conn:on("receive", function(conn, payload) end)
conn:on("connection", function(conn, payload)
conn:send("GET /json.htm?type=command&param=udevice&idx=YOURSENSORIDX&nvalue=0&svalue=" .. string.format("%d",report_data)
.." HTTP/1.1\r\n"
.."Host: 127.0.0.1:8080\r\n"
.."Connection: close\r\n"
.."Accept: */*\r\n"
.."User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n"
.."\r\n") end)
print(string.format("%d",report_data))
end
if bigger_aggregate_counter == 4 then
avg_z = bigger_aggregate_az_val/4
avg_y = bigger_aggregate_ay_val/4
avg_x = bigger_aggregate_ax_val/4
bigger_aggregate_ax_val = 0
bigger_aggregate_ay_val = 0
bigger_aggregate_az_val = 0
bigger_aggregate_counter = 0
end
aggregate_ax_val = 0
aggregate_ay_val = 0
aggregate_az_val = 0
aggregate_abs_ax_val = 0
aggregate_abs_ay_val = 0
aggregate_abs_az_val = 0
aggregate_counter = 0
end
print("d")
end
---test program
i2c.setup(0, sda, scl, i2c.SLOW) -- init i2c
i2c.start(0) -- start i2c
c = i2c.address(0, 0x68, i2c.TRANSMITTER) -- see if something answers
i2c.stop(0) -- stop i2c
if c == true then
print("Device found at address : "..string.format("0x%X",0x68))
else
print("Device not found !!")
end
c = read_reg_MPU(117) -- Register 117 – Who Am I - 0x75
if string.byte(c, 1) == 104 then
print("MPU6050 Device answered OK!")
else
print("Check Device - MPU6050 NOT available!")
end
read_reg_MPU(107) -- Register 107 – Power Management 1-0x6b
if string.byte(c, 1)==64 then
print("MPU6050 in SLEEP Mode !")
else
print("MPU6050 in ACTIVE Mode !")
end
write_reg_MPU(0x6B, 0) -- Initialize MPU, use 8MHz clock
write_reg_MPU(25, 199) -- Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV) >> 40Hz
write_reg_MPU(56, 0x01) -- Enables the Data Ready interrupt, which occurs each time a write operation to all of the sensor registers has been completed.
gpio.mode(8, gpio.INT, gpio.PULLUP) -- set gpio6 as input interrupt
gpio.trig(8, "up", new_data_interrupt) -- new data interupt handler
--read_MPU_raw()
tmr.alarm(0, 10000, 1, second_timer)
--tmr.stop(0)
</pre>
<p>In the configuration shown above the accelerometer outputs data at a 40Hz frequency and triggers an interrupt every time a sample is ready. We then simply aggregate the absolute value of each axis acceleration output (after removing its average value) and send it to Domoticz.<br><br></p>
<h2>Fourth Small Project: Switching on Lights by Tapping on Furniture<br></h2>
<p><img src="https://www.limpkin.fr/public/NodeMCU/.milight_m.jpg" alt="milight.jpg" class="media-center" title="milight.jpg, avr. 2016"><br>
RGBW lamps like the one shown above are starting to be quite popular on websites like eBay, alibaba etc... They use proprietary 2.4GHz signals which <strong><a href="https://hackaday.io/project/5888-reverse-engineering-the-milight-on-air-protocol" hreflang="en" title="mi-light reverse engineering">were recently reverse engineered</a></strong>, allowing anyone to <a href="http://fablab.ruc.dk/controlling-the-mi-light-from-arduino/" hreflang="en" title="RGBW lights with NRF24L01">control them with an NRF24L01</a>.<br>
But if you're lazy like I was, you can also send <strong>UDP packets to the Wifi adapter</strong> that comes with them using a modified version of the script above and these 3 lines to switch on the lights when vibration is detected:</p>
<pre>
conn = net.createConnection(net.UDP, 0)
conn:connect(8899,"WIFIBRIDGEIP")
conn:send(string.char(0x47,0x00))
conn:close()
</pre>
<p>Just in case, I added a MAC filter on my router for that Wifi adapter. And if I'm not mistaken, the adapter doesn't receive signals on the proprietary 2.4GHz. You may find different UDP packets examples <a href="https://www.domoticz.com/forum/viewtopic.php?t=6411" hreflang="en" title="Wifi Bridge packets">here</a>.<br><br></p>
<h2>Doing More with NodeMCU and Domoticz<br></h2>
<p>As you can guess I've shown here basic examples of the capabilities of the NodeMCU + Domoticz combo. Domoticz allows much more complex actions using scripts which can be triggered by the output of your installed sensors.<br>
In my case I'm only using the monitoring capabilities of Domoticz, even though its main purpose it to automatize your complete home!</p>High Voltage Power Supply for Nixie Tubesurn:md5:db96fe5865cb8b200d70c2db529abdad2016-04-02T18:01:00+01:002024-03-09T10:36:43+00:00limpkinMy Projectshigh voltagenixietransformer<p>It's always fun playing with dangerous voltages !<br></p>
<p><img src="https://www.limpkin.fr/public/nixie/.final_result_box_m.jpg" alt="final_result_box.JPG" class="media-center" title="final_result_box.JPG, avr. 2016"></p> <h2>The Idea<br></h2>
<p><img src="https://www.limpkin.fr/public/nixie/.in9_tube_m.jpg" alt="in9_tube.JPG" class="media-center" title="in9_tube.JPG, fév. 2016"><br>
For quite a while I've had this project idea in the back of my head that would involve using <strong>many</strong> <a href="https://en.wikipedia.org/wiki/Nixie_tube" hreflang="en" title="Nixie tube wikipedia article">Nixie tubes</a>.<br>
These funny looking cold cathode displays were actually introduced during the 1950s and unfortunately need quite a high voltage to work (from 100V to 180V depending on the type). This meant that I had to find an easy, cheap and (if possible) not dangerous solution to power them.<br><br></p>
<h2>IN-9 Tubes<br></h2>
<p><img src="https://www.limpkin.fr/public/nixie/.in9_cur_length_m.png" alt="in9_cur_length.png" class="media-center" title="in9_cur_length.png, fév. 2016"><br>
IN-9 tubes can easily be purchased on eBay and other similar websites. These tubes are <strong>current driven</strong>, which means that the length of the glowing bar will be proportional to the current fed to the display.<br>
And as you can see from the graph above, the linearity is quite good between 0 and 8mA but not so much after that. Once the cathode is saturated at 103mm, feeding more current will increase the overall brightness... but the maximum recommended current is around 12mA!<br>
This is a typical IN-9 voltage versus current graph:<br><br>
<img src="https://www.limpkin.fr/public/nixie/.in9_volt_cur_m.png" alt="in9_volt_cur.png" class="media-center" title="in9_volt_cur.png, fév. 2016"><br>
Using more than 50 of these tubes would therefore mean making a power supply capable of delivering up to <strong>0.6A at 106V DC</strong>, which is a total of <strong>64 Watts</strong>. As size isn't a problem, I turned to eBay again to find...<br><br></p>
<h2>A Sealed 150W Toroidal Transformer !<br></h2>
<p><img src="https://www.limpkin.fr/public/nixie/.in9_toroid_m.jpg" alt="in9_toroid.jpg" class="media-center" title="in9_toroid.jpg, fév. 2016"><br>
Isn't it pretty?<br>
As this <a href="http://avellindberg.com/transformers/tech_notes/tech_notes2.htm" hreflang="en" title="Benefits of Toroidal Transformer Design">great webpage explains</a> toroidal transformers have an excellent 90% to 95% efficiency, a good regulation and very low noise, which makes them a perfect solution to my problem.<br>
The one I found has these specifications:<br>
- Output voltage: AC24V-0-AC24V, 0-AC9V, 0-AC9V<br>
- Input voltage: 0-110V-220V<br>
- Size: 106x106x46mm<br>
- Weight: 1.8kg (!)<br>
Living in Europe, I just needed to connect the mains (through a fuse) to the 0/220V wires and I was good to go.<br><br></p>
<h2>Getting More than 110V DC<br></h2>
<p><img src="https://www.limpkin.fr/public/nixie/in9_voltage_doubler.gif" alt="in9_voltage_doubler.gif" class="media-center" title="in9_voltage_doubler.gif, fév. 2016"><br>
So if you've followed until here you might be wondering how we can generate at least 110V DC with a toroidal transformer that has 24V/0V/24V ouputs.<br>
The first step is to use these 2x 24V outputs to get 48V AC, which is approximately <strong>68V peak to peak</strong> as all AC voltage ratings are <a href="https://en.wikipedia.org/wiki/Root_mean_square#Average_electrical_power" hreflang="en" title="RMS">RMS</a>. And with the <strong>full wave voltage doubler</strong> circuit shown above we then get <strong>136V DC</strong>.<br>
It is important to note that one consequence of using such a circuit is voltage ripple, as capacitors have to provide power when the 48V AC isn't at its peak voltage:<br>
<img src="https://www.limpkin.fr/public/nixie/capacitive_rectification.png" alt="capacitive_rectification.png" class="media-center" title="capacitive_rectification.png, fév. 2016"><br>
This ripple (on one capacitor only) can be computed using this formula: Vpp = A / F * C (A = load current, F = AC frequency, C = capacitance).<br><br></p>
<h2>12V for the Main Electronics<br></h2>
<p><img src="https://www.limpkin.fr/public/nixie/.bridge_rectifier_m.jpg" alt="bridge_rectifier.jpg" class="media-center" title="bridge_rectifier.jpg, fév. 2016"><br>
I'm sure you can guess that this future Nixie project will need another voltage than 136V.<br>
I'm therefore using a <strong>bridge rectifier</strong> (or diode bridge) on the AC9V transformer output to get 9*1.414-(rectifier's diodes Vfwd*2) ~= <strong>11VDC</strong>. This voltage will actually depend on how much current is drown, as the rectifier's diodes forward voltage changes with the current going through them.<br>
It's interesting to notice that the voltage ripple on this 11V output will actually be A / <strong>2</strong> * F * C as the bridge rectifier (by definition) provides <a href="https://en.wikipedia.org/wiki/Rectifier#Full-wave_rectification" hreflang="en" title="Full Wave Rectification">full-wave rectification</a>.<br><br></p>
<h2>Inrush Current & Selecting Fuses<br></h2>
<p><img src="https://www.limpkin.fr/public/nixie/Inrush_current.png" alt="Inrush_current.png" class="media-center" title="Inrush_current.png, avr. 2016"><br>
One should tread lightly when dealing with mains voltage. From <a href="http://electrical-engineering-portal.com/overcurrent-protection-transformer-nec-450-3" hreflang="en" title="transformer protection">this webpage</a>:<br>
When voltage is switched on to energize a transformer, the transformer core normally <strong>saturates</strong>. This results in a large inrush current which is greatest during the <strong>first half cycle</strong> (approximately .01 second) and becomes progressively less severe over the next several cycles (approximately 1 second) until the transformer reaches its normal magnetizing current.<br>
To accommodate this inrush current, fuses are often selected which have time-current withstand values of at least <strong>12 times</strong> transformer primary rated current for 0.1 second and <strong>25 times for 0.01 second</strong>. Some small dry-type transformers may have substantially greater inrush currents.<br>
For this 150VA transformer I therefore selected this <strong><a href="http://www.digikey.com/product-detail/en/0217001.HXP/F2392-ND/777108" hreflang="en" title="chosen fuse">1A rated fuse</a></strong>.<br>
However, during my initial tests I managed to blow one fuse and break one of the two SB5100 diodes used in the voltage doubler. I therefore guessed this was due to the massive inrush current going to each of the 3.3mF capacitors.<br>
As the secondaries voltage may start at any state, this could potentially mean that ~70V is applied to a 3.3mF capacitor through a diode. I actually tried finding information that could help me find the maximum inrush current to the capacitors but wasn't successful due to several factors:<br>
- no advanced specification of the toroidal transformer<br>
- the fact that electrolytic capacitors' ESR will change depending on the frequency applied to them (at power-up high frequencies are present!)<br>
- no advanced litterature on how a toroidal transformer behaves when a high capacitive load is applied to the secondaries (does it limit the secondaries current due to its construction?)<br>
Anyway, I'm guessing some heavy maths are required to solve that one, so I just figured I'd just switch to using the massive 80EPF06 diodes, rated at 80A continuous and at <strong>1000A peak</strong>...<br><br></p>
<h2>CNC Milling Time !<br></h2>
<p><img src="https://www.limpkin.fr/public/nixie/.psu_case_raw_m.jpg" alt="psu_case_raw.jpg" class="media-center" title="psu_case_raw.jpg, fév. 2016"><br>
Unfortunately the hole in each corner of the transformer's base plate is not near the edges, which forced me to machine 5 & <strong>15</strong> mm acrylic sheets to make a nice box right under the transformer. As previously mentioned I've selected diodes & a rectifier bridge with very low forward voltages in order to minimize the heat that will have to be dissipated. As the box is closed (for the moment!) I'll be keeping a close eye on its temperature.<br><br></p>
<h2>Gluing and Soldering Everything Together<br></h2>
<p><a href="https://www.limpkin.fr/public/nixie/assembled_box.JPG" title="assembled_box.JPG"><img src="https://www.limpkin.fr/public/nixie/.assembled_box_m.jpg" alt="assembled_box.JPG" class="media-center" title="assembled_box.JPG, avr. 2016"></a><br>
In the end, this is what I managed to fit in this homemade115x115x50mm box:<br>
- 1x 430V surge absorber<br>
- 3x 16V 8.2mF capacitors<br>
- 2x 100V 3.3mF capacitors<br>
- 1x rectifier bridge (for the 12V output)<br>
- 2x 80EPF06 diodes (for the voltage doubler)<br>
- 1x 400VDC 1A fuse for the 140V output<br>
- 1x 125VDC 1A fuse for the 12V output<br>
- 1x mains socket with integrated fuse slot<br>
- 1x high voltage 3 pole high voltage socket<br>
I also attached <strong>small aluminum plates</strong> to the diodes and rectifier bridge so they can help spread the heat to the case. As you can see in the above picture most components are held in place using hot glue.<br><br></p>
<h2>Final Result<br></h2>
<p><a href="https://www.limpkin.fr/public/nixie/final_result_box.JPG" title="final_result_box.JPG"><img src="https://www.limpkin.fr/public/nixie/.final_result_box_m.jpg" alt="final_result_box.JPG" class="media-center" title="final_result_box.JPG, avr. 2016"></a><br>
And here's what the final power transformer looks like!<br>
As the capacitors can take a (very) long while to self-discharge, I'm thinking of adding a small mechanism to discharge them when the transformer is not powered. Anyway, stay tuned for the rest of this project!</p>An Open CVMeterurn:md5:2947de619e049d3e1dc66315500af3e62015-11-23T13:15:00+00:002023-04-14T13:47:14+01:00limpkinMy Projectsatxmegaavrcapacitance meterimpedance<p>Did you know that most ceramic capacitors <strong>lose up to 80% of their capacitance</strong> near their voltage ratings?<br /></p>
<p><img src="https://www.limpkin.fr/public/cvmeter/.1caf75ea73068f55093cef0cf4141b97_original_m.jpg" alt="1caf75ea73068f55093cef0cf4141b97_original.jpg" style="display:table; margin:0 auto;" title="1caf75ea73068f55093cef0cf4141b97_original.jpg, nov. 2015" /><br /></p> <h2>The Idea<br /></h2>
<p><a href="https://www.limpkin.fr/public/cvmeter/10uF_X5R.png" title="10uF_X5R.png"><img src="https://www.limpkin.fr/public/cvmeter/.10uF_X5R_m.png" alt="10uF_X5R.png" style="display:table; margin:0 auto;" title="10uF_X5R.png, nov. 2015" /></a><br />
Not every electronics enthusiast knows that <strong>a ceramic capacitor's capacitance changes with the voltage you apply to it</strong>.<br />
This can be particularly annoying when designing RC filters or DC/DC power supplies... you might therefore think your capacitor's value is 10uF when <strong>it actually is 1.8uF</strong> because of the way you're using it. Moreover, the graph displayed above isn't so easy to find in a capacitor's datasheet... and it sometimes simply isn't there.<br />
That's why I made the <strong>OpenCVMeter</strong>, which aims to provide a Capacitance versus Voltage characterization accurate within 1% of the capacitors for your next project (or already have and are starting to wonder about right now...).<br /><br /></p>
<h2>The Schematics<br /></h2>
<p><a href="https://www.limpkin.fr/public/cvmeter/schem.png" title="schem.png"><img src="https://www.limpkin.fr/public/cvmeter/.schem_m.png" alt="schem.png" style="display:table; margin:0 auto;" title="schem.png, nov. 2015" /></a><br />
<strong>Don't try to read it all at once</strong>. Let's work block by block...<br /></p>
<p><a href="https://www.limpkin.fr/public/cvmeter/usb.png" title="usb.png"><img src="https://www.limpkin.fr/public/cvmeter/.usb_m.png" alt="usb.png" style="display:table; margin:0 auto;" title="usb.png, nov. 2015" /></a><br />
I preferred displaying the CV curve to the user through his/her computer rather than adding a small screen to the device. This obviously meant implementing a USB connection on the OpenCVMeter platform.<br /><br />
There are <strong>three main things</strong> you should notice in the above schematics.<br />
- <strong>ESD protection</strong> is provided using the IP4234CZ6,125 (U9).<br />
- The USB connector's chassis is electrically connected to the OpenCVMeter machined aluminum box and to the platform's ground <strong>through a 1M resistor and a 4.7nF capacitor</strong>. This has the main advantage of making a <strong>pseudo</strong> Farraday cage around the PCB and filtering out the noise on the cable shield connection. Moreover, it coincidentally is what <a href="http://www.atmel.com/Images/doc8388.pdf?doc_id=13448&family_id=607" hreflang="en" title="Atmel AVR1017">Atmel recommends</a>. You may read on all the different types of connections <a href="http://forum.allaboutcircuits.com/threads/usb-device-cable-shield-connection-grounding-it-or-not.58811/" hreflang="en" title="USB connector shield connection">here</a>.<br />
- Lastly, the circuit made by Q4/C38/R30/R32 allows me to limit the <strong>inrush current</strong> after Q4. This is required by the USB specifications and you may read more about this particular topic <a href="http://www.testusb.com/inrush_issue.htm" hreflang="en" title="USB inrush spec">here</a>. In short, <strong>the inrush current shouldn't be above 100mA for too long</strong> when connecting your device. As you can guess, this was the case with the OpenCVMeter, so this circuit will gradually increase the 5V supply and limit the input current.<br />
The inrush current that you can see below is therefore <strong>mostly due to C28</strong>:<br /><br />
<a href="https://www.limpkin.fr/public/cvmeter/inrush.png" title="inrush.png"><img src="https://www.limpkin.fr/public/cvmeter/.inrush_m.png" alt="inrush.png" style="display:table; margin:0 auto;" title="inrush.png, nov. 2015" /></a><br />
Looking closely at this capture you'll notice an <strong>inrush total of 12uC</strong>, which is below the 50uC maximum.<br /><br /></p>
<h2>Bias Generator<br /></h2>
<p><a href="https://www.limpkin.fr/public/cvmeter/biasgen.png" title="biasgen.png"><img src="https://www.limpkin.fr/public/cvmeter/.biasgen_m.png" alt="biasgen.png" style="display:table; margin:0 auto;" title="biasgen.png, nov. 2015" /></a><br />
Obviously the platform needed a controllable voltage generator. Here are the key elements of the above circuit:<br />
- The <strong>Ultra-Low Noise</strong>, <strong>High PSRR</strong>, Low-Dropout Linear Regulator <strong>TPS7A4901</strong> is used to lower a stepup-generated 16V to a desired voltage<br />
- Output voltage control is achieved by varying <strong>VADJ</strong> between 0 and 1.2V, effectively changing the voltage that U5 sees through the FB pin and 'tricking' it to output a lower voltage.<br />
- Generated voltage is measured through the <strong>0.1%</strong> R22 and R23 resistors<br />
- When disabling the voltage generator, C37's charge is dissipated through R37 by enabling Q5.<br />
- When generating voltages under ~4.5V, the <strong>16V is disabled</strong> and <strong>U5 is powered through D1</strong>, leading to less electrical noise in the platform.<br />
I therefore had to design a small algorithm which allowed me to properly set the desired voltage by changing the voltage on VADJ... and it actually ended up being a bit more complex than I thought given the different loads that could be applied to the P3 output terminal.<br /><br /></p>
<h2>Main Oscillator<br /></h2>
<p><a href="https://www.limpkin.fr/public/cvmeter/oscillator.png" title="oscillator.png"><img src="https://www.limpkin.fr/public/cvmeter/.oscillator_m.png" alt="oscillator.png" style="display:table; margin:0 auto;" title="oscillator.png, nov. 2015" /></a><br />
The role of each part in this circuit is:<br />
- D4: ESD protection<br />
- U2/U4/R13-16/R4/R5: RC oscillator<br />
- Q3: limiting the voltage present at U4 to ~5V<br />
- Q1: limiting the voltage present at U2 to ~3.3V<br />
- R29: limiting the current when a voltage is applied to P2 (Q1/Q3 take a few us to limit the voltage)<br />
The complete design was inspired by <a href="http://www.edn.com/design/power-management/4438321/How-to-measure-capacity-versus-bias-voltage-on-MLCCs" hreflang="en" title="edn article">this article</a> but contains major changes as a capacitor Equivalent Series Resistance (ESR) <strong>rendered the proposed circuit useless</strong>. Why? Let's first explain how the OpenCVMeter works.<br />
As mentioned before, the OpenCVMeter is <strong>based around an RC oscillator</strong>. The R in the 'RC' is in our case a 0.1% precise resistor selected through U4 while C is the capacitor we want to measure. In theory, the oscillating frequency should therefore be <strong>directly related to the capacitor's capacitance</strong>:<br /></p>
<p><a href="https://www.limpkin.fr/public/cvmeter/principle.jpg" title="Print"><img src="https://www.limpkin.fr/public/cvmeter/principle.jpg" alt="Print" style="display:table; margin:0 auto;" title="Print, nov. 2015" /></a><br />
However, this is what the voltage at the RC node (on the P2 connector) <strong>really</strong> looks like:<br /></p>
<p><a href="https://www.limpkin.fr/public/cvmeter/reality.png" title="reality.png"><img src="https://www.limpkin.fr/public/cvmeter/.reality_m.png" alt="reality.png" style="display:table; margin:0 auto;" title="reality.png, nov. 2015" /></a><br />
Notice how the voltage 'jumps' ? This is because of the <strong>capacitor ESR</strong>: when charging the capacitor, some voltage will be lost because of it. Hence, the RC oscillator frequency will depend on the capacitor's capacitance <strong>and its ESR</strong>. Not good.<br />
The solution? Measuring the <strong>RC discharge time</strong> between two thresholds:<br /></p>
<p><a href="https://www.limpkin.fr/public/cvmeter/comparator.png" title="comparator.png"><img src="https://www.limpkin.fr/public/cvmeter/.comparator_m.png" alt="comparator.png" style="display:table; margin:0 auto;" title="comparator.png, nov. 2015" /></a><br />
In this circuit U12 will therefore be at a high logic level whenever the RC node voltage <strong>is between AN_THRES1 and AN_THRES2</strong>:<br /></p>
<p><a href="https://www.limpkin.fr/public/cvmeter/comparator_trace.png" title="comparator_trace.png"><img src="https://www.limpkin.fr/public/cvmeter/.comparator_trace_m.png" alt="comparator_trace.png" style="display:table; margin:0 auto;" title="comparator_trace.png, nov. 2015" /></a><br />
How do we know if the RC node voltage is rising or falling? Simply check the COMP_OUT output voltage level!<br />
It is however important to note that the AND gate output may sometimes oscillate around transitions. This will be filtered out later. The two thresholds were set in such a way that even important ESR wouldn't impact the normal OpenCVMeter behavior.<br /><br /></p>
<h2>Current Measurement<br /></h2>
<p><a href="https://www.limpkin.fr/public/cvmeter/current_measurement.png" title="current_measurement.png"><img src="https://www.limpkin.fr/public/cvmeter/.current_measurement_m.png" alt="current_measurement.png" style="display:table; margin:0 auto;" title="current_measurement.png, nov. 2015" /></a><br />
The OpenCVMeter <strong>can also measure leakage currents</strong>, this is the circuit in charge of it.<br />
You might wonder why I didn't simply use a standard operational amplifier instead of a <strong>high-side current sense amplifier</strong>. This was mainly because of the N-Mosfet <strong>leakage currents and Vds voltage</strong> which would offset my measured current outside of my measurement range... I wanted to measure <strong>nA currents</strong> after all.<br /><br /></p>
<h2>The Main Microcontroller<br /></h2>
<p><a href="https://www.limpkin.fr/public/cvmeter/mcu.png" title="mcu.png"><img src="https://www.limpkin.fr/public/cvmeter/.mcu_m.png" alt="mcu.png" style="display:table; margin:0 auto;" title="mcu.png, nov. 2015" /></a><br />
If you're still with me (congratulations!) you may remember that our chosen MCU should therefore have:<br />
- <strong>an ADC</strong>: to measure the generated voltage<br />
- <strong>a DAC</strong>: required to change the output bias voltage<br />
- <strong>a USB transceiver</strong>: to send the measurements to the user's computer<br />
- many IOs pins to drive the different circuits we have<br />
The great <strong>ATXMega16A4U</strong> was therefore chosen for this purpose. Notable features are:<br />
- Internal bootloader for easy reprogramming<br />
- Internal 32MHz oscillator calibrated against an external 32KHz crystal<br />
- 7 event lines, used to <strong>pseudo asynchronously measure the AND gate pulses</strong><br /><br /></p>
<h2>The Complex Bits I Left Out<br /></h2>
<p><a href="https://www.limpkin.fr/public/cvmeter/PCB.JPG" title="PCB.JPG"><img src="https://www.limpkin.fr/public/cvmeter/.PCB_m.jpg" alt="PCB.JPG" style="display:table; margin:0 auto;" title="PCB.JPG, nov. 2015" /></a><br />
You may have noticed that I deliberately <strong>simplified or left out several things above</strong> as they were mainly related to calibration and getting precise measurements:<br />
- very precise voltage references were used for our ADC & DAC<br />
- AN_THRES1 & 2 can be precisely measured by injecting a voltage at OPAMPIN-<br />
- the ATXMega16A4 ADC offset needs to be measured to get reliable measurments<br />
- the ATXMega16A4 input digital filter is used to eliminate the AND gate oscillation glitches<br />
- complete current measurement calibration may be done by placing a known resistor between P2 & P3<br />
- all components around the RC oscillator were deliberately chosen to have a very low input capacitance<br />
- when the OpenCVMeter terminals are shorted, Q3 Vds is equal to Vbias-5. Some power will be dissipated by it<br /><br /></p>
<h2>Interested in an OpenCVMeter?<br /></h2>
<p><a href="https://www.limpkin.fr/public/cvmeter/1caf75ea73068f55093cef0cf4141b97_original.jpg" title="1caf75ea73068f55093cef0cf4141b97_original.jpg"><img src="https://www.limpkin.fr/public/cvmeter/.1caf75ea73068f55093cef0cf4141b97_original_m.jpg" alt="1caf75ea73068f55093cef0cf4141b97_original.jpg" style="display:table; margin:0 auto;" title="1caf75ea73068f55093cef0cf4141b97_original.jpg, nov. 2015" /></a><br />
<a href="https://www.kickstarter.com/projects/limpkin/opencvmeter-rediscover-your-capacitors" hreflang="en" title="OpenCVMeter kickstarter campaign"><strong>I just started a Kickstarter campaign for it.</strong></a><br />
Any support is appreciated, feel free to spread the OpenCVMeter word to your colleagues and friends!<br />
In the meantime you may find most design files in the <a href="https://github.com/limpkin/capmeter" hreflang="en" title="OpenCVMeter repository">official GitHub repository</a> and download the schematics (CERN licensed) here: <a href="https://www.limpkin.fr/public/cvmeter/schematics_v4.pdf" hreflang="en" title="OpenCVMeter repository">schematics_v4.pdf</a>. All hardware files will be released at the end of the kickstarter campaign.<br />
I realized I actually didn't say much about the firmware, it only has 3k4 lines of code after all. It might however be interesting to you if you need a tiny HID stack made from scratch!</p>A Connected Lamp to Wake Me Upurn:md5:1d9511a1b365f4d6ffe31769ed65d00a2015-08-29T12:26:00+01:002024-03-09T11:23:44+00:00limpkinMy ProjectsDC-DCesp8266RGB LEDs<p>I've always wanted to play with these 10W RGB LEDs!<br></p>
<p><img src="https://www.limpkin.fr/public/lamp/.assembly_4_m.jpg" alt="assembly_4.JPG" class="media-center" title="assembly_4.JPG, août 2015"><br></p> <h2>The Idea<br></h2>
<p><a href="https://www.limpkin.fr/public/lamp/lamp.JPG" title="lamp.JPG"><img src="https://www.limpkin.fr/public/lamp/.lamp_m.jpg" alt="lamp.JPG" class="media-center" title="lamp.JPG, août 2015"></a><br>
So for some reason I bought 2 IKEA lamps at a flea market. As IKEA furniture has a long history of being hacker-friendly, I figured they shouldn't be an exception to the rule.<br>
My plan? Fit a few <strong>10W RGB LEDs</strong> in there together with an <strong>ESP8266</strong> to use the final result as an <strong>alarm clock</strong>.<br><br></p>
<h2>The Schematics<br></h2>
<p><a href="https://www.limpkin.fr/public/lamp/schem.png" title="schem.png"><img src="https://www.limpkin.fr/public/lamp/.schem_m.jpg" alt="schem.png" class="media-center" title="schem.png, août 2015"></a><br>
When you are dealing with a LED consuming that much current, you can't simply use a series resistor as the latter would need to <strong>dissipate R*I² in heat</strong>. I'm therefore using a dedicated LED driver that automatically <strong>adjusts the LED voltage</strong> to match a given current. As you can guess, it isn't much different than a standard step-down and just uses a shunt resistor to measure the current flowing through the LED.<br>
The <strong>A6211</strong> has an adjustable switching frequency set using R2/R3/R4 (to 700KHz in our case) and an EN input meant to be connected to a <strong>PWM signal</strong>. Its datasheet is well made so you can easily find all the information needed to select your passive components values. C13/C14/C15 are here to decrease the current ripple.<br>
The complete board is 12V powered through P1. A DC/DC is placed on the board (I was lazy) to provide the 5V needed by my <a href="https://www.tindie.com/products/limpkin/esp8266-wifi-module-breakout/" hreflang="en" title="ESP8266 Dev Board">ESP8266 dev board</a>. The P3 connector therefore serves as an interface beween the latter and our main PCB.<br>
P4 is meant as an expansion connector to which will be connected an <strong>accelerometer</strong>. The goal is to hopefully <strong>measure REM sleep cycles</strong> to gradually increase the light at optimal times.<br>
The great thing in this project is that the <strong>ESP8266 has all the required IOs</strong> for my purpose (PWM outputs, I2C, std IOs).<br><br></p>
<h2>The Realization<br></h2>
<p><a href="https://www.limpkin.fr/public/lamp/lamp_inside.JPG" title="lamp_inside.JPG"><img src="https://www.limpkin.fr/public/lamp/.lamp_inside_m.jpg" alt="lamp_inside.JPG" class="media-center" title="lamp_inside.JPG, août 2015"></a><br>
The inside of the lamp is fairly simple, I just needed to remove the socket to make room for my PCB:<br></p>
<p><a href="https://www.limpkin.fr/public/lamp/PCBA.JPG" title="PCBA.JPG"><img src="https://www.limpkin.fr/public/lamp/.PCBA_m.jpg" alt="PCBA.JPG" class="media-center" title="PCBA.JPG, août 2015"></a><br>
That was a fun PCB to design!<br>
As you can see its outline is made at the right diameter and has slots in which will fit the RGB LEDs. The ESP8266 board will nicely fit in the middle. Keeping in mind that 10W LEDs don't have a 100% efficiency, I machined an <strong>aluminum plate</strong> that will be used for <strong>heat dissipation</strong>:<br></p>
<p><a href="https://www.limpkin.fr/public/lamp/al_ring.JPG" title="al_ring.JPG"><img src="https://www.limpkin.fr/public/lamp/.al_ring_m.jpg" alt="al_ring.JPG" class="media-center" title="al_ring.JPG, août 2015"></a><br>
In this picture you can get an idea of the stackup:<br></p>
<p><a href="https://www.limpkin.fr/public/lamp/assembly.JPG" title="assembly.JPG"><img src="https://www.limpkin.fr/public/lamp/.assembly_m.jpg" alt="assembly.JPG" class="media-center" title="assembly.JPG, août 2015"></a><br>
After applying some heat paste and soldering the LEDs:<br></p>
<p><a href="https://www.limpkin.fr/public/lamp/assembly_2.JPG" title="assembly_2.JPG"><img src="https://www.limpkin.fr/public/lamp/.assembly_2_m.jpg" alt="assembly_2.JPG" class="media-center" title="assembly_2.JPG, août 2015"></a><br>
And this is what it looks like from below:<br></p>
<p><a href="https://www.limpkin.fr/public/lamp/assembly_3.JPG" title="assembly_3.JPG"><img src="https://www.limpkin.fr/public/lamp/.assembly_3_m.jpg" alt="assembly_3.JPG" class="media-center" title="assembly_3.JPG, août 2015"></a><br>
You can notice the M2x6mm brass standoff spacers and the power supply/expansion connector.<br>
Here is the final result:<br></p>
<p><a href="https://www.limpkin.fr/public/lamp/assembly_4.JPG" title="assembly_4.JPG"><img src="https://www.limpkin.fr/public/lamp/.assembly_4_m.jpg" alt="assembly_4.JPG" class="media-center" title="assembly_4.JPG, août 2015"></a><br>
Obviously the USB port won't be used ;-) .<br><br></p>
<h2>All Done!<br></h2>
<p><a href="https://www.limpkin.fr/public/lamp/lamp_on.JPG" title="lamp_on.JPG"><img src="https://www.limpkin.fr/public/lamp/.lamp_on_m.jpg" alt="lamp_on.JPG" class="media-center" title="lamp_on.JPG, août 2015"></a><br>
The hardware is tested (I've been blinded a few times!) and the software is still <strong>a work in progress</strong> but the core functionalities are there.<br><br>
<a href="https://www.limpkin.fr/public/lamp/alarm_control_panel.png" title="alarm_control_panel.png"><img src="https://www.limpkin.fr/public/lamp/.alarm_control_panel_m.png" alt="alarm_control_panel.png" class="media-center" title="alarm_control_panel.png, déc. 2015"></a><br>
You may find all my files in <a href="https://github.com/limpkin/espalarm" hreflang="en" title="espalarm repository">this repository</a> (HW part is CERN licensed). As you will see, all of the code is based on esphttpd with esp-open-sdk.<br>
Cheers!</p>A Timeless Fountainurn:md5:93b5cbcf45d6573c8045b396e9df37452015-06-22T15:08:00+01:002024-03-09T10:59:38+00:00limpkinMy Projectsavrfountainlaserwaterxmega<p>This is one of these "just because" projects...<br></p>
<p><img src="https://www.limpkin.fr/public/fountain/.fountain_night_m.jpg" alt="Timeless Fountain" class="media-center" title="Timeless Fountain, juin 2015"><br></p> <h2>The Idea<br></h2>
<p><a href="https://www.limpkin.fr/public/fountain/Bouncing_ball_strobe_edit.jpg" title="bouncing ball"><img src="https://www.limpkin.fr/public/fountain/.Bouncing_ball_strobe_edit_m.jpg" alt="bouncing ball" class="media-center" title="bouncing ball, juin 2015"></a><br>
I'm sure that most of you are familiar with the <strong>stroboscopic effect</strong>. To paraphrase <a href="http://www.wisegeek.com/what-is-the-stroboscopic-effect.htm" hreflang="en" title="stroboscopic effect">wisegeek</a>, it is a phenomenon of human visual perception in which motion is shown to be interpreted by a brain that receives successive discreet images and stitches them together with automatic aliases for temporal continuity. In short, <strong>motion is an artifact</strong>.<br>
A conventional strobe fountain is a stream of water droplets falling at <strong>regular intervals</strong> lit with a <strong>strobe light</strong>. When viewed under normal light, it is a normal water fountain. When viewed under a strobe light with its <strong>frequency tuned to the rate at which the droplets fall</strong>, the droplets appear to be suspended in mid-air. Adjusting the strobe frequency can make the droplets seemingly move slowly up or down.<br>
However making water droplets fall at regular intervals isn't as easy as it sounds as many physical effects will get in the way of doing so (the main one being <a href="https://en.wikipedia.org/?title=Surface_tension" hreflang="en" title="surface tension">surface tension</a>). For this project to work I'm instead <strong>detecting droplets</strong> with a laser and <strong>flashing a light accordingly</strong>.<br><br></p>
<h2>Detection and Flashing<br></h2>
<p><a href="https://www.limpkin.fr/public/fountain/fountain_front.JPG" title="Fountain Front"><img src="https://www.limpkin.fr/public/fountain/.fountain_front_m.jpg" alt="Fountain Front" class="media-center" title="Fountain Front, juin 2015"></a><br>
The liquid you see in the above picture is simply water with <a href="https://en.wikipedia.org/wiki/Fluorescein" hreflang="en" title="fluorescein">fluorescein</a>, which reacts awesomely under UV light. The two bars on each side of the droplet's fall course therefore include <strong>10 UV LEDs</strong> each, as lots of 'light' is required for very small amounts of time.<br></p>
<p><a href="https://www.limpkin.fr/public/fountain/laser.png" title="laser"><img src="https://www.limpkin.fr/public/fountain/.laser_m.jpg" alt="laser" class="media-center" title="laser, juin 2015"></a><br>
As previously mentioned our left bar includes a small 850nm laser at its top. This particular wavelength <strong>isn't visible by the naked eye</strong>. The laser is therefore powered at its <strong>lowest rating</strong> to avoid any damage if one were to manage putting his/her eye in front of it (even though that is nearly impossible).<br></p>
<p><a href="https://www.limpkin.fr/public/fountain/diode.png" title="diode"><img src="https://www.limpkin.fr/public/fountain/.diode_m.jpg" alt="diode" class="media-center" title="diode, juin 2015"></a><br>
On the other side a <strong>photodiode</strong> detects the laser beam. As you can guess, <strong>good alignment was key</strong> for this build!<br>
The laser beam is very narrow so no signal amplification was required. When a droplet passes in front of the beam the typical voltage variation with a 2k resistor is around <strong>750mV</strong>.... which is very simple to detect.<br><br></p>
<h2>The Pieces<br></h2>
<p><a href="https://www.limpkin.fr/public/fountain/cnc_machining.JPG" title="CNC machining"><img src="https://www.limpkin.fr/public/fountain/.cnc_machining_m.jpg" alt="CNC machining" class="media-center" title="CNC machining, juin 2015"></a><br>
The complete fountain was made with only <strong>four A4 8mm polycarbonate sheets</strong>. Total cost for the 4 sheets was around <strong>$35</strong> on Ebay. I used my <a href="https://www.limpkin.fr/index.php?post/2013/09/29/Entering-the-CNC-world-with-a-probotix-fireball">small CNC machine</a> to mill all the individual pieces. As you can guess... this took quite a while! Precisely drilling the assembly holes on the pieces' edges (to guarantee good final assembly) was the most critical part.<br></p>
<p><a href="https://www.limpkin.fr/public/fountain/led_bar.JPG" title="LED Bar"><img src="https://www.limpkin.fr/public/fountain/.led_bar_m.jpg" alt="LED Bar" class="media-center" title="LED Bar, juin 2015"></a><br>
The two bars are simply two rounded 50x224mm sheets assembled together with M3 screws. They were designed in such a way that the M3 nuts & M3 screws heads are directly integrated <strong>inside the sheet</strong>. A deep groove was machined to allow me to solder all the LEDs together. A standard 0.1" connector was glued at the bars' ends.<br></p>
<p><a href="https://www.limpkin.fr/public/fountain/faucet_pump.png" title="Faucet & Pump"><img src="https://www.limpkin.fr/public/fountain/.faucet_pump_m.jpg" alt="Faucet & Pump" class="media-center" title="Faucet & Pump, juin 2015"></a><br>
The faucet was also purchased on Ebay ($30) while the submersible pump was purchased on dealextreme ($5). It took me a surprisingly big amount of time to find a <strong>tall enough faucet</strong> that could be easily fixed to the main plastic sheet (yes, faucet datasheets are a thing!). A $3 flexible plastic tube (ID 8mm/ OD 10mm) is attached to the pump output and passed inside the faucet to the nozzle.<br></p>
<p><a href="https://www.limpkin.fr/public/fountain/nozzle_laser.JPG" title="Nozzle and Laser Barrier"><img src="https://www.limpkin.fr/public/fountain/.nozzle_laser_m.jpg" alt="Nozzle and Laser Barrier" class="media-center" title="Nozzle and Laser Barrier, juin 2015"></a><br>
The nozzle turned out to be the <strong>hardest piece to design</strong> as it took me around 15 tries to get it right! A good rule of thumb seems to be a very small output hole (0.5mm in my case) to guarantee good water pressure and a sharp nozzle angle (70degrees).<br></p>
<p><a href="https://www.limpkin.fr/public/fountain/magnets.JPG" title="Magnets"><img src="https://www.limpkin.fr/public/fountain/.magnets_m.jpg" alt="Magnets" class="media-center" title="Magnets, juin 2015"></a><br>
The main reservoir is assembled using screws and acrylic glue was used to provide good sealing. The top plastic sheet <strong>isn't attached to the rest of the assembly</strong>. I instead used small magnets embedded inside the reservoir edges and the top plastic sheet so <strong>cleaning could easily be done</strong>.<br><br></p>
<h2>The Electronic Side of Things<br></h2>
<p><a href="https://www.limpkin.fr/public/fountain/atxmega.png" title="internals"><img src="https://www.limpkin.fr/public/fountain/.atxmega_m.jpg" alt="internals" class="media-center" title="internals, juin 2015"></a><br>
The small PCB I made for this project is based around the <strong>ATxmega16A4</strong>. In the above diagram you can see how the drop detection and LED flashing are implemented.<br>
The Analog to Digital Converter (<strong>ADC</strong>) is used at the platform start to measure the droplet detection and non-detection photodiode output levels. Using these values and the internal Digital to Analog Converter (<strong>DAC</strong>) a detection threshold is set on the ATxmega internal comparator. The comparator output will therefore be set to logical 0 <strong>every time a droplet is detected</strong>.<br>
This output is programmed as both an <strong>internal event and an interrupt</strong>. The interrupt is used by the microcontroller to count the number of droplets per second while the event is used <strong>by our internal counter as a reset signal</strong>. In our latter we just set a compare value of X for channel 0 and a compare value of (X + Y) for channel 1, use an external XOR gate and as a result <strong>our UV LEDs will flash after a delay X after droplet detection for a duration of Y</strong>.<br>
You'll therefore notice that droplet detection and UV LEDs flashing are (more or less) done <strong>completely asynchronously</strong> as we just 'wired' the different internal peripherals together so they can provide our desired functionality.<br></p>
<p><a href="https://www.limpkin.fr/public/fountain/ldo.png" title="LDO"><img src="https://www.limpkin.fr/public/fountain/.ldo_m.jpg" alt="LDO" class="media-center" title="LDO, juin 2015"></a><br>
Finally, I just needed to adjust the <strong>pump outflow</strong> (therefore its supply voltage) depending on the photodiode output to provide a constant number of droplets per second. This is done using an LDO whose feedback resistor divider is adjusted depending on the required output voltage. I had to write a <strong>simple control loop feedback mechanism</strong> inside the ATxmega's firmware.<br><br></p>
<h2>Final Result<br></h2>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/D54QVBCBhno" frameborder="0" allowfullscreen></iframe>
</div>
<p>And voila! This fountain actually was a side project I did over the last few months. You'll also notice that I skipped over the non-interesting (yet tricky) details: internal wiring, power supply... You'll find the kicad files made for this project <a href="https://www.limpkin.fr/public/fountain/kicad.rar">here</a>.<br>
I'll finally add that the original idea <a href="http://cre.ations.net/creation/the-time-fountain" hreflang="en" title="original project">wasn't mine</a> and that I actually made a v1 of this concept nearly 10 years ago!<br>
Click on the below picture for high-resolutiion:<br></p>
<p><a href="https://www.limpkin.fr/public/fountain/fountain_night.JPG" title="Timeless Fountain"><img src="https://www.limpkin.fr/public/fountain/.fountain_night_m.jpg" alt="Timeless Fountain" class="media-center" title="Timeless Fountain, juin 2015"></a><br></p>
<p>Cheers!</p>A Personal Perspective on Managing an Open HW Project - Part 2urn:md5:10bc320fe3b43e576d4e12313447e9102015-04-13T01:09:00+01:002023-04-14T13:47:04+01:00limpkinMy Projectsavrmooltipassopen hardwareopen source<p>$120k and a year after my previous article, you might be interested to know what happened behind the scenes...<br /></p>
<p><img src="https://www.limpkin.fr/public/mooltipass/.holder_with_mooltipass_m.jpg" alt="Mooltipass with holder" style="display:table; margin:0 auto;" title="Mooltipass with holder, mar. 2015" /><br /></p> <h2>Let's pick things up where we left off<br /></h2>
<p>I can't believe the Mooltipass project is already more than 15 months old... it has been (and still is) an incredible ride. In my <a href="https://www.limpkin.fr/index.php?post/2014/04/10/A-Personal-Perspective-on-Managing-an-Open-Hardware-Project">previous article</a> the project had only started 4 months earlier.<br />
I'm happy to say that during the months following that post everything went pretty smoothly. We however had a few contributors <strong>disappearing from the grid</strong> (without any warning) or simply making extremely little progress. This forced me to take over their work, I ended up taking care of the complete USB stack and rewrote few pieces of the Mooltipass code.<br />
As contributors were <strong>not remunerated</strong> (only hand soldered devices were sent to them) these events were to be expected, especially for a project lasting this long. To be completely honest I had considered and accepted the possibility that I might end up doing most of the work when I started this adventure.<br /><br /></p>
<h2>Hackaday and Crowdfunding Campaign Preparations<br /></h2>
<p><a href="https://www.limpkin.fr/public/mooltipass/code_lines.png" title="mooltipass code lines"><img src="https://www.limpkin.fr/public/mooltipass/.code_lines_m.jpg" alt="mooltipass code lines" style="display:table; margin:0 auto;" title="mooltipass code lines, mar. 2015" /></a><br />
Obviously our code related progress updates didn't attract a lot of attention. We were one of the only projects that hit a crowdfunding platform with <strong>most of the code already written and tested</strong>. I'm guessing we were the <strong>only project</strong> with all its code already published for everyone to see. We had (and still have) wonderful beta testers who gave us invaluable feedback and suggested features we never would have thought of.<br />
To keep the interest going, we asked our project followers to subscribe to our <strong>official mailing list</strong> to be informed of the launch date. This way they could get <strong>preferential pricing</strong> by backing the campaign early. As you can see, this was an excellent strategy:<br /></p>
<p><a href="https://www.limpkin.fr/public/mooltipass/funding.png" title="Funding progression"><img src="https://www.limpkin.fr/public/mooltipass/.funding_m.jpg" alt="Funding progression" style="display:table; margin:0 auto;" title="Funding progression, mar. 2015" /></a><br />
It was mentioned somewhere that successful campaigns raise at least <strong>30% of their funding goal in less than a week</strong>. We hit 50% in a week, yet we had a <strong>10 days campaign extension</strong> for the mere 3% we were missing.<br />
Designing the campaign took around <strong>two months</strong>. This is not something that should be quickly done. Ideally a project <strong>should already have a community</strong> before hitting Kickstarter / Indiegogo, so it can benefit from its feedback and make sure that the message you want to send is perfectly understood. When you've been working full time on something, you sometimes lose track on how to <strong>clearly explain</strong> what you're making and how to adapt your message to all audiences. This can be a show stopper when what you're trying to sell is a <strong>technical product</strong>. Writing the video's script took many days and a lot of back and forth with selected reviewers.<br /><br /></p>
<h2>The Crowdfunding Campaign<br /></h2>
<p>In short: an emotional roller coaster.<br />
I was pleasantly surprised to see that very few people asked questions that were already present in the FAQs. Of course there were a few internet trolls and other guys saying "I'm keeping my passwords on a piece of paper so that's safe". Managing the campaign took <strong>a lot of time</strong>. You will need to contact websites, target their writers, make press releases, get your backers to promote your campaign, run a referral contest...<br />
<a href="https://www.limpkin.fr/public/mooltipass/referrals.png" title="Campaign Referrals"><img src="https://www.limpkin.fr/public/mooltipass/referrals.png" alt="Campaign Referrals" style="display:table; margin:0 auto;" title="Campaign Referrals, mar. 2015" /></a><br />
As you can see we could have benefited from someone from the <strong>marketing world</strong>. The Mooltipass project is made and run by technical guys who only used the <strong>wisdom of the crowd</strong> to find ways to promote their idea. Anyway... we hit our goal!<br /><br /></p>
<h2>The People Who Stuck Around<br /></h2>
<p>I want to emphasize the fact that the developers <strong>who stick around since the beginning are truly exceptional people</strong>, who programmed for <strong>the love of open source</strong>. Nobody (including me) received any money, except the programmer we hired to work on the Chrome App and Extension that none of us (and the Hackaday followers) could do. Unfortunately we are currently waiting for this programmer to finish his tasks for the production to start, as only him can make sure that several firmware functions <strong>are correctly implemented and beta-tester proof</strong>.<br />
Unfortunately (bis) it seemed he wasn't fully aware of what he was getting into even though we provided him with an <strong>extensive, well detailed</strong> todo list and told him we were here to answer all the questions he could have before making us a final quote. This resulted in inevitable delays...<br />
Interestingly enough we also lost a few beta testers who got taken in other things... as with our contributors, this was inevitable. I however noticed that these particular beta testers <strong>purchased devices during our campaign</strong>.<br /><br /></p>
<h2>The Extra Mile<br /></h2>
<p>People often don't realize <strong>how many things should be taken care of</strong> once the campaign ends.<br />
In our case, among others, we had to design our electrical and functional tests, finalize the production and assembly processes, handle the many emails we received to add perks to the original orders, check the shipping addresses, handle special cases in which backers were not sure what they had chosen... <strong>This also took a lot of time</strong>.<br />
We are trying to provide our backers with <strong>weekly updates</strong> while making sure that all the pieces fit together. There are so many components with very <strong>different lead times</strong> we had to order... you end up always making sure you haven't forgotten anything.<br />
However, with the mass production about to start, it seems that everything is set to succeed!</p>Trying to Make a Tiny NFC Reader with a TRF7970Aurn:md5:9d254e92633f3336f24ac58af2f5c91f2015-01-11T15:44:00+00:002023-04-14T13:47:00+01:00limpkinMy Projectsnfctrf7970a<p>Want a free board? Read below!<br /></p>
<p><img src="https://www.limpkin.fr/public/NFC/.nfc_board_m.jpg" alt="NFC board" style="display:table; margin:0 auto;" title="NFC board, janv. 2015" /><br /></p> <p>My regular readers may already know that I never stop working on a project half-way. This is unfortunately the only exception so far, motivated by the fact that an IC isn't doing what it's supposed to do, that my thread on the TI support forum was left unanswered for months and that I'd like to upgrade some of the chosen hardware.<br />
So a few months ago I wrote a <a href="https://www.limpkin.fr/index.php?post/2014/10/07/Using-a-Standard-Coil-for-NFC-Tag-Implant-Reading">quick post</a> about using a standard coil for NFC tag implant reading. The PCB you saw in the article is the one I'll be writing about.<br /><br /></p>
<h2>The Schematics<br /></h2>
<p><a href="https://www.limpkin.fr/public/NFC/nfc_schems.png" title="NFC schematics"><img src="https://www.limpkin.fr/public/NFC/.nfc_schems_m.jpg" alt="NFC schematics" style="display:table; margin:0 auto;" title="NFC schematics, déc. 2014" /></a><br />
The main components are:<br />
- the USB-enabled ATMega32U4<br />
- a connector for the NRF24L01<br />
- a Lithium-Ion battery charger<br />
- an NFC transceiver<br />
- a proximity sensor<br />
The main idea of this platform is to read NFC tags while <strong>keeping its power consumption low</strong>. The microcontroller is communicating with the NFC transceiver so you can use the platform as a <strong>standalone device or computer peripheral</strong>.<br />
You could therefore control a switch (using the expansion header), send the tag data via RF (using a NRF24L01 you'd connect) or simply have the ATMega32U4 forward the read/write commands sent from your computer. The original idea was to <strong>support libnfc</strong>.<br /><br /></p>
<h2>The Li-Ion battery charger<br /></h2>
<p><a href="https://www.limpkin.fr/public/NFC/bq24232h.png" title="bq24232"><img src="https://www.limpkin.fr/public/NFC/.bq24232h_m.jpg" alt="bq24232" style="display:table; margin:0 auto;" title="bq24232, déc. 2014" /></a><br />
The <strong>bq24232h</strong> is a neat little chip that is very convenient when having a USB powered platform. It'll of course charge your battery but will also behave like a standard LDO when none is connected. As Li-on battery charges can be very complex it has several inputs used to set the optimal charging parameters (charging/termination current, pre-charge/fast-charge safety timers, maximum current on the 5V USB input...). If you look at <a href="http://www.ti.com/product/bq24232" hreflang="en" title="bq24232h">its datasheet</a> you'll see on page 17/18 how a proper li-ion charge should be done. The chip can also monitor the battery temperature and even has short-circuit protection.<br /><br /></p>
<h2>The Microcontroller<br /></h2>
<p>A USB interface was required to operate the platform as a computer peripheral.<br />
The chosen ATMega32U4 has several low power modes, an integrated bootloader and has all of its IO pins used in our platform. As the voltage will vary anywhere between <3V and 4.6V we are running it at <strong>8MHz</strong>. Its 3.3V regulator is used to power an external NRF24L01. Given that the latter accepts 5V signals and that the ATMega32U4 also sees 3.3V signals, <strong>no voltage translation is required</strong>.<br />
Unfortunately the bq24232 doesn't have any battery <strong>under-voltage lockout</strong> so the li-ion battery voltage could theoratically go as low as 2.7V (minimum voltage for the ATMega32u4 and NFC transceiver).<br /><br /></p>
<h2>The proximity sensor<br /></h2>
<p><a href="https://www.limpkin.fr/public/NFC/pcf.png" title="pcf8883 principle"><img src="https://www.limpkin.fr/public/NFC/.pcf_m.jpg" alt="pcf8883 principle" style="display:table; margin:0 auto;" title="pcf8883 principle, janv. 2015" /></a><br />
The <strong>PCF8883</strong> is a capacitive touch/proximity switch with auto-calibration and very low power consumption (3uA). The goal of this chip in our platform (when operating as a standalone device) is to <strong>wake-up the microcontroller</strong> when the NFC tag/implant is close. Our device will therefore always be in power-down and will only consume power when <strong>it is actually needed</strong>. Given its voltage range is 3V->9V our platform will never wake-up once the li-ion battery goes under <strong>3V</strong>.<br /><br /></p>
<h2>The NFC transceiver<br /></h2>
<p><a href="https://www.limpkin.fr/public/NFC/trf.png" title="trf7970a block diagram"><img src="https://www.limpkin.fr/public/NFC/.trf_m.jpg" alt="trf7970a block diagram" style="display:table; margin:0 auto;" title="trf7970a block diagram, janv. 2015" /></a><br />
I chose the (not so cheap) <strong>TRF7970A</strong> from TI. This decision was motivated by a collaboration with Amal Gaafstra (the xNT tag creator), who was interested in having a transceiver with <strong>NFC peer to peer mode support</strong>. The TRF7970A is the updated version of the quite popular TRF7960.<br />
This transceiver is <strong>supposed to</strong> take care of all the low level stuff for you (modulation, framing and such) for the ISO15693/ISO18000-3, ISO14443A/B and FeliCa protocols. In short, you just need to give it the data you want to send to the tag using one of its interfaces (SPI or parrallel). It even has a 127 bytes FIFO.<br /><br /></p>
<h2>The problem<br /></h2>
<p><a href="https://www.limpkin.fr/public/NFC/nfc_debugging.JPG" title="NFC debugging"><img src="https://www.limpkin.fr/public/NFC/.nfc_debugging_m.jpg" alt="NFC debugging" style="display:table; margin:0 auto;" title="NFC debugging, janv. 2015" /></a><br />
To put it simply: the TRF7970A isn't doing what it's supposed to. I found several examples (provided by TI) of tag reading procedures that I implemented <strong>as is</strong>.... without success. I put the sniffed communications on the <a href="http://e2e.ti.com/support/wireless_connectivity/f/667/t/375663" hreflang="en" title="e2e forum">e2e forums</a> demonstrating the odd behavior yet my thread is left unanswered. In more details, among other things, I was forced to use 10ms delays to fetch data from the internal FIFO instead of using the dedicated RX interrupt.<br />
Thinking that I may have made a mistake on my PCB <strong>I even bought the official development board</strong>! This is something I practically never do :-) ... but that didn't help as I was still getting the same odd behavior. I couldn't find anything in the erratas either.<br /><br /></p>
<h2>The solution?<br /></h2>
<p><a href="https://www.limpkin.fr/public/NFC/nfc_debugging2.JPG" title="NFC debugging"><img src="https://www.limpkin.fr/public/NFC/.nfc_debugging2_m.jpg" alt="NFC debugging" style="display:table; margin:0 auto;" title="NFC debugging, janv. 2015" /></a><br />
If you want a <strong>free PCB</strong> and a small bag with most of the platform components in it, please <strong>drop me a message</strong> and I'll gladly send them to you. I decided to stop working on it because the official development board with the official tag reading commands <strong>didn't work</strong> but also because I currently am very busy working on the <strong>Mooltipass production process</strong>.<br />
I might get back to it some point in the future, though I may replace the NRF24L01 with an ESP8266.<br />
<strong>Edit (03/19/2015): 5 months later I got a reply, it seems that a possible solution to the problem would be <a href="http://e2e.ti.com/support/wireless_connectivity/f/667/t/326537" hreflang="en" title="errata">here</a>.</strong> Will try and let you know.<br /><br /></p>
<h2>The files<br /></h2>
<p>They're all CERN & GPLv3 licensed. If you look at the firmware you'll see that I implemented my own ISO14443A activation and selection procedure following the official specs.<br />
<a href="https://www.limpkin.fr/public/NFC/nfc_kicad.rar">kicad files</a> <a href="https://www.limpkin.fr/public/NFC/nfc_fw.rar">NFC firmware</a> <a href="https://www.limpkin.fr/public/NFC/nfc_ti_advices.rar">TI examples and advices</a> <a href="https://www.limpkin.fr/public/NFC/BoM_nfc_reader.xlsm">NFC reader BoM</a></p>First Steps with the ESP8266-03 Development Boardurn:md5:340ca93490962db5f0570ad73be37d492014-12-06T19:07:00+00:002024-03-09T12:14:58+00:00limpkinMy Projects<p>A fun afternoon project with two platforms...<br></p>
<p><img src="https://www.limpkin.fr/public/esp8266/.esp8266_fun_m.jpg" alt="fun with the esp8266s" class="media-center" title="fun with the esp8266s, déc. 2014"><br></p> <p>As mentioned in my <a href="https://www.limpkin.fr/index.php?post/2014/11/27/A-Development-Board-for-the-ESP8266-03">previous blog post</a> I was very optimistic when designing my ESP8266-03 development board and didn't even prototype it before launching a batch in production. As I just received a few of these boards in the mail today and given that information about this module is scattered all over the internet, I'll detail here my first steps with it...<br><br></p>
<h2>Configuring the FT230X<br></h2>
<p><a href="https://www.limpkin.fr/public/esp8266/ftdi.png" title="FT230X default configuration"><img src="https://www.limpkin.fr/public/esp8266/.ftdi_m.jpg" alt="FT230X default configuration" class="media-center" title="FT230X default configuration, déc. 2014"></a><br>
The onboard USB to UART adapter has 4 CBUS pins that can be configured as GPIOs or status pins. Three of them (CBUS0/1/3) are connected to green LEDs so if you want to change the default settings, you can download the FT_Prog utility <a href="http://www.ftdichip.com/Support/Utilities/FT_Prog_v3.0.56.245.zip" hreflang="en" title="FT Prog utility">here</a>, program your new settings, disconnect/reconnect the dev board.<br><br></p>
<h2>Playing with the default firmware<br></h2>
<p>This part is inspired by <a href="http://tomeko.net/other/ESP8266/" hreflang="en" title="playing with the default firmware">this awesome web page</a>.<br>
Connect the development board to your computer using a micro-usb cable, launch your favorite terminal program (in my case <a href="http://sourceforge.net/projects/realterm/files/" hreflang="en" title="Realterm">Realterm</a>), set a 9600 baudrate, head to the "Send" tab, tick the +CR & +LF boxes, enter these different commands and click "Send ASCII".<br><br>
Testing the communication<br></p>
<blockquote><p>>AT<br>
OK<br></p></blockquote>
<p>Getting the firmware version:<br></p>
<blockquote><p>>AT+GMR<br>
0018000902-AI03<br></p></blockquote>
<p>Setting Wifi mode as AP+STA and listing nearby Access Points (APs):<br></p>
<blockquote><p>>AT+CWMODE=3<br>
OK<br>
>AT+CWLAP<br>
+CWLAP:(3,"mysuperwifi",-76,"90:xx:xx:xx:xx:xx",1)<br>
+CWLAP:(4,"zak-52122",-79,"a4:xx:xx:xx:xx:xx",3)<br>
+CWLAP:(3,"ZyXEL_133A",-80,"cc:xx:xx:xx:xx:xx",2)<br>
+CWLAP:(3,"somewifi",-81,"e0:xx:xx:xx:xx:xx",4)<br>
+CWLAP:(0,"HP-Print-0C-Photosmart",-82,"6c:xx:xx:xx:xx:xx",4)<br>
+CWLAP:(4,"anotherwifi",-83,"fc:xx:xx:xx:xx:xx",1)<br></p></blockquote>
<p>As you can see you'll find the APs names together with their MAC addresses and <a href="http://en.wikipedia.org/wiki/Received_signal_strength_indication" hreflang="en" title="rssi">RSSIs</a>. The first digit is the encryption type (0:open, 1:wep, 2:wpa_psk, 3:wpa2_psk, 4:wpa_wpa2_psk).<br>
Connecting to your access point:<br></p>
<blockquote><p>>AT+CWJAP="mysuperwifi","mypassword"<br>
OK<br></p></blockquote>
<p>Checking that you're actually connected:<br></p>
<blockquote><p>>AT+CWJAP?<br>
AT+CWJAP:"mysuperwifi"<br>
OK<br></p></blockquote>
<p>Download and run this TCP server/terminal made by tomeko: <a href="https://www.limpkin.fr/public/esp8266/BcbServer.zip" hreflang="en" title="TCP client test">Bcbserver</a>, send data to your main computer:<br></p>
<blockquote><p>> AT+CIPMUX=0<br>
OK<br>
>AT+CIPSTART="TCP","your computer IP",7778<br>
OK<br>
Linked<br>
+IPD,24:Connection established<br>
OK<br></p></blockquote>
<p>Here the TCP connection is established, you need to specify how many bytes you want to send (here 4)<br></p>
<blockquote><p>>AT+CIPSEND=4<br>
> (type your 4 bytes long text here)<br>
SEND OK<br></p></blockquote>
<p>You should see your text displayed in BCBcostam.<br>
Finally, stop your TCP connection:<br></p>
<blockquote><p>>AT+CIPCLOSE<br>
OK<br>
Unlink<br></p></blockquote>
<p>You'll find a lot more AT commands <a href="http://www.electrodragon.com/w/Wi07c" hreflang="en" title="electrodragon's page about the ESP8266">here</a> and <a href="https://nurdspace.nl/ESP8266" hreflang="en" title="nurdspace's page about the ESP8266">here</a>.<br><br></p>
<h2>Building the Espressif toolchain<br></h2>
<p>Until now we've used the ESP8266 as a <strong>peripheral</strong>, meaning that we need a computer/phone/microcontroller to operate it. However, since the ESP8266 manufacturer released the chip SDK we can reprogram it with our own code so it can work as a <strong>standalone device</strong>. To do so, we first need to build the Espressif toolchain.<br>
This will unfortunately take quite a while... so only do it when you have some time to spend! I highly recommend following the great guide that can be found <a href="https://github.com/esp8266/esp8266-wiki/wiki/Toolchain" hreflang="en" title="ESP8266 toolchain installation">here</a>.<br>
Please note that in the Linux tutorial, at the time of writing I had to run "mv esp_iot_sdk_v0.9.3/* ESP8266_SDK" and not "mv esp_iot_sdk_v0.9.3 ESP8266_SDK".<br><br></p>
<h2>Making our own program<br><br></h2>
<p>Let's learn by example. In 4-5 hours I managed to make this fun setup:<br></p>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/cw2yjEPAaz8" frameborder="0" allowfullscreen></iframe>
</div>
<p><br></p>
<h3>The Doppler station<br></h3>
<p>First, we need to setup one ESP8266 pin as input with its internal pull-up enabled so we can just connect our button between this IO and our platform ground:<br></p>
<blockquote><p>PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13); // Set GPIO13 function<br>
gpio_output_set(0, 0, 0, BIT13); // Set GPIO13 as input<br>
PIN_PULLDWN_DIS(PERIPHS_IO_MUX_MTCK_U); // Disable pulldown<br>
PIN_PULLUP_EN(PERIPHS_IO_MUX_MTCK_U); // Enable pullup<br></p></blockquote>
<p>Given that we don't have access to the ESP8266 english datasheet and want to use all its already included features, we are forced to use the SDK. Have a look for "ESP8266EX SDK Programming Guide" on your favorite search website.<br>
As a given pin can be driven by several controllers inside the ESP8266, the first line specifies that we want to use the GPIO controller on GPIO13. The three others.... well read the comments ;-) . This is a simple and non energy-saving way to use a button as you'll need to <strong>poll</strong> its state rather than having an <strong>interrupt based readout</strong>:<br></p>
<blockquote><p>ETS_GPIO_INTR_DISABLE(); // Disable gpio interrupts<br>
ETS_GPIO_INTR_ATTACH(doppler_int_handler, 12); // GPIO12 interrupt handler<br>
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12); // Set GPIO12 function<br>
gpio_output_set(0, 0, 0, GPIO_ID_PIN(12)); // Set GPIO12 as input<br>
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(12)); // Clear GPIO12 status<br>
gpio_pin_intr_state_set(GPIO_ID_PIN(12), 3); // Interrupt on any GPIO12 edge<br>
ETS_GPIO_INTR_ENABLE(); // Enable gpio interrupts<br></p></blockquote>
<p>The doppler sensor has a <strong>5 volts frequency output</strong> (don't forget the voltage divider!) meaning that it'll toggle its pin several times per second at a frequency proportional to an object speed. In the simple firmware you can download below we're using a very simple strategy: everytime the HB-100 FOUT pin toggles, an interrupt is generated on the ESP8266 which will increment a counter. Every 0.5s we read this counter value and broadcast it to our computer and other ESP8266-03 module.<br>
The interesting part above is the second line that registers doppler_int_handler as the GPIO12 interrupt function. Every time this function is called we increment our counter.<br></p>
<blockquote><p>PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2); // Set GPIO2 function<br>
gpio_output_set(0, BIT2, BIT2, 0); // Set GPIO2 low output<br></p></blockquote>
<p>These two lines set GPIO2 as an output to drive the red LED. Given that the ESP8266-03 board already includes current limiting resistors you can directly connect your LED. As you can see in the video, this red LED blinks every 0.5sec:<br></p>
<blockquote><p>os_timer_disarm(&led_timer); // Disarm led timer<br>
os_timer_setfn(&led_timer, (os_timer_func_t *)led_timerfunc, NULL); // Setup led timer<br>
os_timer_arm(&led_timer, 500, 1); // Arm led timer, 0.5sec, repeat<br></p></blockquote>
<p>The ESP8266 'operating system' allows you to specify timers (functions) that will be fired at a pre-defined frequency. Here we specify that the led_timerfunc function should be called every 0.5sec indefinitely.<br></p>
<blockquote><p>char ssid[32] = "mywifissid"; // Wifi SSID<br>
char password[64] = "mywifipassord"; // Wifi Password<br>
struct station_config stationConf; // Station conf struct<br>
wifi_set_opmode(0x1); // Set station mode<br>
os_memcpy(&stationConf.ssid, ssid, 32); // Set settings<br>
os_memcpy(&stationConf.password, password, 64); // Set settings<br>
wifi_station_set_config(&stationConf); // Set wifi conf<br>
//wifi_status_led_install(13, PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13); // Wifi LED status<br></p></blockquote>
<p>Having your board connect to your home Wifi is so simple! The last line allows you to specify an LED dedicated to Wifi status indication. It will blink when trying to connect/having an error, it will switch off when everything is ok.<br></p>
<blockquote><p>void ICACHE_FLASH_ATTR network_check_ip(void)<br>
{<br>
struct ip_info ipconfig;<br>
<br>
os_timer_disarm(&network_timer); // Disarm timer<br>
wifi_get_ip_info(STATION_IF, &ipconfig); // Get Wifi info<br>
<br>
if (wifi_station_get_connect_status() == STATION_GOT_IP && ipconfig.ip.addr != 0) <br>
{<br>
network_start(); // Everything in order<br>
}<br>
else <br>
{<br>
os_printf("Waiting for IP...\n\r");<br>
os_timer_setfn(&network_timer, (os_timer_func_t *)network_check_ip, NULL);<br>
os_timer_arm(&network_timer, 1000, 0);<br>
} <br>
}<br></p></blockquote>
<p>This 1sec timer is called until the platform gets an IP from your home's DHCP server (usually your router). Once it has an IP address, you can start establishing connections to you computer and other devices.<br></p>
<blockquote><p>global_tcp_connect.type=ESPCONN_TCP; // We want to make a TCP connection<br>
global_tcp_connect.state=ESPCONN_NONE; // Set default state to none<br>
global_tcp_connect.proto.tcp=&global_tcp; // Give a pointer to our TCP var<br>
global_tcp_connect.proto.tcp->local_port=espconn_port(); // Ask a free local port to the API<br>
global_tcp_connect.proto.tcp->remote_port=7778; // Set remote port (bcbcostam)<br>
global_tcp_connect.proto.tcp->remote_ip[0]=ip1; // Your computer IP<br>
global_tcp_connect.proto.tcp->remote_ip[1]=ip2; // Your computer IP<br>
global_tcp_connect.proto.tcp->remote_ip[2]=ip3; // Your computer IP<br>
global_tcp_connect.proto.tcp->remote_ip[3]=ip4; // Your computer IP<br>
espconn_regist_connectcb(&global_tcp_connect, tcpNetworkConnectedCb); // Register connect callback<br>
espconn_regist_disconcb(&global_tcp_connect, tcpNetworkDisconCb); // Register disconnect callback<br>
espconn_regist_reconcb(&global_tcp_connect, tcpNetworkReconCb); // Register reconnection function<br>
espconn_connect(&global_tcp_connect); // Start connection<br></p></blockquote>
<p>Setting up a TCP connection is not so complex. You specify your destination IP/port together with functions to call if the connection is made, disconnected or reconnected.<br></p>
<blockquote><p>global_udp_connect.type=ESPCONN_UDP; // We want to make a UDP connection<br>
global_udp_connect.state=ESPCONN_NONE; // Set default state to none<br>
global_udp_connect.proto.udp=&global_udp; // Give a pointer to our UDP var<br>
global_udp_connect.proto.udp->local_port=2222; // Set local port<br>
global_udp_connect.proto.udp->remote_port=2222; // Set remote port<br>
global_udp_connect.proto.udp->remote_ip[0]=ip1; // The other ESP8266 IP<br>
global_udp_connect.proto.udp->remote_ip[1]=ip2; // The other ESP8266 IP<br>
global_udp_connect.proto.udp->remote_ip[2]=ip3; // The other ESP8266 IP<br>
global_udp_connect.proto.udp->remote_ip[3]=ip4; // The other ESP8266 IP<br>
if(espconn_create(&global_udp_connect) == 0) // Correctly setup<br>
{<br>
os_printf("UDP connection set\n\r");<br>
udp_conn_ok = TRUE;<br>
}<br></p></blockquote>
<p>UDP connection are much simpler given that there's strictly no added logic on the data sending part like with TCP. The ESP8266 is just sending bytes to a given IP address.<br></p>
<p>I think I covered most of the low level stuff. I'll summarize what the firmware does in case you want to have a look at the source code:<br>
- setup the input/outputs<br>
- register a 0.5sec timer in charge of toggling the red LED, reading the doppler frequency, sending it to your computer and other ESP8266<br>
- register a 1sec timer that will check the ESP8266 connection status. Once it has an IP, start making a TCP connection to the computer and a UDP one to the ESP8266<br><br></p>
<h3>The indicating platform<br></h3>
<p>The code here is much simpler:<br>
- Connect to your Wifi<br>
- Set 3 pins as outputs for the green/orange/red LEDs<br>
- Create a UDP connection<br>
- Parse the incoming data to know which LEDs to turn on/off.<br></p>
<p>Want the files? Here they are: <a href="https://www.limpkin.fr/public/esp8266/doppler_sensor.rar">doppler sensor code</a> <a href="https://www.limpkin.fr/public/esp8266/esp8266_client.rar">esp8266 client code</a><br>
If you want more examples have a look at <a href="https://github.com/zarya/esp8266_status_display" hreflang="en" title="zarya's status display">this github repository</a> and don't hesitate to come to #esp8266 on freenode!<br>
Thanks zarya for the help and code!</p>