Sunday, August 30, 2015
Calibrating a cheap crappy tire multimeter
Anyone living in Canada is likely familiar with CT products carrying the Mastercraft branding. They are significantly overpriced to allow for heavy sale discounts of 50-60% that usually happen a few times a year. About 10 years ago I bought a Mastercraft model 52-0052-2 auto-ranging multimeter when it was on sale for C$20 (about US$15 at current exchange rates). I use it for low-voltage, and have another multimeter with a current clamp that I use for household (mains) 120/240V testing.
I've been using it a lot over the last few years, and started getting a feeling that it was reading a bit high, based on readings from 3.3 and 5V regulators, and even from comparisons with battery voltage readings. After testing a batch of TL431 voltage references, I was able to confirm that it is reading between 0.6% and 0.7% high. I also ordered a couple 0.05% REF5050s, which will allow me to double-check my TL431 measurements.
After opening up the meter, I found there are 8 trimmer pots, and no indications on the board as to which of these adjusts the voltage. I eventually found a discussion on EEVblog that indicates the meter is made by the Hong Kong company Colluck, and is spec'd for 0.8% accuracy on voltage readings. I have what DIPlover calls the old model, which measures 9cm wide and 18.5cm long. While I still couldn't find documentation on how to adjust the calibration, I did find a review of another cheap multimeter that had several trimmer pots, and the pot labled VR1 was the voltage calibration trimmer. I figured I had little to loose by trying the same pot on my meter.
In case VR1 didn't adjust the voltage, I needed to adjust it back to it's original position. I used an ultra-fine sharpie to mark a small line on the top and the base of the trim pot so I could locate the original position. I used a TL431 which was reading 2.513V, which I though should read around 2.496V, connecting it to my meter probes with a hook probes. With the first small adjustment of the pot, the voltage reading went up to over 2.53V, so I had the right pot. The sensitivity was a bit of a problem, as the tiniest adjustments I could make were undershooting and overshooting. After several tries, I got a reading of 2.496V, which I think is within 0.1%. With a couple of REF5050's it should be possible to calibrate it to +- 1mV, or 0.04%. But given how sensitive the trim pot is, I won't touch it as long as it is within 2mV.
Thursday, August 27, 2015
Cheap TL431 voltage references
Until a year ago I had never heard of the TL431. Then I read Ken Shirriff's blog post, as well as other mentions of the TL431 on hackaday.com and eevblog.com. I found out the 431 is useful not only as a voltage reference, but also as a constant current control, and even a voltage controlled oscillator.
I had started suspecting my cheap (~$20) auto-ranging multimeter was reporting voltages a bit on the high side, and when I found 100 TL431s selling for less than 150c, I ordered them. While waiting for them to arrive I tried to find out more information about the manufacturer, Wing Shing Computer Components of Hong Kong. I could not find an active web site (at least in English), and although I found an old datasheet for the WS-TL431, I could not find anything current. I did find another Aliexpress seller that posted a photo of a box full of WS-TL431A showing a 0.3% accuracy rating, which, considering the low price, is quite good. Even 1% rated genuine TI TL431 parts are difficult to find for less than 2c each.
Once I received the package, I checked out the chip markings, which were all the same:
WS
TL431A
155SD
I suspect the 155 is a date code for 2015, 5th week, indicating these are new parts. The old datasheet from Wing Shing shows the TL431A part as only 1%, and a TL431AA as 0.5%, and nothing listed for a 0.3% part. I don't think I'm perpetuating an unfair stereotype to say that the Chinese are notorious for bad or non-existent documentation. I think that the parts I received are actually rated to within 0.3% at 25C, and the manufacturer has not undertaken to produce an updated datasheet (or English website, for that matter). Other compatible parts such as Linear's LT1431 is rated at a 0.4% initial tolerance, and the price is in line with similar Chinese TL431 parts such as the ALJ TL431A and the CJ431. After checking the WS TL431 chip markings, I setup a simple circuit on my breadboard with a 270 Ohm input resistor (which should give about 9.5mA) from a ~5V USB power supply to test the parts.
The next thing I tried was to crack open the TO-92 package with a pair of pliers in an attempt to expose the die. Like Ken, I was able to expose the copper anode (seen in the very first picture), but was not able to expose the die. The die appears to be around 0.6mm x 1mm, so even if I was able to expose the die, with only a magnifying glass, I doubt I would have been able to see much.
My intention in trying to expose the die was to see if the Wing Shing parts are fuse trimmed like the TI part depicted by Ken. Two fuses give four different combinations of trimming options, which should show up as more than one peak in the distribution of the voltages. Without a die, I could still analyze my measurements and look for peaks. A simple shell command was all I needed:
sort voltages.txt | uniq -c
1 2.506
1 2.508
2 2.509
3 2.510
2 2.511
3 2.512
1 2.513
3 2.514
3 2.515
3 2.516
3 2.517
Even with only a quarter of the parts tested, it is evident the voltages are concentrated around 2.510V, 2.512V, and 2.515/2.516V. While more data points would be helpful, the testing is consistent with fuse-trimmed 0.3% parts.
The first practical circuit I made with the TL431 uses it as a 2.5V zener for battery reconidtioning. I had been using a 270 Ohm resistor to discharge the batteries. With the TL431 acting as a 2.5V zener, a high current red LED and 160 Ohm resistor add up to an addition 2.5V drop, very close to the 4.8V total when discharging a 12-cell battery to 0.4V/cell.
I'd like to have a discharge closer to 0.1C, which would be around 130mA, but the red LED is rated for 50mA maximum continuous current. The TL431 datasheet has a simple constant current circuit, and by making a couple small modifications to that circuit I think I can make a 130mA constant current discharge circuit with a cut-off voltage just below 5V.
2015/09/22 Update
I did a quick test of the dynamic impedance, or the change in reference voltage vs change in shunt current. Increasing the current from 3mA to 15mA resulted in a 2mV increase in reference voltage, indicating a dynamic impedance in the range of 0.15 to 0.2 Ohms.2015/12/20 Update
Based on my testing with an AD584, I now believe these are 2.5V references, not 2.495.
Sunday, August 23, 2015
DC converter modules using fake LM2596 parts
Kerry Wong recently tested some cheap LM2596 DC buck converter modules, very similar to the ones I purchased off Aliexpress a over a year ago for around 80c ea. One of the comments indicated these actually use clones of the LM2576 re-labeled as 2596. The switching frequency of the LM2576 is around 50KHz, vs 150KHz for the LM2596, making it easy to see the difference on a scope.
I pulled out my DS1054Z, one of the DC buck converter modules that I had previously adjusted for 3.3V output, and connected the input to 5V. Here's the output on pin 2:
Measuring of the 5us scale, two cycles takes about 36us, or 18us per cycle, or 55.5kHz. So the ones I received are fakes. I did test the modules after I received them, and found they are good for about 2A @5V with 12V in, so they weren't a total waste of money.
The latest "LM2596" modules I've seen online clearly do not use a real or even fake 2496. The SOIC-8 part appears to be a MPS MP1584. With a switching frequency of up to 1.5Mhz and a smaller form factor, the modules look like a reasonable value at 42c ea, even though they're falsely advertised as LM2596. Strangely, some sellers correctly advertise the same modules as MP1584 converters, but at several times the price.
Sunday, August 9, 2015
Pigggy-prog project ideas
I've started working on a new project I'm calling piggy-prog. The hardware requirements are cheap and simple - a Pro Mini and a breadboard. The pro mini boards are cheaper than a USBasp (around 150c on Aliexpress), and by piggy-backing over a DIP AVR (like the ATtiny pictured above), no jumper wires or custom programming cable will be required. The plan is to support the 8-pin tinies like the tiny13a and the tinyx5, and the 14-pin tiny84.
The piggy-prog should be a lot safer than socket-based programmers like the stk500, especially for the 8-pin parts like the tiny85. With the 8-pin AVRs, putting the chip in the wrong way around (rotated 180 degrees) results in reversing the polarity of the power - Vcc to Gnd and Gnd to Vcc:
By selectively powering the pins of the target chip with the low-current I/O pullup power from the Pro Mini, it is possible to probe and detect the target chip without any risk of damage to either the target chip or the pro mini. Given the lack of a clamping diode on the reset pin going to Vcc, it is possible to detect which pin is reset, and therefore detect when the chip is rotated 180 degrees.
I'll use the stk500 protocol since it is supported by avrdude, and is the protocol used when "AVR ISP" is selected in the Arduino IDE programmers menu. And since my picobootSTK500 bootloader implements a stripped down version of the stk500 protocol, I'll be able to leverage some of the code I've already written.
Proof of concept
To test the idea, I wired up an ATtiny85 on a breadboard with connections to piggyback a pro mini running ArduinoISP.
I modified the code to change LED_ERR from 8 to 2, since pin 8 connects to Gnd on the tiny85, and I changed LED_PMODE to 3. I first tested the ArduinoISP code without the connection to the tiny85, but was always getting a "programmer not responding" error:
$ avrdude -C /etc/avrdude.conf -c avrisp -p t85 -P com16 -b 19200
avrdude: stk500_recv(): programmer is not responding
After connecting an LED and resistor to pin9, I could see the LED heartbeat, but whenever I ran avrdude the heartbeat would stop (and another LED connected to LED_ERR would not light up). This seems to be a bug in the ArduinoISP code, since when I plugged the pro mini into the breadboard on top of the tiny85 it worked fine:
$ avrdude -C /etc/avrdude.conf -c avrisp -p t85 -P com16 -b 19200
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.06s
avrdude: Device signature = 0x1e930b
avrdude: safemode: Fuses OK (E:FE, H:DF, L:E1)
avrdude done. Thank you.
If I can find the but that is causing the ArduinoISP code to hang when there is no target, I'll probably build on that code rather than starting from scratch.
Sunday, August 2, 2015
Ralph's rant: non-portable AVR code
One thing I like about AVR MCUs is that in addition to instruction-set, a number of them have some degree of I/O register-level compatibility. For example, both the ATtiny85 and ATtiny84a have PORTB at I/O address 0x18. Because of this, I was able to write my 64-byte picoboot bootloader, which uses a soft UART on PB1, so that a single binary works on both the tiny85 and tiny84.
I recently though I could take advantage of the register-level compatibility between the ATmega328p and ATmega168p in my arduino compatible picoboot bootloader. The source is already identical, and the only difference in the binary files is the flash start address and the signature bytes reported. My idea was to build a version which returned the signature bytes of the 328p, but that loaded on the 168p. When flashed to a 168p, it would look like a Uno to the Arduino IDE, so people could switch between a 328p board and a 168p board without having to modify the boards.txt file. Obviously projects with a code size larger than 16Kb wouldn't work, but for everything else, I thought it was a great idea. But it didn't work.
The bootloader would initially work OK; clicking Upload in the Arduino IDE would seem to upload the code to the 168p board when Uno was selected as the target, but the uploaded code wouldn't work. I double-checked the fuse settings for the 168p. I flashed the board back to the regular 168p bootloader, selected my modified pro mini 168 target in the boards menu, and uploaded. Everything worked fine, so there was nothing wrong with the board. I compared the disassembly of the normal 168p bootloader and my 168p masquerade bootloader as I was calling it; the only difference was the signature bytes reported. I even reviewed the 168p/328p datasheet in case I missed an important difference - and found nothing.
I then decided to verify that the bootloader was properly flashing the uploaded code and hadn't somehow corrupted the flash. I uploaded a basic blink program using the 168p masquerade bootloader, then connected a USBasp to read back the full contents of the flash, including the bootloader:
avrdude -c usbasp -C /etc/avrdude.conf -p m168p -U flash:r:flash168masq.hex:i
Then I used avr-objcopy to convert the hex file to elf:
avr-objcopy -I ihex flash168masq.hex -O elf32-avr flash168.elf
Finally, I used avr-objdump to disassemble the elf file:
avr-objdump -D flash168.elf
The reset vector was a jump to 0x00ae:
0: 0c 94 57 00 jmp 0xae ; 0xae
...
ae: 11 24 eor r1, r1
b0: 1f be out 0x3f, r1 ; 63
b2: cf ef ldi r28, 0xFF ; 255
b4: d8 e0 ldi r29, 0x08 ; 8
b6: de bf out 0x3e, r29 ; 62
b8: cd bf out 0x3d, r28 ; 61
The code at 0x00ae first clears the zero register (r1), then clears SREG(0x3f). Clearing SREG is redundant since section 7.3.1 of the datahsheet shows that SREG is always cleared after reset. Clearing it again wasn't going to cause any problems though. The next four instructions initialize the stack (SPL and SPH). I immediately recognized this as the problem. I described how this was redundant in Trimming the fat from avr-gcc code. In this case it wasn't redundant, it was wrong! Since avr-gcc thought it was generating code for a m328p, it included the (normally just redundant) code to initialize the stack to 0x08FF. But on the m168p, the end of RAM, and therefore the reset value of the stack pointer, is 0x04FF. With an improperly initialized stack, it was obvious why programs uploaded to the 168p masquerading as a 328p weren't working.
So the superfluous code emitted by avr-gcc not only wastes space, it interferes with releasing binary code that runs on a number of different AVR MCUs. I think it also demonstrates the dangers of developers writing code with a "it shouldn't hurt," attitude rather than a "is it necessary?" attitude. I don't know who first said it, but it was a wise man that recognized when building a project you should include everything necessary but nothing more.
I recently though I could take advantage of the register-level compatibility between the ATmega328p and ATmega168p in my arduino compatible picoboot bootloader. The source is already identical, and the only difference in the binary files is the flash start address and the signature bytes reported. My idea was to build a version which returned the signature bytes of the 328p, but that loaded on the 168p. When flashed to a 168p, it would look like a Uno to the Arduino IDE, so people could switch between a 328p board and a 168p board without having to modify the boards.txt file. Obviously projects with a code size larger than 16Kb wouldn't work, but for everything else, I thought it was a great idea. But it didn't work.
The bootloader would initially work OK; clicking Upload in the Arduino IDE would seem to upload the code to the 168p board when Uno was selected as the target, but the uploaded code wouldn't work. I double-checked the fuse settings for the 168p. I flashed the board back to the regular 168p bootloader, selected my modified pro mini 168 target in the boards menu, and uploaded. Everything worked fine, so there was nothing wrong with the board. I compared the disassembly of the normal 168p bootloader and my 168p masquerade bootloader as I was calling it; the only difference was the signature bytes reported. I even reviewed the 168p/328p datasheet in case I missed an important difference - and found nothing.
I then decided to verify that the bootloader was properly flashing the uploaded code and hadn't somehow corrupted the flash. I uploaded a basic blink program using the 168p masquerade bootloader, then connected a USBasp to read back the full contents of the flash, including the bootloader:
avrdude -c usbasp -C /etc/avrdude.conf -p m168p -U flash:r:flash168masq.hex:i
Then I used avr-objcopy to convert the hex file to elf:
avr-objcopy -I ihex flash168masq.hex -O elf32-avr flash168.elf
Finally, I used avr-objdump to disassemble the elf file:
avr-objdump -D flash168.elf
The reset vector was a jump to 0x00ae:
0: 0c 94 57 00 jmp 0xae ; 0xae
...
ae: 11 24 eor r1, r1
b0: 1f be out 0x3f, r1 ; 63
b2: cf ef ldi r28, 0xFF ; 255
b4: d8 e0 ldi r29, 0x08 ; 8
b6: de bf out 0x3e, r29 ; 62
b8: cd bf out 0x3d, r28 ; 61
The code at 0x00ae first clears the zero register (r1), then clears SREG(0x3f). Clearing SREG is redundant since section 7.3.1 of the datahsheet shows that SREG is always cleared after reset. Clearing it again wasn't going to cause any problems though. The next four instructions initialize the stack (SPL and SPH). I immediately recognized this as the problem. I described how this was redundant in Trimming the fat from avr-gcc code. In this case it wasn't redundant, it was wrong! Since avr-gcc thought it was generating code for a m328p, it included the (normally just redundant) code to initialize the stack to 0x08FF. But on the m168p, the end of RAM, and therefore the reset value of the stack pointer, is 0x04FF. With an improperly initialized stack, it was obvious why programs uploaded to the 168p masquerading as a 328p weren't working.
So the superfluous code emitted by avr-gcc not only wastes space, it interferes with releasing binary code that runs on a number of different AVR MCUs. I think it also demonstrates the dangers of developers writing code with a "it shouldn't hurt," attitude rather than a "is it necessary?" attitude. I don't know who first said it, but it was a wise man that recognized when building a project you should include everything necessary but nothing more.