Looking at the timing requirements for the TCD1304 you quickly realize that it will be a small nightmare to toggle three GPIOs with for/while loops within the tolerance needed. Luckily this can be handled with the timer peripherals on the MCU.
The master clock
The TCD1304 requires a master clock (fM) with a frequency in the range of 0.8-4 MHz. The datasheet gives a typical value of 2 MHz. The CCD output data-rate is 1/4·fM and the ADC must be able to keep up with this.
The fM-frequency is set in main.h.
With fM = 2 MHz the data-rate is 0.5 MHz which gives a maximum conversion time of:
(0.5 MHz)⁻¹ = 2 µs
This is fine for the STM32F401RE’s 2.4MSps ADC¹, which runs with speeds up to 30 MHz, so fM is set to 2.0 MHz.²
There are eight timers on the STM32F401RE. Two of them are 32 bit and the rest are 16 bit. For fM, which has a short period, we (obviously) choose a 16 bit timer (TIM3).
TIM3 runs with a clock of 84 MHz. It can be prescaled, but I haven’t done so. To get a frequency of 2.0 MHz for the fM-pulses the period of the timer must be:
84 MHz / 2.0 MHz = 42
The data-rate is 0.50 MHz, and to start the conversion of each pixel at the proper time, the ADC is triggered with the 16-bit timer TIM4. As with TIM3 this timer also runs with a clock of 84 MHz, so the period is set to 168.
On a side-note, enabling/disabling TIM4 starts and stops the ADC+DMA, without the need to reconfigure the DMA-controller and ADC.
TIM4 is enabled in an interrupt generated when the ICG-pulse is created, and disabled in a different interrupt created by the DMA-controller servicing the ADC. On the scope it looks like:
The SH- and ICG-pulses
The SH-pulses control the integration time, and the ICG-pulses the moment the pixel-values are sent to the shift register. Obviously it is desirable to be able to integrate over very long periods of time, so these pulses are controlled by the two 32-bit timers TIM2 and TIM5.
The maximum time-resolution is determined by the frequency of fM, so by prescaling TIM2 and TIM5’s timer-clocks to 2.0 MHz, we save ourselves from having to think too much about synchronization, while achieving integration times of up to
2³² / 2.0MHz = 35 min
The duty cycle or pulse of the two timers must comply with the timing requirements. The SH-pulse must be at least 1000 ns (the datasheet gives no upper limit). With a 2.0 MHz clock a pulsewidth of 4 cycles gives:
4/ 2.0 MHz = 2.0 µs
The ICG-pulse must be at least 1000 ns longer than the SH-pulse. A pulse of 10 cycles corresponds to 5 µs. On the oscilloscope it looks like this:
The lowest integration time for the TCD1304 is according to the datasheet 10 µs, so the lowest period for TIM2 which controls the SH-pulses is:
10 µs · 2.0 MHz = 20
The total readout-time is given by the data-rate (0.50 MHz) and the total number of pixels – including dummies:
3694 / 0.5 MHz = 7.4 ms
which with a clock of 2.0 MHz equals a minimum period for TIM5 of:
7.4 · 2.0 MHz = 14776
As the SH- and ICG-pulses must coincide, it’s advisable to use periods for TIM5 in multiples of the period of TIM2.
Whenever TIM5 creates an ICG-pulse, it also generates an interrupt which enables TIM4. This way the ADC is restarted every time the TCD1304 outputs its pixels.
For more details about setting up the timers look in the source code in:
Beware that there are three timer-polarity registers to invert around lines 60, 250 and 260 if you do not employ a hex-inverter between the MCU and the TCD1304.
¹ Read more about this the ADC section.
² Until recently I had misunderstood the ADC’s timing diagram, which led to the misconception that the ADC in single conversion mode needs a stabilization time (tstab) of 2 µs between every measurement. This in turn led to the conclusion that 1.4 MHz was about the top speed for the CCD with the STM32F401RE.