Linear CCD module

TCD1304-based linear CCD module driven by a Nucleo F401RE or an STM32F103 blue pill

Similar projects worth following
The TCD1304 is a high sensitivity 3648 pixel linear CCD. It's used in some Ocean Optics spectrometers, but because of the difficulty of driving CCDs it has not found widespread use in DIY projects. This project describes a low cost linear CCD module based on the TCD1304. The TCD1304 is connected to an STM32 microcontroller, which takes care of the time-critical driving and reading of the CCD. A Raspberry Pi or a regular laptop hosts a GUI or a CLI for easy control of integration time and display the collected data.At the time of writing there's linux (CLI and GUI), macOS (CLI and GUI) and Windows (GUI only) support.For more information about the TCD1304 go to: which contains the latest firmware and software, and where the instructions are also up-to-date with the latest firmware.

Driving the TCD1304:

The TCD1304 requires the following input to function

  1. The master clock (fM)
  2. The shift gate (SH)
  3. The integration clear gate (ICG)

The frequency of fM must be in the 0.8-4 MHz range. In this project fM = 2.0 MHz (but it is user changeable)

The SH-period defines the integration time. The ICG-pulse defines the moment the pixels are moved to the shift register.

The datasheet provides the following figure for the timing requirements for the SH and ICG pulses:

This translates to the following:

  1. SH must go high with a delay (t2) of between 100 and 1000 ns after ICG goes low.
  2. SH must stay high for (t3) a minium of 1000 ns.
  3. ICG must go high with a delay (t1) of minimum 1000 ns after SH goes low.

This is all taken care of by the timers in the STM32F401RE. In fact once they're set up the MCU is not doing any work. The only thing the user has to do is to choose ICG-periods that are multiples of the SH-period.

Since the timers controlling the SH- and ICG-pulses are 32 bit (and run with a frequency of 2.0 MHz) the possible integration times are in the range of 10 µs - 2147 s.

Reading the TCD1304:

The data rate of the CCD is 1/4 of fM, which means the pixels are clocked out at 0.50 MHz. The ADC in the STM32F401RE is fast enough to do 12 bit conversions at this rate. The pixel values are sent to a 16 bit array using DMA. From here they are sent to the Raspberry Pi over SPI at 16 MHz - also utilizing DMA - or through UART to a regular PC via the built-in ST-link's USB-connection.

The voltage of an "dark" pixel is around 3.0 V and a "white" pixel has a voltage of around 1.5 V. In other words the data is upside down.

Total cost of the project:

Raspberry pi zero 5$ (optional)

Nucleo F401RE 11$

TCD1304 2-3$

miscellenaeous 5$

All in all it can be built for around 25$

More information:

The source code is littered with comments as best I could, so dig into it if you want to know more details about setting up the STM32F401RE's peripherals.

This project is part of The Otter DIY Raman Spectrometer. You can read more about that here:


Everything comes with the FreeBSD-license, so do with it what you want. The only exception is the Nucleo F401RE which is under ST's evaluation license.

TCD1304 PCB Buy it directly from

Zip Archive - 139.84 kB - 10/28/2018 at 07:53


  • 1 × Raspberry Pi (optional*) *not needed for the UART-enabled firmware
  • 1 × Nucleo F401RE
  • 1 × TCD1304 Sensors / Image
  • 1 × 74HC04 Electronic Components / Misc. Electronic Components
  • 1 × 2SA1015-Y Discrete Semiconductors / Transistors, MOSFETs, FETs, IGBTs

View all 10 components

  • Double-vision

    esben rossel09/18/2019 at 19:56 0 comments

    This is not really a new feature. I made the first double-CCD firmware two years ago for a group of students in Germany. I forgot what they used it for, but they paid me in delicious german food.

    I've since received a couple of requests for this feature from others, and rather than do a per-bratwurst-offering, I've decided to include it in the downloads-section at There you'll also find a more in-depth walkthrough about considerations to make before changing the 4 or 5 lines of code required.

    The long story short is that you can drive and read up to four CCDs with one STM32F401RE nucleo with an MCLK of 2,0 MHz. If you lower the CCD-clock, you can get away with up to eleven CCDs (my back-of-the-envelope calculations say). Of course you may run out of gpio's for ADC-input with that many CCDs, I haven't checked.

    Anyway, here are some pictures.

    One CCD is covered with M2-washers, the other with ball-point pen spring. Here's what's captured:

  • Live-view

    esben rossel04/08/2019 at 10:14 0 comments

    The pyCCDGUI has received a lot of love this weekend. I'm most proud of moving the serial port handling  to a separate thread, so the GUI remains responsive during long integrations, but the most interesting new feature is probably the "live-view".

    Ok, so it's not super lively with the nucleo F401 which can only transmit at a frame-rate slightly higher than 1 Hz (because of the slow UART-connection to the ST-link), but with the STM32F103 where there's real USB, the pyCCDGUI can now read the TCD1304 and update the plot at up to 9,5 Hz.

    There's also a few other new things (filehandling, a flashy new progressbar, compensation for shift register imbalance and few updates to the help-section). Check it out for yourself. Files are available at

    Here's a screenshot for the impatient:

    I've not yet updated the firmware for the STM32F405 to support continuous output, so I cannot yet report the frame-rate with this mcu.

  • STM32F103 blue pill driver for the TCD1304

    esben rossel03/03/2019 at 11:27 0 comments

    The blue pill is very popular (and cheap), and I've spent this weekend porting the TCD1304 driver firmware to it. It's a less capable chip than the STM32F401, there are limits to the applications. Most importantly, it doesn't support integration times longer than 82 ms.

    The specifications are:

    • USB-connection
    • MCLK of 800 kHz
    • max t_int  is 2¹⁶ / 800 kHz = 82 ms

    Pin-out is:

    • OS - PA1
    • ICG - PA10
    • SH - PB4
    • MCLK - PA15

    The board attaches as a virtual com-port, so the usual tools work ie. the pyCCDGUI and the CLI (UART).

    Everybody loves pictures, so:

    Get it while it's hot. Go to

  • Platform independency

    esben rossel08/19/2018 at 16:19 0 comments

    I'll keep this short. I've written a graphical user interface for python 3. pySerial handles communication, so there are no ties to Linux and/or macOS with this one.

    The program can be found in the files-section and on of course.

    And here's the stand-alone windows executable

  • Noise

    esben rossel06/28/2018 at 17:32 0 comments

    Driven by a nucleo board,  the signal from the CCD in the typical drive circuit with a low-noise low drop-out voltage regulator exhibits roughly ±4 mV of noise. This figure is the same for the custom STM32F405 board, however because the opamp has a gain of ca. 2, the S/N-ratio has improved with app. 50%.

    Still, the output looks kind of fuzzy, as seen in this figure showing the CCD at close to saturation:

    However, because the noise-level is now a little lower, it's become very easy to estimate the CCD's register imbalance, and when correcting the data for it, the same data now looks like this:

    I'm not sure I'll get a cleaner picture than this. I'm certainly not in the mood for trying.

  • Straight to USB

    esben rossel06/27/2018 at 13:08 0 comments

    The UART-firmware uses the USB-connection on the nucleo's ST-link, and it's limited by the bitrate of the ST-link's USB-UART connection.

    The latest firmware is written for the STM32F405-board from this project:

    and it uses the USB-controller in full speed mode (12Mbps) to communicate directly with the PC.

    I've used ST's USB-driver (SPL-version), and the MCU presents itself as a virtual com port, so the CLI and GUI for UART can be used without modification for the firmware.

    Clocks, PWMs and communication are all working. I'm going drinking, so tests with a TCD1304 in place will have to wait.

    oh right and the firmware can be found in the files section.

  • Setting the CCD up with a custom MCU-board

    esben rossel06/16/2018 at 05:59 0 comments

    I've ben working on a custom STM32F405 board with better analog options in a separate project.

    The key difference is the utilization of an opamp on the input, to squeeze the last bit out of the STM32F4's 12-bit ADC.

    The opamp circuitry looks like this:

    For reasons I don't fully understand, the opamp's input and feedback resistor values affect the output from the CCD's typical drive circuit, but changing the resistors to:

    there's no clipping of the output. I guess my quantum chemistry professor was right, you can't measure a system without changing it.

  • 100 Hz frame-rate for the TCD1304

    esben rossel12/24/2017 at 16:24 0 comments

    With a slight redesign of the SPI-firmware and the accompanying command-line-interface, I'm proud to present a record high (for me at least) frame-rate for the TCD1304 of theoretically 125 Hz.

    I'll be conservative and state that 100 Hz is possible. Because of x-mas I'm away from my scope, so a proper speed-test will have to wait.

    The very short version of the story is that wiringpi has been replaced in favour of pigpio, and that SPI-communication is triggered by monitoring the logic state of one of the nucleos GPIOs.

    Oh and you can collect 65535 integrations in one go.

    For more details read this:

    or look in the source code.

    Downloads are available at

    The UART-firmware is still crawling away at a pace of just above 1 Hz, but with lots more convenience.

  • New PCB: 12% smaller, 12% cuter, 24% easier

    esben rossel11/12/2017 at 14:44 0 comments

    The latest firmware and PCB is here:

    besides from being smaller, there's now a regulator on the supply voltage:

    Vs = 1.22 (1 + R₂/R₁) = 1.22V(1+ 2.7kΩ / 1.2kΩ) = 3.96V

    The pinout has been changed:

    and so has the GPIOs on the STM32F401re, so everything's much easier to connect:

    (The CCD-PCB in the picture is a prototype)

    As always go to to be sure to get the latest and greatest firmware and software, and instructions to match.

    The PCB (slightly improved compared to the one in these images) is available directly from

    It's only the UART-firmware that has been updated. The SPI-version will follow shortly.

    Both firmwares (SPI and UART) been updated with the new GPIO-configuration:

    • fM on PB0
    • SH on PA1
    • ICG on PA0
    • OS on PC0

  • Windows support

    esben rossel08/18/2017 at 16:34 0 comments

    Jens-Ulrich Fröhlich has written a Java-based graphical user interface for the Linear CCD module for Windows, and I must say I'm impressed. It has many of the features that I wanted to include in my early attempts at a GUI.

    And it comes at just the right time. In this school year I will 'convince' my students to try and build their own spectrometers, so a Windows interface is greatly appreciated, as my nerdier students prefer this OS.

    Take a look at his blog:

    and the github-repository:

View all 20 project logs

  • 1
    Step 1

    Connecting the TCD1304 board to the STM32F401RE:

    Or if you went with the 2nd SMD-version:

    Or the version with a regulated voltage supply:

    The connections depend on the firmware. If in doubt download the latest firmware from and follow the instructions at that site (I don't always remember to keep HAD up-to-date.)

    1. fM connects to PB0
    2. SH connects to PA1
    3. ICG connects to PA0
    4. Output connects to PC0

    Ideally the TCD1304 runs on 4.0 V, but connecting V+ to the +5V pin works fine.

  • 2
    Step 2

    Connect Nucleo F401RE to Raspberry Pi:

    The SPI headers on the raspberry pi are located on:

    1. MOSI P1-19
    2. MISO P1-21
    3. SCLK P1-23
    4. GND P1-25

    On the nucleo board these are located on:

    1. MOSI on PB15
    2. MISO on PB14
    3. SCLK on PB13
    4. GND - there are lots to choose from
  • 3
    Step 3

    Setting up the cross-compiler on linux:

    Download the gcc-arm-none-eabi

    Unzip to a directory, and add the compiler to path by adding this line to .bashrc:

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

    Download the standard peripherals library (SPL) for the STM32F4.


    Download the TCD1304 driver firmware for the Nucleo F401RE

    Unzip to the directory the SPL unzipped to. Enter directory and type 'make'.

    Upload the resulting .bin file to the nucleo board.

    NB: If you haven't got a 74HC04 or other inverter between the nucleo and the TCD1304 there are a couple lines in timer_conf.c you'll want to change. Inverse the timer polarity registers.

View all 5 instructions

Enjoy this project?



Henning Paul wrote 02/27/2016 at 18:28 point

Where did you get the CCD that cheap? Usually they're around 10$.

  Are you sure? yes | no

esben rossel wrote 02/27/2016 at 23:15 point

*bay. If you can find the TCD1304DG which is the older non-RoHS compliant version you should be able to get a better price than for the TCD1304AP. They have identical specifications.

  Are you sure? yes | no

esben rossel wrote 02/23/2016 at 17:13 point

I'm going to build several :D (different types)

First on the list is a Raman spectrometer. You can also follow the progress at

  Are you sure? yes | no

zakqwy wrote 02/23/2016 at 17:45 point

Cool! I'm sure you've done the research at this point, but if you haven't seen it, make sure to check out #ramanPi - Raman Spectrometer. TONS of great documentation..!

  Are you sure? yes | no

esben rossel wrote 02/23/2016 at 17:59 point

Yes the Ramanpi is a supercool project.  In fact it was what got me started in the first place. Then I sort of diverged from fl@tc@t's design.

  Are you sure? yes | no

zakqwy wrote 02/23/2016 at 17:10 point

Wow, I'm surprised how cheap those modules are online. What's your plan for this project? Building a spectrometer?

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates