Last year, a colleague and I made a small spectrophotometer-workshop for kids in my school’s science classes. In brief they had to assemble something like this:


The “optical table” is a 15x20x0,8 cm aluminium plate covered with 0,6 mm self-adhesive ferrofoil and all the optical components have magnetic feet.

The students were first asked to characterize the DVD-grating using 532 nm laser pointers and a bit of trigonometry. Then we had them calculate the geometry of the spectrophotometer and finally they were asked to place all the components according to their calculations.

(Ok, it wasn’t that brief, the students spent 4x 90min in the lab, and they received a bit more wisdom than what’s outlined here, I’m just to lazy to do a full write-up)

It was fun (and I hope the kids thought so too, if nothing else they were bribed with cake during each lab-session), but I had underestimated the problems we’d encounter setting up their computers to work with the linear CCD module – Windows was particularly hard to play with.

This year we’re redoing it, and during the holidays I’ve been trying to learn enough python 3 to write a platform-independent graphical user interface for the CCD, so hopefully we can concentrate on the fun stuff next time.

Anyway, the new GUI looks like this:


I’ve only scratched the surface of matplotlib, so I expect to add more features, for now it can do just the basic stuff.

Get it here: python interface for the TCD1304

I will create stand-alone executables for macOS and windows in the coming days.



Mirror-alignment on a shoestring

I don’t have the right tools for this, so how do I then proceed?

The spectrograph looks like this:


The light enters from a fiber port near the top left corner and is reflected of off a mirror (not installed at the time the photo was taken). The beam from the fiber is horizontal and must be turned 90° in the xy-plane, and 6,6° upwards in the xz-plane (x being left-right, y being top-bottom and z orthogonal to the baseplate).

The distance from the mirror to the center of the 1st parabolic mirror, which is where the two pencil-lines in the photo cross each other is 111,5 mm in the xy-plane and 112,3 mm in space. It will be impossible to align the first mirror with a ruler – which is all I have.

The precision of my ruler is around 1/4 of a mm, which is around 2% on a distance of 11 cm. However, if I “extend” the spectrograph to 2 m, this number decreases to less than 0,1%.

This is shown in this next photo:


The laser beam comes in from the top right and is reflected by the mirror on a 3D-printed kinematic mount. At a distance of 11,5 cm from the mirror the laser beam must be 13 mm higher on the z-axis, but at 2 m from the mirror this translates to 23,2 cm.

Obviously it’s much easier to achieve an elevation of 23,1 cm with acceptable tolerance compared to 1,3 cm, when all you have is a ruler..


Morbo’s good friend, the Compass 115M-5

With my girlfriend out of the flat for a few days (I know, I know, this has come to be the standard opening of my posts), it was time to play with a new toy:

Coherent Compass 115M-5 laser, lighting up some nicotine vapors (ok, so it’s mostly glycerin and propylene glycol).

Or in fact new old toy: I managed to get my greasy paws on two Compass 115M-5 lasers some time ago. These are apparently not as nice a the other lasers in the Compass-series, but at least they were very cheap. The heatsink comes from another ebay-adventure, I think it came with the PSU for my single frequency laser (the coherent 115M is not SLM) but right now I simply cannot remember for sure.

Continue reading

USB-firmware complete

The USB-enabled STM32F405RG firmware for driving the TCD1304 is complete. The firmware is written for this custom board:

which has high speed rail-to-rail opamps on four analog inputs.

The STM32F4 MCU is identified as a virtual com port (VCP) when connected to a PC. On linux it’s attached as a ttyACM-device, just as the ST-link on a nucleo board. Unlike the nucleo’s St-link (which is setup as a USART-bridge) that has a maximum bit-rate of 115.2 kbps, the STM32F405RG  is working in full speed mode (12 Mbps).

Of course high speed is also possible, but the HS-USB-OTG core of the STM32F405 is on different pins, and so require a different layout of the board, and 12 Mbps is fast enough that the real bottleneck becomes the read-out time of the CCD.

Using essentially the same VCP framework as the UART-FW, there’s not a lot of difference in the source code (except for the large USB-stack of course). so the CLI and GUI for UART work just as well for the USB-fw.

This whole ordeal was an attempt to lower noise, and here’s how that’s going:

With the good old nucleo board I would see fluctuations of about 8 mV ..and at first glance there’s no real improvement with the new board, I still see the same 8 mV. However, since the opamp on the analog input has a gain of ~2, the noise is actually down 50% 🙂

That still makes for a slightly fuzzy line though:

The CCD at close to full saturation. The opamp has inverted and scaled the signal to match the 12-bit ADC’s input range.

However the CCD’s register imbalance is now quite obvious, and subtracting 10 from the signal of every odd pixel, it looks like this:

The same data as in the previous figure, but the CCD’s register imbalance has been taken into account yielding a much cleaner signal.

So mission accomplished. I will update the tcd1304.wordpress site someday in the near future.


[I can’t squeeze any more acronyms into this title]

It’s probably very easy to setup an STM32F4 as a virtual com port (VCP) with the CubeMX software, but I’m getting old and new tricks are getting increasingly hard to learn, so I did it with the standard peripherals library (SPL). Here’s how:

Download the STM32 SPL USB OTG host and device library.

Unzip to somewhere. It should give you a directory like this:


Download the USB CDC VCP Loopback firmware and place the zip-file in the above directory and unzip.

Set the HSE-frequency in:


Modify this file:


Specifically line 98. Change the declaration of *pIf_DataTx from
uint16_t (*pIf_DataTx) (void);
uint16_t (*pIf_DataTx) (uint8_t* Buf, uint32_t Len);

You will of course need the gcc-arm-none-eabi compiler, and put it in your path, so add a line similar to this to .bashrc:

export PATH=/home/user/gcc-arm-none-eabi-4_9-2015q1/bin:$PATH

(of course change “/home/user” and the version number).

After that it should simply be a matter of entering the directory of the firmware and typing make.

Let me know if it’s not working for you..

ps. I realize there’s a more straighth-forward example in the project-directory of USB library, but I just couldn’t get it working.

Inverting and scaling

Fiddling a little (I don’t have a fiddle) with the resistors for the opamp, I finally ended up with this:


It’s the thorlabs logo again, covering the TCD1304. The opamp (AD8027) has scaled end shifted the output to match the ADC’s range. Zero light corresponds to 145mV and full saturation is around 3.23V.

I don’t think I can get closer to 0-3.3V than this without buying fancier resistors. The values are:

R₁ = 510
R₂ = 1k
R₃ = 620
R₄ = 510

for this:


Not exactly what LTspice suggested, but who cares.

Oh yeah and with everything soldered up, it looks like this:


Pin headers for the GPIOs and u.fl. connector for the analogi input.

Did I mention USB is working.. someday soon I’ll have the firmware ported to the STM32F405 🙂

An ideal world

I’m still trying to figure out the purrrfect combination of resistors for the opamp-section of the new STM32 board.

The circuit is the same as my previous experiments with signal conditioning:


Gain is still:

G = - R₂ / R₁

and the level shift is still:

S = R₄/(R₃+R₄)·(1+R₂/R₁)·Vref

The output voltage still becomes:

Vout = G·Vin + S = -R₂/R₁·Vin + R₄/(R₃+R₄)·(1+R₂/R₁)·Vref

Having learnt to use LTspice a little since last, I thought it best to simulate the circuit before putting the iron to the solder. And it works just as it’s supposed to ..until the typical drive circuit from the CCD is connected. Which, in case you spent your life with something meaningful and hence forgot, is here:

tcd1304 typical drive circuit

Then it looks like this:


The green trace is the output from the CCD. The blue trace is the input for the opamp. The red trace is the output from the opamp. The blue trace is clipped. Having read some excellent posts on HaD I didn’t understand about transistor biasing, I thought this could be remedied by adjusting the resistor values around the 2SA1015, and sure enough:

By replacing the 150R resistor to gnd and the 2k2 resistor to +4V with 50R and 150R respectively, everything is back to what it’s supposed. (If any clever ee-geniouses knows if this is not a good idea, please let me know asap). The circuit now looks like this, well in LTspice it looks like this:


And the simulation like this:


No clipping this time 🙂 But of course as my good friend Kensha’s dog Feynmann would say, it’s nothing without an experiment. And so I soldered up the opamp with the resistors (and changed the two on my TCD1304-board).

And of course it didn’t work.. Well it sort of did. The input doesn’t clip (and I tried with the CCD in an unaltered circuit, and the clipping is real with the old resistors). It’s just that I didn’t measure the output from the CCD’s drive circuit with adequate precision before, and so the gain and the level shift needs adjusting.

Which is why I’m writing all this, so I won’t forget about my latest findings. So back to the algebra:

The CCD’s drive circuit delivers output from just above 1.45 V to just under 3.10 V when connected to the opamp (this will sure change with R₁ and R₂).

So anyway, the gain should be (the ADC range is actually 0-3.3V, but playing it safe I’m aiming for a signal range of 3.2V):

3.2V = G(3.10V - 1.45V)     
G = 3.2V/(3.10V - 1.45V) = 1.94

So I will try R₂ = 750R and R₁ = 390, once I get some more time on my hands.

With an input of 3.10V I’d like an output of 0V (slightly above, to keep the ADC happy), so the next equation becomes (the gain is actually negative, because the opamp is in inverting mode, so observe the signs):

Vout = G·Vin + S
S = Vout - G·Vin = 0.05V + 1.94·3.10 V = 6.064V

To find nice resistor values for R₃ and R₄, we need to look at S’ dependence on those:

S = R₄/(R₃+R₄)·(1+R₂/R₁)·Vref
6.064V = R₄/(R₃+R₄)(1+1.94)·Vref
6.064V/(2.94·Vref) = R₄/(R₃+R₄)
6.064V/(2.94·Vref)·(R₃+R₄) = R₄
6.064V/(2.94·Vref)·R₃ = R₄(1 - 6.064V/[2.94·Vref])
R₃ = R₄·(1 - 6.064V/[2.94·Vref])/(6.064V/[2.94·Vref])

Vref is 4.65V, so this all then becomes:

R₃ = 1.254·R₄

So I will try with R₃ = 620R and R₄ = 510R  ..but not tonight. I deserve TV now.