Reading a photodiode array


This Arduino code example read the output of a linear sensor array (photodiode array), TSL1402, made by TAOS (TSL1402R datasheet).

Linear sensor array TSL1402R

The TSL1402R sensor consists of two sections of 128 photodiodes each, adding up to 256 pixels. The TSL1402R belongs to a family of linear sensor arrays who share a common pin interface. The TSL1402R only needs to be connected with 3 logical cords if the output is read in serie, or 4 if the parallel mode is used, as in this example. The logical cords to the TSL1402R are clock (CLK), Serial Input (SI) and (1 or 2) Analog Output (AO). In addition there are the cords for +5V and GND.

Arduino connected with TSL1402R

The Arduino is used to control and read the output of the photodiode array. The Arduino program creates the clock pulses for the linear sensor. Once the Arduino clocks in an SI pulse to the sensor, the sensor makes the voltage of pixel 1 available on the analog output pin (AO). Each nextcomming clock pulse will make the voltage of a new pixel available on the AO. The voltages of the pixels can be read from two sections of the photodiode array simultaneously in order to save time and thus enable a shorter integration time. The setup use 6 cords from the Arduino to the linear sensor in the following way:

  • +5 Volt to pin 1 of the sensor (Vdd)
  • Ground to pin 5 and pin 12 of the sensor
  • Analog pin 1 to pin 4 of the sensor (AO 1)
  • Analog pin 2 to pin 8 of the sensor (AO 2)
  • Digital pin 4 to pin 3 of the sensor (CLK)
  • Digital pin 5 to pin 2 of the sensor (SI pulse)
  • Pin 2 of the sensor to pin 10 of the sensor (SI1 to SI2)

The last connection enables parallel reading of the two sensor outputs by synch'ing their clocks.

I made a setup to sample the diffraction pattern from a single slit illuminated by a red diode laser. The collected data is transferred through RS232 to a host computer where it is plotted.

Setup to collect the single slit diffraction pattern

The picture above: A battery powered diode laser illuminates a narrow slit created using a razor blade. Behind the slit is a polarizer (from 3D cinema glasses) placed to decrease the intensity of the laser light. The polarizer obscures the slit.

Single slit diffraction pattern

The picture above: A plot from the host computer that displays the sensor output. The intensity of the laser light saturates the center line at ~140 pixels. The X-axis displays the pixels of the sensor and the Y-axis displays the intensity. The Arduino ADC resolution of 10 bits translates to 0 --> 1024.

The Arduino code

Note that, as mentioned in the datasheet, the integration time starts at the ~18th clockpulse after an SI pulse is inserted into the sensor array, i.e. is clocked in. For the Arduino program the integration time in each loop is ~3ms and the sensor array is clocked at ~30 kHz, then paused while the measurement is transmitted through RS232 to the host computer. The Arduino transmission of the 256 integers takes ~90 ms at 115200 bps.

// Parallel read of the linear sensor array TSL1402R (= the sensor with 256 photodiodes)

// Define various ADC prescaler:
const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0);
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
int CLKpin = 4;    // <-- Arduino pin delivering the clock pulses to pin 3 (CLK) of the TSL1402R
int SIpin = 5;     // <-- Arduino pin delivering the SI (serial-input) pulse to pin 2 of the TSL1402R
int AOpin1 = 1;    // <-- Arduino pin connected to pin 4 (analog output 1)of the TSL1402R
int AOpin2 = 2;    // <-- Arduino pin connected to pin 8 (analog output 2)of the TSL1402R
int IntArray[256]; // <-- the array where the readout of the photodiodes is stored, as integers

void setup()
  // Initialize two Arduino pins as digital output:
  pinMode(CLKpin, OUTPUT);
  pinMode(SIpin, OUTPUT);  

  // To set up the ADC, first remove bits set by Arduino library, then choose
  // a prescaler: PS_16, PS_32, PS_64 or PS_128:
  ADCSRA &= ~PS_128;  
  ADCSRA |= PS_32; // <-- Using PS_32 makes a single ADC conversion take ~30 us

  // Next, assert default setting:

  // Set all IO pins low:
  for( int i=0; i< 14; i++ )
      digitalWrite(i, LOW);  

  // Clock out any existing SI pulse through the ccd register:
  for(int i=0;i< 260;i++)

  // Create a new SI pulse and clock out that same SI pulse through the sensor register:
  digitalWrite(SIpin, HIGH);
  digitalWrite(SIpin, LOW);
  for(int i=0;i< 260;i++)


void loop()
      // Stop the ongoing integration of light quanta from each photodiode by clocking in a SI pulse
      // into the sensors register:
      digitalWrite(SIpin, HIGH);
      digitalWrite(SIpin, LOW);

      // Next, read all 256 pixels in parallell. Store the result in the array. Each clock pulse
      // causes a new pixel to expose its value on the two outputs:
      for(int i=0; i < 128; i++)
          delayMicroseconds(20);// <-- We add a delay to stabilize the AO output from the sensor
          IntArray[i] = analogRead(AOpin1);
          IntArray[i+128] = analogRead(AOpin2);

      // Next, stop the ongoing integration of light quanta from each photodiode by clocking in a
      // SI pulse:
      digitalWrite(SIpin, HIGH);
      digitalWrite(SIpin, LOW);

      // Next, send the measurement stored in the array to host computer using serial (rs-232).
      // communication. This takes ~80 ms during whick time no clock pulses reaches the sensor.
      // No integration is taking place during this time from the photodiodes as the integration
      // begins first after the 18th clock pulse after a SI pulse is inserted:
      for(int i = 0; i < 256; i++)
          Serial.print(IntArray[i]); Serial.print(";");
      Serial.println(""); // <-- Send a linebreak to indicate the measurement is transmitted.

      // Next, a new measuring cycle is starting once 18 clock pulses have passed. At  
      // that time, the photodiodes are once again active. We clock out the SI pulse through
      // the 256 bit register in order to be ready to halt the ongoing measurement at our will
      // (by clocking in a new SI pulse):
      for(int i = 0; i < 260; i++)
              // Now the photodiodes goes active..
              // An external trigger can be placed here

      // The integration time of the current program / measurement cycle is ~3ms. If a larger time
      // of integration is wanted, uncomment the next line:
      // delay(15);// <-- Add 15 ms integration time

// This function generates an outgoing clock pulse from the Arduino digital pin 'CLKpin'. This clock
// pulse is fed into pin 3 of the linear sensor:
void ClockPulse()
  digitalWrite(CLKpin, HIGH);
  digitalWrite(CLKpin, LOW);