Pages: [1] 2 3   Go Down
Author Topic: linear CCD TCD1201d readout and timing issue  (Read 8931 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 2
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,
I try to read out a TCD1201d linear CCD. It has 2048 pixel and two clock pulses (one is the invert of the other). I have been able to read the CCD but it looks like the pixel data is always the data of the first pixel, as the output of all pixels varies with the light that gets to that first pixel.
According to the data sheet, the timing of the two clock is critical and the rising and falling pulses have to cross. I coded this by writing to the PORTD directly setting the respective bits. The allowed time is 60 ns which is in line with the 16 MHz. However, the readout is not advancing ... (also the value of the dummy pixels and dark pixels is the value of the first pixel that sees light). The noise compared to the comparator output is less than 0.2%, so the chip seems to be ok.

Has anyone been able to read the TCD1201d?

Other linear CCD like the ILX511 or TSL CCDs use only one clock and no boost and reset. And yes, I have read all articles I was able to find on this chip using the common search engines and all linear CCD articles in this forum without success (I have now spent multiple days on this search)
Any help is welcome ...
[Update]
using a logic analyzer, I was able to verify the right sequence of the signals. This includes the timing of the boost and reset versus integration time. I would love to see if someone has read the TCD1201 and could give me the right timing ...
[/Update] 

Ciao, Mathias
« Last Edit: December 23, 2012, 06:23:00 pm by GastonLagaffe » Logged

Offline Offline
Newbie
*
Karma: 2
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Salut,
attached the timing taken from the pins. Ch1=Phase-1, Ch2=Phase-2, Ch3=Reset, Ch4=boost
The overlap between p1 and p2 when switching is 40 ns
The code for reading the chip, using an arduino UNO R2:
Code:
/*
  Linear CCD readout
  lCCD: Toshiba TCD 1201D, 2048 pixel
  Pinmap: 22 DIL
  Chip                               Arduino Pin
    1  :  OS (Output Signal)           A0
    2  :  DOS (Compensation Output)    A1
    3  :  OD (Power +5V)               +5V
    4  :  RS (Reset Gate)              6
    5  :  BT (Boost Pulse)             7
    6  :  P2 (clock Phase 2)           5
    19 :  P1 (clock Phase 1)           4
    21 :  SH (Shift Gate)              3
    all other pins connected to GND    GND
*/
#define OS_PIN A0
#define DOS_PIN A1
#define SH_PIN 3
#define P1_PIN 4
#define P2_PIN 5
#define RS_PIN 6
#define BT_PIN 7

int bt_time = 50; // length of boost
int rs_time = 50; // length of reset
int p1_time = 1; // length of P1
int p2_time = 1; // length of P2
int sf_time = 1; // shift between BT and RS

int sadc[256];  // signal output values read
int sdummy1[32];
int sdummy2[14];


void setup() {
  Serial.begin(9600);
  Serial.println("Setup start");
  for (int i=3;i<8;i++) pinMode(i,OUTPUT);
  pinMode(OS_PIN,INPUT);
  pinMode(DOS_PIN,INPUT);
  // take all to LOW
  PORTD = B00000000;
  Serial.println("Setup Complete");
}

void loop() {
  // do nothing - all done via SerialEvent
  Serial.println("start loop");
  readCCD();

  delay(5000);
}

void readCCD() {
  int dos = 300;
  int dwt = 1;
  int j;
  int val;
  for (int i=0; i<256;i++) sadc[i]=0;
  // start read cycle
  Serial.println("Start read cycle");
  // take all to LOW
  PORTD = B00000000;
  delay(1);
  // set inital state
  //       BRPPSxxx
  //       TS21H
  PORTD = B10011000; 
  delay(1);
  // take BT low
  //       TS21H
  PORTD = B00011000;
  delayMicroseconds(bt_time);
  // take RS high
  //       TS21H
  PORTD = B01011000;
  delayMicroseconds(rs_time);
  // take BT high
  //       TS21H
  PORTD = B11011000;
  delayMicroseconds(bt_time);
  // take RS low
  //       TS21H
  PORTD = B10011000;
  delayMicroseconds(rs_time);
  //
  Serial.println("read dummy output");
  // take gate to low
  //       TS21H
  PORTD = B10010000;
  for (int i=0; i<16;i++){
    // read cylce part 1 (p1=high,p2=low)
    // wait integration time
    delayMicroseconds(dos);
    sdummy1[i*2] = analogRead(DOS_PIN) - analogRead(OS_PIN);
    // p1 high - BT/RS cycle (4 steps)
    PORTD = B00010000;
    delayMicroseconds(bt_time);
    PORTD = B01010000;
    delayMicroseconds(rs_time);
    PORTD = B11010000;
    delayMicroseconds(bt_time);
    PORTD = B10010000;
    delayMicroseconds(rs_time);
    // switch P1/P2 state
    PORTD = B10110000;
    PORTD = B10100000;
//    PORTD = B10110000; // take p2 high
//    delayMicroseconds(p2_time);
//    PORTD = B10100000; // take p1 low
    // read cylce part 2 (p1=low,p2=high)
    // wait integration time
    delayMicroseconds(dos);
    sdummy1[i*2+1] = analogRead(DOS_PIN) - analogRead(OS_PIN);
    // p1 low - BT/RS cycle (4 steps)
    PORTD = B00100000;
    delayMicroseconds(bt_time);
    PORTD = B01100000;
    delayMicroseconds(rs_time);
    PORTD = B11100000;
    delayMicroseconds(bt_time);
    PORTD = B10100000;
    delayMicroseconds(rs_time);
    // switch P1/P2 state
    PORTD = B10110000;
    PORTD = B10010000;
//    PORTD = B10000000; // take p2 low
//    delayMicroseconds(p2_time);
//    PORTD = B10010000; // take p1 high
  }
  for (int i=0; i<32;i++){
    Serial.print(sdummy1[i]);
    Serial.print(" ");
  }
  Serial.println();
  Serial.println("read sensor output");
  for (int i=0; i<1024;i++){
    j = i / 4;
    // read cylce part 1 (p1=high,p2=low)
    // wait integration time
    delayMicroseconds(dos);
    sadc[j] += analogRead(DOS_PIN) - analogRead(OS_PIN);
    // p1 high - BT/RS cycle (4 steps)
    PORTD = B00010000;
    delayMicroseconds(bt_time);
    PORTD = B01010000;
    delayMicroseconds(rs_time);
    PORTD = B11010000;
    delayMicroseconds(bt_time);
    PORTD = B10010000;
    delayMicroseconds(rs_time);
    // switch P1/P2 state
    PORTD = B10110000;
    PORTD = B10100000;
//    PORTD = B10110000; // take p2 high
//    delayMicroseconds(p2_time);
//    PORTD = B10100000; // take p1 low
    // read cylce part 2 (p1=low,p2=high)
    // wait integration time
    delayMicroseconds(dos);
    sadc[j] += analogRead(DOS_PIN) - analogRead(OS_PIN);
    // p1 low - BT/RS cycle (4 steps)
    PORTD = B00100000;
    delayMicroseconds(bt_time);
    PORTD = B01100000;
    delayMicroseconds(rs_time);
    PORTD = B11100000;
    delayMicroseconds(bt_time);
    PORTD = B10100000;
    delayMicroseconds(rs_time);
    // switch P1/P2 state
    PORTD = B10110000;
    PORTD = B10010000;
//    PORTD = B10000000; // take p2 low
//    delayMicroseconds(p2_time);
//    PORTD = B10010000; // take p1 high
  }
  for (int i=0; i<256;i++){
    sadc[i] /= 8;
    Serial.print(sadc[i]);
    Serial.print(" ");
    if ((i%16)==0) Serial.println();
  }
  Serial.println();
  Serial.println("read second dummy output");
  for (int i=0; i<7;i++){
    // read cylce part 1 (p1=high,p2=low)
    // wait integration time
    delayMicroseconds(dos);
    sdummy2[i*2] = analogRead(DOS_PIN) - analogRead(OS_PIN);
    // p1 high - BT/RS cycle (4 steps)
    PORTD = B00010000;
    delayMicroseconds(bt_time);
    PORTD = B01010000;
    delayMicroseconds(rs_time);
    PORTD = B11010000;
    delayMicroseconds(bt_time);
    PORTD = B10010000;
    delayMicroseconds(rs_time);
    // switch P1/P2 state
    PORTD = B10110000;
    PORTD = B10100000;
//    PORTD = B10110000; // take p2 high
//    delayMicroseconds(p2_time);
//    PORTD = B10100000; // take p1 low
    // read cylce part 2 (p1=low,p2=high)
    // wait integration time
    delayMicroseconds(dos);
    sdummy2[i*2+1] = analogRead(DOS_PIN) - analogRead(OS_PIN);
    // p1 low - BT/RS cycle (4 steps)
    PORTD = B00100000;
    delayMicroseconds(bt_time);
    PORTD = B01100000;
    delayMicroseconds(rs_time);
    PORTD = B11100000;
    delayMicroseconds(bt_time);
    PORTD = B10100000;
    delayMicroseconds(rs_time);
    // switch P1/P2 state
    PORTD = B10110000;
    PORTD = B10010000;
//    PORTD = B10000000; // take p2 low
//    delayMicroseconds(p2_time);
//    PORTD = B10010000; // take p1 high
  }
  for (int i=0; i<14;i++){
    Serial.print(sdummy1[i]);
    Serial.print(" ");
  }
  Serial.println();
  Serial.println("read cycle complete");
}


Still hoping, someone has an interest in this problem
Ciao, Mathias


* timing01.png (46.89 KB, 1313x735 - viewed 262 times.)
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

Code:
   PORTD = B10010000;
    delayMicroseconds(rs_time);
    // switch P1/P2 state
    PORTD = B10110000;
    PORTD = B10100000;

I think it's a mistake to switch the clock phases in two operations by writing B10110000 and then B10100000, rather than just writing B10100000. You are introducing a 60ns or more likely 120ns skew between the clock phases, and I can't see anything in the datasheet that allows that. Try writing B10100000 directly, and similarly when switching the other way.

The Arduino high and low output resistances are not very different, so the clocks should cross over at about 2.5V with no extra effort. However, if getting the clock phases to cross above 1.5V is a problem, then try a hardware solution. Between each Arduino clock output and the corresponding sensor clock input connect a small signal Schottky diode, anode to Arduino, cathode to clock input. Connect a resistor of about 22 ohms in parallel with the diode. This will slow down the fall of the clock edge by about 10ns.
« Last Edit: December 25, 2012, 07:49:11 am by dc42 » Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Offline Offline
Newbie
*
Karma: 2
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Salut,
I had originally switched p1/p2 in one statement but then thought the error would be that the crossing point is below 2.5V - So to be on the safe side, I moved the P2 forward. Unfortunately, this is not resolving the problem.

Ciao, Mathias
Logged

Dallas, TX
Offline Offline
Sr. Member
****
Karma: 10
Posts: 318
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You know, sometimes we don't consider that we don't have to do everything with the Arduino. You could use a flip-flop or something to produce your two phases and they would be exactly overlapping. If you use a flip-flop, you would clock it at twice the frequency you needed. At least that would answer the question about whether or not the clocks were the issue.
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You could use a flip-flop or something to produce your two phases and they would be exactly overlapping .... At least that would answer the question about whether or not the clocks were the issue.

Not necessarily. Many type of logic chips have outputs that sink current more strongly than they source it. So even with a flip flop, you might still have to resort to the sort of hardware I suggested to make sure the clocks cross at 2.5V or higher.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

BTW the clock and ground connections between the Arduino and the sensor need to be really short, otherwise you are likely to get ringing on the clock lines. The clock pins have input capacitance of 400pF typical, which is rather high for an Arduino (and most logic chips generally) to drive.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Offline Offline
Newbie
*
Karma: 2
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Salut,
thanks for the reply!

I have no flip-flop at hand and due to the Christmas break, it will take some time to get one. However, if I read the documentation right, the cross-over voltage may not fall below 2.5 Volt, so raising P2 prior to lowering P1 will move the crossing voltage to 5 V well above 2.5 V.[Edit] I guess a NE 555 chip will do as flop flop - will try[/Edit]

In my understanding of the CCD, p1 creates in the first step a trap for the charge created by the captured light. Then P2 is lowered so that the charge flows into the P2-trap and P1 is raised to avoid a flow back. Now I can read the charge into my Arduino ADC. Then, via Reset (RT), the charge is removed. P1 is now lowered to let the charge from the left P2-trap flow into the P1-trap and P2 is raised to close the trap. (Just to confirm)

Still looks like the charge transport is not working and I read out pixel 1 ...

Ciao, Mathias
« Last Edit: December 26, 2012, 06:36:57 pm by GastonLagaffe » Logged

Dallas, TX
Offline Offline
Sr. Member
****
Karma: 10
Posts: 318
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I guess a NE 555 chip will do as flop flop - will try[/Edit]

My suggestion to use a flip flop was because of its complimentary outputs, Q and /Q. The NE555 doesn't have a /Q output.
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I can't any reason why a flip flop would perform better than direct port access on the Arduino.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Offline Offline
Newbie
*
Karma: 2
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Salut,

looks like there is no way to read this CCD with an arduino. I have tried all permutations including a flip-flop and a comparator for the signal. I played with all timing and had the same timing on the logic analyzer as it is in the data sheet. Interesting fact is that the DOS signal varies as well with the light intensity.
However, when searching the web I find that all successful linear CCD readouts use CCDs that have the phase1/phase2 signal generation inside the chip (i.e. ILX551 or TCD1304).
So I will give up the attempt to use the TCD1201 (too bad for the four chips I have) and trash them in favor of the Sony ILX511.

I´ll keep you updated once the chips have arrived.
Ciao, Mathias
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm sure it's possible to read fro that chip using an Arduino. However, unless you have an oscilloscope, you won't know whether you have the signal timings right.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Offline Offline
Newbie
*
Karma: 0
Posts: 11
I like to play with Arduino on the side and sometimes have questions so I come here. Watching the Arduino community grow has been a wonderful experience.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi guys. I've been searching for the answer to this problem for months now. I have 3 TCD1201d chips that I need working. I am curious if there is any progress on this topic? If the Arduino doesn't work what will? A comment earlier says that it won't be able to be fixed without a oscilloscope. If I have a oscilloscope, what would I have to do to fix it?

I apologize if my questions seem dumb. I've never had to drive a sensor like this before. The code is a tad bit over my head. Any help would be awesome. Thanks!
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Here are my suggestions:

1. Keep the ground and clock wires between the Arduino and the CCD as short as possible. Run these 3 wires right next to each other to minimise the inductance. Even a small amount of inductance will cause ringing, because of the high capacitance of the CCD clock inputs. If you can't keep the length of the wires to a few cm, then use a 74HC04 chip to buffer the signals, as shown on the datasheet (and keep the wiring between the 74HC04 and the CCD as short as possible).

2. Make sure you have a 0.1uF decoupling capacitor connected across the CCD power and ground pins, as close to the CCD as possible.

3. Switch the clock lines simultaneously using direct port access. To help make sure that they cross above 2.5V, try either:

(a) a 150 ohm pullup resistor on each clock line, connected as close to the CCD as possible; or

(b) the Schottky diode/parallel resistor arrangement I suggested earlier.

4. Double check that you are sequencing all the CCD inputs correctly.

What do you have the output of the CCD connected to?
« Last Edit: January 12, 2013, 09:27:15 am by dc42 » Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Ottawa,Canada
Offline Offline
Jr. Member
**
Karma: 0
Posts: 82
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm using a Due to create the signals for a UPD3799CY (5300 pixels/line)
  it can create two phase clocks  and syncronous RB  signals using 2 channels of the PWM,
  which can also trigger the ADC
  AND also use PDC to fill the buffer(s) ...
 
downside is the need for level converters of the Due output (clocks,RB & TG1-3 )
 & voltage followers on the Due input (ADC) to adjust the level   and of course the 12 vdc for the sensor ...

 NOTE: this is not 100% tested / waiting for the scope to be delivered before doing the final hookup
 BUT  raw tests look like i can get 37 lines a sec (4096 pixel lines)  and near 88 lines (2048 pixels)

the reason i chose the UPD3799CY is that is ripped out of desktop scanner & came with its own circuit board / decoupling , input & output buffers . .. 
Logged

Pages: [1] 2 3   Go Up
Jump to: