HP5508A interferometer replacement hardware 2.0! - Homodyne...

Paul Stoffgren released the Teensy 4.0, and it looks like a great match for a 2.0 version. Here links to the docs :

The Teensy uses a NXP iMXRT1062 chip at up to 600 Mhz clock rate and has a large range of integrated peripherals that are going to be useful.

I talked with Sam Goldwasser and he mentioned that it would be really nice to have the unit capable of receiving the Sin/Cos signal from Homodyne interferometers. These are described in great detail here:


He explains how the quadrature signals get produced:

The signal in each channel is a sine wave oscillating as the distance changes. These two are related by a 90 degree shift, so that the signal can be represented as a sin/cos rotation of a unit vector. This is very similar to quadrature decoders as they are used in motion control to determine the position of a motor shaft. There is a nice explanation of these devices here: https://en.wikipedia.org/wiki/Rotary_encoder

But the gist of it is that these devices:

Produce a digital pulse train that looks like this:

Maybe with a code wheel or some other method.

These pulse trains are also in quadrature, and because they are incredibly popular there is ready made decoder hardware inside the NXP iMXRT1062. It has 4 hardware decoders ready to accept these digital signals. It is possible to use the analog signals in quadrature, if properly rectified like this:

This can be achieved by using a differential line receiver. In fact, the UA9637 (Sorry for the typo on the following picture) we have been using previously will do this very well. Consider the following simple test setup:

The UA9637 is powered by 5V coming from the USB bus. The output is reduced from 5V to 3.3V using a simple resistor divider. An OLED on the IIC bus allows the displaying the encoder count.

I modified a test sketch for the encoders available here: https://github.com/mjs513/WIP/blob/master/ENC1_test_xbar1/ENC1_test_xbar1.ino

in order to display the counts on the OLED as well as write them to the serial console. The results are great:

The next step is to maybe add the heterodyne functionality. But the uMD1 does that quite well. For now, here the code in the current messy state.

// uMD2// homodyne interferometer firmware for Teensy 4.0// Jan Beck 2020// required libraries// Teensy 4.0 Hardware encoder library available from https://github.com/mjs513/Teensy-4.x-Quad-Encoder-Library// u8g2 graphics library available though the Library Manager#include <U8x8lib.h>#include "QuadEncoder.h"
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/U8X8_PIN_NONE);char buffer[50];//The Teensy 4.0 Encoders are supported on pins: 0, 1, 2, 3, 4, 5, 7, 30, 31 and 33QuadEncoder encoder1(1, 1, 2, 0); // Encoder on channel 1 of 4 available; Phase A (pin1), PhaseB(pin2), Pullups Req(0)QuadEncoder encoder2(2, 3, 4, 0); // Encoder on channel 2 of 4 available; Phase A (pin3), PhaseB(pin4), Pullups Req(0)QuadEncoder encoder3(3, 5, 7, 0); // Encoder on channel 3 of 4 available; Phase A (pin5), PhaseB(pin7), Pullups Req(0)
void setup(){ while (!Serial && millis() < 4000); delay(2000); // Initialize the ENC module. encoder1.setInitConfig(); encoder1.init(); encoder2.setInitConfig(); encoder2.init(); encoder3.setInitConfig(); encoder3.init(); // initialize and clear display u8x8.begin(); u8x8.setPowerSave(0); u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.drawString(0, 0, "Started!");}
int32_t encoder1Value = 0;int32_t encoder2Value = 0;int32_t encoder3Value = 0;int32_t compareValue = 0;int32_t velocity = 0;uint64_t sequenceNumber = 0;void loop(){ sequenceNumber++; Serial.print("0 0 "); // 0: REF Frequency Count; 1: MEAS Frequency Count 1 compareValue = encoder1.read(); velocity = compareValue -encoder1Value ; // calculate velocity if (compareValue != encoder1Value) { encoder1Value = compareValue; u8x8.drawString(0, 0, " "); sprintf(buffer, "A - %li", encoder1Value); u8x8.drawString(0, 0, buffer); } Serial.printf("%li ",encoder1Value); // 2: Displacement 1 Serial.printf("%li ",velocity); // 3: Velocity Count 1 Serial.print("0 "); // 4: Phase 1 Serial.printf("%llu ",sequenceNumber); // 5: Sequence Number Serial.print("20 "); // 6: LowSpeedCode Serial.print(0x0304); // 7: LowSpeedData - 3 axes 4 counts/cycle Serial.print(" 0 "); // 8: MEAS Frequency Count 2 compareValue = encoder2.read(); velocity = compareValue - encoder2Value; // calculate velocity if (compareValue != encoder2Value) { encoder2Value = compareValue; u8x8.drawString(0, 1, " "); sprintf(buffer, "B - %li", encoder2Value); u8x8.drawString(0, 1, buffer); } Serial.printf("%li ",encoder2Value); // 9: Displacement 2 Serial.printf("%li ",velocity); // 10: Velocity Count 2 Serial.print("0 "); // 11: Phase 2 Serial.print("0 "); // 12: MEAS Frequency Count 3 compareValue = encoder3.read(); velocity = compareValue - encoder3Value; // calculate velocity if (compareValue != encoder3Value) { encoder3Value = compareValue; u8x8.drawString(0, 2, " "); sprintf(buffer, "C - %li", encoder3Value); u8x8.drawString(0, 2, buffer); } Serial.printf("%li ",encoder3Value); // 13: Displacement 3 Serial.printf("%li ",velocity); // 14: Velocity Count 3 Serial.println("0"); // 15: Phase 3}