Firmware revision

Summer brought a revision of the STM32F401RE TCD1304 driver.

In the firmware for the nucleo board the data collected by the ADC is stored in memory using DMA. Until now the ADC+DMA was turned on by an interrupt created by the timer controlling the ICG-pulses (remember that the ICG pulse moves the pixels to the shift registers on the TCD1304). The ADC and DMA are turned off again by an interrupt created by the DMA-controller once the write-buffer is full.

Enabling the DMA from a timer interrupt is painless, but disabling it using an interrupt triggered by the same DMA-stream that you want to turn off is not. The reason is that disabling the DMA-stream creates a new interrupt – the same interrupt in fact – so you can easily get stuck in the interrupt routine.

To avoid this there are several possibillities:

  • You can switch the DMA-mode from circular to normal, then the DMA shuts itself down once the write-buffer is full. The downside is that that means reconfiguring the DMA-controller every time it needs restarting. But time is of the essence and there’s only 91 µs from the ICG-timer overflows until the first pixel arrives at the ADC – and I have no idea how long the interrupt latency is or how long it takes for the DMA to start.
  • You can probably find a clever way to only switch off the DMA-controller once, even if the interrupt routine disabling it is also called when it’s disabled. However I couldn’t, my hangover from the day before was too severe.
  • You can read the reference manual for the STM32F401RE again and realize that you don’t need to touch neither the DMA nor the ADC. You simply disable the timer that paces the ADC. With the timer disabled the ADC won’t start new conversions and won’t make new DMA-requests. So that’s how it’s handled from now on.

I thought I would be able to write a firmware with UART instead of SPI during the summer holiday, but it’s only halfway done as I ended up spending my time listening to jazz and drinking beers instead. It’s high on my autumn-todo-list though and it will enable direct communication over the nucleo’s built-in ST-link through USB.

This means saying goodbye to the raspberry pi – unless of course you stick with the SPI-version. It also means that the nucleo board will have a say in just exactly when data is transmitted – in contrast to SPI where the rpi must be master, there’s no such restriction with UART. The downside is that while SPI is fast – it takes just 4 ms to transmit all the data from the TCD1304 – UART is not. The transmission time is around 320 ms with a baud-rate of 230400 bps (the highest I’ve been able to achieve) with UART.


5 thoughts on “Firmware revision

  1. Jarrah Peddie says:

    Heya Mate,

    I ended up getting some code up and running based on the original ramanPi code to successfully drive the TCD1304 with your CCD board. See below for minimal working example, ill get it onto github or somesuch once i get around to setting all that up 😛

    #include “mbed.h”

    PwmOut shiftGate(PB_8);
    PwmOut icg(PB_3);
    PwmOut masterClock(PB_4);

    AnalogIn imageIn(PA_0);

    DigitalOut led1(LED1);

    InterruptIn masterClock_int(PB_4);

    int main() {
    // set the masterClock
    masterClock.period_us(2); //2 def
    masterClock.pulsewidth_us(1); //1 def

    // set the shiftGate and have it start 15us after the masterClock – this will sync the clocks up so the shiftGate is going high just
    // after (t2:100-1000ns, 500ns typical) a clock cycle is going high
    shiftGate.period_us(20); //20 default
    shiftGate.pulsewidth_us(10); //5 defualt

    // set the ICG clock and have it start 82.76ms after the shiftGate – this will sync the clocks up so the ICG is going low slightly
    // before (t2: 100-1000ns, 500ns typical the shiftGate is going high
    wait_us(82758); //82760 default
    icg.period_us(80000); //80000 def
    icg.pulsewidth_us(16); //79990 def

    // do something while it’s having fun..
    while(1) {
    led1 = !led1;


  2. Cool, you got the CCD running with mbed. I didn’t think that was possible.

    It surprises me it that it works for you with a master clock of 500 kHz. I had the impression from the datasheet for the TC1304 that the minimum fM frequency was 800 kHz.

    If I understand the code correctly you’ve set up PA0 as ADC-input. I would love to know if you can get mbed to handle the CCD-output fast enough. If I recall correctly this is where flatcat hit the wall with the Nucleo F401.

    I never used mbed because I felt the hardware-abstraction-layer (if that’s what it is) kept me from being able to use the features of the STM32F401RE MCU properly, but I do recognize it’s very easy to get started with it.


    • Jarrah Peddie says:

      Yeh, I’ve only done basic things with it and it already seems like I’m going to run into limitations quick. CCD seems to work fine on 0.5khz, although perhaps with more noise than normal. The ADC does seem like a puzzle to be sure.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s