Archive for the ‘Arduino’ Category

Canon ETTL protocol

March 19, 2009

This is a continuing story from https://billgrundmann.wordpress.com/2009/03/18/sniffing-canons-ettl-protocol-2/ and previous posts.

Good news!  I found out today that the drop of CLK to ground (after command message 0xb4 0x3d) before the “X” pin drops is exactly 4.00 msec.  This has been measured several times.  This is good as we now have a leading indicator when the flash is requested to do its job!   This is sufficient time for even wireless modes.  Of course I don’t really have the data of the shutter curtain positions relative to the “X” pin.

I’m working on a collective document that describes everything that I’ve found so far.  This would be easier for people to look at than these piece-meal postings.

 

bill

Advertisement

Canon ETTL protocol continued

March 10, 2009

I’m getting back to this interface and looking more closely at the signaling between the XSi and 580ex flash.   This is a continuance of the post: https://billgrundmann.wordpress.com/2009/03/04/ettl-interface/

I realized that I needed to look at how the flash informs the camera that it exists and is turned on.

img_2598

This picture shows “D1” from the camera (on top) and the leading edge of “CLK” from the camera (on bottom).  It looks like the flash informs the camera of its “on” status by pulsing high right after the clock goes high.  This particular pulse starts about 1.6usec after the clock and last for about 11usec.

The flash also seems to indicate a ready concept using D1 as shown in the following picture.  This is a capture of D1 (on top) and CLK (on bottom).  D1 seems to go high before the camera starts to clock some data.  D1 stays high until the clock drops and then, for this example, changes for the first bit of the clocked data (in this example the data bit is “0”.    This D1 high before the clock is likely the flash ready to receive flag to the camera.  This also means that if the last data bit, for the current clocked byte, is “1”, then D1 has to drop to “0” so that it can rise again as ready later.

img_2599

The following picture shows a chain of clocked bytes from the flash (D1 on top, clock on bottom).  Notice that D1 always goes high before the first clock of a new byte and then changes to whatever is the value of the first bit after CLK 1st falls.  Notice also at the point marked with an “X”; this is a case where the last data bit is a “1” and D1 returns to zero and later returns to one to indicate ready for the next byte.

img_2600

So, you can see that there is a handshake between the flash and camera.  The camera can’t send another byte of data until the flash indicates it is ready to receive it.

I found no similar characteristics on the camera’s data, D2.

eTTL interface

March 4, 2009

I want to build a flash interface for my Canon XSi camera.  Unfortunately, it is Canon, which means it is a proprietary interface.  There is some information that has been found on the web and it is a very good starting point:

http://81.216.246.116/e/ettl/

For now I’m tapping into the communication by opening up my shoe cord adaptor instead of trying to build a hot-shoe adaptor myself.  Here’s a picture of the internal connections of the Canon off-camera shoe cord 2. 

img_2543

 The connections are blue: “X” or flash, white: “CLK” from the camera, green: “D1” or data from flash, red: “ID”,  black: “D2” or data from camera, and the braided wire is the ground reference.  I took a picture of the CLK waveform as it starts after I do a pre-focus:

img_2544

This is the leading operation of the CLK pin with a Canon XSi and Speedlite 580ex.  The CLK starts out at 0 volts and has a High of 4.6v and a signal low of 2.1v.  It looks like there is about 80ms between bytes of data (the smaller blips down to 2.1v).  If true, then this means we have plenty of time to analyze the received bytes and even send their data over the slower USB Serial connection.

Here is a close up of the clock chain for one byte of data transfer (one of those blips in the previous picture).  The clock as shown has a period of ~9.6usec, which is ~104KHz.  Measuring all 8 clocks; the average is 9.5usec per clock cycle.  The levels looks like we could use a comparator against 3.3v to determine “0” and “1” of the clock and another comparator with about 1.5 v to detect active clock or communication.

img_2545

The following picture has an example of the data from the flash + clock.  The data only transitions betweens 2.1v and 3.1v.  The voltage swing is probably limited by the battery in the flash which I measured to only be 4.5v (4 AA batteries = ~6v).  The other web site reported D1 swinging between 3.7 and 2.2.

img_25471

Now to go  build an Arduino interface circuit.  This protocol looks doable with Arduino with a little bit of hardware support – at least for sniffing the traffic.   It also looks possible to output the data bytes in real-time through the USB serial port.  To actually create an alternative flash will first take some studying of the traffic while changing different parameters (both camera and flash).  Second, I’ll have to come up with additional circuitry to do the level shifted outputs.

update.. march 5th:

I built a translation circuit for the Arduino.  I had an old LM339 comparator that I knew was fast enough for the purpose and with 7 resistors it was everything I needed.

opamp

I selected v1 = 2.6v, v2 = 1.5v.  I wrote a simple program for the Arduino to sample the bytes of data on both D1 and D2.  The program used interrupt on rising edge of CLK’.  “active” was needed to determine when I was in a commication window.

Here is a sampling of the data that occurred right after a cold start of the XSi camera (aka, I pushed the shutter button all the way when the camera was shutdown and the flash happened).  I haven’t captured data after the “X” pin is set to zero.  Counter to the other web’s information, I see a “8C” versus “86” acknowledgement byte from the flash.

D1 D2 with some translation:

 

8C FF
8C BD set zoom
AA 00
59 28
00 99
FF FF
8C B7 aperture
CC 4C
8C B9 camera mode
00 80
8C BD set zoom
18 00
61 20
32 FB flash mode
02 FF
8C F9 status
74 FF
8C B3 unknown
00 03
00 46
00 2F
00 F5 anoter status
53 FF
49 FF
5C FF
0F FF
00 BE ???
8C 20
8C BB ISO 400
00 58
00 FF
8C FF
9C A5 ???
CC 4C
8C B9 camera mode
00 80
8C BD set zoom
18 00
69 28
32 FB flash mode
02 FF
8C F9 status
54 FF
8C B3 unknown
00 13
00 46
00 2F
00 F5 snother status
53 FF
49 FF
5C FF
0F FF
00 BE ???
8C 20
8C BB ISO 400
00 58
00 FF
8C B3 unknown
00 13
00 46
00 2F
00 B7 aperture
8C 2D
 
March 6th update:
I reformed the output from Arduino to what seems to be messages.
 https://billgrundmann.files.wordpress.com/2009/03/cold_start_flash_taken1.docx
 
March 8th update:
I’ve done two things: 1) I’m using putty.exe as an interface to arduino.  It lets me log all of the messages. 2) I wrote a separate C++ program on windows to process the putty logs and reduce the total messages to the unique messages.  Since the messages from the camera are highly redundant, I needed to reduce it down to just those that are unique.  I can then sample different camera/flash switches to see what changes.  For instance, I now have the complete shutter speed and aperture numbers and their correspondence to the camera settings.
 
fstop
 
I also have the 54 entry shutter timing information.  I’ve written the C++ processing program to start to convert the camera/flash messages to english statement.  I’ll continue to see how the different camera/flash options show up in the messages.
 
 
Stay tuned…

Another NunChuk to Arduino adaptor

March 3, 2009

I saw the little PC board that someone is selling on the Web, but I wanted to brushup on PC layout techniques and low-volume PC board manufacturing (aka diy PC boards).  I measured the size of the connector on NunChuk and used the pin-out information I found and designed my own board.  It is a two-sided board without plated-through holes (which causes yet other problems).  Since the individual boards are so small, I decided to do a strip containing 4 at a time and then cut them out for use later.

These work great.  Here are some pictures.  I beg your forgiveness on the sloppyness of the soldering as I had hole drilling problems and non plated holes.

img_2539

img_2538

I printed the image using a laser printer on photo-paper, a hot iron to transfer the image to the board, water to remove the paper, and etched using a 2-to-1 mixture of Hydrogen Peroxide and Muriatic Acid.  The etching itself only took about 2-3 minutes – very fast.  I didn’t have the correct drill bits (this time around), so I kindof burned the holes with a wire (not the recommended way to do this).  Since I made these I have invested in the appropriate drill hardware.

for now..

To use or not use digitalWrite

March 3, 2009

All Arduino users are familiar with “digitalWrite”.  This is just one of the built-in functions that have made the Arduino an easy to use device.   This particular function was built to reduce the burden of the software details of working with hardware and to generalize input/output across a variety of different parts.

But, do you know the consequences of using this type of function?  The following is a simple program, similar to the the example program that everyone 1st run on their board.  This program doesn’t do any explicit delay from turning on an output to when an output is turned off.

void setup() {
  pinMode(2, OUTPUT);  // LED on board
}

void loop() {
  while(1) {
    digitalWrite(2, HIGH);
    digitalWrite(2, LOW);
  }
}

The program is simple enough.   Here is the waveform produced on pin #2 (16MHz Arduino board).

img_25311

The waveform high time is about 3.3usec (~53 clock cycles) , the low time is about 3.45usec (~55 clock cycles, picture is not shown), and a pulsing frequency of ~148KHz.   Now let’s change the program to something a bit more difficult to understand, but more efficient

void loop() {
  while(1) {
    PORTD |= _BV(2);
    PORTD &= ~_BV(2);
  }
}

Now the high time is only 125ns (only 2 clocks), the low is 251ns (only 4 clocks), and a pulsing frequency of  2.7MHz.  This is considerably faster.

img_25341

img_2536

 The GNU compiler that is used for the Arduino IDE optimizes the “PORT |= _BV(2)” to a single instruction “SBI”, while the other operation is converted to a single instruction “CBI”, each taking 2 cycles.  

The primary difference between the first and second approaches is flexibility and portability.  The “digitalWrite” is more portable and the pin parameter is a variable, while the second approach is a fixed pin parameter (at compile time) and you have to know the port group (PORTB, PORTC, etc.).  For example, the equivalent of “digitalWrite(13, HIGH)” is “PORTB |= _BV(5)” – you have to look at the schematic to see that pin #13 is on PORTBand is bit 5.  Most often, the pin and port connections are frozen early in the design and this manual mapping isn’t a problem.

In addition, there is another not well known hardware feature for pins declared as OUTPUT.  For those who don’t know, there are several registers associated with a port that are readable/writable.  The most popular are the PORTx, which is used for output operations, and the PINx, which is typically used for input operations.  But many don’t know that if you write to the PINx when the port is declared as output will toggle the current output value.

So, if I change the loop to the following:

void loop() {
  while(1) {
    PIND |= _BV(2);
  }
}

Observe that the high and low times are exactly the same at 250ns each and the pulsing frequency is 2MHz.

img_2537

I typically create a C macro to contain the operation, but you could also use an “inline” function.  Using “inline” as a function modifier is another subject altogether.

for now…

Sniffing the i2C traffic of a NunChuk

March 3, 2009

There are several articles on the web about how to use a NunChuk with an Arduino.  There are also articles about how to get NunChuk data via communication to the WiiRemote.  But what I haven’t found is a sampling of the actual interchange between the NunChuk and WiiRemote during their initialization and use.  I developed this program to help me understand that communication traffic.

The communication between the NunChuk and Remote utilizes i2C at 400KHz.  I studied the atmega128 product specification and couldn’t determine how to use Arduino’s i2C hardware for sniffing and not as a master or slave device.  I decided to write my own i2C protocol parsing algorithm. 

i2C is a simple communication protocol.  There are only three wire connections needed: SCL, SDA and ground reference.  SDA is primarily data, but is used for signifying start and end of message.  SCL is the data clock.   The state relationship is shown in the following diagram.

capture91

There are six fundamental operations: 1) Idle, 2) Start condition, 3) Sample SDA, 4) Process Sampled SDA Bit, 5) Stop condition, and 6) Repeated Start condition.  Startup condition is in the idle state.  A byte of data occurs by accumulating the first 8 bits (from MSB 1st bit to LSB) of the sampled SDA.   A ninth bit is then processed as the byte acknowledge with a “0” meaning acknowledged and “1” a not acknowledge.  The next byte + ack is then processed unless there is either a “stop condition” or a “repeated start” condition.  A message is a collection of bytes that start with a “start condition” or “repeated start” and ending with a “stop condition” or “repeated start”.   The first byte of a message is the message address and message read/write information.

Because of the i2C data rate, the Arduino USB serial interface is not fast enough and has too much overhead to simultaneously transmit the data received.  Because of this, we have to store the bytes in Arduino memory, which isn’t very much (<<1024 bytes).  This also means that this memory will fill rather quickly.  This full condition is checked every time a new data byte has been accumulated.  When “full” is detected, the process shown above is aborted and the program outputs all of the accumulated messages that were received.

Now for some of the messages.   The following stream of messages occurs immediated upon powerup of both the NunChuk + Remote (with comments).  The syntax of each line is the message byte count (e.g “(2):” for two bytes) and each of the message bytes (in hex).   After each byte is either a “+” or “-” signifying acknowledge/not-acknowledge respectively.  The first byte of a message always contains the address of the device (bits 7:1) and bit 0 is either read (=1) or write (=0).  Bytes with 0xa4 or 0xa5 have been previously identified as NunChuk messages by others in their web sites.  I don’t know what is being addressed by all of the other addresses.  Keep in mind that several of the values in these messages are particular to my NunChuk and other NunChuks will likely have different values.  I’m assuming at this point that the sequence of messages won’t change with the values however.  It would be nice to get any confirmation to that assumption.

 .. looks like a non-NunChuk addressed device
(2):A0+ 00-
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(2):A0+ 00-
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(2):A0+ 00-
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(2):A0+ 00-
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(2):A0+ 00-
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(2):A0+ 00-
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(2):A0+ 00-
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(2):A0+ 02+
(8):A1+ 00+ 00+ 00+ 00+ 00+ 00+ 00+
(2):A0+ 00+
(8):A1+ 1E- F5+ 5A+ 46+ 09+ CE+ 80-
(8):A1+ 2C+ E5+ E2+ F5- A8- D2- 30+
(2):A0+ 00-
(8):A1+ 2E+ CC+ 1A+ 63- 29- 0F- A0+
(8):A1+ FE+ 15+ C2+ B4- 01+ 88+ 3D-
(2):A0+ 00-
(8):A1+ FE- 04- F8+ 54- 09- D3+ 04-
(2):A1+ 80-

.. something happening with NunChuk addresses
(3):A4+ F0+ 55+
(3):A4+ FB+ 00+
(2):A4+ FA+
(7):A5+ 00+ 00+ A4+ 20+ 00+ 00-
(3):A4+ F0+ AA+
(8):A4+ 40+ AC+ B9+ 8B+ 35+ 1F+ C8+
(8):A4+ 46+ 28+ BE+ B2+ 89+ 07+ 18+
(6):A4+ 4C+ 19+ FF+ 01+ C6+

… the following looks like the calibration data being read
… this is the parameters for my NunChuk
(2):A4+ 20+
(9):A5+ 3F+ 6B+ 0C+ 67+ BD+ D2+ 5F+ 72-
(9):A5+ 3F+ 6B+ 0C+ 67+ BD+ D2+ 5F+ 72-
(2):A4+ 30+
(9):A5+ 3F+ 6B+ 0C+ 67+ BD+ D2+ 5F+ 72-
(9):A5+ 3F+ 6B+ 0C+ 67+ BD+ D2+ 5F+ 72-

.. some more non-NunChuk data
(2):B0+ 60+
(8):B0+ 00+ 08+ 00+ 03- 20+ 40+ 2A-
(3):B0+ 0E+ 00-
(3):B0+ 34+ 8C+
(2):B0+ 66+
(2):B0+ 60+
(2):B0+ 60+
(8):B0+ 00+ 08+ 00+ 03- 20+ 40+ 2A-
(3):B0+ 0E+ 00- (3):B0+ 34+ 8C+
(2):B0+ 66+
(2):B0+ 60+
(1):B0+
(8):B1+ FE- FD- FB- F7- EF- DF- BF-
(2):B1+ FE-

… the following 5 messages are then repeated, which is the polling of the accelerations and buttons
… of course the NunChuk data varies with changes of position of the NunChuk device
    (2):A4+ 00+
    (7):A5+ B0+ EB+ B3+ 1F+ 00+ B7-

… non-NunChuk messages (part of the 5 repeating messages)
    (1):B0+
    (8):B1+ FE- FD- FB- F7- EF- DF- BF-
    (2):B1+ FE-

————————————————————————————————-

Here is the program.  The way the “loop” routine was written was to make it possible to process the i2C messages at 400KHz.  It does not follow normal structured programming rules – there are lots of “goto” statements instead of for/while/do structured techniques.   I found that normal structured C code executed too slowly and missed the SDA data.

i2c_sniffer2

The overhead of Arduino Interrupts

March 2, 2009

I wanted to build an application that could sniff  i2C transactions.  In particular, I was interested in the actual data transactions between the Wii NunChuk and WiiRemote.  This particular data interchange utilizes 400KHz i2C protocol.  So, I thought this was a good opportunity to use arduino interrupts, especially the change on pin interrupts.  What I envisioned is a state-machine that would perform work on transitions of either SCL or SDA – or so I thought.

What I found out was the overhead in the simple version of attaching interrupts was too much to do anything useful at the 400KHz data rate.  I changed to edge-sensitive interrupts without any improvements.  I had to find out what was going on.

I started looking at the actual assembly code generated from the “attachInterrupt” arduino reference library.  Here’s what I found.

Here’s a simple code example:

#define LED_PIN 5  // digital pin #13 (portb)
#define LED_ON() PORTB |= _BV(LED_PIN)
#define LED_OFF() PORTB &= ~_BV(LED_PIN)

void myfunc() {
  LED_OFF();
}
void setup() {
   pinMode(13, OUTPUT);
  attachInterrupt(0, myfunc, RISING);
}

void loop() {
  LED_ON();
  delayMicroseconds(20);
}

I tied the LED output back to Digital pin #2 and this is running on a 16MHz Arduino.  Notice, all this program does is turn an LED on then the interrupt, which responds to the rising of the LED voltage, turns off the LED.  Here is a picture of the LED “on” strobe:

img_25261

As can be seen, the width of the LED “on” is 3.435usec, which is considerable longer than the 600ns that SCL of the i2C protocol is high!  So, this won’t work to respond to SCL changes.  This is about 55 clock cycles @ 16MHz!  What is going on?  Also, what about the 20usec delay in the loop?

img_2527

Notice that the total period for the LED is 26.60usec.  That means the off time for the LED is 23.165usec, which is 3.165usec longer than the delay statement request.   Let’s now look at what happens under the hood.  To do that we have to look at the assembled instructions that came from the program’s compile.

The following is what is generated for the interrupt handler for INT0.  Using the atmegas168 datasheet and information about instructions we can count the number of instruction cycles.  There are 45 cycles before there is a call to the “myfunc” and there are 35 cycles after return of “myfunc” and return from the interrupt handler.  There is also 3 cycles in the pin synchronizer and another 3 cycles for a JMP instruction (which is in the interrupt vector table).  So, we have a total of 51 cycles before we start to execute “myfunc”.

capture4

Now the “myfunc” has some amount of delay before it sets the LED off.   As can be seen, the overhead for a “cbi” instruction  is about 1 cycle.  We’ve accounted for 52 cycles, there are another in 2 cycles in the “sbi”  instruction in the “loop” that actually turns the LED on, and also this blocks interrupts until after the instruction completes.  Now we’ve accounted for 54 cycles.  The other cycle is likely due to the fact that we are setting the LED synchronously with the same clock as the interrupt sampling; this will add another cycle for synchronization.  There we are, all 55 cycles accounted for!

capture51

So, the simple to use “attachInterrupt” has a too much of a significant overhead for the application that I would like to do.  I’ll have to find another solution. 

I made changes to the program.  I got rid of the generic “attachInterrupt” and manually enabled the interrupt.  I also used the “ISR” construct to declare the interrupt handler.  To compile this I had to unfortunately modify Arduino’s “WInterrupts.c” source (located in the \hardware\cores\arduino folder) – I commented out the SIGNAL operations for INT0_vect as this conflicts with the use of “ISR” statement in my application.

#define LED_PIN 5  // digital pin #13 (portb)
#define LED_ON() PORTB |= _BV(LED_PIN)
#define LED_OFF() PORTB &= ~_BV(LED_PIN)

ISR(INT0_vect) {
  LED_OFF();
}
void setup() {
  pinMode(13, OUTPUT);
  // enable INT0 interrupt on change
  EICRA = 0x03;  // INT0 – rising edge on SCL
  EIMSK = 0x01;  // enable only int0
}

void loop() {
  LED_ON();
  delayMicroseconds(20);
}

The changes to the actual waveform on LED were remarkable:

img_2528

The overhead of 1.118usec is now only about 18 clock cycles.  Unfortunately, this is still too much for me to use interrupts to process i2C message.  In addition, it may now be obvious that the background interrupts to keep the delay clock alive are also adding cycles everytime that supporting interrupt occurs.  This extra delay occuring at random places in your application could be significant and cause the occasional strange behavior.

This is a good example of using the instruction and cycle counting methodology to better understand how to improve critical timing in an application.

cheers!

Looking at code generated by Arduino compiles

March 2, 2009

Most of the time you don’t need to do this.  But, if you are writing real-time code that is time sensitive or if you interested in what the compiler did with your C or C++, then this is for you.

You may have noticed that when you create a new SketchBook you get a new folder that has the name of the Sketch.  Inside of this folder is another folder that is named “applet”.  This applet folder is created by a successful compile of the Sketch AND a successful upload to the Arduino board.  In the applet folder there are several files, but the ones we are interested in are the ones with the “.o” file name suffixs.  These are the individual object files created by the compiler.  Each one of these correspond to an associated C/C++ source.  As you will notice, there are more in the folder than you probably wrote.  These additional files are all of the other arduino associated files that complete your application.

These object files are binary.  Fortunately, there is another program supplied by the Arduino system that permits looking at a textual version of those files.   The “objdump” executable found in the \hardware\tools\avr\avr\bin\ area of your arduino installation folder.  This program reads an object file (.o) and creates a text file.  To make it easy, create a batch file, I called it objdump.bat.  I put the single following line into this batch file:

for %%f in (*.o) do C:\arduino-0012\hardware\tools\avr\avr\bin\objdump -S %%f > %%~nf.txt

(Please ignore the extra spaces created in the blog)   Of course you also need to change the path to the program to match where you have it located (C:\arduino….)

Ok, now after you have uploaded to the arduino, copy the batch file into the applet folder.  The reason for a copy is that this folder is deleted and recreated everytime you do another upload – hence, you have to have the batch file somewhere else and copy eacy time.  Run the batch file and you should see several new files of type .txt.  Each of these new files are then viewable to see both the original source code and the assocated assembly statements.

Enjoy.

The nature of gravity

March 2, 2009

Actually, I’m referring to things dropping and how long it takes for that thing to drop a certain distance.  If you use this information along with controlling a camera then you can capture things that are falling in a repeatable fashion.  For instance, a drop of water as it just hits a pool of water, or maybe just a little later when the water pool splashes back up after reacting to the water droplet.

The favorite equation used for this dropping behavior is

distance, acceleration and time

where “s” is the distance, “a” is the acceleration rate, and “t” is the amount of time.  This equation assumes the object starts at rest and t=0.  The acceleration “a” can be assumed constant with a value of approximately gravity constant

I was able to build a simple setup that allowed me to experiment with Arduino controlling a Laser, a light sensor, and a camera (Canon XSi).  The experiment performed the following steps:

1.   Turn on a laser and insure that the light sensor detected the laser

2.   Drop an object through the laser-sensor beam

3.   Upon sensing the laser-sensor beam broken, start a delay

4.   Once delay has finished, take a picture

5.   Turn off the laser

6.   Look at the picture to evaluate object’s dropped distance

7.   Repeat with different delay amounts

Ok, simple enough.  The problem I had was how to release the object repeatedly from a fixed position and as close to already breaking the laser-sensor beam as possible.  The object I chose was as ruler, permitting me to visually see the distance traveled. 

img_25221

My object (ruler) release was simple – a nail that I pulled back that released the ruler.  I carefully positioned the ruler to just before breaking the light between the laser and sensor.  I then release, recorded what the camera saw and repeated. 

I also changed the amount of delay.  After I had several interesting data points, I plotted the results.  I recorded 6 different results for the same delay, plotting the average/min/max.  I also plotted a curve-fitted line to determine the least-square best fit for the modified equation (instead of “t”, I used “(t + y)”, where “y” is the unknown amount of camera delay).  From this particular experiment, I determined that “y” is about 106msec, which is for some reason, different from other experiments for the same camera.

capture3

Here is an example picture taken:

img_2407

The arduino code is:

#define shutter_close PORTD |= _BV(2);
#define shutter_open PORTD &= ~_BV(2);

#define focus_on PORTD |= _BV(3);
#define focus_off PORTD &= ~_BV(3);

#define laser_on PORTD |= _BV(4);
#define laser_off PORTD &= ~_BV(4);

#define nolight (PINB & 1)  // digital pin #8
#define ledon PORTB |= _BV(1)
#define ledoff PORTB &= ~_BV(1)


void setup() {
  pinMode(2, OUTPUT);  // camera shutter
  pinMode(3, OUTPUT);  // focus control
  pinMode(4, OUTPUT);  // Laser control
  pinMode(8, INPUT);   // light input
  pinMode(9, OUTPUT);  // led indicator
  shutter_open;
  focus_off;
  ledoff;
  laser_off;
  Serial.begin(9600);
}
unsigned long amt = 0;  // 0 = no extra delay … just the inherent delay

void get_delay() {
  unsigned long delay = 0;
  unsigned char len = 0;
  while(1) {
    while(!Serial.available());  // wait for first character
    unsigned char c = Serial.read();
    if (c >= ‘0’ && c <= ‘9’) {
      delay = (delay * 10) + (c – ‘0’);  // add in digit
      len++;
    } else {
      if (len == 0) {
        Serial.println(“Have to enter a delay”);
        return;
      } else {
        amt = delay;
        Serial.print(“new extra delay of “);
        Serial.println(amt);
        return;
      }
    }
  }
}

void loop() {
  while(1) {
    Serial.println(“Command? (D, T, A)”);
    while(!Serial.available());  // wait for command
    unsigned char c = Serial.read();
    switch(c) {
      case ‘A’: case ‘a’:
        laser_on;
        while(!Serial.available()) {
          if (nolight) ledon;
          else ledoff;
        }
        Serial.read();
        laser_off;
        break;
       
      case ‘T’: case ‘t’: {
        Serial.print(“Delay is camera + “);
        Serial.print(amt);
        Serial.println(“ms”);
       
        laser_on;
        while(nolight);  // wait for laser and sensor together
        focus_on;
        delay(1000);  // pre-focus
        while(nolight == 0);  // wait for light trigger

        // turn off laser
        // laser_off;
        delay(amt);  // time to shutter
        shutter_close;  // close the shutter
        ledon;  // flag progresst
        delay(200);  // delay some amount for the shutter/flash to work
        shutter_open; // release shutter
        focus_off;
        ledoff; // flag progress
        laser_off;
      } break;
     
      case ‘D’: case ‘d’:
        get_delay();
        break;
     
      case ‘F’: case ‘f’:
        focus_on;
        delay(1000);
        focus_off;
        break;
       
    }
  }
}
 

 

Characterizing shutter curtain delay of Canon XSi

March 2, 2009
I wanted to know the delay from closing the shutter of my camera to when the actual picture is taken. With this information, then it becomes easier to setup various stop-motion picture captures.
For this experiment, I needed three things:
  • A way of controlling the Canon XSi camera
  • A bright enough LED with a short flash time while the camera was in total darkness
  • An accurate accounting for delay from control of camera to LED flash

The LED I used was a Luxeon I, which was controlled via a simple transistor driver (2N2222 + base resistor). The flash time for the LED was chosen to be only 1msec. To get an accurate delay I found I had to write my own delay routines. The delay routines provided by the Arduino library were not really adequate for my purpose.
My software hardware algorithm was simple. Have the arduino close the camera shutter, have it delay a predetermined (but user variable) amount, and flash the LED at a piece of paper, for which the camera was taking a picture. I then manually looked at the resulting picture to see the amount of light that was exposed in the picture. I recorded the results and changed the amount of delay and repeated. Because the LED flash time was only 1msec, I had to shoot with an ISO of 1600.
 
I did two different sets of pictures. The first picture set was just of an arbitrary piece of paper I had laying around. It had some garbage writing on it, but this was to determine if the setup worked ok. The shutter speed was set at 1/100. I approximated from these pictures the actual shutter speed at 1/100.6, which is within 0.6% of the camera’s setting. Also the delay begins at 84msec through 86msec depending upon the position in the camera’s sensor.
Notice how the sensor is opened from the bottom and the 2nd curtain also starts at the bottom (as it should).
 
The second set of pictures was of a sheet of paper that had printed on it lines labelled from 0 through 10. This ruling would permit me to better estimate the delay time to % position of the shutter open or closed. I carefully positioned the paper and camera zoom so that the “0” line was just at the bottom and the “10” line was just at the top of the camera’s sensor.
 
Here is an example of one of these shots.
 
Lastly, I used the perceived % opening/closing of shutter to plot the delay of the shutter. I posted these as two excel charts, the first for the shutter opening, the second for closing.      
 
 
 
 
 
 
 
 
 
 
 

my_flash program