Gas station without pumps

2015 July 29

LED strobe using dimmer board

Filed under: Uncategorized — gasstationwithoutpumps @ 23:49
Tags: , , , , , ,

In the evenings this week, I soldered up another PWM controller for the LED lamp projects, and programmed it with the ISP cable I made.  The intent was to use this dimmer either with the breakfast-room lighting fixture (which I’ve not made yet) or reprogram it to act as a strobe rather than a dimmer, to replace the Xenon-tube-based Velleman strobe kit that failed last Thanksgiving.

This project took me much longer than expected, because of stupid mistakes I made:

  • I forgot that there was a silkscreen error on the dimmer boards that I had designed.  The outline for the voltage regulator is flipped, because I had not noticed when reading the spec sheet shows the device from the bottom—I’m used to chip views being from the top.  This is the second time that I’ve soldered a voltage regulator on one of the boards backwards, and had to cut it off and replace it with a new one.  I guess I’d better take a permanent felt-tip marker and draw the correct orientation on the remaining boards, so that I don’t make that mistake a third time.
  • When playing with new code for the strobe, refamiliarizing myself with the ATtiny13A processor, I changed the prescaling on the system clock from the default 1.2MHz down to about 75kHz.  What I had not realized is that the on-chip clock is used during the reprogramming also, and the Arduino ISP is not set up for slowly clocked chips.  I found code for TinyISP, which has code for 128kHz clocks, but even when I modified it for 75kHz clocks I couldn’t reprogram the chip (always getting the “Yikes! invalid device signature” message with a signature of 0). Eventually, I gave up, unsoldered the ATtiny13A and put in a new one.  I’ll be very careful in future not to slow down the system clock so much.
  • I got the strobe working this morning, but when I looked at the output pin that was driving the FET gate, it was only going up to 1.3V, not 5V, and the pulse was much longer than I expected.  This mystified me for a while, but I finally realized that I had forgotten to turn the pin on as an output, so I was driving the output just through the built-in pullup resistor, resulting in a very large RC time constant.  The flat top I was seeing on the pulse was probably the Miller plateau.  Enabling the output pin correctly got me back to crisp 5V pulses of the designed duration.
  • The designed duration for the pulses was a bit too short, resulting in a somewhat dimmer than desired flash.  Lengthening the pulse to 1ms was fine for the slow strobes, but at high flash rates the strobe got too bright. So I reprogrammed the flashes so that the on-time was 1/64th of the off-time, but with a maximum on-time of 1.6ms. (I also tried on=off/128 with a maximum of 1ms, but I liked the 1/64 better).

I timed the strobe pulses from the board (looking at the output of the ATtiny13A pin 6, which is also connected to the MISO pin of the ISP header, so is easy to connect a jumper wire to) with PteroDAQ (through a voltage divider, to drop the voltage from 5V to 2.75V).  By triggering the PteroDAQ on edges of the signal, and averaging many measurements, I got very precise timing measurements:

setup on-time off-time
slowest setting, 1:64 1.63745ms 1.52372s
fastest setting, 1:64 104.958µs 6.98761ms
slowest setting, 1:128 955.277µs 1.55881s
fastest setting, 1:128 51.3123µs 6.99286ms

The difference in the “slowest” settings is probably just from my inability to set the knob identically—it has to be just above a threshold below which the strobe doesn’t flash at all. In any case, I have a period from 7.1ms (141Hz) to 1.525s (0.6556Hz), which is a pretty useful range.  I also made the range very smooth, by taking the 10-bit ADC range and converting it to this 215:1 range sort of exponentially with just a few instructions:

if adc<40, then OFF
exp = adc >> 7
frac = 0xff - (adc & 0x7f)
on_time = (frac << 8) >> exp
The tiny number of instructions provides a surprisingly smooth and strictly decreasing approximation to the desired exponential.

The tiny number of instructions provides a surprisingly smooth and strictly decreasing approximation to the desired exponential.

The transition is smooth because every time an increment increases the exponent, the frac part is doubled (from 0x80 to 0xff).I use a 16-bit word for the on_time and count it down with an interrupt once every 26.67µs (256 of the approximately 9.6MHz clock ticks). I think that I’ll do a similar thing for controlling the duty cycle of the dimmer, rather than the table of bytes that I currently use, though the duty cycle is limited to a single byte, so I’ll only have 256 levels, and not 1024, and I’ll want the duty cycle to increase exponentially, rather than decreasing, but those are easy fixes.

I also reduced the size of the program in flash, by getting rid of some of the overly general code from core13 and just manipulating the peripheral control registers directly.  I didn’t need to do this, as the ATtiny13A has 1kB of flash, but I got down to 364 bytes (and could probably strip out another 50–100 by getting rid of even more of core13).  The old dimmer code, which doesn’t have much more to do, currently takes 806 bytes, so I might try tightening that up tomorrow.

I also tried powering the strobe off a 9V battery.  The LED board takes about 117mA when turned on (see LED board I-vs-V curve), and if I keep the duty cycle below 1.5%, then the average current is dominated by the ATtiny13A’s worst-case 6mA current, and the total current for the board is probably less than 8mA.  According to Duracell’s data sheet for their 9V alkaline battery, I should be able to get about 50 hours of life before the voltage drops below 6.7V (at which point the LED board no longer maintains the constant current, but I could run the strobe a bit longer getting dimmer).  The 6.7V is also about the voltage where the LDO voltage regulator starts being unable to supply 5V to the ATtiny13A, though that is less of a bottleneck, as the chip can run with the 9.6MHz internal clock down to 3V with no problems.

The battery does not have to provide a full 117mA for the pulses, as there is a 470μF polymer electrolytic capacitor on the dimmer board.  Delivering 117mA for 1.6ms is only 187μC, so the voltage on the capacitor would dip at most 0.4V during the pulse, even without the battery.  The 9V battery has an internal resistance of 2Ω–4Ω, so it could provide 117mA with about a 0.35V drop, so the capacitor isn’t really necessary for one LED board.  It probably increases the efficiency slightly, as the I2R power loss in the internal resistor is reduced if the current is spread out (half the current for twice as long is only half the I2R loss).

I could put more LED boards on the strobe, as the dimmer is designed to handle 5A or more, but battery  operation would limit me to about 10 boards before the voltage drop was large enough to cause problems for the current regulation.  One LED board is bright enough for a Halloween pumpkin, but I could run wires between pumpkins to power several off the same controller.  (I could also keep the controller in the house, powered by a wall wart, and run wires out to the LED boards—I could then power 40 or 50 LED boards off the strobe, though I’d have to watch out for IR drop in the wiring.)

I might try wiring up 10 boards tomorrow, and see whether a battery really can power that many.

2015 July 27

Arduino as ISP

Filed under: Uncategorized — gasstationwithoutpumps @ 20:39
Tags: , , , ,

For the LED lamp projects, I’ve been using ATtiny13A chips for the dimmer board, programmed with the Arduino IDE and an Arduino board as an In-System Programmer (ISP).  The Arduino code is too big for an ATtiny, so I’ve been using a version of the core13 stripped-down system.

I got rather tired of wiring up the 6 wires for the ISP, checking to make sure that each one was correct.  What I wanted to do was just plug in a standard 6-pin cable from the Arduino board to the ATtiny board, but the ISP header on the Arduino board has the Arduino reset line, not the reset line that has to go to the ATtiny board.

I decided to modify a standard cable to do the right thing, separating the reset line from the rest. The reset line is on pin 5, so on a standard ribbon cable, it is the fifth of the six wires.

First I carefully cut wire 5 near one of the plugs with a razor knife, peeled it back and spliced on another piece of stranded wire:

The blue wire and wire 5 of the ribbon cable were soldered together and covered with heat-shrink tubing.

The blue wire and wire 5 of the ribbon cable were soldered together and covered with heat-shrink tubing.

I taped the soldered joint to rest of the ribbon cable for strain relief, and added a crimp-on female header at the other end. (I prefer female crimp-on headers, because they are more versatile than male pin—I can stick in a double-ended male header pin to convert them to male connectors when needed.)

The electrical tape stabilizes the splice and the crimp-on female header allows connecting to male or female headers on the Arduino board. Here there is a double-ended male header pin in the female header, to convert it to a male header.

The electrical tape stabilizes the splice and the crimp-on female header allows connecting to male or female headers on the Arduino board. Here there is a double-ended male header pin in the female header, to convert it to a male header.

Here is a Leonardo board being used to program one of the dimmer boards:

With the new cable, it is easy to unplug the cable after programming to test out the system, then plug it back in with the right orientation (I used a shrouded header on the dimmer board) when reprogramming is needed.

With the new cable, it is easy to unplug the cable after programming to test out the system, then plug it back in with the right orientation (I used a shrouded header on the dimmer board) when reprogramming is needed.

Note that the reset line for the ISP cable connects to pin 10 of the programming Arduino board, which would be connected via a USB cable to the laptop that has the Arduino development environment on it.

I’ve seen several kluges on the web for connecting up Arduinos as ISPs, but none were as simple as and easy to use as what I did here, so I thought I ought to share it.

2015 July 15

PteroDAQ board calibration

Filed under: Circuits course,Data acquisition — gasstationwithoutpumps @ 19:02
Tags: , , , ,

Yesterday, while I was in the circuits lab, I checked the calibration of the voltage references on the KL25Z boards and the 4 Arduino boards I had with me.

What I did was to measure the power-supply voltage on the board with a good multimeter and make several of the PteroDAQ self-calibrations of the reference voltage (v0.2b1 does a new calibration every time the “pause” button is pressed).

For the KL25Z board, the voltage regulator on the board was well calibrated—I got a reading of 3.3001V with the bench multimeter.  The 33 PteroDAQ calibrations I recorded gave an average reading of 3.3095V with a standard deviation of 400.6µV. That means that the PteroDAQ reported voltages will be about 0.28±0.01% too high (much better than the ±3% specification for the bandgap voltage reference on the chip).   This is probably better than any of the cheap meters I have at home.

For the Arduino boards, the reference is normally the USB 5V power supply, which was not stable enough to do these comparisons with—I couldn’t get a constant reading on the good voltmeters but saw fluctuations of almost 10mV.  I should have had a 9V wall-wart power supply with me, so that I could get a more stable voltage source from the on-board regulators, but lacking that, I used a bench power supply directly connected to the +5V and Gnd pins of the Arduino to force specific voltages around 5V and did the same comparisons as for the KL25Z board.

board measurements voltage reading
KL25Z 33 +0.28±0.01%
Sparkfun Redboard 10 +0.08±0.10%
Duemilanove  11 –0.26±0.15%
Leonardo  10 –1.81±0.13%
Uno  8 +1.68±0.05%%

The greater fluctuation for the Arduino boards is probably due to the lower resolution of the ADC—the 10-bit ADC should have a reading around 225 at 1.1V with a 5V reference, so ±0.15% is only ±1/3 LSB.  The ATMega chips are guaranteed to have ±10% accuracy on the bandgap reference, but that is over the full temperature range, so ±2% seems about right for room temperature.

The USB power-supply is not a constant voltage, and the fluctuation in the USB power-supply voltage (which can be as much as ±10%) is a problem when using the Arduino boards, so powering them off of a wall wart is a good idea when trying to measure signals accurately.

The voltage measurements are as good as with super-cheap handheld voltmeters (which generally have a specification of about ±1%), so the PteroDAQ system is good enough for first electronics courses and hobbyist labs.

2015 July 14

PteroDAQ v0.2b1 released!

Filed under: Circuits course,Data acquisition — gasstationwithoutpumps @ 21:57
Tags: , , , ,

For the past couple of years, I’ve been using the PteroDAQ data acquisition system that my son wrote for the KL25Z board (a second-generation system, replacing the earlier Arduino Data Logger he wrote). Over the past week, he has been transferring the project to me, and together we did a lot of debugging and enhancements.

Today, we tested the code on the ancient Windows 7 machines in the circuits lab at UCSC (we only have Mac OS 10 and Linux at home), and decided it was ready for a beta release.

The new code is way better than the old code! Here are a few of the bigger changes:

  • We now support all the ATMega-based Arduino boards, while still supporting the KL25Z.  The KL25Z board is a better choice for a new user, since it is cheaper and has a much better analog-to-digital converter than the Arduinos, but there are a lot of Arduinos and Arduino clones already in hobbyist hands, and PteroDAQ now works for them with no new hardware.
  • Sampling rates have improved enormously, particularly for the KL25Z and the Leonardo Arduino boards, which have USB serial communication without the bottleneck of a UART, but even the UART-based Arduino boards have a decent throughput of 2600Hz for a single analog channel. Leonardo gets 5370Hz, and the KL25Z is limited by the Python program on the host—7.8kHz on the old Windows machines, almost 10kHz on my old MacBook Pro (buffer overflow in the operating system loses some packets after a million samples), and about 19kHz on my son’s Linux laptop (again starting to lose samples after about 1 million).  That’s not fast enough for high-quality audio, but it would do for speech-quality audio. It’s a lot better than the old v0.1 PteroDAQ, which was much more limited by the host, having trouble getting even 180Hz on the old Windows machines.
    For short stretches, PteroDAQ can run somewhat faster—I can get 15kHz for about 400,000 samples on my MacBook Pro, which is long enough for a lot of lab experiments.
  • We’ve removed the need for PySerial. My son reimplemented the USB serial interface (based heavily on the PySerial implementation), so that we could have everything in a single download with no dependencies outside the standard modules that come with Python.  The implementation may still be a bit inefficient (like the PySerial one), and we are considering working on it.
  • Sparklines for the different signals now scroll smoothly even at the highest sampling rates, without taking up much of the host processor.
  • Most recent data for each channel is shown numerically next to the channel (which is particularly useful when doing single samples).
  • Resizing the window now works well, shrinking and stretching in the appropriate places.
  • The GUI now reports errors when PteroDAQ can’t keep up with the requested sampling rate, which makes trading off the sampling rate and averaging easier.

The speed limitations are partly in how fast the Python program on the host machine can accept and process the data, and partly in how fast the KL25Z or Arduino board can do the analog-to-digital conversion. The Arduino boards hit the conversion limits before any of the host machines we used ran into Python limitations, but the KL25Z board with 1× averaging can produce data faster than any of our machines can accept it, so there is still work to be done on improving the efficiency of the Python code.

The software now needs a few users to test it out and find out what problems remain. Some things we won’t be able to do anything about—if Python crashes or the operating system messes up the communication link, there isn’t a lot we can do. Some things are not worth our time (like internationalizing the interface—though we do plan to get unicode characters properly handled in the Notes field—getting that to work in both Python2 and Python3 may be a bit tricky).

I encourage any one who has an Arduino or KL25Z board to try out the new system and tell what problems they have (other than the dire lack of documentation, which I will try to work on with my son over the summer). Ideas for new features are welcome also, though probably won’t come soon.

The software was a complete refactoring of the previous code, with much cleaner interfaces between the modules, which should help with maintenance and extension in future.  I have a huge wish list for new features to add to PteroDAQ, but my son needs to get back to work on the new product for Futuristic Lights, and I need get back to work on my book, so I’ll mainly be putting ideas onto the issue tracker, with the intent of getting back to them later.

2015 July 11

Improving PteroDAQ

Filed under: Circuits course,Data acquisition — gasstationwithoutpumps @ 19:53
Tags: , , , , ,

For the past couple of years, I’ve been using the PteroDAQ data acquisition system that my son wrote for the KL25Z board (a second-generation system, replacing the earlier Arduino Data Logger he wrote).  He has been working on and off on a multi-platform version of PteroDAQ for over a year, and I finally asked him to hand the project over to me to complete, as I want it much more than he does (he’d prefer to spend his time working on new products for his start-up company, Futuristic Lights).

It has been a while since he worked on the code, and it was inadequately documented, so we’ve been spending some time together just digging into the code to figure out the interfaces, which I’ve been adding comments and docstrings to, so that I can debug the code.  Other than the lack of documentation, the code is fairly well written, so figuring out what is going on is not too bad (except in the GUI built using tkinter—like all GUI code, it is a complicated mess, because the APIs for building GUIs are a complicated mess).

The man goal of his multi-platform code was to support Arduino ATMega-based boards and the KL25Z board, while making it relatively easy to add more boards in future.  The Arduino code is compiled and downloaded by the standard Arduino IDE, while the KL25Z board code is compiled and downloaded with the MBED online compiler.  He has set up the software with appropriate #ifdef checks, so that the same code files can be compiled for either architecture.  The knowledge of what features are available on each board and how to request them is stored in one module of the python program that runs on the host computer.  As part of the cleaning up, we’ve been moving some of the code around to make sure that all the board-specific stuff is in that file, with a fairly clean interface.

He believed that he had gotten the new version working on the Arduino boards, but not on the KL25Z board.  It turned out that was almost true—I got the system working with the Leonardo board (which uses USB communication and has a weird way to get reset) almost immediately, but had to do a number of little bug fixes to get it working with other Arduino boards (which use UART protocol and a different way of resetting). It turned out that the system also worked with the KL25Z after those bug fixes, so he was very close to having it ready to turn over to me.

One of the first things I did was to time how fast the boards would run with the new code—the hope was that the cleaner implementation would have less overhead and so support a higher sampling rate.  Initial results on the Arduino boards were good, but quite disappointing on the KL25Z boards, which use a faster processor and so should be able to support much higher speeds.  We tracked the problem down to the very high per-packet overhead of the USB packets in the mbed-provided USBSerial code.  (He had tried writing his own USB stack for bare-metal ARM, but had never gotten it to work, so we were using the mbed code despite its high overhead.)

There was a simple fix for the speed problem: we stopped sending single-character packets and started using the ability of the MBED code (and the Arduino code for the Leonardo) to send multi-character packets.  With this change, we got much better sampling rates (approximate max rate):

channels Leonardo Uno/Duemilanove/Redboard KL25Z 32x avg KL25Z, 1x avg
0  13kHz  4.5kHz  8.2kHz
1 analog  5kHz  2.7kHz  5.5kHz  8.1kHz
2 analog  3kHz  1.9kHz  3kHz  8.1kHz
7 digital  6.5kHz  3.4kHz  8.2kHz

It is interesting that the Leonardo (a much slower processor) manages to get a higher data rate than the KL25Z when sending just time stamps.  I think that I can get another factor of 3 or 4 speed on the KL25Z by flushing the packets less often, though, so I’ll try that.

By flushing only when needed, I managed to improve the KL25Z performance to

channels KL25Z 32x avg KL25Z, 1x avg
0  17kHz
1 analog  6.3kHz  10kHz ??
2 analog  3.3kHz

Things get a bit hard to measure above 10kHz, because the board runs successfully for several hundred thousand samples, then I start losing characters and getting bad packets. The failure mode using my son’s faster Linux box is different: we lose full packets when going too fast—which is what PteroDAQ is supposed to do—and the speed at which the failure starts happening is much higher (maybe 23kHz). In other words, what I’m seeing now are the limitations of the Python program on my old MacBook Pro. It does bother me that the Mac seems to be quietly dropping characters when the Python program can’t clear the USB serial input fast enough.

The KL25Z slows down when doing the 32x hardware averaging, because the analog-to-digital conversion is slow—particularly when doing 32× hardware averaging.  I think that we’ve currently set things up for a 6MHz  ADC clock, with short sampling times, which means that a single-ended 32× 16-bit conversion takes around 134µs and the sampling rate is limited by the conversion times (differential measurements are slower, around 182µs).

There is a problem in the current version of the code, in that interrupts that take longer to service than the interrupt time result in PteroDAQ lying about its sampling rate.  I can fix this on the KL25Z by using a separate timer, but the Arduino boards have rather limited timer resources, and we may just have to live with it on them.  At least I should add an error flag that indicates when the sampling rate is higher than board can handle.

We had a lot of trouble yesterday with using the bandgap reference to set the voltage levels.  It turns out that on the Arduino boards, the bandgap channel is a very high impedance, and it takes many conversion times before the conversion settles to the final value (nominally 1.1V).  Switching channels and then reading the bandgap is nearly useless—the MUX has to be left on the bandgap for a long time before reading the value means anything.  If you read several bandgap values in quick succession, you can see the values decaying gradually from the value of the previously read channel to the 1.1V reference.

The bandgap on the KL25Z is not such a high-impedance source, but there is some strange behavior when reading it with only 1× averaging—some values seem not to occur and the distribution is far from gaussian.  I recorded several thousand measurements with 1×, 4×, 8×, 16×, and 32× averaging:

The unaveraged reading seems to be somewhat higher than  any of the hardware-averaged ones.

The unaveraged (1×) reading seems to be somewhat higher than any of the hardware-averaged ones.

I was curious about how the noise reduced on further averaging, and what the distribution was for each of the averaging levels. I plotted log histograms (using kernel-density estimates of the probability density function: gaussian_kde from the scipy python package) of the PteroDAQ-measured bandgap voltages.  The PteroDAQ is not really calibrated—the voltage reference is read 64 times with 32× averaging and the average of those 64 values taken to be 1V,  but the data sheet says that the  bandgap could be as much as 3% off (that’s better than the 10% error allowed on the ATMega chips).

Without averaging, there is a curious pattern of missing values, which may be even more visible in the rug plot at the bottom than in the log histogram.

Without averaging, there is a curious pattern of missing values, which may be even more visible in the rug plot at the bottom than in the log histogram.

The smoothed log-histogram doesn't show the clumping of values that is more visible in the rug plot.

The smoothed log-histogram doesn’t show the clumping of values that is more visible in the rug plot.

With eight averages, the distribution begins to look normal, but there is still clumping of values.

With eight averages, the distribution begins to look normal, but there is still clumping of values.

With 16 averages, things look pretty good, but mode is a bit offset from the mean still.

With 16 averages, things look pretty good, but mode is a bit offset from the mean still.

Averaging 32 values seems to have gotten an almost normal distribution.

Averaging 32 values seems to have gotten an almost normal distribution.

Interestingly, though the range of values reduces with each successive averaging, the standard deviation does not drop as much as I would have expected (namely, that averaging 32 values would reduce the standard deviation to about 18% the standard deviation of a single value). Actually, I knew ahead of time that I wouldn’t see that much reduction, since the data sheet shows the effective number of bits only increasing by 0.75 bits from 4× t0 32×, while an 8-fold increase in independent reads would be an increase in effective number of bits of 1.5 bits.  The problem, of course, is that the hardware averaging is of reads one right after another, in which the noise is pretty highly correlated.

I think that the sweet spot for averaging is the 4× level—almost as clean as 32×, but 8 times faster.  More averaging improves the shape of the distribution a little, but doesn’t reduce the standard deviation by very much.  Of course, if one has a low-frequency signal with high-frequency noise, then heavier averaging might be worthwhile, but it would probably be better to sample faster with the 4× hardware averaging, and use a digital filter to remove the higher frequencies.

The weird distribution of values for the single read is not a property of the bandgap reference, but of the converter.  I made a voltage divider with a couple of resistors to get a voltage that was a fixed ratio of the supply voltage (so should give a constant reading), and saw a similar weird distribution of values:

The distribution of single reads is far from a normal  noise distribution, with fat tails on the distribution and clumping of values.

The distribution of single reads is far from a normal noise distribution, with fat tails on the distribution and clumping of values.

 

With 32× sampling, the mean is 1.31556 and the standard deviation 5.038E-04, with an excellent fit to a Gaussian distribution.

Next Page »

The Rubric Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 315 other followers

%d bloggers like this: