EMC PCB Layout Notes

  • Implicit RLC (potentially filters) and antennas formed by traces
  • Large ground/voltage planes serves as EMI shield, low impedance path current sink
  • True differential signals can be generated by current sources
  • Decouple with ferrite beads if radiation inevitable by geometry/placement
  • Avoid / minimize large current swings on analog plane (e.g. buffer digital signals)
  • Star ground when splitting sections: don’t let heavy digital current sink through analog ground by cascading the grounds.
  • Don’t really need to split planes as long as large digital current’s preferred return paths are localized and far away from the analog section.
  • AGND/DGND refers to the grounds responsible for different sections of a mixed-signal IC. Has nothing to do with which actual ground to tie to. (e.g. DGND pin in ADC chips still goes to analog ground plane as it has low switching current)

13 total views, 1 views today

TDS 500 600 Series (and TDS 820) Monochrome CRT Horizontal Linearity

I have a batch of TDS 620A which everything looks shiny new, but the display will stretch vertically and eventually gone unstable after turning it on continuously for a long time.

Turns out there’s a specific batch of flyback transformer (120-1841-00) on the monochrome CRT driver board (640-0071-06) that has quite a bit of infant mortality. The newer the unit looks (of the CRT tube looks shiny new without burn-in), the more likely it’s a victim of the bad batch.

The transformer is almost impossible to source (other than getting another CRT driver board), but I was able to find a Chinese supplier who makes it. It was usable, but it’s a nightmare to get it on because it’s really done with the stereotypical Chinese (PRC) manufacturing caliber.  When I received the unit, it’s a WTF moment! Leave me a comment if you want me to write about it.

The replacement transformer is only pin and functionality compatible, but it’s not a drop in replacement (not even geometrically). The characteristics are different and I had to adjust the trimmers all over the place.

I was able to get the screen width I want by adjusting the variable inductor (L105, HOR SIZE) by nearly pulling ferrite rod out, but the horizontal linearity was way off (the left side is very squeezed):

I looked into the TDS520B Component Service Manual (Same CRT board circuit diagram) and found this:

But L100 looks like this, which doesn’t seems trimmable:

The right hand side is the same L100 choke I extracted from a CRT driver board (same model) that I’ve disposed of. I saw two suspicious pieces of metal-like objects strapped on the choke on the left (installed) which I haven’t seen in other identical boards. 

Thinking that by changing the magnetic property of the core, I can adjust the inductance of an otherwise non-adjustable inductor. I took a few bits of magnets sitting on my bench and swing it around the L100 choke, the horizontal display widens/narrows depending on which pole of the magnet is facing the L100 choke.

After a few trial and error, I picked the right amount of magnet discs to correct the horizontal linearity so the squares have roughly the same width:

I guess I cracked the code! Here’s the result of correction by magnet:


85 total views, 1 views today

RTC / NVRAM in Test Equipment

HP Infiniium Series Atlas III Motherboard (Oldest generation Infinium oscilloscopes still branded as HP):

  • [RTC. There’s no exposed batteries] bq3287AMT = DS1288

Tektronix TDS Series (500, 600, 700, 800)

  • Older TDS (without alphabet suffix): Dallas DS1245Y
  • Model number that ends with ‘A’:  Dallas DS1650Y

The NVRAM in TDS series only contains the options data. Since I can reprogram the options, I can start with a blank NVRAM without reprogramming it). 

Will keep updating this page when I came across more test equipment.

65 total views, 1 views today

C Traps and Pitfalls

Here’s a concise paper describing common C programming pitfalls by Andrew Koening (www.literateprogramming.com/ctraps.pdf) corresponding to be book with the same title. 

As a reminder to myself, I’ll spend this page summarizing common mistakes and my history with it.

Here are the mistakes that I don’t make because of certain programming habits:

  • Operator precedence: I use enough parenthesis to not rely on operator precedence
  • Pointer dereferencing: I always do *(p++) instead of *p++ unless it’s idiomatic.
  • for() or if() statements executing only first line: I always surround the block with {} even if it’s just one line. Too often we need to inject an extra line and without {} it becomes a trap.
  • Undefined side effect order: I never do something like y[i++]=x[i]
  • char* p, q: very tempting since C++ style emphasize on pointer as a type over whether the variable is a pointer. I almost never declare multiple variables in one line.
  • Macro repeating side effects: use inline functions instead whenever possible. Use templates in C++.
  • Unexpected macro associations: guard expressions with (). Use typedef.

Did these once before, adjusted my programming habits to avoid it:

  • counting down in for() loop with unsigned running variable: I stick with signed running variables in general. If I’m forced to use unsigned, I’ll remind myself that I can only stop AFTER hitting 1, but not 0 (i.e. i=0 never got executed). 

Haven’t got a chance to run into these, but I’ll program defensively:

  • Integer overflow: do a<b instead of (a-b)<0. Calculate mean by adding halfway length to the smaller number (i.e. (a+b)/2 == a + (b-a)/2 given a<b). Shows up in binary search.
  • Number of digits to shift is always unsigned (i.e. -1 is a big number!)

What I learned from the paper:

  • stdio buffer on stack (registed with setbuf()) freed before I/O flushed: use static buffer (or just make sure the buffer lives outside the function call).
  • char type might be signed (128 to 255 are -128 to -1) so it sign extends during upcast. Use unsigned char go guarantee zero extend for upcasting.
  • toupper()/tolower() might be implemented as a simple macro (no checks, incorrect /w side effects)
  • Can index into a string literal: “abcdefg”[3] gives ‘d’

Mistakes that I usually make when I switch back from full-time MATLAB programming:

  • Logical negation using ~ operator instead of ! operator.

Common mistakes I rarely make because of certain understanding:

  • Forgetting to break at every case in switch block. It’s hard to forget once you’re aware of the Duff’s device.
  • sizeof(a[])/sizeof(a[0]) after passing into a function does not give array length: hard to get it wrong once you understand that array (declared on stack) has meta-info that cannot be accessed beyond the stack level it’s initialized. 

44 total views, 1 views today

Symantec Ghost in Windows hangs for mSATA to SATA adapter board Solution: Start Ghost with -NOTRIM

I was trying to image a mSATA SSD with Ghost in Windows (I’m using version Corporate Edition as I bought the Altiris license) and I ran into internal consistency error 8027 right at the very beginning of the copying process.

For some reason, it doesn’t happen if I boot to the DOS version (provided by Agilent) to do the cloning.

Luckily the status bar tells me what’s going on during the process. I notice it always hangs when ghost tells me that it’s TRIMming the SSD. I looked up the help file (ghost32.exe -help) and noticed that there’s a “-NOTRIM” option. Tried it and the clone completed successfully.

Turns out Symantec is aware of it. The title of the support article is called “Cloning Solid State Disk (SSD) drives fails when using the UEFI 12.0.0.x Ghost executables“.

The summary says it since older versions (11.5.1.x) does not have TRIM, this isn’t a problem, and

“Build (from GSS 3.0 early build) resolved the issue with the partition restore”

I’m not sure what it means. But the solution is the same as what I did: disable TRIM when copying SSD in Windows.

142 total views, no views today

Create user account using email address (like your Microsoft account) in Windows 7/2008

If you live in a mixed environment of Windows 7 and 8/10 computers, you might want to set the usernames to be the same so you can share the files/printers without managing Homegroup.

Nonetheless, in Windows 7/2008, if you try to create a user account using the traditional tool (Local Users and Groups) in Computer Management, you are not allowed to use email address as user name because they banned the at-mark (@):

I searched the web for quite a while, came across stuff like UPN (User Principal Name) without luck (No active directory on Windows 7, nor I want to setup a domain controller in Windows 2008 for home network). Turns out the solution is dead simple: use the “User Account” from Control panel to create the user account. No questions asked!

81 total views, no views today

Tektronix S1001 DIP switch: Open pin 3 to boot for fast self-test (TDS 744, 744A, 684A, 784A)

Normally for most TDS 500 series oscilloscopes, the DIP switch (S1001) typically all closed for normal operation. The only described use in the service manual is opening pin 6 and 7 to reveal the hidden composite test pattern screen for display adjustment.

However, I got a TDS 744 scope that boots very slow. Almost 5 mintues! To the extent that it’s unbearable. Initially I thought it’s just the non-A type booting slow. Nonetheless, I got a chance to open up another TDS 744A with boots much faster (in half a minute) with calibration seals on, and I noticed the pin 3 of S1001 is opened. Initially I thought it was out of place so I closed it again. Guess what? A slow 5 minute boot sequence!

I suspected opening pin 3 of S1001 puts the oscilloscope in the quick boot mode. I experimented with the pin 3 opened and manually initiating the full blown self-test (utility menu). Turns out I was correct! The full self-test is 5 minutes!

Since it was the settings from the calibration house, I looked up the TDS 744A/684A/784A service manual and noticed that the factory default is with pin 3 opened, while the old TDS 544A manual says pin 3 is closed. I suspect that the self-test for the new models 744/744A/684A/784A is unbearably long that the Tek decided to have it disabled for boot-up self-test.

In any case, try opening pin 3 to have the scopes boot faster!


142 total views, no views today

MATLAB Quirks: struct with no fields are not empty

As far as struct() is concerned, I’m more inclined to using Struct of Array (SoA) over Array of Structs (AoS), unless all the use cases screams for SoA. Performance and memory overhead are the obvious reasons, but the true motivation for me to use SoA is that I’m thinking in terms of table-oriented programming (which I’ll discuss in later posts. See table() objects.): each field of a struct is a column in a table (heterogeneous array).

Since a table() is considered empty (by isempty()) if it has EITHER 0 rows INCLUSIVE OR 0 columns (no fields) and the default constructor creates a 0 \times 0 table, I thought struct() would do the same. NOT TRUE!

First of all, the default constructor of struct() gives ONE struct with NO FIELDS (so it’s supposed to correspond to a 1 \times 0 table). What’s even harder to remember is that struct2table(struct()) gives a 0 \times 0 table.

The second thing I missed is that a struct() with NO fields is NOT empty. You can have 3 structs with NO fields! So isempty(struct()) is always false!

I usually run into this problem when I want to seed the execution with an empty struct() and have the loop expand the fields if the file has contents in it, and I’ll check if the seeded struct was untouched to see if I can read data from the file. Next time I will remember to call struct([]) instead of struct(). What a trap!

At the end of the day, while struct is powerful, but I rarely find AoS necessary to do what I wanted once table() is out. AoS has pretty much the same restrictions as in table() that you cannot put different types in the same field across the AoS, but table allows you to index with variables (struct’s field) or rows (struct array index) without changing the data structure (AoS <-> SoA). So unless it’s a performance critical piece of the code, I’ll stick with tables() for most of my struct() needs.


189 total views, 1 views today

MATLAB Techniques: onCleanup() ‘destructor’

If your program opens a file, creates a timer(), or whatever resources that needs to be closed when they are no longer needed, before R2008a, you have to put your close resource calls at two places: one at the end of successful execution, the other at the exception handling in try…catch block:

FID = fopen('a.txt')
   // ... do something here

Not only it’s messy that you have to duplicate your code, it’s also error prone when you add code in between. If your true intention is to close the resource whenever you exit the current program scope, there’s a better way for you: onCleanup() object. The code above can be simplified as:

FID = fopen('a.txt')
obj = onCleanup(@() fclose(FID));
// ... do something with FID here

The way onCleanup() works is that it creates an object which you define what its destructor (delete()) does on creation (by the constructor of course) by specifying a function handle. This way when ‘obj’ is cleared (either as it goes out of scope or your explicitly cleared it with ‘clear’), the destructor in ‘obj’ will be activated and do the cleanup actions you specified.

Due to copyright reasons, I won’t copy the simple code here. Just open onCleanup.m in MATLAB editor and you’ll see it that the code (excluding comments) has less words than the description above. Pretty neat!

Normally we use onCleanup() inside a function. The best place to put is is right after you opened a resource because anything in between can go wrong (i.e. might throw exceptions): you want ‘obj’ to be swept (i.e. its destructors called) when that happens.

Technically, you can make an onCleanup() object in the base (root) workspace (aka command window). The destructor will be triggered either when you clear the ‘obj’ explicitly using ‘clear’ or when you exit MATLAB. You can see for yourself with this:

obj = onCleanup(@() pause);

It kind of let you do a one-off cleanup on exit instead of a recurring cleanup in finish.m.

So the next time you open a resource that needs to be closed whether the program exits unexpectedly or not, use onCleanup()! It’s one of the elegant, smart uses of OOP.


144 total views, no views today