A look at a Power Designs TP340

It’s fair to say that I’ve been an electronics hobbyist for almost two decades, yet during that expanse of time I’ve never owned a “real” lab bench power supply. At home I got away with wall-warts, ATX supplies, and homebrew linear deals, and at work and school I had access to The Good Stuff. Somehow I’ve gotten by, until I recently felt the need to obtain a quality, low-noise lab supply for home use.


trying not to bury the lede too much

The hardest part was deciding what model of supply to get. I knew I wanted a triple supply, which generally has a ~5V rail and a positive/negative tracking 20V -ish pair. My default is to go with HP/Agilent/Keysight. At work we have Agilent/Keysight E3631A triple supplies, which I don’t enjoy the interface of, and are more spendy than I’d like. (Disclosure: I work for Keysight Technologies. Opinions are my own.) Plus I was told by old-timers that the noise performance of the E36xx couldn’t match the older range of models, which were apparently acquired from a company called Harrison. So for a while I was interested in the HP 6236B, which can do 6V@2.5A and +/-20V@0.5A, enough for my purposes. I started trolling eBay to get an idea of how much they were going for. But then things took an unexpected turn.

A friend of mine watched the eevBlog video on the Power Designs 2005A and decided to get one of his own. The 2005A is a different beast, a precision voltage source, but nonetheless I was intrigued by this company that I’d never heard of, with its brushed-aluminum aesthetic and reputation for high quality. Looking around, I found that Power Designs had (they seem to be dead now) produced some triple supplies as well. The PD 340 and 340A have dual rails that go to 32V@1A, and a peculiar third rail that showcases PD’s “Uniply” design: 6V@5A or 15V@2.5A. Aside from the move to plastic knobs, I am not sure if there is a difference between the 340 and 340A.

What is a Uniply and what is it good for? (A colleague said that it sounded like a cheap brand of toilet paper. He also doesn’t like the brushed aluminum, FWIW.) To set the scene, a linear power supply generally consists of a rectifier stage, a big honking capacitor filter, and a pass element. If, say, the supply produced 20V internally in order to support a 15V output, 5V would be ‘burned’ across the pass element. If 5V was requested at the output, 15V would have to be burned. This is not great in terms of efficiency, to say the least. Now enter the Uniply. Let’s say we change up the rectifier/capacitor scheme to make a 10V rail as well as a 20V rail internally. With the right arrangement of diodes and pass elements, a 15V output will use the 20V rail only. A 5V output will use the 10V rail, up to a certain current, whereupon it will make use of the 20V rail as well. This grand idea (US Patent 3699352) allows for power savings at lower output voltages when a wide output range is required. (Contrast this to a common but different strategy of having many switchable secondaries with different winding ratios.)

I made a $50 offer on a ‘parts’ TP340 that seemed to be in decent cosmetic shape, though one of the fault lights was on, and the offer was accepted. On closer inspection, the fault-y channel had a control pot that had somehow gotten bashed in, popping out the plastic housing of the Bourns 3590S. The pot was open for most of the travel; I deemed it unrecoverable after halfheartedly trying to put it back together, so I had to order a new one. On initial power-on, the dual rails seemed to work, and tracked well.

TP340 as received

as received

The middle pot’s knob had a bit of lean, but it was still working smoothly. Though it’s a mechanical issue and not an electrical one, I find this the most puzzling aspect of this unit. The holes for the pots are 3/8″, which goes with the diameter of the threaded portion of the pot shaft. However there is a feature at the bottom of the shaft which is 0.405″. What the factory had done was try to balance the 3/8″ anti-rotation washer on the 0.405″ feature, to get the pot shaft perpendicular to the surface of the the front panel, but it seems to be a precarious arrangement; indeed the middle pot had developed a lean; a real-world example of spontaneous symmetry breaking. What the Bourns datasheet recommends is to drill a ‘Z’ sized hole in the front panel which the 0.405″ feature can fit into. I was going to enlarge the holes, but my backup idea turned out to be simpler.  A 7/16″ anti-rotation washer fits loosely around the 0.405″ feature and keeps the body of the pot aligned with the front panel. The washer (Grainger 22UJ14) is rather thick but leaves just the right amount of thread on the face side.


big lock washers

I didn’t have a good mental model of this unit before it arrived. Manuals and pictures of the TP340/TP340A are available around the internet from those in the know, but I was still surprised by the design when I opened it up. The back case is held on by the four outermost front screws plus three in the back. The box is mostly empty, with boards on the top and right sides, sheet metal with three transistors on the left, and the bottom open. The power transformer is attached to the back wall, opposite to the heatsink. A mess of wires runs between boards and parts, zip-tied into bundles. The wire used feels like that fancy Teflon-jacketed stuff, silver-plated stranded copper.

I’m not an expert on line voltage safety, but this box seems a little deficient in that regard. My unit has a bit of clear heat-shrink (?) on the power switch, but the terminals on the fuse holder are totally exposed. Line voltage finds its way through two terminals on the front output board, unprotected. The filter cap on the primary is a plain Y5U 1KV type; I replaced it with an X1-rated film cap. I plan to replace the fuse holder whenever I open the box next, since the plastic retaining nut has cracked.

The PCBs are a little odd. They are single-sided, probably laid out by hand, without soldermask. The larger components are attached via hollow turrets which seem totally unnecessary. The big primary filter caps are axial electrolytics, zip-tied to the boards for mechanical strength. Rumor has it that PD swore by manual assembly (likely contributing to their eventual demise) and there is a remarkable amount of rosin splatter on these boards. When I removed the big caps, the smell of the rosin took me back to the cheap Radio Shack solder of my childhood…

About those big caps. There are three 10000uF 25V and two 2200uF 80V that serve as the main filtering caps. A few months ago I acquired a DER EE 5000 LCR meter, so I was able to use it to check out all the electrolytic caps. I found a small one with a high DF that I replaced (C304), but it turns out I was using the LCR completely wrong on the big filter caps. What did I do? Well I failed to realize that big caps have extremely low impedance. If you don’t use a Kelvin connection, which compensates for measuring lead impedance, your results will be wonky. Hence when using grabber cables with the DER EE 5000, I was Doing It Wrong™.


doing it wrong (though one end is lifted)

I thought my caps were dead or high ESR and ordered new ones. Curiously, Digi-Key carries the exact same axial caps, the Illinois Capacitor TTA series. (I am not sure if these were the factory original caps though. There is no capacitor date code, and most of the date codes in this unit are 1987.) Something happened to the font over the years; I think the new font looks cheap.


weighing for fun. old: left, new: right

It was in the process of installing the new caps that I realized my error when measuring the old caps. I went back to the old set, measured them with Kelvin clips, and found something strange. While the dissipation factor (DF) for the 2200uF caps is similar between the old and new (~0.05), it’s quite different for the 10000uF caps. The new ones have DF=~0.2 and the old ones have DF=~0.1! Yes, the new caps would appear to be worse than the old. I had already installed the new caps so I will leave them be, but this is one of those things that leaves you feeling unsatisfied.


hole in 4

One oddity on the inside, perhaps best left for a rainy day. The way my box is wired leaves out the fuse in the picture. There ought to be a wire attached to post 4, but there isn’t. Between the patchy image quality on the schematic and the wire bundle scheme, it’s not easy to tell where the wires are supposed to go.


new feet

And finally, I replaced all the feet, since two were missing. The new feet are Keystone 721 (Newark 25C3781) rubber feet. They are supposedly designed for #4 screws, but I used 6-32 hardware and nylon locking nuts. The screws could be a little shorter (I used 1/2″) but there seems to be enough internal clearance.


one action photo

That’s about it for now. At some point I’d like to verify this power supply’s performance more rigorously. I can check stability and accuracy with a 3456A. Ripple, if the specs are to be believed, I am not equipped to measure. Load step, I will have to come up with an electronic load. Anyhow, I now have a usable lab supply and no more excuse for holding up my other projects.

Posted in electronics, test equipment | Leave a comment

HP 3456A Repair, Part 1

What did you do last summer? It was kinda a long time ago, right? Well, I did some stuff that I wrote up and never got around to publishing. For me, last summer was the summer of aspirational Volt-Nuttery, which involved skimming a lot of EEVBlog Forum posts and NIST papers. The truth eventually sank in, though: Josephson Junction voltage standards are super expensive. Calibrations are expensive. Anything you buy cheap from eBay is not going to have a recent cal. Basically, no free lunch.

Regardless, I decided to dip my toe in the waters by getting a 6.5 digit meter for my home lab. Although a 6.5 is pretty pedestrian these days in real labs, the HP 3456A is a big step up for me, whose ‘nice’ multimeter is an Extech EX505 with 0.5% basic accuracy. Looking on eBay, I thought about getting a newer, standard HP/Agilent 34401A, but the prices put me off (and the vacuum fluorescent display eventually wears out). The 3457A, an older model 7.5 digit meter, was trending at $300, whereas the 3456A is south of $150 if you’re lucky. I took a cursory look at Keithleys but they are not really my style.

I ended up making an offer on one of those “we plugged it in and it turns on but didn’t do any further testing cough cough” listings. It was shipped in a huge box, wrapped up in bubble wrap and ensconced in a nest of packing foam. The first look was not promising — Self-Test produced the dreaded “-3” error:

HP 3456A Self-Test error “-3”

The “-3” error means that the Outguard can’t talk to the Inguard. [Brief overview of the 3456A architecture: The Outguard handles the front panel and GPIB. The Inguard handles the A/D. The Inguard floats with respect to the Outguard, which is referenced to instrument ground. The Inguard and Outguard communicate over a transformer-coupled serial scheme.] The service manual contains quite detailed step-by-step troubleshooting instructions, helpfully. So by unplugging the Inguard comms and sticking in a loopback connection, the problem could be isolated to the Outguard comms section on board A3. With a bit of poking around, I could see that the transistor array U21 on the receiver was not interpreting the signals correctly. For example, the recovered clock looked quite ‘thin’…

Trace 1: A3 at the receiver; Trace 2: A3 U21 pin 14, recovered receive clock

Now U21, a CA3046 transistor array, is, shockingly, no longer commercially available. There is old stock rattling around out there, but I didn’t want to bother tracking one down. What exactly does this part do in this circuit, and can I come up with an alternative repair? It appears that this chip is set up to interpret the serial input data; clock and data are extracted, which go to a shift register. For the clock recovery circuit, two transistors are set up to activate when the input voltage exceeds one V_BE from zero, positive (Q1) or negative (Q2). If either of these transistors are on, the following transistor (Q3) will not be turned on, letting the overall output float high.

Clock recovery at A3 U21

The other connection at U21 (not shown, sorry) is a little mystifying at first glance: base and emitter hanging off the data line, +5V to the collector. As connected, the transistor doesn’t do anything, so what’s the point? My guess is this connection serves as a diode clamp, since the BC junction will act as a clamp to +5V. Additionally, what’s not shown on the CA3046 schematic are the parasitic diodes that are a fact of life in IC design. The receiver circuit must handle an input voltage that goes lower than -0.6V, which would be a problem for the subsequent TTL shift register, so it stands to reason that any negative excursions should be clamped to ground.

What does this mean? This means that we can replace a CA3046 with some discrete transistors and diodes. Nothing special, just 2N3904 NPNs and 1N914 small-signal diodes. The pinout on the 2N3904s is not a perfect match for two of the transistors, but it’s not a big deal. The CA3046 contains a matched pair, but the design doesn’t appear to utilize it in any way.

Replacing A3 U21 with discretes

I would love to tell you that this fix was an immediate success, but the truth is harsher: it didn’t work. Scratching my head, the signal appeared to be right, but the slopes were a little weak. It took me a while to realize that my loopback jumper, constructed from two pairs of Pomona minigrabber/banana cables, represented a considerable inductance, slowing down the slew rate. Lacking the appropriate jumper, I cut to the chase and hooked up the Inguard. The “-3” was vanquished!

This is how I received it…

Well, the “-3” turned into a “-4”, actually. So I did some poking around the analog section. A fuse was loose and the big relay was marked “BAD”, but nothing seemed terribly amiss. It was evidence that someone had already been inside, though. Flipping the box upside down, back and forth, eventually I noticed that the Inguard logic board was skewed. Whoever had been inside the box last hadn’t plugged it in all the way! (It’s possible it came loose in shipping, due to those blasted plastic Nylatch things falling apart.)

I also replaced the two caps on the Inguard power supply that support the unregulated +33V supply. At the time, I thought this made a difference, but now I don’t think it was necessary.

So we come to the present day. This box mostly works. If you leave it alone for a while, or look at it wrong, it locks up and the main relay does a twitch of death. So the next suspect is this DIP socket. There was actually a Service Note issued by HP, saying to get rid of the socket and solder the AM8048 directly to the board, so I feel somewhat confident in my suspicions. Removing that 40-pin thing is going to be a major pain though, so I’ll save that work for a rainy day.

Nice red socket causing issues

Since I’m a glutton for punishment, I ended up buying a second 3456A which I fixed recently, so stay tuned for part 2.

Posted in electronics, repair, test equipment | 1 Comment

Repairing a Canon S100 ‘Lens Error’

A few weeks ago, over Labor Day weekend, my Canon S100 stopped working. The barrel wouldn’t retract — something ticked rapidly inside for a second and the back panel reported a Lens Error. I tried turning it on while twisting one way, pushing down, etc. but aside from one time where it retracted and came back out, nothing seemed to change.

Canon S100 Lens Error

lousy webcam image, new assembly in foreground

This doesn’t appear to be the same error experienced by certain serial number ranges of the S100; mine is a 45xxx whereas the original lens error recall was for serials 29xxx through 41xxx. Also the original error seemed to be related to a flex cable getting loose.

Searching led me to a couple posts by bigboss97 on the DPReview forums. He appeared to have the same error, and more importantly, fixed it by getting a new lens assembly.

Thus I went to eBay and ordered a replacement lens assembly for about $20 (including shipping). What’s interesting is that what I received appears to be a remanufactured/refurbished part, complete with QC stickers. I was only able to preserve the bottom sticker, but I tried to write down the characters on the top one. Intriguingly, the top sticker was dated 9/20/2015, and the bottom one 9/18/2015, which implies to me that these refurb assemblies are produced in relatively small batches. It would be interesting to find out how exactly the pipeline works.

qc sticker

notesTaking apart the camera was pretty straightforward; I mostly followed the video but took off the front early on. A pair of tweezers helps with the flex cable snaps and such. The click ring on the front of the camera is much more substantial mechanism-wise than I expected it to be.

in progress (blurrycam)


As you can see, my replacement assembly works great. Cosmetically it’s got a few scratches, and the top part of the I in ‘IS’ is scratched off. It’s also missing the top screw in the metal slug that’s attached to the sensor.

While I was at it, I decided to tear apart my original assembly.


It’s remarkable what’s inside this thing, and it’s also remarkable that it’s made out of plastic. Unfortunately that also means eventually something will wear down inside the zoom assembly and create too much resistance for the motor to drive. That’s my impression based upon playing with mine, as it required quite a bit of force to move at a certain point (specifically, around the zoom level where the inner barrel backtracks a little before going back out).

I’m a little disappointed that my camera developed this problem after only two years (I bought it used). My previous camera was an SD1000, and it’s still working just fine. My upgrade cycle is closer to 5 years, so I guess I’ll pick up another lens assembly, just in case.

Posted in consumer electronics, repair | Leave a comment


Now for something a little different. A couple years ago I heard about the USB-DVB dongles that you could use for software radio, so I picked one up. Of course it sat around in a box until a few weeks ago, when I scratched my computer-building itch by getting an Intel NUC. The NUC DN2820 is kind of annoying due to the UEFI BIOS, but waiting around for a BIOS update paid off and I was able to install Mint 16 (Mate) using unetbootin. I installed gnuradio from the Mint repository, and librtlsdr 0.5.3 from source.

mjng@nuc ~/librtlsdr-0.5.3/src $ lsusb
 Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
 Bus 001 Device 002: ID 8087:07dc Intel Corp.
 Bus 001 Device 003: ID 046d:c063 Logitech, Inc. DELL Laser Mouse
 Bus 001 Device 005: ID 413c:2110 Dell Computer Corp.
 Bus 001 Device 004: ID 413c:1010 Dell Computer Corp.
 Bus 001 Device 007: ID 0bda:2832 Realtek Semiconductor Corp. RTL2832U DVB-T
 Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

So there it is. One additional wrinkle was that the kernel’s DVB driver was interfering with the RTLSDR library, so I had to turn that off.

mjng@nuc ~ $ rtl_test -t
 Found 1 device(s):
 0:  Generic, RTL2832U, SN: 777711111x

Using device 0: Generic RTL2832U
 Found Elonics E4000 tuner
 Supported gain values (14): -1.0 1.5 4.0 6.5 9.0 11.5 14.0 16.5 19.0 21.5 24.0 29.0 34.0 42.0
 Sampling at 2048000 S/s.
 Benchmarking E4000 PLL...
 [E4K] PLL not locked for 51000000 Hz!
 [E4K] PLL not locked for 2210000000 Hz!
 [E4K] PLL not locked for 1105000000 Hz!
 [E4K] PLL not locked for 1239000000 Hz!
 E4K range: 52 to 2209 MHz
 E4K L-band gap: 1105 to 1239 MHz
mjng@nuc ~ $ rtl_fm -f 103.7e6 -M wbfm -s 200000 -r 44100 - | aplay -r 44100 -f S16_LE
 Found 1 device(s):
 0:  Generic, RTL2832U, SN: 777711111x

Using device 0: Generic RTL2832U
 Found Elonics E4000 tuner
 Tuner gain set to automatic.
 Tuned to 104016000 Hz.
 Oversampling input by: 6x.
 Oversampling output by: 1x.
 Buffer size: 6.83ms
 Sampling at 1200000 S/s.
 Output at 200000 Hz.
 Playing raw data 'stdin' : Signed 16 bit Little Endian, Rate 44100 Hz, Mono
 underrun!!! (at least 16487.192 ms long)

Playing FM radio takes 9-10% of the CPU, which although it is a Celeron, it’s a Bay Trail dual-core Celeron…

One can look for LTE signals and use them to do crystal calibration. I thought this was pretty interesting.

./CellSearch --freq-start 715e6 --freq-end 768e6 --correction 0.9999721 --ppm 10
 Detected the following cells:
 A: #antenna ports C: CP type ; P: PHICH duration ; PR: PHICH resource type
 CID A      fc   foff RXPWR C nRB P  PR CrystalCorrectionFactor
 257 2    739M  1.63k -12.9 N  50 N one 0.99997430722744262699
 161 2    751M   1.6k -30.7 N  50 N one 0.99997423474091573503

There seems to be an amazing amount of info out there now. I’m quite interested to dig deeper.

Posted in linux, sdr | Leave a comment

Xilinx PlanAhead/XPS annoyances

So I know Xilinx wants everybody to move on to Vivado now, but being wary of new software, I am still using PlanAhead. One very annoying thing about the whole IP core business is figuring out how to roll your own without failing the implementation stage. I just did one where I could swear that the presence of an underscore in the filename killed it. Yep.


When I make AXI peripherals, I’ve been putting my logic into a hierarchy that I then instantiate inside a Xilinx-generated AXI template. Otherwise it’s hard to test without using a BFM. In order to do it this way, I have to add one line to the MPD with the name of the module. It’s the bottom one here:

lib proc_common_v3_00_a  all 
lib axi_lite_ipif_v1_01_a  all 
lib fifotest_v1_00_a user_logic vhdl
lib fifotest_v1_00_a fifotest vhdl
lib fifotest_v1_00_a fifotestcore vhdl

And would you believe that when the module was named “fifotest_core”, it didn’t want to work?

That one was a pure HDL module (it has a Xilinx FIFO instance, but that’s easy). What’s really annoying is when you want to put a Core Generator module into your peripheral. Apparently you need to put your NGCs into a /netlist folder, but I haven’t figured out how to get the PAO and MPD and such correct by hand. So far I’ve ended up completely re-importing everything in the XPS wizard, which is a little messy and annoying, but works. Par for the course I suppose.

Posted in Uncategorized | Leave a comment

MicroZed & Linaro: odds and ends

It’s been a bit quiet here because I screwed up my board and MicroZed. The PS still works but I seem to have blown out parts of the FPGA and maybe the digital side of one ADC. How did this happen? I put a terminator on DAC channel B while it was active. Well, that’s what I thought was the cause; testing found the DAC to be fine. But it seems that in putting on the terminator I flexed the board enough to upset the 2.5V powergood signal, which promptly turned off everything else. My guess is that the unclean shutdown put all the energy through a nasty path. Anyway, I bought a new MicroZed (the ethernet lights don’t blink maniacally on this one) and fixed up my backup board. Before I get back into the deep end, though, I wanted to organize some notes on some various aspects of the platform.

Avahi for great laziness

Avahi is a protocol for enabling network devices to be discoverable. That means no more figuring out the IP address through the serial terminal and writing it down so you can type it out repeatedly in the course of development. Whew. It turned out to be really easy to set up once I found the right writeup to follow. It’s just a matter of installing the daemon on the MicroZed:

# apt-get install avahi-daemon

At this point, assuming you have the right utilities on your client machine, and everything is on the same subnet, the device should be discoverable (avahi-browse -a). Unfortunately I didn’t confirm this for myself, but powered ahead and set ssh to be a discoverable service:

# cp /usr/share/doc/avahi-daemon/examples/ssh.service /etc/avahi/services/
# restart avahi-daemon

Then I can see the following on another machine:

mjng@X200s ~ $ avahi-browse -a | grep aleph
+   eth0 IPv6 aleph                                         SSH Remote Terminal  local
+   eth0 IPv4 aleph                                         SSH Remote Terminal  local
+   eth0 IPv6 aleph [00:0a:35:00:01:22]                     Workstation          local
+   eth0 IPv4 aleph [00:0a:35:00:01:22]                     Workstation          loca

And now I can ssh directly to aleph.local. At least I can from my Mint laptop; still have to ask the admin to install the avahi utils on the Red Hat box.

Boot file updating like a boss

After a few iterations I got tired of updating binfiles and devicetrees “by hand”: physically removing the microSD and putting it into a card reader. It may be blindingly obvious to you, dear reader, but it took me a while to realize that I could probably update the boot files from inside Linux.

Following the ADI/Jan Gray method, my SD card is set up with two partitions: one contains the boot files, and the other contains the rootfs. It stands to reason that I should be able to mount the boot partition and modify it. Thanks to some clues in the Zedboard forums, I was able to figure out how to do this.

The key is identifying the block devices that correspond to the SD card partitions.

# ls -l /sys/dev/block | grep mmcblk
lrwxrwxrwx 1 root root 0 Mar 15 00:08 179:0 -> ../../block/mmcblk0
lrwxrwxrwx 1 root root 0 Mar 15 00:08 179:1 -> ../../block/mmcblk0/mmcblk0p1
lrwxrwxrwx 1 root root 0 Mar 15 00:08 179:2 -> ../../block/mmcblk0/mmcblk0p2

Then we can create a device entry for the first partition and mount it as a filesystem. I wrote a little script for this:


if [ -e /dev/mmcblk0p1 ]; then
    echo "device already exists, mounting"
    mount /dev/mmcblk0p1 /root/boot
    echo "mknoding device and mounting"
    mknod /dev/mmcblk0p1 b 179 1 && mount /dev/mmcblk0p1 /root/boot

(At the time I wasn’t sure if mknod was persistent across reboots, but it appears that it is.) So now I mount the boot partition to the folder /root/boot, where I can copy files to it from inside Linaro. I also have a staging area and a few scripts that are set up to scp a new bootfile, dtb, uImage, etc. over from my development machine. When the new files are in place, it’s a simple umount and shutdown -r now to complete the cycle.

Much network performance

I installed iperf 2.0.5 on both the MicroZed and my laptop (X200s running Mint 14), and thought I’d share the results.

root@aleph:~/iperf-2.0.5/src# ./iperf -c 129.79.x.x -t 60
Client connecting to 129.79.x.x, TCP port 5001
TCP window size: 20.0 KByte (default)
[  3] local 129.79.x.x port 53334 connected with 129.79.x.x port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-60.0 sec   674 MBytes  94.2 Mbits/sec

root@aleph:~/iperf-2.0.5/src# ./iperf -c 129.79.x.x -P 2 -t 60  
Client connecting to 129.79.x.x, TCP port 5001
TCP window size: 44.1 KByte (default)
[  3] local 129.79.x.x port 53337 connected with 129.79.x.x port 5001
[  4] local 129.79.x.x port 53336 connected with 129.79.x.x port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-60.0 sec   336 MBytes  46.9 Mbits/sec
[  4]  0.0-60.0 sec   339 MBytes  47.4 Mbits/sec
[SUM]  0.0-60.0 sec   675 MBytes  94.3 Mbits/sec

root@aleph:~/iperf-2.0.5/src# ./iperf -c 129.79.x.x -u -b 100m -t 60
Client connecting to 129.79.x.x, UDP port 5001
Sending 1470 byte datagrams
UDP buffer size:  160 KByte (default)
[  3] local 129.79.x.x port 40334 connected with 129.79.x.x port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-60.0 sec   685 MBytes  95.7 Mbits/sec
[  3] Sent 488345 datagrams
[  3] Server Report:
[  3]  0.0-60.0 sec   684 MBytes  95.7 Mbits/sec   0.124 ms   82/488344 (0.017%)
[  3]  0.0-60.0 sec  1 datagrams received out-of-order

This was through a ProCurve 408 (10/100). Watching top during transfer, CPU utilization hit 14% but stayed mostly around 9%. I’m impressed. Will have to find a gigabit switch to try out.

One weird trick that symlinks hate

This is just a note to myself. When copying over the kernel module build products, one can’t simply scp ’em over without bringing along the entire kernel tree for the ride. So a trick is to pipe tar through ssh:

cd /destination/directory
ssh user@remote.host "cd /original/directory; tar cf - ./" | tar xvf
Posted in Uncategorized | Tagged | Leave a comment

MicroZed: SPI

I did two arguably dumb things that kept my SPI experience from being smooth sailing. The first was putting in a 3-8 decoder on the slave select lines and assuming there was driver support for it. The second was not connecting the MISO line for all of the devices on the bus save one; when I was designing, this had seemed like one less net to route, but during bring-up it was like driving a car with the windshield blacked out.


Well, let’s start at the beginning. In XPS, I activated SPI 1 and assigned it to the MIO range which corresponds to the PMOD on the MicroZed. Looking at various devicetree examples, it seemed that the generic spidev driver was the way to go. Of course this meant rebuilding the kernel with the spidev option (I have gotten quite accustomed to building the kernel nowadays), which I opted to do as a module. Figuring out the proper devicetree entry for the PS SPI device was, as Jan Gray put it, very cargo-cult. I still haven’t bothered to figure out what an aper_clock is, but I guess I picked the right one.

I decided to go with Python for testing the SPI bus. (Coming from a FPGA/microcontroller background, part of me finds this faintly ridiculous. But gosh, it’s so convenient.) In order to install py-spidev, I had to apt-get the python-dev package first. Then with a bit of 3rd-party documentation, I was ready to move on to the next step.

I needed to see if my devices were being talked to, and like I mentioned at the top, I had helpfully left the MISO pins disconnected for the most important chips. Since readback was impossible (without annoying board surgery) I needed some other approach. Thankfully there was one straightforward solution: chip 0 on my bus is an AD9512 clock distribution chip that has an output to the PL. By default, the output in question has a divide-by-4. Going back to Jan Gray’s uio counter example, I made a version with a register clocked from an external source. With one counter clocked internally and one counter clocked externally, I could check whether the AD9512 was taking SPI writes.

Of course, there was another wrinkle. Working from the loop example in the tightdev.net doc, I spammed the bus in order to see which SS pins were going down for device 0. It was easy enough to see with a multimeter. In this way I found that the default driver only supports one-hot (or is that one-cold?) SS. This was a problem, since I’ve got six devices total and a 74HC138 on decode duty. Ultimately I had to sit down with the driver code and figure out where to modify it; thankfully it was just a couple lines once I understood enough of what was going on. The file in question is drivers/spi/spi-xilinx-ps.c; I’m still on the 3.10 kernel whereas the ADI kernel repo has moved on. (I backported a couple of bug fixes, but beyond a certain point there was a reorganization that I haven’t bothered to look through.) The first change is in the xspips_init_hw function, where the PERI_SEL bit needs to be set.

//xspips_write(regs_base + XSPIPS_CR_OFFSET, 0x0000FC01);
xspips_write(regs_base + XSPIPS_CR_OFFSET, 0x0000FE01);

Next is the function that handles the chip select, xspips_chipselect. As it stands, the code just left-shifts by the bus number. It is also possible, I might add, to set 0b0111, which is reserved according to the documentation in the back of UG585. Naturally the docs don’t bother to explain how things work in 3-8 mode, so we guess that the lower three bits of the CS field map directly to the SS lines.

/*ctrl_reg |= (((~(0x0001 << spi->chip_select)) << 10) &
ctrl_reg |= (((0x7 & spi->chip_select) << 10) &

Anyway, after modifying the driver and compiling yet another kernel, SPI was working correctly. Writes to the AD9512 had the expected effect.

root@aleph:~# python
 Python 2.7.3 (default, Sep 26 2012, 22:50:53)
 [GCC 4.7.2] on linux2
 Type "help", "copyright", "credits" or "license" for more information.
 >>> import spidev
 >>> spi = spidev.SpiDev()
 >>> spi.open(32766,0)
 >>> spi.xfer2([0x00,0x52,0x00]) # set clk/2
 [255, 255, 255]
 >>> spi.xfer2([0x00,0x5a,0x01]) # update
 [255, 255, 255]
 >>> spi.xfer2([0x00,0x53,0x80]) # set clk/1
 [255, 255, 255]
 >>> spi.xfer2([0x00,0x5a,0x01]) # update
 [255, 255, 255]

While in another terminal:

root@aleph:~./a.out -d /dev/uio0
Estimate clock speed 1:100.012672 MHz
Estimate clock speed 2:31.255272 MHz      // divide by 4
root@aleph:~# ./a.out -d /dev/uio0 
Estimate clock speed 1:100.011963 MHz
Estimate clock speed 2:62.511162 MHz      // divide by 2
root@aleph:~# ./a.out -d /dev/uio0
Estimate clock speed 1:100.012581 MHz
Estimate clock speed 2:125.020943 MHz     // bypass divider

It was also possible to do a DAC -> ADC test with the MCP4822 and MCP3202 on the bus.

 >>> spi.open(32766,4)
 >>> spi.xfer2([0x30,0xff]) # write 0x0FF to DAC
 [255, 255]
 >>> spi.close()
 >>> spi.open(32766,5)
 >>> spi.xfer2([0x01,0xa0,0x00]) # read out ADC
 [255, 224, 156]                 # take last 12 bits

It turns out that the mapping isn’t 1:1 because the DAC uses a 2.048 V reference. Oh well.

It’s a little annoying to think about how much time it took to get to this point, compared to running on bare metal, but I guess them’s the breaks. At least I can move on to the FPGA side of things now.

Posted in linux, zedboard | Leave a comment

MicroZed: I2C through the EMIO

Sometimes it feels like this project goes really slowly. I guess it’s because I’m juggling a number of things and don’t always have the time to do a deep dive into Zynq stuff. Anyway, the next goal is some low-hanging fruit: use the PS I2C block to talk to my I2C peripherals, on Linux. My custom carrier board uses up the MIO/PMOD for SPI (which is the next goal I guess), so I2C has to go through the EMIO to the PL.


I went back to my MicroZed project, which actually already had the I2C selected in XPS — without constraints, the EMIO doesn’t get connected. You can see my MIO config below; a few other things in there are specific to my design.

Screenshot-Zynq PS MIO Configurations

To get the I2C through the EMIO to the PL, first have to set them as external pins in XPS.

Screenshot-Xilinx Platform Studio (EDK_P.68d) - -nfs-apiucf3-scratch-mjng-zedboard-microzedlinux-microzedlinux.srcs-sources_1-edk-sys-sys.xmp - [System Assembly View]

We also need to make some constraints, which we do by creating a new constraint source.

# connect PS I2C to PL through EMIO
# SCL on microzed JX2 13 -> bank35 G14
NET processing_system7_0_I2C0_SCL_pin IOSTANDARD=LVCMOS25 | LOC=G14 | PULLUP;
# SDA on microzed JX2 14 -> bank35 J15
NET processing_system7_0_I2C0_SDA_pin IOSTANDARD=LVCMOS25 | LOC=J15 | PULLUP;

(I forgot to add pullup resistors to my I2C lines, so I’d like to see if I can get by with the weak built-in pullups and a reduced bus speed.) I imagine that setting the constraint file “as target” is important… I didn’t bother to try it without. And don’t forget to regenerate the top HDL. From there, it’s straightforward to rebuild the FSBL and boot binfile (I should figure out how to script this).

Device Tree shenanigans

It’s time to take a closer look at the DTS. I started by looking at zynq-zed-adv7511-xcomm.dts, which includes zynq-zed.dtsi at the top and adi-fmcomms1.dtsi at the bottom; this is the default device tree for the ADI/Zedboard demo. Looking at zynq-zed.dtsi, we need everything here (since the MicroZed has 1GB of RAM, we could increase the memory address range here, I think, but that comes later). Looking at zynq.dtsi, and comparing to the Address Map in SDK, we currently don’t have a number of things that are in the file, yet Linux works fine (file this under ‘things to look into later’).

Anyhow, I hacked together a DTS file with only one include, going mostly from the ADI/Zedboard example and taking the I2C portion from the ZC702 example. I tried adding a line to set a local-mac-address for the ethernet, but the last two octets show up as 01:22; I think I’ve seen a post somewhere online with similar results.

Let’s take a closer look into how the device tree works. During boot, the “i2c-clk” field in the device tree gets punted to the appropriate driver (defined by the “compatible” field). By doing a bit of grepping in the linux/drivers directory, we find the appropriate file (i2c-xilinx_ps.c). There appears to be a bit of code in the driver dedicated to calculating the right divider settings from i2c-clk, which turns out to be the desired bus speed in Hz. So I’ll set that to 100000 to start out with.


There’s a package called i2c-tools that contains some useful utilities (here are some useful examples).

root@aleph:~# i2cdetect -l
i2c-0    i2c           XILINX I2C at e0004000              I2C adapter
root@aleph:~# i2cdetect -F 0
Functionalities implemented by /dev/i2c-0:
I2C                              yes
SMBus Quick Command              no
SMBus Send Byte                  yes
SMBus Receive Byte               yes
SMBus Write Byte                 yes
SMBus Read Byte                  yes
SMBus Write Word                 yes
SMBus Read Word                  yes
SMBus Process Call               yes
SMBus Block Write                yes
SMBus Block Read                 yes
SMBus Block Process Call         no
SMBus PEC                        yes
I2C Block Write                  yes
I2C Block Read                   yes

It seems that the proper driver was loaded, thanks to the device tree entry. Now time to probe the bus (read about the -r flag before you do this):

root@aleph:~# i2cdetect -r 0
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0 using read byte commands.
I will probe address range 0x03-0x77.
Continue? [Y/n] 
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 1e -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: 30 31 -- -- 34 35 36 -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- 51 -- -- -- -- 56 -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

Hmm, I wasn’t expecting this many devices… Let’s check the datasheets.

I have two chips on my bus. First up is a RTC-8564, which should be at 0xA3/0xA2. I’m going to guess that i2c-tools drops the R/W bit and shifts everything over, giving us 0x51. Great, it’s in there.

The other is an Atmel AT30TSE004A EEPROM/temp sensor. It has three addresses (the three LSB are user-selected):

1010 110x -> 0101 0110 -> 0x56 (EEPROM R/W)
0110 110x -> 0011 0110 -> 0x36 (EEPROM other)
0011 110x -> 0001 1110 -> 0x1e (temp sensor)

So what are the remaining ones: 30, 31, 34, 35? I’m pretty sure there’s nothing else on this bus. It’s probably due to the weak pullups. Anyway, I’ll try reducing the bus frequency in the device tree and see if they go away.

But for the time being I’d like to see if it’s possible to read a temperature or manufacturer ID. The temperature part of the Atmel chip uses the annoying LM75-style “pointer register”, so it doesn’t look like i2cget will work for this. I’ll use py-smbus, for which documentation appears to be rather hard to find.

root@aleph:~# python
Python 2.7.3 (default, Sep 26 2012, 22:50:53) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from smbus import SMBus
>>> bus = SMBus(0) # i2c bus 0
>>> bus.read_i2c_block_data(0x1e,0x07,2) # addr, reg, bytes
[34, 0]
>>> bus.read_i2c_block_data(0x1e,0x06,2)
[17, 20]
>>> bus.read_i2c_block_data(0x1e,0x05,2)
[195, 220]
>>> bus.read_i2c_block_data(0x1e,0x05,2)
[195, 222]
>>> bus.read_i2c_block_data(0x1e,0x05,2)
[195, 220]

I was scared for a moment, but then I realized that the numbers were decimal. Register 0x07, the device ID, is supposed to be 0x2200, which checks out. Reg 0x06, the manufacturer ID, is supposed to be 0x1114, which also looks good. The temperature is a little annoying, since it runs from bit 11 down to bit 1. I calculate about 62 degrees C, which… (ouch, yes, it does seem to be that hot. I ran a fan on it a little, which got it down to 40.)

Well, even with the mystery addresses, I2C seems to work okay. The next thing to try is to activate the real-time clock’s entry in the device tree. And then onward to SPI.

Addendum: Reducing the bus clock to 25 kHz didn’t make a difference in terms of addresses responding to queries… I should take a look at what the code actually does. Reducing the bus to 1 kHz just fails.

Posted in linux, zedboard | 2 Comments

MicroZed: UIO notes, kernel modules

UIO notes

I tried following part 2 of Jan Gray’s guide, but ran into some snags. Looking at the history of the ADI/Xilinx kernel repo, it seems that there were some major changes in the UIO code over the summer. I’m using a checkout from September, after things were consolidated, and try as I might, I was unable to figure out the magic words to put into the device tree to get the counters to show up under /dev. If I had more time or patience, I would sort through the diffs, but I perversely figured that my time is better spent learning how to write kernel modules.

EDIT: Right after I posted this, I noticed that I have a /dev/uio0 device listing! I’m pretty sure it wasn’t there previously… I’m not exactly sure which device tree I’m using, but I think it’s one with a fake interrupt. I’ll check later.

root@aleph:~# ls -l /dev/uio0
crw------- 1 root root 250, 0 Dec 31  1969 /dev/uio0
root@aleph:~# cd /sys/devices/62600000.counters/uio/uio0/
root@aleph:/sys/devices/62600000.counters/uio/uio0# ls
dev  device  event  maps  name  power  subsystem  uevent  version
root@aleph:/sys/devices/62600000.counters/uio/uio0# cat dev name version

The corresponding device tree entry is

counters@62600000 {
        compatible = "generic-uio";
        reg = < 0x62600000 0x1000 >;
        //interrupts = < 0 57 0 >;
        //interrupt-parent = <&gic>;

Kernel Modules

In order to build kernel modules, we need kernel headers. Since I’m using a “handbuilt” kernel with a prebuilt distro, simply apt-getting kernel headers isn’t going to work. And while being able to develop directly on the MicroZed would be nice, my linux build directory is 2.3 GB and I’m not sure what I can afford to cut out. So for the time being I will just cross-compile modules and scp them over to the MicroZed.

Before all that though, I made a new config file and a few dts files and committed them locally. e.g.

$ pwd
$ diff zynq_xcomm_adv7511_defconfig zynq_uio_defconfig 

You have to commit them with git, otherwise you end up building a “dirty” kernel. (I ended up rebuilding once because of that. Thankfully I’ve discovered multithreaded make, e.g. make -j6.) For the modules, I targeted a different location just to be clear what ended up there.

$ make INSTALL_MOD_PATH=/scratch/mjng/modules modules
$ make INSTALL_MOD_PATH=/scratch/mjng/modules modules_install

Then I copied that stuff over to the MicroZed’s /lib/modules (note that scp will follow symlinks by default, so be careful not to copy over your build tree if you don’t actually want to). Following the Linux Kernel Module Programming Guide, I compiled hello-1.c using the following makefile, set up for cross-compiling:

export ARCH:=arm
export CROSS_COMPILE:=/opt/Xilinx/14.6/ISE_DS/EDK/gnu/arm/lin/bin/arm-xilinx-lin
KDIR := /scratch/mjng/zedboard/linux
obj-m += hello-1.o

    make -C $(KDIR) M=$(PWD) modules

    make -C $(KDIR) M=$(PWD) clean

The resulting kernel object insmod-ed just fine, and produced the expected output in /var/log/syslog.

root@aleph:/lib/modules# insmod ./hello-1.ko 
root@aleph:/lib/modules# cat /proc/modules 
hello_1 734 0 - Live 0xbf06c000 (PO)
ipv6 346756 16 - Live 0xbf000000
root@aleph:/lib/modules# rmmod hello-1
root@aleph:/lib/modules# tail /var/log/syslog
Nov 14 21:12:06 aleph kernel: hello_1: module license 'unspecified' taints kernel.
Nov 14 21:12:06 aleph kernel: Disabling lock debugging due to kernel taint
Nov 14 21:12:06 aleph kernel: Hello world 1.
Nov 14 21:14:05 aleph kernel: Goodbye world 1.

Anyway, that’s where I stand. I’m planning to skim the LKMPG and the Linux Device Drivers book, and we’ll see where this rabbit hole goes.

Posted in linux, zedboard | Leave a comment

MicroZed: First Impressions

I finally got my MicroZed (in Avnet leadtime, apparently 1 week means 4 weeks) so I gave it a spin. I was pleased to see that the package included a retail-packaged 4GB Kingston microSD card, and a very nice Monoprice USB cable. My board has a rather long patch wire that looks to be securely glued down.

It plugged in and worked right out-of-the box this time; the jumper settings were what the quick-start card said they’d be. Note though, that the boot select jumpers are in reverse order and upside down from how the schematic has them… turn the board 180 degrees, I guess.

I built an empty-PL project, selecting the xc7z010clg400-1 and using the XML file on the Zedboard website. (It built really quickly.) From there I exported to SDK and built the FSBL. I took the uboot, kernel, and no-PL device tree from my previous explorations with the Zedboard, loaded them up with Linaro into the SD card, et voila, Linux.

I spent some time looking at cooling solutions for the Zynq chip. It’s about 17 or 18 mm square, and the mounting holes are about ? mm apart. So far I haven’t found anything that fits the holes. Also, the 1210 caps right at the chip are really tall, which means that the contact area of the cooler needs to match that of the chip. Sure, the little heatsink like the one on the Zedboard would work but I feel like there must be something better out there.

Posted in electronics, linux, zedboard | Leave a comment