Tuesday 7 March 2017

GW INSTEK GSP-827 Sprectrum Analyzer Repair

I was lucky to find a GW INSTEK GSP-827 for sale in Australia. The advert said it had a screen issue and didn't pick up any RF signals. I managed to buy it quite cheaply (or cheaply enough that I felt I could get it past SWMBO).

It's not a particularly high-end unit. For starters it has a monochrome screen and it's RF specs aren't stellar (phase noise, sweep rate etc). It does however go from kHz up to 2.7GHz and importantly it has the tracking generator option fitted.

How it came

The unit was packed really well and the whole thing was really clean and tidy. There was a sticker on the lid listing a capacitor and a couple of resistors that had been replaced. These turned out to be on the motherboard.

The seller was a nice chap and explained that he bought it at auction from a College of Technical and Further Education (TAFE as they are known here). He hadn't gotten around to repairing it and had other (better) instruments so decided to sell it as-is.

The unit was as he described in that it powered on, the bottom half of the screen was messed up and when I adjusted the trace so I could see it at the top of the screen, I couldn't get it to respond to an external signal. All the functions I could see seemed to respond and when I enabled the tracking generator I could see a signal on my scope at the tracking generator output. There was a 10MHz reference out at the back and when I brought up the system config screen (in the bit I could see) it said that all three LOs were locked.

My guess at this stage was (a) the screen issue was a due to a hot-bar attachment on the LCD and (b) the unit was deaf due to having been overloaded by a TAFE student.

Screen Repair

I started taking the unit apart and was pretty impressed by the construction. It is a motherboard with a series of plugin boards and the whole thing is pretty tidy. Each screw is threaded and everything is nicely tied down.


I decided that repairing the screen would make repairing the rest easier so I started there. The screen looked like this when I ran the unit (at this point I had taken the screen out).


I took the diffuser and the backlight off the back of the LCD screen and looked for bad joints etc. I tried heating (with hot-air) and pressing the screen down but none of this seemed to make a significant difference. At a couple of point the screen did change as I was pressing on the board at the edges which made me think it must be the screen.

I couldn't understand how it could be anything but the screen since only half was not working. I felt that if it was a cable issue then all of the screen wouldn't work. 

One confusing thing was that the date/time at the top of the screen was messed up - the year was a big number and the last digit of the seconds would count up to 9 then turn into a '>' symbol.

Do we have a signal?

The LCD signal is generated from the DSP board of the analyzer. The EPSON chip at the top left is a S1D13705. There is an SRAM right next to so I suspected the problem might be with that. There isn't an easy way of determining this however. There is a LVTHR16245  between the EPSON chip and the LCD connector which I think is just a level translator/driver. The board had loads of these at each interface. The nearest datasheet I found for the EPSON chip was a S1D13700 which I thought might cover the whole family and this described the signalling to the LCD.



While we are here I thought I would mention the red/black wires at the top of that photo - these go to a coin-cell battery that was in a holder screwed to the case above the power input. There is a Dallas semiconductor DS1689 that manages the current time plus it holds a small amount of NVRAM that no doubt is where the options configuration is stored! I really didn't want to lose my tracking generator option so I was careful not to short this thing. No idea why an instrument this modern would use this ancient crap instead of EEPROM.

I ordered a replacement EPSON chip as I knew these take weeks to come from China but I decided to try and analyze the signals going to the LCD to see if there was data on the bottom half.

The pin pitch was too fine to directly attach logic probes and there was a series of resistor packs between the driver and the LCD so instead I soldered wire-wrap wires to these.


It's a bit of a mess and hard to connect up when the DSP is in the box as I can't use the microscope. It looked like this connected up.

There are 12 lines but I can only connect 8 as that is how many logic channels I have on my scope.

The EPSON datasheet described the signalling as :
  • FPFRAME that is pulsed once per frame start
  • FPLINE pulses once per line
  • YSCL which clocks once per pixel
  • FPDATA[0-3] which is a 4 bit data bus containing the grey level for each dot.
There is other stuff like a method of disabling the displace etc.

I wasn't sure what line was what but after connecting some up I found the lines described above. Here is a snapshot showing the timing of the FPLINE pulse. As you can see the frame-rate is around 77 frames per second.


If we zoom in, here is the timing of the line pulse. 


And finally zooming further we can see the timing of the pixel clock pulse.

After I was finished being chuffed by how my fancy scope can hold all of this in memory at once I started looking at some of the timing information. So the clock pulse period is 320ns and the line pulse period is 53.4us - that works out to 166.8 dots. This doesn't make sense but reading the EPSON datasheet a bit further it turns out the YSCL only occurs every 4 pixels which gives us 667 which might be near enough to 640 dots.

Then the frames period is 12.9ms and the line period is 53.4us which works out to 241 lines. This isn't nearly enough - in fact it is roughly half of what I expect.

Next I wanted to know if I watched the data at the end of the frame - i.e. just before the frame pulse - if I would see changes. The data doesn't change much unless you adjust the amplitude so there is something going on in that bit of the screen (which is tricky as you can't see it) but I managed to do it and sure enough the data did change (see video below). So that means it has to be the LCD panel right as we have data for the bottom half of the screen.




Replacement LCD


I decided I would order a replacement screen. The screens has a bunch of numbers on the back include LM64K112 but the datasheet for these was pretty brief and mostly just the mechanical specs. Some places that sell these list them as 320x200 which makes no sense as there is no way the screen res is that low. 

It also had a part number of LTBGCHB91J1K and I was able to find a screen with this part number on Taobao for a reasonable price. All the matching screens on ebay were $120-$200AUD which is a significant amount of the price I paid for the unit!

I ordered the screen and waited. Taobao was a bit of an adventure actually since it is all in Chinese. I had to use Google translate at every step to figure out what was going on. Amuzingly Taobao roughly translates as 'treasure network' and they refer to items as treasure (baobei). The funny thing about that is google translates this as 'baby' so every screen is filled with stuff like 'baby arrival' and 'baby attributes' etc etc.

The screen came and with some excitement I plugged it in and... it still didn't work! In fact when I first plugged it in it didn't work at all (totally blank) which turned out to be significant later.

So what is it?

At this point I was really stumped. The last number on the back of the LCD was HDM6448-1. I searched on this before but this time I found a datasheet! The interesting thing is this LCD has the same control lines I described above but has two sets of bus lines for the pixel data! One for the upper half and one for the lower half. Also now I know what pins are what it's easier to track. This also explains how half the screen could fail.

But the EPSON chip didn't mention any of this. I searched a bit harder and found there was a datasheet for the S1D13705. It turns out this unit can support either 8 bit colour displays or monochrome 'dual' displays like the one the analyzer has.

So I checked the signal on one of the lower screen data lines at the EPSON chip and sure enough I can see signal. Then I repeated this at the LCD connector on the DSP board and I can see a signal there too. Finally I checked the signal on the LCD panel itself and there was no signal! One line sometimes worked but three didn't,

I pulled the flat-flex cable off at both ends and checked its continuity - sure enough some of the lines were dodgey. Face-palm! All this work and it was a bad cable! Under the microscope you could see the break right at the fold in the cable near where it is stripped back to go in the connector.

I spend a long time looking for a replacement cable and the nearest I could find was expensive and in the UK. I thought I would have to buy it but before I did that I would try soldering the wires back together. This was a disaster as it melted the cable and caused the broken bits to float off and stick to my iron etc.

My next idea was to trim off the end (at the break) and *very* carefully scrape the insulation off to reveal new conductors. This worked pretty well and looked ok. I plugged it into the unit and guess what!


RF Problem

So given that the local oscillators are all fine and the tracking generator is fine, I thought the problem is likely to be at the front-end of the instrument. This part of an spectrum analyzer is highly susceptible to damage from overloading also and the unit did come from a teaching lab.

I pulled the RF module out - it has a billions screws holding a cover onto a diecast frame that is held in with another billion screws from the PCB side.


I removed the covers to see the components.


I was greeted with the usual RF voodoo in the form of distributed element filters, RF absorbing pads and lots of MMIC amplifiers and hybrids,

It's pretty easy to follow as each little box is a different circuit stage. The front-end consists of a capacitor to couple the input followed by some resistors and some very fast diodes. The diodes will open if the input power is too high and the resistors limit the current.

The diodes are a likely source of failure but they are hard to check in circuit. Also they are under the edge of the first box which makes it doubly hard to test them and impossible to remove them. To make matters worse, when I removed the bottom side screws to remove the die-cast frame I realized I couldn't because the N type input connectors is threaded through the frame and soldered onto the board!

So I broke out the soldering iron and braid and had to de-solder the damn thing to get started. I decided I wasn't doing this again so I cut a slot in the die-cast frame so I could get it on and off in the future (Grrr!). Admittedly this is the only part of this unit's physical construction that annoyed me so far.



So here is the front-end circuitry out of the can - first the input cap, resistor pad and two diodes (right where the can edge was). I removed the diodes from the board and tested them. They seemed fine. I'm afraid I lost the details of these but they were a very fast PIN diode in SOT-3 package.


The next stage of the circuit goes through a series of attenuation stages that are switched using these Skyworks AS169 switches. They are a pretty cool bit of gear as they are Galium Arsenide ICs that are good for 2.5GHz or more.


Finally we end up at a MMIC amplifier just before the first mixer (which is under the RF absorber).


The MMIC is a Sirenza SBA-4086 which is a 2GHz 15dbm amplifier.

My plan was that if the problem is the first mixer then I won't be able to tell as it is way outside of the frequency range of my scope. If I inject a low frequency signal into the front-end however I should be able to see this at the output of the MMIC. I soldered a small wire on the board so I could tap the signal at this point and using my spring clip ground I attached a probe, I carefully stuffed the PCB back into the motherboard and powered it up.

I put a 0dbmV signal into the front-end (pretty loud in other words) and sure enough I got a strong 400mV signal at the amplifier. So the amplifier is find and so is the front-end up to that point.

Mixer

The mixer is a mini-circuits SKY-60 part, Unfortunately you can't buy these via RS or element 14 etc. I found some other SKY-60 parts (SKY-60MH etc) on ebay but the specs looked different enough that I didn't want to risk it.

You can buy them directly from Mini-circuits but the minimum order quantity is 10 and they are $12USD each. The Australian distributor is Clarke and Severn but they didn't have this part on their sight. I contacted them and they added it for me and I could order single quantities. The problem is they have to back-order it from the states so it would take a couple of weeks. Pretty cool!

GW INSTEK Support

When I started all this I contacted GW Instek support to see if I could get a service manual and/or parts. They took a little while to respond and initially asked for the serial number of my unit so they could forward it to the correct regional support. I expected they would come back and tell me where I could get it serviced but not provide anything else.

After I ordered the mixer I was pleasantly surprised that they came back and sent me a service manual. They said they couldn't give me schematics as I wasn't an authorized repairer but if I agreed to sign an NDA they could give me some info. This is way more than I expected (way more than many other big brands would offer). Massive thank you and kudos to GW INSTEK. While it's not as good as the old Agilent stuff where they publish full schematics in their service manuals it is understandable given the rampant copyright violations that happen in China.

Another look

Given I was stuck waiting for a part I thought I would try a few experiments. The service manual included block diagrams showing the path through the mixers and indicated the IF coming out of the RF board should be 452MHz. It also showed a 100MHz reference signal that got divided down by 10 to generate the reference signal on the back of the unit and got multiplied by 32 to generate the second LO.

I decided I would start by probing the IF signal since even though it is out of the range of my scope it still might be viewable. Weirdly the signal I saw was a 100MHz slightly distorted sine wave. When I fiddled with the frequency range and settings it didn't change.

The semi-rigid cables in the unit are slightly confusing. They are labelled but for example two of the cables going to the RF board had the same label. Others showed the J number of the connector but often the boards didn't have this silk-screened onto them. There are coax sockets with no connectors in them also.

Someone on the EEVBlog had problems with their unit having a 6dB offset. They published photos of the internals including this one (note they have no tracking generator like mine).


I must have looked at this 10 times but the cables on mine looked to be out of place. Also the markings on the cables indicated one was to go to the IF board and the other to the LO board but in my case one went to the TG board and the other the IF board (so they were one board out).

Here is how they were connected in my unit


Here is the shot from the EEVBlog showing the correct placement again.

Could it be that simple? I re-connected the cables, rebooted the unit and it worked! So now I just have to put all the screws back into the RF board :(


Screen Dim

So while it all works now the screen is very dark. There is a brighness control but it doesn't help much and seems to do nothing until it you get to a certain range and then it suddenly changes a bit.

I looked at how this works and there is a 13-24V bias voltage that goes to the LCD to set the brightness. I traced this on the DSP board and it went over to the other side of the board near the input. I found an 8 bit Analog devices AD5300 DAC (U13). This was connected to an OPA237UA opamp (U12) and a transistor (Q12). The resistor nearby (R88) is what connects directly to the LCD bias line and I noted (under the microscope) it had a hole in it!


Thankfully the service manual had the component values as the marking codes made no sense. It was a 27.4 ohm 0603 resistor and I had a 27 ohm one on hand and replaced it. This still didn't fix it so I watched the voltage first at the output of the DAC and then at the resistor to see what happens when I vary the contrast. The DAC output changed smoothly but the voltage to the LCD did this weird jump I could see from the screen change. The output of the opamp seemed to be going from one rail to the other across this jump.

The transistor was a MMBT3906LT1 accoding to the service manual and it is a general purpose PNP that can handle around 200mA. The only SMD PNP I have is a BC857 and that only goes to 100mA. Given this one died of over-current damage I figured I shouldn't risk it. Jaycar (bless their souls) recently started carrying some surface mount parts and the one surface mount PNP they carry is an BC807. As it turns out this is a fine replacement for the MMBT On-semi part so I bought some and replaced it. This worked just fine!

Conclusion



So here is the SA re-assembled and happily integrated into my bench. I can see the internal cal signal just fine and the power level is within a couple of dbmV of the specified -30. If I use the tracking generator the trace is flat right across the spectrum to within a few db (impressive! with my shit cable!). I found some N-type to BNC converters and am using my BNC cables for now. I've ordered some n-type to SMA and SMA cables. I'll need loads more bits and pieces to use this thing though.

So overall I am very happy indeed. Got very lucky with this purchase.


Friday 3 March 2017

Using Spring Validation in Angular

I was recently working on a web project where I needed support for substantial modal web dialogs inside web pages. My first approach was to use what what was familiar to me which was  JSP with spring MVC controllers. The problem is this isn't very convenient with modal components as you  you have to manually bundle up  the value in the form with java script code and post it yourself.

So I started exploring Angular JS as a way of doing this and basically it took over my life (in a good way I think).

One are I struggled with was validation but I found a solution I was happy with and hence this post.

Problem

Since I started with Spring I had my models annotated with validation constraints like the example below :

 class User  
 {  
   // ...  
   @Size(min=1, message="First Name must be provided.")  
   private String firstName;  

   @Size(min=1, message="Last Name must be provided.")  
   private String lastName;  

   private String organisation;  
   @Size(min=1, message="Email must be provided.")  

   private String email;  
   @Size(min=1, message="Password must be provided.")  

   private String password;  
   private boolean isAdmin;  
 }  

Then the controller can validate objects of this type using the SpringMVC magic as follows:

 
   @RequestMapping(value="/user",method=POST)  
   public @ResponseBody ModelAndView editUser(  
       @Valid @RequestBody User user,  
       BindingResult    result)  
   {  
     if ( result.hasErrors() )  
     {  
       return ...  
     }  
    ...  

The BindingResult is then available in the JSP so you can write code in your form like this to display the errors (using some tag library stuff).

  
    <form:input path="firstName"   
       cssClass="field input medium"  
       cssErrorClass="field input medium error" />  
    <form:errors path="firstName" cssClass="error" element="p" />  

But if we aren't using JSP then how do we get these errors out? If we are using Angular then we post the form data as JSON asynchronously and the page isn't reloaded.

Outline

When I searched for a solution to this problem, the first things that came up were techniques for implementing validation in Angular. While its good to validate the content before leaving the page the problem is you still have to validate the content at the server as otherwise a rogue user could mess you up.

So there is some desire to not implement this validation in two places and to report the validation errors from the server in the client.

Server

So on the server we define a new type that will carry the validation results.

  
 public class ValidationResponse  
 {  
   public String getStatus()  
   {  
     return status;  
   }  
   public void setStatus(String status)  
   {  
     this.status = status;  
   }  
   public List<ObjectError> getErrorMessageList()  
   {  
     return this.errorMessageList;  
   }  
   public void setErrorMessageList(List<ObjectError> errorMessageList)  
   {  
     this.errorMessageList = errorMessageList;  
   }  
   /**  
    * A general validation error not specific to a field  
    * @return The error text  
    */  
   public String getGeneralErrorText()  
   {  
     return generalErrorText;  
   }  
   /**  
    * A general validation error not specific to a field  
    * @param generalErrorText The error text  
    */  
   public void setGeneralErrorText(String generalErrorText)  
   {  
     this.generalErrorText = generalErrorText;  
   }  
   private String status;  
   private String generalErrorText;  
   private List<ObjectError> errorMessageList;  
 }  


Then the methods that accept REST POST calls and that will validate objects do something like this:

    
   @RequestMapping(value="/user.json",method=POST)  
   public @ResponseBody ValidationResponse editUser(  
       @Valid @RequestBody User user,  
       BindingResult    result)  
   {  
     ValidationResponse response = new ValidationResponse();  
     if ( result.hasErrors() )  
     {  
       response.setErrorMessageList(result.getAllErrors());  
       response.setStatus("FAIL");  
     }  
     else  
     {  
       ....  
     }  
     return response;  

In addition if you want to have an error that applies to the whole form rather than a specific field you can use the general text field in the ValidationResult above.

Web

In the form we define error spans for each field as follows. The error fields us ng-show to toggle if they will be displayed based on a hasError() method in the controller and display the content returned by a getError() method.

 
    <div ng-controller='registerController'>  
    <div class="form-group">  
      <label for="userFirstName">First name<span class="required">*</span></label>  
      <input class="form-control" ng-model="object.firstName" name="firstName" />  
      <span class="help-inline" ng-show="hasError('firstName')">{{getError("firstName")}}</span>  
    </div>  
    ...  
 </div>  

Angular Controller

As this pattern would be applied to every form, I created a base controller that the form controllers could extend to provide the validation methods.

The controller takes the resource and context (to build the URL) from its parameters when it is instantiated. The controller provides the hasError() and getError() methods as well as method for posting the updated object and checking if the result was an error.

 
 angular.module("MyApp").controller("formController",function($scope, $http, $q, object,context,resource)  
 {  
   $scope.formErrors = {};  
   $scope.context = context;  
   $scope.resource = resource;  
   $scope.object = object;  
   $scope.hasError = function(fieldName)  
   {  
     if (typeof ($scope.formErrors) != 'undefined')  
     {  
       return fieldName in $scope.formErrors;  
     }   
     else  
     {  
       return false;  
     }  
   }  
   $scope.getError = function(fieldName)  
   {  
     if (typeof ($scope.formErrors) != "undefined" && fieldName in $scope.formErrors)  
     {  
       return $scope.formErrors[fieldName];  
     }   
     else  
     {  
       return "";  
     }  
   }  
   $scope.postUpdate = function()  
   {  
    var deferred = $q.defer();  
     $scope.formErrors = [];  
     $http.post($scope.context + $scope.resource,$scope.object).then(  
       function(response)  
       {  
         if (response.data.status == "SUCCESS")  
         {  
           return deferred.resolve();  
         }   
         else  
         {  
           for (i = 0; i < response.data.errorMessageList.length; i++)  
           {  
             $scope.formErrors[response.data.errorMessageList[i].field] = response.data.errorMessageList[i].defaultMessage;  
           }  
         }  
       });  
     return deferred.promise;  
   };  
 });  

Then every controller that needs this will extend the form controller like this:

  
 angular.module("MyApp").controller("registerController",function($scope,$controller,$http,$rootScope,$location)  
 {  
   $scope.object = { }  
   angular.extend(this,$controller('formController', {$scope: $scope, object : $scope.object, context: '/MyApp', resource: '/register' }));  
   $scope.submit = function()   
   {  
     if ( $scope.object.password != $scope.passwordConfirm )   
     {   
        $scope.formErrors["passwordConfirm"] = "Passwords do not match";   
     }   
     else   
     {   
        $scope.postUpdate().then(  
          function($location.path('/registersuccessful') } );  
     }   
   }  
 });  

In this case the submit function also does some validation before sending the form content (using the postUpdate() method) to the server. When the postUpdate() completes it invokes the function for moving the URL to the success page (via the promise returned by the post method).

Conclusion

The benefits provided by the method are worth the small additional overhead. While I still find the syntax of Javascript a bit of a puzzle at times Angular is growing on me.