Monday, 10 October 2016

Broken 53131A Frequency Counter

While ago I bought a broken 53131A frequency counter from ebay. The repair turned out to be more of a jigsaw puzzle than I expected but I got there in the end.

Buying the Unit

For me to buy a broken unit from overseas means the unit is pretty cheap. In this case it was cheap but not super cheap. I asked the seller what options were included and he said it included the ovenised time-base. I figured just the parts value was high enough to be work it. He also said the unit hadn't been opened.

I placed the order and waited for the ebay shipping program to get it here. The shipping cost wasn't too bad.

When it arrived the first thing was the box was atrocious -I am amazed it made it here at all. The cardboard was soft and while in contained packing peanuts there was nothing to stop it moving around. Total rubbish!

The next problem was that when I picked up the unit it rattled. The screws were loose and it clearly had been opened before. The power supply board wasn't even screwed in and was rattling loose inside the box


So I started looking at the power supply and not only had it been removed but a repair had been attempted. What I found was that
  • The main switching transistor (on the big heatsink) was missing.
  • A Zener diode (ZD1) near the switcher was missing
  • A diode was missing
  • The main filter caps had been replaced (and with 250V rated ones although this turned out to be ok - see below).
  • The fan was missing
I approached the seller about this. I didn't really want to send it back as then I lose the shipping twice. We negotiated a reduced sale price and I notched this up to experience.

He is still selling stuff though and he has another advert with the same misleading text and similar blurry photo. The seller is mannd1deborah Here is one of his dodgy ads. You've been warned!

The Damage

The power supply seems to have suffered a pretty catastrophic failure of the main switching transistor. There is a significant scorch mark on the PCB around it and a few associated components have been removed by whoever attempted the repair.


A few of the tracks lifted in the area around where it got hot. Also on the secondary side there is a diode with some adjacent heat damage to the board. The fact that the fan was missing made me think it must have failed and caused the power supply to overheat.


Missing Parts

I downloaded the component level service manual from Keysight for the unit but unfortunately it doesn't include the schematics of the power supply. The power supply is labeled 'SMP-43DP' in the silkscreen and 'SMP-43DL' on the bottom of the metal plate that holds it and is made by Delta.

I tried contacting Delta but they said they had no records on it and told me to contact Keysight. I contacted Keysight and got nothing. In fact you can buy the power supply as a spare part but when I asked about it my email was never responded to.

In the past when I repaired a switch mode supply like this the first thing would be to look up the datasheet for the main switching controller IC as often the circuit is very similar to the typical one listed in the datasheet. In this case however the unit is old enough that it doesn't have an IC controlling it.

My first assumption was that the main transistor would be some kind of switching MOSFET.  I asked on the HP/Agilent Test equipment yahoo group and someone pointed out that the zener diode going to one of the transistor legs is connected to the positive rail of the main filter caps (i.e. 340V) so that wouldn't be much good for clamping a gate. The conclusion was that it must be a bipolar transistor.

Also the guy on the yahoo group explained why the capacitors are only rated for 250V - the thing is there are four of them and they are not all in parallel but the arrangement is more complicated. It turns out the supply contains a circuit for detecting the mains input voltage and if the voltage is around 100-110V it will use the bridge rectifier in a configuration where it doubles the voltage (there is a good description of how this works here). The upshot is that if the supply is running somewhere like the US where the mains voltage is 110V then the point between the pairs of capacitors is .at the input voltage but in Europe or Australia then the caps in series have 220/240V across them (in total).

There are a bunch of youtube videos where people teardown or repair these counters (such as this one and this one). The problem is that all of these have a different version of the supply. So even if I could see the parts in question then they will be different. Someone called JF2014 even posted a schematic on the EEVBlog of a 53131A supply but it too was for the other version).

Subterfuge and Guile

So then what are the missing parts? So I started looking at transistors rated for 1000V VCE and ones that could handle a couple of amps. What worried me is that guessing might result in a charred mess.

I found a guy selling a replacement power supply for a 53131A on Amazon and US ebay (doesn't ship internationally) which was the same version as mine. He wanted more for the supply than I paid for my unit (and shipping) so it wasn't an option.

I contacted him and asked very nicely if he would read the numbers off the big transistor and the adjacent zener diode. After a couple of emails back and forward (including some pictures and arrows) he said the transistor was a BUV48A. Winner! I didn't have the heart to ask him to go back and get the numbers off the zener however.

So luckily this transistor is available on RS - not cheap but available. So good news as now I have the most critical part covered.

Other Parts

After much googling I figured out the fan is a Fonsan Delta DFB0412M. Believe it or not I found some parliamentary expenditure report that listed 53131A and the fan part number. Since then I found a fair bit of discussion about using quieter fans and Gerry Sweeney modified his counter to switch off the power when the switch is clicked. Anyway I found a seller on ebay that sells the original fan and ordered one (again - not cheap).

So the missing diode was likely to be exactly the same as the one next to it which was a RFP203 - a chunky 4A, fast recovery diode intended for swithmode supplies. I found a suitable (i.e. fast and high current handling capability) replacement and ordered one. The diode on the secondary side was much smaller and was in a tight spot so using the chunky diode wouldn't work. I ended up just ordering a EGP20D.

Zener Diode


So now I only had one part to work out and that was the zener diode. The only thing I could think of was to draw out the circuit and try to work out what voltage rating it needed to have.

Initially I started drawing the entire circuit but this was pretty time consuming and it occurred to me that I only needed to work out the part near the switching transistor.

I sketched out the following:

While probing around to draw the circuit I noticed a short in places where I didn't expect to see one. It looked like the short was Q1 so I removed it from the board and sure enough it was dead. Unfortunately it is a discontinued Sanyo part (2SD1247) so I ordered some NOS from Greece on ebay.

There are a few interesting things here:
  • The frequency is determined by the resonant frequency of the transformer primary and other capacitors
  • The feedback is provided not by an opto-coupler but by a transformer! Talk about old-school.
The problem was I couldn't see what would need the voltage drop of ZD1. It looked too me like if you removed ZD1 the 47K resistor (R6) would limit the current enough that it would all work. I put the circuit into LTSpice and by measuring a few inductances and capacitances using my LCR meter I could get the circuit to run under simulation (even with the wrong transistor models). The problem is it didn't seem to make a big difference if I made the zener 10V or 200V.

I put up a question on EEVBlog but after a couple of days nobody replied. I then put up the same question on the HP forum and I got an answer - basically the zener prevents the supply from starting if the voltage on the capacitors is too low. So if instead of 110 the input voltage was 80V or if it was 180V instead of 220V this would prevent it running. Basically the zener needs to be rated for around 180V to prevent the circuit starting.

Putting it all Together

So the 180V zeners arrived from RS, the transistors from Greece and the fan was here. I had everything I needed and put it together.

I attached the supply to my isolation transformer, stood back and switched it on - I was elated to see the fan spin as this must mean the primary is switching! I did some more testing and found the 12V wanders a bit if the 5V is under no load (I used my dummy load to load up 5V as it is the highest current output). Otherwise all the output voltages were very good. 

Crossing fingers and toes I connected it up to the counter and it worked!


I haven't checked the performance specification but it seems very close. The output of my signal generator measures to within 1Hz up to 20Mhz. They can't both be out by the same amount!

The annoying thing is the fan run constantly even when the device is off. The screen is just a little dim but quite usable. Overall this turned out to be a good score and another valuable learning exercise.

Lab Power supply Pi Control and Auto-Cal


The Raspberry PI power input control boards arrived and I assembled one and tested it. I built a wiring harness for the fan and for the temperature sensors and attached the temperature sensors to the heatsink. I built the final channel and put it in the case.

Also control interface got re-oriented and got a much needed speed up, I figured out how to start the software when the operating system boots and I built some code to automatically calibrate each channel and store the calibration values in EEPROM.

Raspberry Pi Power Control Board


So the power control board came back and looked pretty good overall. One problem was that the holes for some of the connectors were a bit tight. I tried slightly reaming out the holes but stuffed up one board in the process. Then it occurred that I could just file down the pins of the connector and this worked really well.

Oddly the female header connector for interfacing with the Raspberry PI isn't stocked at my local electronics store and so I had to order one from RS. This one connector however cost $5AUD which is totally silly.

I built a small board for the LED and power switch. The idea is the board is mounted on stand-offs that are just tall enough for the switch to protrude through the front panel. The problem was that there wasn't enough space for the connector as it has to mount on the component side (same side as the switch and LED) as it is a single sided PCB. To get around this I just soldered wires directly to the board and hot-glued them for mechanical strength. I screwed standoffs onto the board and hot-glued this to the back of the front panel. This works Ok overall.



Otherwise everything fitted nicely and worked very much as the proto-type did. Pretty happy with it. Only thing is the LEDs are a bit bright.

Temperature Sensors

In hindsight I really wish that I had integrated temperature sensing into each PSU channel and read the temperature via the channel interface.

Instead I built a wiring harness for the temperature sensors that basically wires them all in series. The termination resistor for the temperature sensor's 1-wire bus is on the Pi Power board so this is pretty simple.

The not-so-nice part is that then I have to mount them on the heatsink which involved hot-glue and a lot of cursing. What is worse is that they don't make very good thermal contact so the readings aren't the best (the temperature readings are much lower than what I get with a probe or non-contact thermometer). Still it will do for fan control purposes.

The reading rate of the sensor is quite low. I integrated this into the software by having it only read the temperature every few updates. I added a simple algorithm for fan control that basically ramps up the fan when the temperature goes over 30C. The fan hits full speed at 40C.

Starting the GUI

I didn't realize that Kivy doesn't actually run under X-Windows but basically directly accesses the frame-buffer. As a result I can use raspi-config to change the boot options and not start X-Windows. Now when I run the Kivy application from an ssh session is starts as before and works fine.

I created another daemon script (see previous post) for starting the power GUI. One change I had to make was that for some reason if I run the app as root the app will run but it doesn't respond to user input. A small change to the script allows it to run as the pi user and we are all good.

Now the Raspberry PI will boot and then will go straight into the power supply application.

Here is the daemon script (which again was derived from a template).

#!/bin/bash

### BEGIN INIT INFO
# Provides:          labpower-gui
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starts the Lab power supply GUI
# Description:       Starts the Lab power supply GUI
### END INIT INFO

# Change the next 3 lines to suit where you install your script and what you want to call it
DIR=/home/pi/LabPSU/LabPowerSupplyCtrl
DAEMON=$DIR/MainWindow.py
DAEMON_NAME=labpower-gui

# Add any command line options for your daemon here
DAEMON_OPTS=""

# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=pi

# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid

. /lib/lsb/init-functions

do_start () {
    log_daemon_msg "Starting system $DAEMON_NAME daemon"
    start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS
    log_end_msg $?
}
do_stop () {
    log_daemon_msg "Stopping system $DAEMON_NAME daemon"
    start-stop-daemon --stop --pidfile $PIDFILE --retry 10
    log_end_msg $?
}

case "$1" in
    start|stop)
        do_${1}
        ;;

    restart|reload|force-reload)
        do_stop
        do_start
        ;;

    status)
        status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?
        ;;

    *)
        echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}"
        exit 1
        ;;

esac
exit 0



Ninety Degree Shift

The original GUI design was based around having the outputs for each channel below the screen. With the big 7" display there isn't enough space below to do this so instead the outputs are beside the screen. So to make this more usable I re-oriented the display to be in rows instead of columns. This way the details of each channel roughly lines up with the connector. The GUI is still a work in progress. Later I plan to add graphing and maybe a virtual knob to adjust voltage/current.



Speedup

Now that I have three channels running I found the GUI painful to use. The problem is that when you hit the voltage/current set buttons it can take quite a bit for the dialog to appear. This is because the code is sequentially cycling through and reading back the voltage/current/status from each channel and as the interface to the channels is relatively slow (115200 baud) this takes time. If you hit a button at the same time the code is running through some updates you have to wait for them to complete before it will respond to the button press.

I thought about how to speed this up and I thought perhaps I could increase the baud rate or even create a new 'uber' command that fetched all the relevant details back within a single exchange. The problem is that even if I do this the ADC is relatively slow and so the command will take some time to complete. I don't need it to be super-fast but I just want the GUI to be responsive.

I found out that python has quite good support for threading out of the box. I modified the code that manages each power supply channel so that it kicks off a thread that constantly fetches the status in the background. The thread reads the status into a bunch of class members which can then be read by the GUI whenever it updates. This way the updates to the three channels can happen concurrently and the GUI is never tied up.

The problem then is that if the GUI requests a change (say to set the voltage or whatever) while the thread is running, the commands generated by the thread and by the GUI will clash. Instead when the GUI requests a change the power supply channel code puts the request into a queue. Each time the thread goes round to do an update it checks to see if there is a command to process and sends that to the channel first before fetching the status.

To make accessing the status held by the power supply channels thread safe I created a small class that contains a mutex and which holds a copy of a variable. It has a setter and a getter method and it copies the value passed in and returns a copy on the way out. It locks the mutex before accessing the data in both directions to avoid problems with concurrent writes and reads.

I also changed the channel code so that when a dialog comes up it stops all the updates (not just the updates for the channel being commanded).

So now the dialogs still come up a little slow but when they do come up the buttons are responsive. The update speed of the GUI is fine and overall the GUI now works quite well.

Auto-Calibration

The tables of points used to calibrate the ADC/DAC readings was stored in constants within the code. I generated these constants using a small python script that commanded the supply to go through the full range for voltage/current outputs while reading back values from a LAN attached multimeter.

The problem with this is that each channel needs a different table of values and I don't really like having different firmware images per board.

The logical thing is to update the firmware so the table of points is stored in EEPROM and provide functions to read/write these values. The python code for stepping through the output range can then be integrated into the Kivy GUI.

This turned out to be a bigger job than I hoped. I had to:

  • Create a class for reading the linearizer data from EEPROM
  • Update the Linearizer code so it can be setup after construction.
  • Add a command to set the number of points and to set each point in the linearizer table for the Voltage ADC/DAC and Current ADC/DAC
  • Modify the Kivy GUI to pause everything, allow the GUI to directly (not via the thread) command the channel to move through each point and to communicate with the multimeter to read-back the voltage. The GUI needed a progress bar display and needed to allow the user to enter the hostname/IP of the DMM.

Running out of RAM on the Microcontroller


The first thing that happened was I loaded the code into a channel and it basically was non responsive. After some poking and the addition of text debugging I figured out that the firmware ran out of RAM (the ATMEGA328P only has 2K)

I was able to figure this out by using this bit of code for working out how much free RAM there is based on the stack address

int freeRam () 
{
    extern int __heap_start, *__brkval;
    int v;
    return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
printf("Free ram is %d\r\n",freeRam());

This was I could pepper the code to see where the RAM was being consumed and how much. Because of the way the interpreter works, most of the RAM is allocated when the main object is created.

My biggest problem was that in addition to the tables for each of the ADC/DAC linearizers I had static constants containing default tables (in case the EEPROM is blank). Static constants end up using both EEPROM *and* RAM. The compiler allocates RAM for the constant, reads it from EEPROM and copies it into RAM. I changed the defaults to be dumb one point tables and this brought the usage down considerably.

The other thing was I included a pointer to the LabPSU object in every command. Assuming pointers are 4 bytes, as there are 26 commands this equates to quite a bit of RAM wasted. I changed the code so the pointer is passed in during parsing and recovered loads of RAM.

The final change was I switched from 32 points to 16 points for the tables and this was enough for the code to run reliably.

Next Steps

There are a few things I'd like to add to this project but none of them are urgent. Furthermore I've been working on this for nearly two years and I feel like it is time to do something new for a while. So for now I am calling this complete although I might add some new features in the future.

The future list includes:
  • Virtual onscreen knob for adjusting voltage/current
  • In addition to displaying the current/voltage/power a graph mode where you can see a graph of the output current/power
  • A curve tracer mode for plotting IV characteristics of LEDs etc
  • Maybe a battery discharge simulator.
Here it is on my bench in action.