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.

Replacing the STM32F4 nucleo

If you are a recurring visitor of this blog you probably know that the detector in the Raman spectrometer is the TCD1304DG linear CCD, driven by an STM32F401RE nucleo board. If not, you do now. And it looks like this:


The firmwares for the STM32F401 are stable, and I’ve not encountered any problems or bugs in neither the SPI- nor the UART-version.

Each firmware has its merits.

The UART-version is usable with any computer with a USB-port, but because of the limitations of the ST-link’s implementation of a virtual com port it’s rather slow and cannot achieve frame-rates much higher than 1 Hz. This is not a problem for Raman spectroscopy which will probably require long integration times anyway.

The SPI-version is fast, but requires a raspberry pie or something else with an SPI-controller. The frame-rate can be as high as 125 Hz (or higher still, with a slight modification of the DMA-setup). This is high enough that it can be used for glowstick kinetics.

But regardless of the firmware, the nucleo board is not tailored for reading the CCD. The CCD output needs conditioning to match the input range of the ADC, and a (very) cheap development board like the nucleo doesn’t include that.

I’ve tried to do the signal conditioning on the TCD1304 circuit board:


While very cramped it works. However it didn’t do anything positive (or negative) for the noise that always seems to be present, even with very low noise voltage regulators like this (here there’s no opamp for signal conditioning):


the noise is still there:


ok maybe it doesn’t look super-noisy, but in this graph (which is one of the cleanest) the baseline is constantly fluctuating ±4 mV. 8 mV doesn’t sound like a lot, but it’s actually a magnitude higher than the resolution of the ADC (and it’s evident from the data, that it’s not the register imbalance of the CCD in play).

So after a few different PCBs (with and without opamp) the conclusion is that the noise is inherent to the nucleo board. Whether it’s the board’s layout or the choice of voltage regulators I don’t know, though Bertrand in Switzerland suggested that it could be the connection and choice of wire between the nucleo and the CCD (he’s most probably right).

Anyway, it’s great to have an excuse to try something new, and here is the substitute for the nucleo board¹:


It’s an STM32F405RG on a 4-layer PCB, with discrete power planes for the digital and analog parts of the board. All regulators have a noise level of 20 µV (that’s 40x beneath the ADC’s LSB). The analog section features a ±4.65 V power supply for the four AD8027 high speed, low distortion, rail-to-rail opamps (not fitted).

The circuit around opamps U0 and U1 looks like this:


(correct for the supply voltages) and the simulation like this:


(sorry for the mess of the circuit). The blue trace represents the signal from the TCD1304 in the LDO-version of the PCB. The green trace is the conditioned signal, inverted and scaled to fit the range of the ADC.

The plan is to use STMicro’s USB-driver to attach the board as a virtual com port. So far the DfuSe bootloader appears to be working, but I’m back to scratch for getting my compiler to produce working binaries.

Being an absolute dummy with makefiles this may take a while..

Update: I hugely overestimated the troubles I would have with this last part. I can’t even remember what I changed in my f401 makefile (though I do know I did change something).

The board is working. At least my blinky works, and initial speed test with a timer yielded a timer clock with the expected 72 MHz. Which means that the clock configuration is correct:


[1] The board is inspired by the STM32F4Stamp and I’ve tried to follow all recommendations in the datasheets and application notes for every component. Still I’m sure there’s room for improvement.

Other sites of interest

Here’s a list of pages I find interesting (occasionally steal inspiration from):

    A belgian chemist and optical engineer who does many different things from counting bubbles to building thin film refractometers.
    A subsection of the astrosurf site with a lot of information for building spectrometers. (There’s lots more on the astrosurf site itself.)
    T.J. Nelsons site contains information about lens and spectrograph design.

The list is so I don’t forget about these resources (because I’m sure I already forgot some). Feel free to send me more links.


(my) Latest spectrograph advances

With my girlfriend out of the flat for a few days, it was time to finally do something about the spectrograph. If you’ve been looking at my hackaday projects you may know I’m trying to make a Gil-Simon spectrograph.¹

Much like nuclear fusion reactor technology, my Raman spectrometer has been close to completion since the beginning, and right now I’m closer than ever, and I have the pictures to prove it:


All mirror mounts approximately in their final positions.

As evident from the photo, I’ve become quite adept at anodizing aluminium.

The geometry of the spectrograph is more apparent here:


Here a few of the mirrors are in place:


In the vertical mount: Two 90° off-axis parabolic mirrors (OAP).
In the top center kinematic mount: A 25,4mm elliptical plane mirror.

The mirrors work: The reflection of Little My is caught by mirror on the aluminium angle on the right and focused by the two OAPs:


Unfortunately my 3D printer is out of commision for the time being, so for the time being, I cannot print a mount for the grating..

[1] M. A. Gil and J. M. Simon, “New plane grating monochromator with off-axis parabolical mirrors,” Appl. Opt. 22, 152-158 (1983)