Controlling an ILX511 Linear CCD Sensor

float pulsetimer = 0;

Are you figuring on having fractional pulses?

CLKState = digitalRead(CLKPin);

You've made it an output, yet you're reading it.

Thanks for the replies.

ralphnev,
I'm using the SHSW mode (set to grd). It gives a smoother plot of data points compared to not using it, which outputs waves of different amplitudes. Although, if I actually got the sensor to change pixels, not using the SHSW mode may be useful in distinguishing what pixel gave what reading because the output gives a constant voltage when clock pulses are LOW and then outputs the reading of the next pixel in line when the clock pulse is HIGH. This way, you can see the shifting from pixel to pixel. Keep me posted on your progress.

AWOL,
Right now, I'm not using fractional pulses. Would I gain anything from this other than not having to count to as high as 12568?
Also, digitalReading an output pin will still return the state it is in.

Why isn't the CLKPin set in the setup() as pinMode(CLKPin, INPUT) or pinMode(CLKPin, OUTPUT)?

Also, digitalReading an output pin will still return the state it is in.

But you wrote the state it is in!

This is not the FULL code is it?

DDRD = B00101000; //Pins 3 and 5 as outputs

Nevermind my previous post

Why isn't the CLKPin set in the setup() as pinMode(CLKPin, INPUT) or pinMode(CLKPin, OUTPUT)?

I didn't know "B00101000" was possible to do with arduino.

I appreciate ya'll checking my code

AWOL,
I realize that I'm writing what state it is in. The point of reading it is to check the state and set it to the opposite state. If it's high, set to low. If it's low, set to high.

HazardsMind,
And yes this is the full code. I tried keeping it simple since I'm reading and writing so often, and it is imperative that the clock pulses remain consistent.

I'm looking for advice on generating square wave pulses with a constant frequency and duty cycle, and reading the outputs of a sensor in between the pulses. Or suggestions if anyone has interfaced a CCD sensor with arduino.

Did you get anywhere with your project?
I have started to mess about with an ILX511 but found it started to get warm at one end when grounding pin 4 to do S/H mode so stuck with pin 4 to VCC. What circuit did you use for S/H mode?
Below is some code I just wrote to test (for non S/H mode) but have not tried plotting it's results yet to know if it works.
As the UNO does not have enough memory to read the entire CCD I sample every other pixel and right shift the result 2 places to fit result into a byte.

#define CLK 5
#define ROG 11
#define LED 13
#define CLKSPEED 50

#define FASTADC 1
// defines for setting and clearing register bits
#ifndef cbi
  #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
  #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

byte sampleArray[1044];
unsigned long sampleTime;

void setup() {
  Serial.begin(115200);
  #if FASTADC
    // set prescale to 16
    sbi(ADCSRA,ADPS2) ;
    cbi(ADCSRA,ADPS1) ;
    cbi(ADCSRA,ADPS0) ;
  #endif
  
  pinMode(ROG,OUTPUT);
  digitalWrite(ROG,HIGH);
  pinMode(CLK,OUTPUT);
  digitalWrite(CLK,LOW);
  pinMode(LED,OUTPUT);
  delay(1000);
}

void loop() {
  digitalWrite(LED,HIGH);
  digitalWrite(CLK,HIGH);
  delayMicroseconds(500);
  digitalWrite(ROG,LOW);
  delayMicroseconds(1000);
  digitalWrite(ROG,HIGH);
  delayMicroseconds(500);
  for( int x = 0; x < 2088; x++){
    digitalWrite(CLK,LOW);
    
    sampleTime = micros();
    while ((sampleTime + CLKSPEED) > micros()){
    }
    digitalWrite(CLK,HIGH);
    
    sampleTime = micros();
    if (x & 1) {
      int y = analogRead(A0);
      sampleArray[x >> 1] = y >> 2;
    }
    while ((sampleTime + CLKSPEED) > micros()){
    }
  }
  digitalWrite(CLK,LOW);
  digitalWrite(LED,LOW);
  delay(100); 
  
}

Hi Riva,

I never got past being able to read only the first pixel. I even checked the logic with an analyzer and still didn't get an entire array of pixel data. The circuit I was using was the one directly from the datasheet for the sensor. I used an arduino with the sensor and collected data with an external data acquisition device I had lying around at work using Labview. Were you actually able to receive data from the whole array of pixels? If so, what did your circuit look like? Were the CLK and ROG pins on the sensor connected directly to the arduino, or did you have additional circuitry in between? I might have to come back to this project now haha.

No luck yet reading the entire pixel data. Like you I only seem to have the first pixel as the level raises/lowers when I cover only one end of the array.
I'm not even reading the dummy pixels or the optical black before the first actual pixel so suspect I'm not close yet.
After the array heating up I discovered a poor ground was to fault and though I may have fried the CCD but trying a new CCD gave the same results.
I still have a few ideas to try but am beginning to wonder if the arduino UNO & MEGA are maybe to slow at clocking & reading the device. The datasheet does not give upper limits on most signal timings but there is a large difference between something like 3000ns and 20us that is as fast as I can analogue sample the data using arduino.
I will let you know if I manage to get it working.

In my tweaks & tests today I noticed that even if I disconnect ROG & CLK lines from the arduino I still get the same (first pixel) waveform as with them connected so they seem to have no effect.
Maybe CLK is not running quick enough though I cannot go much faster as it takes 24uS to analogue sample and store a pixel and with CLK running at 64uS PP I only have 8uS overhead when sampling.

Hi Bumpasticka,

I laid out the hardware again as the old board was a bodge and also used a faster transistor for amplifying Vout and I am starting to get something now. The CCD is very sensitive to light so after applying an electrical tape mask and working in a dim room I managed to get an output.
First is covering the entire CCD with my finger and as expected the trace is flat but I am getting the dummy pixels before and maybe after (harder to see) the effective pixels.
The second picture is with my finger hovering over the middle of the CCD. It's not as good as expected as I think the setup is in need of a lens to focus light and mask off stray ambient light.

Hi guys,

perhaps you have a huge progress already on interfacing ILX511 with Arduino.
Could you please post some complete wiring scheme and sample code for basic reading from the sensor.
I'm complete nub, so will be thankful for any details here or on the WIKI.

This might be a silly question, but do you have to use a transistor to amplify the Vout? Is it possible to just connect directly to an analogue input? I realize I'll lose resolution, but that's not so important here.

I have the ILX511 wired up to the arduino, with CLK and ROG connected to digital outputs. I pulse ROG low for 5000us, then wait 1000us before alternating the clock - I've tried different frequences from 10us up to 10ms. SHSW is held low so that I activate the internal S/H circuit. I record the minimum and maximum values read, which are around 250-380.

mdma:
This might be a silly question, but do you have to use a transistor to amplify the Vout? Is it possible to just connect directly to an analogue input? I realize I'll lose resolution, but that's not so important here.

I have never tried without a transistor on the output so cannot say.

So, since this was my first attempt at anything with electronics, I realized I was way over my head and needed to learn the basics. Recently, I picked up coding again and came back to this project. Using the Timer1 library, I got something that works, granted it will only control the ILX511 sensor. You need an oscilloscope to view the output.

#include <TimerOne.h>
#define pwmRegister OCR1A

const int rog_pin = 4;
const int clock_pin = 9;
long period = 1;
long duty = 512;
unsigned long current = 0;
unsigned long previous = 0;
unsigned long difference = 0;

void setup() {
  pinMode(rog_pin, OUTPUT);
  pinMode(clock_pin, OUTPUT);
  Timer1.initialize(period);
  PORTB = B000010;
  PORTD = B00010000;
  Timer1.pwm(clock_pin, duty);
}

void loop() {
  current = micros();
  difference = current - previous;
  if(difference >= 2087) {
    Timer1.disablePwm(clock_pin);
    PORTB = B000010;
    delayMicroseconds(500);
    PORTD = B00000000;
    delayMicroseconds(500);
    PORTD = B00010000;
    delayMicroseconds(500);
    previous = micros();
    Timer1.pwm(clock_pin, duty);
  }
}

It works very well. The long microsecond delays are to make it easier to view the end of the pixels on an oscilloscope. As it is now, it will pulse the clock_pin at 1 Mhz. The major problem with the code is that upon reinitializing pwm at the beginning of each read, the duty cycle is sometime distorted from 50% for the 1st pixel. Also, the same goes for the last pulse when pwm is paused. If anybody has ideas, that would be awesome. I'll need to optimize that portion at some point...and then figure out how I'm going to store the pixel data at 500k - 1M hz :fearful:

Bumpasticka,

Do you mind posting your schematic or pin wiring for the arduino with the sensor? Also, did you use a transistor as suggested in the previous posts or did you just leave Vout un-amplified?

Have you tried running this with other arduinos? I believe the mega, for instance, prefers timer3 instead of timer1 because of the output pins.

Thanks!

I also revisited this project as I was considering using a faster MCU but in the end found the voltage translation needed between 3.3V & 5V to much hassle so tweaked and tested my original Mega code to confirm it still worked okay.
You have to be aware the CCD is very sensitive and to reduce the light levels enough to do a finger test I have to put a piece of thin card on the CCD, my finder on this card and then another piece of cardboard to shade direct light from the ceiling light falling on my finger/CCD.

Attached is the Mega sketch, logic analyser capture of CLK/ROG output + test pin output used to determine time spent in different sections of the timer ISR.
Also attached are the outputs with my finger on the middle of the CCD and one with no finger. They were make with a simple sketch written in processing.

ILX511_v5_MEGA.ino (5.22 KB)

Attached is the processing sketch used to read out the data from the ILX511 CCD running on the Arduino Mega.

boolean myDebug = false;

int sampleBufferSize = 2201;                                // The sample buffer
int[] sampleBuffer = new int[sampleBufferSize + 1];         // Samples
int sampleCount = 0;                                        // Sample position counter
int timeout = 0;                                            // Used for timeout counter while waiting for Serial data

import processing.serial.*;
Serial arduinoSerial;                                       // The serial port

void setup() {
  if (myDebug)
    println(Serial.list());                                 // List all the available serial ports
  else {
    //arduinoSerial = new Serial(this, Serial.list()[0], 230400);// Open the port you are using at the rate you want:
    arduinoSerial = new Serial(this, Serial.list()[0], 115200);// Open the port you are using at the rate you want:
    arduinoSerial.clear();                                  // Flush serial buffers
  }
  println("*******************************");
  println("* -= ILX511 Scanner v5 MEGA=- *");
  println("*******************************");
  if (!myDebug)
    delay(500);                                             // Delay some to allow scanner to reboot and start sending serial data

  if (myDebug) {                                            // Put some data in the buffer if debugging
    for (int x=0; x < sampleBufferSize; x++) {
      sampleBuffer[x] = x & 255;
    }
  }

  size((sampleBufferSize+10)/2, 300);                       // Display size just wider than sample buffer size
  frameRate(15);                                            // Reduce framerate to save CPU load
}

void serialEvent(Serial arduinoSerial) { 
  if (millis() > timeout + 50) {                            // Timeout if no serial received for 50 milliseconds or more
    //print("Timeout ");
    //println(millis());
    sampleCount = 0;                                        // Timout so reset counter
  }
  sampleBuffer[sampleCount++] = arduinoSerial.read();       // Add value to buffer
  if (sampleCount > sampleBufferSize) {                     // End of buffer?
    print("Overflow ");
    println(millis());
    sampleCount = 0;                                        // zero it
  }
  timeout = millis();                                       // Get current time
}

void draw() {
  int y = 0;
  background(180);                                          // Clear to background colour
  doScale();                                                // Paint on the scale
  stroke(255, 255, 0);                                      // Set pen colour
  for (int x = 0; x < sampleBufferSize; x++) {              // Draw the buffer data
    if ((x % 2) == 0) {
      y = sampleBuffer[x] * 256;
    }
    else {
      y = y + sampleBuffer[x];
      //line((x/2)+5, sampleBuffer[x], (x/2)+5, 280);
      //point((x/2)+5, sampleBuffer[x]/2);
      point((x/2)+5, 280 - (y / 4));
    }
  }
}

void doScale() {
  stroke(0);
  line(0+5, 280, 0+5, 280 - 255);
  line(16+5, 280, 16+5, 280 - 255);
  line(1040+5, 280, 1040+5, 280 - 255);
  line(1043+5, 280, 1043+5, 280 - 255);
}