Tuesday 30 December 2014

TNDJG:0007 Repair of Audio Technica ATM33a Microphone






















The ATM33a from Audio Technica is a general purpose small diaphragm electret microphone. This style is also known as a "fixed-charge back plate" or a "permanently polarized condenser" microphone. The ATM33a has now been replaced with the AT8033 in the manufacturer's catalogue but there are very few (if any?) cosmetic or technical differences between the two.

These little mics have always offered quite good performance so I was saddened when one of mine started giving a low-level of hiss that rendered it essentially useless for anything professional. I thought I'd have a go at fixing it ...

Disassemble It

To open the microphone, first unscrew the lower barrel and slide it down as normal to reveal the battery compartment. Then, insert a sharp knife blade between the top of the decorative ring and the upper barrel so that this ring can be slid down to reveal the small screw that holds the two halves together. Unscrew that screw. Carefully pull out the transformer and PCB from the upper barrel and remove the insulation from the back of the PCB.

The decorative ring is not threaded so does not need to be rotated before it can be moved down, but it may be lightly tacked in place with some varnish and might need a bit of force to free it.
ATM33a Internal Components
 

Underside (mirror image) PCB plan.
ATM33a Integral Preamp PCB

Circuitry

I reverse engineered the circuit. The only gain stage is an NPN emitter-follower stage that buffers the high-Z signal from the FET in the electret to drive the output transformer primary.

You can see there is an additional FET that acts as a switch to alter the bias condition and hence the dynamic range depending on whether fantom power is available. When the 5 volt supply from the fantom is present, the P-FET switches off to increase the capsule's load resistance and reset its bias point.



The output transformer has five coloured connections: a primary and a centre-tapped secondary for extracting the fantom supply.


The output transformer.

The Potential Causes of Failure

The failure of nearly any component (except the transformer) could potentially cause a hiss. Fortunately all of the components are very cheap and readily available except for the transformer and the capsule. Therefore the only 'unfixable' fault is likely to be the capsule itself.


The first step, as always, is to check the DC operating point of the capsule's FET and the main NPN transistor when  both fed from fantom and battery supply and then to further check the level of hiss with the range-switch FET shorted. Shorting the range-switch FET eliminates it as a source of hiss without greatly altering the microphone's performance (except under high SPL). Further checks that should not effect performance are to try an additional bypass capacitor in parallel with each of the existing capacitors to see if that eliminates or reduces the hiss.

I measured the operating points as follows (table  values in volts)
Measurement Point   Battery Feed   Fantom Feed  
White Capsule 0.67 2.2
NPN Base 1.3 3.0
NPN Collector 1.4 4.4
NPN Emitter 0.78 2.4
Battery 1.6 -
Xformer-CT - 41.0
Fet Drain 0.003 1.5
Fet Gate - 5.0

The operating point voltages are all pretty much perfect and give no indication of the problem.

One mystery is how the diode in series with the fantom supply from the transformer centre-tap manages to drop 35 volts. Visually, it looks like a large and special diode but if it were a zener it would have to be in the other way around and then the mic would not work from 22 or 12 volt fantom supplies, so it appears to be a normal diode with a high intrinsic forward resistance. However, I decided not to investigate that any further. I just annotated it with a series resitance and a question mark in the schematic above.

Bypassing the FET did not alter the hiss. Adding an additional capacitor in parallel with each of the capacitors, one by one, did not fix it either.

The (unexpected) Fix

While examining the PCB the white output wire from the capsule broke away from the PCB.  I soldered it back straightaway.  This amazingly fixed the problem.  There was no longer any hiss and the microphone was working perfectly.  A nice property of the electret microphone (compared with a true condenser) is that all of the exposed circuitry is fairly low impedance and it is possible to work on the circuit board with only a little hum pickup.  So when I say 'perfectly' I mean without the troublesome hiss but with a little hum that was already present alongside the earlier hiss.  The hum is not present when the mic is fully assembled because of the shielding effect of the metal mic barrel.

Again I measured the operating point again with battery feed and noticed a small change: after the 'fix', the "White Capsule" output voltage was 0.66 on battery feed, a shift of 14 mV.  This indicated that the 6K2 resistor had been slightly duff and had been the source of the noise, but that heating it with the soldering iron, when reattaching the capsule output wire on the underside of the PCB had fixed it.  If. instead, the coupling capacitor (0.5 uF/50V) that is also soldered to that pad would have been faulty it is possibly less likely to have altered the DC operating point when heated.  I gave both components some physical abuse to see if the hiss would return, but it did not. To be on the safe side, the best way forward was to replace both the capacitor and the resistor.


The Happy End

After fitting the new components I reassembled the mic and left it running for a day to keep an eye on it.  All seems well now and let's hope it stays that way...  All the best for 2015, David J Greaves.



Sunday 5 January 2014

TNDJG:006:Carlsbro Sidewinder Persistent Reverb Fault


My friend has a Carlsbro Sidewinder guitar amplifier on which the reverb valve keept blowing every few months.  He replaced it twice and it went again so he asked me to have a look at the amplifier to see if there was a fault with it.

Pulling out the front panel reveals that the preamp uses four ECC83 double triodes:








One of these is for the springline reverb with one half driving the send through the small yellow transformer and the other being the return amplifier.  Banging the springline gives the normal clanking sound through the speaker which showed that the return side was working fine.  However, there was no signal on the send side, as revealed with a quick look using the oscilloscope.


A word of warning:  this amplifier has two on/off switches.  If you turn them both off at once, the high-tension is disconnected and is not discharged.  It sits at about 480 volts almost indefinitely. After my first shock I thought about fitting a 1 Mohm discharger resistor for safety but then I discovered if you switch it off on the mains switch while leaving the HT switch on then the HT is discharged while the valves still have some heat in them. So I decided to leave this aspect of the amplifier unmodified and keep the HT switch on all the time while working on the unit.

Diagnosing the problem


A quick measure of the electrode voltages on the reverb valve send side did not look healthy.  They were
  Anode:  496V and
 Cathode: 0.2V.

The grid was at 0V, the cathode bias resistor was 470 ohms and the primary of the output transformer was 560 ohms.   Replacing the valve restored operation and resulted in the anode being at  494V and the cathode at 2.1V.  This means the replacement valve was running at roughly 4mA x 500 V = 2W.

Looking more carefully at the circuit I saw that the other seven anodes in the preamp used an HT feed that came from the power amplifier.  This was at 350 volts or so.   It comes along the little cable that caries the line out from the preamp to the power amplifier; a cable that also carries a -50 volt bias rail.

On the other hand, the reverb driver was fed directly from the main HT voltage for the power amplifier, accessed via a wire link to the output side of the HT on/off switch.  I mentioned this to my father, who has designed many valve circuits and he immediately spotted a potential design fault in this amplifier: many versions of the ECC83 have a recommended maximum nominal anode voltage of 400 volts with 500 Volts and 1 Watt being the absolute maximum ratings under all circumstances.

Clearly the new valve would not last long either!

Fixing the problem


  The fix for the problem, as my father put it, was to "lose 200 Volts or so". An easy way to do that would be to wire the reverb send to the lower tension supply, but this was likely to overload that supply and it was presumably for that reason the designers at Carlsbro connected the reverb send to the main HT in the first place.


Since the anode feed came through a wire link, the obvious fix was to replace the link with a dropper resistor and to rebias the valve with a new cathode resistor.  The nominal valve plots above show that for 4mA the anode should be at 250V and the cathode at 0.5V.


The parts needed are as follows:


  • A new anode resistor:  60K ohm, 1 Watt (made from 27K+33K 0.5W resistors in series.
  • A replacement cathode resistor 165 ohms (two 330R in parallel).
  • A replacement ECC83 valve (hard to come by now - Farnell, CPC and Maplin no longer stock, neither does GEE in Cambridge, so purchased for £15.00 in PMT East Road Cambridge).
  • An anode supply capacitor: I used 150 uF 400V that I had to hand, but a lower capacitance would be fine and preferably a 500V capacitor should be used so that it would not be over-volted if the send valve is removed or failed again.

Here the wire link for the anode supply is removed (dotted line to right of large blue supressor capacitor (that is across the HT on/off switch poles):

Here the new anode resistor is fitted (I moved the suppressor to the left using the handy hole in the PCB for a larger physical suppressor):


Here I have started making a cradle for the new anode capacitor.  These two pots have four large lugs to the PCB and using the top of them as well I had six fixing points for making a snug capacitor bracket using tinned copper:

Here is the anode capacitor installed and you can also see the replacement cathode resistor parallel pair (between the valve and the xformer):


To wire the anode capacitor to the track between the anode resistor and the top of the xformer I drilled a small hole in the PCB (not shown) and passed the wire through the hole for easy soldering on the track side.

New operating Point

Measuring the new operating point for the valve we have
   HT Supply 494V 

   Dropped HT Supply: 265V

   Anode:  262V

   Cathode: 0.56V.

The new current is 0.56V / 165 = 3.4 mA which is about the same as before but the valve power is now 0.86 Watts which should not blow it.


Conclusion


Well it all seems to work fine at the moment.  I suppose there is the question of whether the reverb send will suffer transient clipping with its lower headroom but this really does not matter since the springline will be very good at rounding off such corners!
I hope you find this useful and if you try it yourself then do watch out for the high voltages!

DJG
/*

TNDJG:005:ControlSurface-Daemon

ControlSurface-Daemon: A Mapper Daemon for Novation Control Surfaces and others where management is needed.

A daemon that exports an ALSA midi client that speaks over a private USB connection to a studio control surface.


The source code for this mini-project is here.  Please let me know if you find it useful or enhance it.  My apologies for its quality: it was written very quickly:  LINK: Source Code Download.



The Novation series of control surfaces, such as the "ZeRO II" that I have ship with a separate program called "Automap" which is not supported for Linux.

The control surface can be used with and without Automap, but without it there is no simple way to control any of the LEDs on the control surface. The other control surfaces I own, which include a Korg NanoKontrol2, a Yamaha 02R (DAW layer) and a Bheringer BCF2000 all simply respond to control change information sent to them to update their status LEDs, encoder rings and motorised flying faders (or pickup points for non-motorised faders).


When using the Novation device in its 'advanced mode', which means without using the Automap program on an ancillary computer, it will update its leds and indicators as you adjust the associated local buttons. But as these are commonly used for track cuts and solos and record readys and so on, that are updated from other places as well, such as the GUI of a DAW or an automation track on a sequencer, they will soon become meaningless if they cannot be remotely controlled.


To solve this problem I contacted Novation by phone and email a few times. It was not clear to me that the person who handled my question understood the problem, but he did kindly send me a Novation internal document that describes the Automap protocol between the surface and the required external program. I soon realised I could quickly write my own basic version of the Automap program, sufficient to bring the Novation product up to the same basic operational level of my other control surfaces. It turned out that very little information was needed from the protocol description document, since all the basic exchanges are completely straightforward control change midi commands. However, there are several exclusive messages that would have had to be extracted using a USB sniffer program in the absence of the document. The exclusives I ended up using were to update the LCD display on the control surface and to put it into Automap mode automatically (although the latter can be done with a front panel hard button and also with a particular control change message too).

Implementation Details


When you run 'lsusb -v' to list the details of the Novation controller it reports three endpoints: two of these are the 'MIDI 1' and 'MIDI 2' ports that show up under Alsa (e.g. can be seen with the command "amidi -l") and the third is what Novation refers to as the 'hidden port'. Alsa connects perfectly and automatically to the two native ports and leaves the hidden port alone and unclaimed. Hence my mapper daemon connects to that endpoint and it then exports its own Alsa Midi port which DAWs etc must connect to, leaving the native pair of ports unused.


Control surfaces have various behaviours for the buttons: momentary, latching and so on. The most useful one, given a reasonably flexible DAW, is that they emit a CC message on both the push and release edge and that the associated LED indicator is in 'manual' mode. The word 'manual' is used on the Korg nanoKontrol but this is the mode that is sadly missing from the Novation controller and which needs the daemon to be running elsewhere.
For the infinite shaft encoders, relative output is the primary output form, sending a small +ve or -ve number as record of a rotation. I decided to integrate these inside the daemon and report a 0 to 127 absolute value to ALSA, but this is easily changed if desired.


I implemented four 'soft contexts' whereby each physical controller on the surface could have up to four mappings to actual controllers. For instance, it is then relatively easy to control 32 channels with the 8 actual channel strips on a controller. One knob is reserved to change context. On the Novation ZeRO II I used the central 'speed dial' for this adjuster. Of course, flying fader pickup points and track LED status information continues to be received while a context is not active and when that context is next selected the current settings are pushed down to the surface. For the non-motorised faders on the ZeRO II this essentially means they enter pickup mode if their physical position is wrong.


A fader that has been remotely 'moved' but which has no motor and so cannot actually move needs to enter 'pickup mode'. In pickup mode, when the user moves it, some LEDs flash and no events are sent on to the controlled target. The LEDs indicate which direction the user must move it to catch up with the current value and when it is put there it exits pickup mode.


On the Novation we have five LEDs down the left side - we use the lower two for 'too high/move down' indication and the upper two for 'too low/move up' indication. We can flash the middle one briefly when the pickup point is reached.


Further work...

TODO: Hot plug reconnection Instructions on how to make it autoload.  I may have some time at Easter to describe these.  Best regards for a happy 2014!

DJG.
/*













Tuesday 27 August 2013

TNDJG:0004: I converted my processor design to Bluespec and it went more than twice as fast!


The Cake ML Project, https://cakeml.org/, is developing a fully-verified ML system that includes the hardware, run-time system and compiler. An important hardware component is the processor that executes the bytecode.
 
Last year I wrote an implementation of the  processor in standard Verilog and used it for a couple of demos.  The processor is a simple stack machine with the top three items from the stack held in on-chip registers.  The other registers are the stack pointer, the program counter and the free space pointer.


Overview block diagram of the system:


My Verilog implementation was 600 lines long (the module HWML_CPU_CORE in cpucore0.zip). 

Last week I manually converted the processor core from Verilog to Bluespec with the help of a few emacs regexps (the file Hwmlcore.bsv in bsvcore0.zip). It came out shorter at just over 400 lines, but most surprisingly, its instructions-per-clock metric had more than doubled! And interestingly, the design had returned to about 700 lines of RTL at the output of the Bluespec compiler (toy-bluespec-compiler).

Both implementations were written fairly quickly with no special attention to performance.  Being a direct implementation of a simple stack machine, the main performance bottleneck should be the stack memory read/write port.  For instructions that pop two items from the stack, such as JNZ, two stack RAM reads are needed.

The test application program I was using was a simple, massively recursive implementation of Fibonacci implemented by Magnus Myreen.  The difference in performance is apparent from the execution times of the first five instructions.

The CPU is released from reset after four clock cycles, each of 10 ns. The Bluespec implementation execute its fifth instruction after a further 90 ns whereas the older implementation requires 180 ns to get to the same point:

Instruction timings Bluespec version:
55: sp=0000 tos = [[ xxxxxxxx xxxxxxxx xxxxxxxx ]]  pc='h0000  ins='h4a Push 0a
75: sp=0001 tos = [[ 0000000a xxxxxxxx xxxxxxxx ]]  pc='h0001  ins='h44 Push 04
95: sp=0002 tos = [[ 00000004 0000000a xxxxxxxx ]]  pc='h0002  ins='h12 Call 4
115: sp=0002 tos = [[ 00000003 0000000a xxxxxxxx ]]   pc='h0004  ins='h0c Swap
135: sp=0002 tos = [[ 0000000a 00000003 xxxxxxxx ]]  pc='h0005  ins='h40 Push 00

Instruction timings original version:
65 sp=00000000 tos= [[ xxxxxxxx xxxxxxxx xxxxxxxx  ]] pc=10000000  i=4a 
105 sp=00000001 tos= [[ 0000000a xxxxxxxx xxxxxxxx  ]] pc=10000001  i=44 
145 sp=00000002 tos= [[ 00000004 0000000a xxxxxxxx  ]] pc=10000002  i=12 CALL
185 sp=00000002 tos= [[ 10000003 0000000a xxxxxxxx  ]] pc=00000004  i=0c SWAP
225 sp=00000002 tos= [[ 0000000a 10000003 xxxxxxxx  ]] pc=00000005  i=40 

Overall, using Bluespec, the 2831 instructions consumed 6804 clocks, an IPC of 0.42 compared with the IPC 0.16 achieved in the original design.

Analysis

A careful look at the fetch/execute control logic and memory interface design in each of the two variants reveals that the original design had an extra two clock-cycles' worth of pipeline delay.  A little more care over the manual design could perhaps have avoided this.  I was rather hoping the Bluespec compiler would have done something fancy, such as merging the actions of several rules into a single clock cycle.  But nonetheless, it is clear that the Bluespec version is shorter, easier to read and modify and gave better performance.


David Greaves - August 2013. 

Wednesday 12 June 2013

TNDJG:0003 Hello World x86_64 assembly language program for linux


 What is the shortest Hello World program on linux?

$ cat syscall.s
# Minimal program on linux x86_64
# (C) 2004 DJ Greaves.
# Compile and run with: as -o a.o syscall.s;ld -o a.out a.o; ./a.out

#int main()
#{
#  char *s = "Hello Worldly\n";
#  write(1, s, strlen(s));
#  exit(0);
#}


# Calling convention uses %rdi, %rsi, %rdx, %rcx, %r8 and %r9 in order.
# Low syscall function numbers are 0=read,1=write,2=open,3=close,4=stat


      
        .global _start
_start:
        mov    $14,%rdx
        mov    $message,%rsi
        mov    $1,%rdi # stdout file description number is 1
        mov    $1,%rax # Kernel function number for write is 1
        syscall

        movq   $0,%rdi # Zero return code
        mov    $60,%rax # Kernel function number for _exit is 60
        syscall

        ret

message:
        .string "Hello Worldly\n"


$
as -o a.o syscall.s
ld -o a.out a.o
./a.out
Hello Worldly
$
strace ./a.out
execve("./a.out", ["./a.out"], [/* 60 vars */]) = 0
write(1, "Hello Worldly\n", 14Hello Worldly
)         = 14
_exit(0)                                = ?
$

Thursday 2 February 2012

Dining Philosophers Deadlock Example Using Bluespec

The dining philosophers were invented in 1965 by Edsger Dijkstra and the problem they pose has become the classical example of a system that is liable to deadlock.



Five philosophers are evenly spaced around a round table.   Each has a bowl of soup but there are only five spoons and each needs (for some strange reason) two spoons to eat.  So they cannot all eat at once, but must take it in turns.



In Bluespec Verilog, a spoon is easily coded as follows. The pickup method is blocking, so any philosopher attempting to pickup a fork that is already held by his neighbour will wait until his neighbour puts it down.



interface Spoon_if;
  method Action pickup();
  method Action putdown();
endinterface

module spoon (Spoon_if) ;

  Reg#(Bool) inuse <- mkReg(?);

  method Action pickup() if (!inuse);
   action
     inuse <= True;
   endaction
  endmethod

  method Action putdown();
   action
     inuse <= False;
   endaction
  endmethod

endmodule 

The complete system can be described as follows:


(*synthesize *)
module philoBENCH (Empty) ;

       Spoon_if spoon0 <- spoon;
       Spoon_if spoon1 <- spoon;
       Spoon_if spoon2 <- spoon;
       Spoon_if spoon3 <- spoon;
       Spoon_if spoon4 <- spoon;

       Diner_if din0 <- mkDiner (3, 7, spoon0, spoon1);
       Diner_if din1 <- mkDiner (4, 4, spoon1, spoon2);
       Diner_if din2 <- mkDiner (2, 9, spoon2, spoon3);
       Diner_if din3 <- mkDiner (3, 6, spoon3, spoon4);
       Diner_if din4 <- mkDiner (3, 6, spoon4, spoon0);

endmodule: philoBENCH


And the behaviour of an individual philosopher can be coded as follows:

module mkDiner #(UInt#(15) on, UInt#(15) seed) (Spoon_if left, Spoon_if right, Diner_if i);

  Reg#(Bool) eating <- mkReg(?);
  Reg#(UInt#(15)) timer <- mkReg(0);

  Random_if gen <- mkRandom_gen(seed);

  rule foo (timer != 0);
     timer <= timer - 1;
  endrule


  Stmt seq_behaviour =
  (seq while (True) seq
     action UInt#(15) x <- gen.gen(); timer<=x & 31; endaction await(timer== 0);

     left.pickup();
     noAction;

     action UInt#(15) x <- gen.gen(); timer<=x & 31; endaction await(timer== 0);

     right.pickup();

     eating <= True;
     timer <= on; await(timer==0);
     eating <= False;

     noAction;

     left.putdown();
     noAction;
     right.putdown();
     noAction;
  endseq endseq);

  FSM fsm <- mkFSM (seq_behaviour);

  rule kickoff  ;
     fsm.start;
  endrule


endmodule
 

What happens ?
 
 
Not suprisingly, after a little while the system reaches deadlock, as shown in this waveform trace:

The obvious source of deadlock is that each philosopher first picks up his left fork and then tries for his right.  This is clearly a bad policy: in concurrency terms, each spoon is a lock and the resulting cyclic ring of dependencies is known as a `knot' in the lock graph.


The Solution ?

There are many solutions the problem:  one that appears to work is for one philosopher to first pick up his right fork.  We change the system configuration as follows:

       Diner_if din0 <- mkDiner (3, 7, spoon0, spoon1);
       Diner_if din1 <- mkDiner (4, 4, spoon1, spoon2);
       Diner_if din2 <- mkDiner (2, 9, spoon3, spoon2); // <-- Spoon swap!
       Diner_if din3 <- mkDiner (3, 6, spoon3, spoon4);
       Diner_if din4 <- mkDiner (3, 6, spoon4, spoon0);
 
Now when we run the system, it does not seem to lock up however long we simulate for.  Here's some example output:



A good and permanent fix ?

But can we be sure this system is now deadlock free?