Category Archives: Uncategorized

Shutter emulation EOS1100D, part 2

Plan of approach

If you plan to do this mod yourself, please read the postscript first!

This post describes how to replace the shutter by the microcontroller that will emulate the signals. Any micro can be used; the only requirement is enough GPIOs for the 5 signals and trigger, and sufficient effective speed to handle sequential timings up to about +- 100us resolution. I like ARM, so I go with a STM32F042 I had lying around. If you prefer Arduino, go ahead. It will work, too.

One additional requirement for me is to be able to fit all the parts back in the camera body, leaving it outwardly intact. Because of these, the STM32F042 works nicely. It is a large package to hand-solder, yet small enough to fit inside the EOS1100D body. The body has plenty of free space inside, so that’s no problem.

eos1100d_shutter_mcu1

Figure1: the STM32F042 on the operation table. Some wires are already soldered on, and fixated with some glue.

Except for signal P1, the remainders are simple limit switches that are mechanically connected to GND. P1 is the output of a phototransistor, and typically this is also pulled to ground. All signals are pulled-up by the camera PCB. This was explicitly confirmed by measuring signal levels without the flatcable being connected. This means we can hook up to the signals by just using a N-MOSFET with the source connected to GND, and we don’t need to care about any bias resistors.

Figure 2: Schematic of the microcontroller interface based on the STM32F042 ports. The comparator is necessary to convert the trigger level to CMOS/TTL levels. Alternatively, the signal can be pulled off the “6B” chip as indicated in part1 of the post, but then consequently, the “mod” is not flatcable-only.

Finally, to activate (active-LOW) a signal, one needs to drive PA[3:7] high. This way, the interface is complete, once the timings are taken care of.

Implementation

I decided to hand-solder a small PCB that would fit inside the EOS1100D body. First, all the necessary wires were soldered to the MCU, see the table for reference. When this was done, I selected some small strip PCB unused from another project, and layed out the FETs to minimize the wiring (i.e. dead-bug style source pins tied together). The FETs, MCU were fixed to the PCB with a drop of super glue. Next, two “bars” were placed, one for GND and one for VDD (+3.3V). This makes it easier to solder many wires to the GND/VDD without risking dislodging the previously soldered wires. The wire is thin coil wire, the ends burned away with the soldering iron to expose the bare copper.

PinFunctionInput/OutputSpecialFunction AfterRemarks
7NRSTInput/OutputSWD resetOnly for programming
8VSSAPowerGNDUsed for Reset+RCC subsystem
9VDDAPower3.3VUsed for Reset+RCC subsystem
13PA3Outputpush-pullFC-P1
14PA4Outputpush-pullFC-P9
15PA5Outputpush-pullFC-P10
16PA6Outputpush-pullFC-P8
17PA7Outputpush-pullFC-P12
18PB0Inputpull-downFC-P5
20PB2Inputpull-down, 5V tolerant I/OFC-P7
23VSSPowerGND
24VDDPower3.3V
34PA13Input/OutputSWDIOOnly for programming
35VSSPowerGND
36VDDIO2Power3.3V
37PA15Input/OutputSWCLKOnly for programming
44BOOT0InputPulled to GND for flash boot
47VSSPowerGND
48VDDPower3.3V
EOS1100D shutter emulation MCU pinout
ALT

Figure3: the emulation logic, with the FETs and STM32F042C6T6 MCU.

Figure 4: The completed work with the emulation PCB and the EOS1100D mainboard. Except for P5, all signals are intercepted from the flatcable test points. The only connections to the main board are for the 3.3V power and trigger P5.

Figure 4: The completed work with the emulation PCB and the EOS1100D mainboard. Except for P5, all signals are intercepted from the flatcable test points. The only connections to the main board are for the 3.3V power and trigger P5.

Finally, using Gary Honis’ excellent camera disassembly instructions (link), the camera can be put together easily again. After the shutter and mirror have been removed, there is a lot more space available than I first anticipated, so the emulation PCB didn’t need to be that small. Of course, the PCB can also be left outside – perfect if you want to implement this with an Arduino or STM32-DISCOVERY. Just keep the wires as short as possible, because long wires can pick up noise that couples back into the camera electronics.

The picture below shows the final product. The camera looks like new and unmodified, except for the missing mirror and shutter.

Figure 5: the finished product. The only sign of modification are the missing shutter and mirror.

Figure 5: the finished product. The only sign of modification are the missing shutter and mirror.

Source code

Full source code for the MCU is available on the github project. The code is “bare-bones”, no IDE or special tools are needed to compile it. Just run the make file with a GCC ARM-CORTEX toolchain. Here is an excerpt for the relevant parts of the source code.

Below are the interrupt handlers. The first, “irq_trigger”, will take action based on P5 rising or falling edge. It will simply pass the event to the active state machine.

/**
 * @brief Handle the P5 IRQ (rising & falling edges)
 */
__attribute__((__interrupt__)) void irq_trigger(void)
{
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
        uint8_t const set = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0);
        if (set == Bit_SET) {
            /* Rising Edge */
            shutter.state(&shutter, TRIG1_ACTIVATE);
        } else {
            shutter.state(&shutter, TRIG1_DEACTIVATE);
        }
    }

    EXTI_ClearITPendingBit(EXTI_Line0);
}

/**
 * @brief Handle the application timer
 */
__attribute__((__interrupt__)) void irq_tim2(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

        timer_do(&shutter);
    }
}

The state machine implementation is done in the following blocks. The most interesting one is “handler_state_open()”, which has to decide, based on P7, if the shutter is going into a “short” exposure mode (1/50s or less), or will stay in long mode. It does this by monitoring signal P7 in a certain time window.

The “timer_do()” function should be called with sufficient timer granularity so as to keep up to date with the timings. In this code, it is tuned to run at +- 100us intervals. It doesn’t matter so much, as long as it is faster than 500us. The function will toggle the outputs according to the timings.

/**
 * @brief Handle events when shutter is in the close state
 */
static void handler_state_close(T_SHUTTER* const sh, T_TRIGGER const action)
{
    __disable_irq();
    if (action == TRIG1_ACTIVATE) {
        start_timebase();
        sh->active = 1;
    } else if (action == TIMER) {
        if (!sh->timing->trig) {
            stop_timebase();
            sh->phase = PHASE_IDLE;
            sh->state = handler_state_idle;
            sh->timing = NULL;
            sh->active = 0;
        }
    }
    __enable_irq();
}

/**
 * @brief Handle events when the shutter is in the open state
 */
static void handler_state_open(T_SHUTTER* const sh, T_TRIGGER const action)
{
    __disable_irq();

    if (action == TIMER) {
        // Assume we are in long mode, unless
        // Trig2/P7 signfies we are short mode instead
        if ((TIMESTAMP() >= TRIG2_P7_SAMPLE_WAIT) && (TIMESTAMP() < TRIG2_P7_SAMPLE_HOLD) &&
           (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2)==Bit_SET)) {
            start_timebase();               // reset counter
            sh->phase = PHASE_CLOSE_SHORT;
            sh->state = handler_state_close;
            sh->timing = timing_close_short;
        }
    } else if (action == TRIG1_DEACTIVATE) {
        // Reset P1 (in line with falling edge of P5/Trig1
        GPIO_WriteBit(GPIOA, GPIO_Pin_3, Bit_RESET);
        sh->active = 0;
        stop_timebase();
        sh->phase = PHASE_CLOSE_LONG;
        sh->state = handler_state_close;
        sh->timing = timing_close_long;

    }

    __enable_irq();
}

/**
 * @brief Handle events when the shutter is in the idle state
 */
static void handler_state_idle(T_SHUTTER* const sh, T_TRIGGER const action)
{
    __disable_irq();

    if (action == TRIG1_ACTIVATE) {
        start_timebase();
        sh->phase   = PHASE_OPEN;
        sh->state   = handler_state_open;
        sh->timing  = timing_open;
        sh->active  = 1;
    }

    __enable_irq();
}

/**
 * @brief Called every 100us or so for timekeeping
 */
static void timer_do(T_SHUTTER* const sh)
{
    if (!sh->active)
        return;

    /* Check for the I/O timings and set them */
    if (sh->timing && sh->timing->trig && (TIMESTAMP() >= sh->timing->trig)) {
        *sh->timing->io_reg = sh->timing->state;
        sh->timing++;
    }

    /* Handle state dependent timer events */
    sh->state(sh, TIMER);
}

Finally, all the timings are contained in tables, and are organized in the relevant shutter states. The first line shows the trigger time in microseconds, since elapse of initial trigger from P5. The second column shows the pin action, i.e. P9_CLR means turning P9 GPIO “low”, which has the effect of making P9 high, because it is pulled up by the EOS mainboard. On the other hand, P1_SET means energizing the FET gate, making the Source-drain channel conductive, hence pulling P1 to GND (making it “low”).

/** Shutter-open timings */
static const T_SHUTTER_TIMING timing_open[] =
{
     {25850/TB,        P9_CLR},
     {34000/TB,        P1_SET},
     {35100/TB,        P10_SET},
     {39400/TB,        P1_CLR},
     {42000/TB,        P1_SET},
     {62900/TB,        P10_CLR},
     {71400/TB,        P12_SET},

     {0, 0, 0},       // END
};

/** Shutter-close timings for long mode */
static const T_SHUTTER_TIMING timing_close_long[] =
{
     {200/TB,           P1_SET},
     {5900/TB,          P1_CLR},
     {7200/TB,          P1_SET},
     {8600/TB,          P1_CLR},
     {34800/TB,         P12_CLR},
     {71100/TB,         P8_SET},
     {107600/TB,        P8_CLR},
     {108000/TB,        P9_SET},

     {0,0, 0},         // END
};

/** Shutter-close timings for short mode */
static const T_SHUTTER_TIMING timing_close_short[] =
{
     {2800/TB,          P1_CLR},
     {4300/TB,          P1_SET},
     {5600/TB,          P1_CLR},
     {31600/TB,         P12_CLR},
     {67800/TB,         P8_SET},
     {104000/TB,        P8_CLR},
     {105000/TB,        P9_SET},

     {0,0, 0},         // END
};

Postscript

This mod has a big impact on the function of your camera. So beware! To name a few we came across:

  • Removal of the mirror (mandatory in this EOS1100D mod, but not so for more advanced models that support an independent mirror-lock-up function) causes you to loose automatic metering and the ability to look through the viewfinder/lens. You can still use the movie-mode though.
  • Movie mode works, but will give “err. 20” after you switch back. So you have to power off the camera to restore function (remove battery).
  • The shutter is necessary for bright scenes to keep the chip from over-exposing. It turns out that while the camera is reading out the image sensor, the “lower part” is still sensitive to light. After this mod, the camera is totally useless in bright scenes like daylight! It will only work if the exposure time is about equal the read-out time (i.e. 1″ or more). In dusk or night conditions its fine. Alternatively, if aperature can be really fixed, then daylight might also be okay, but I didn’t test this.

Credits

  • Kanoa Withington, (CFHT, pikotek), who started the EOS450 mod, and for many helpful discussions and encouragements during development
  • Gary Honis, for his excellent EOSxxx disassembly page
  • Mark-Jaap ten Hove & Jaap van ‘t Leven for donating a EOS1100D for the mod. (link, link)
  • Volkssterrenwacht Bussloo, for testing out the mod (link)

Shutter emulation on Canon EOS1100D DSLR

Canon must be proud to produce one of the most hacked cameras out there. From custom ROMs (see the brilliant Magic Lantern project), IR-cut filter removal, to full peltier-cooled mods.

This post describes how to add yet another EOS mod to this increasing list.
Besides astro-photography, a major application for DSLRs is in all-sky stations for weather, night-time or meteorite observations. Not to mention time-lapse photography. The bane of these frontiers is the fact that the mechanical shutter in the camera body tends to wear out after so many clicks. Then either a new body must be found, or the shutter unit replaced.

Fortunately, it turns out that there is an easy alternative! The shutter unit can be removed entirely, and the signals can be generated by an off-board processor that emulates the proper signals to keep the camera happy. In essence, the camera thinks its happily talking to a (non-existent) healthy shutter. This way, the body can be used indefinitely,

Theory of operation

Shutter assemblyThe EOS1100D shutter basically consists of two connected and spring-loaded blades. An electromagnetic coil triggers the main tension spring that folds the shutter blades to the bottom of the assembly, thereby opening the shutter. Another spring then opens the blades again, closing the shutter. In the end, the DC motor (top, with red/black wires) re-tensions the springs for the next actuation.

Although the shutter is mostly mechanical in nature, with a simple triggering mechanism, the camera still wants to monitor the various components to see if they are in working order (if not, report an error). Here comes in the flatcable.

Flatcable

shutter_flatcableFigure 1: flatcable (pins marked 1 through 12)
This 12-pin flatcable interfaces the shutter to the camera electronics. Two of these pins, marked “coil”, trigger the shutter actuation. The rest is used for status & feedback to the camera, either the optical feedback and (limit-)switch feedback from the big rotary disk.

Below is a picture that shows the optical feedback part deep inside the shutter housing. On lid contains the IR-LED, the other lid (blue, bottom) shows the phototransistor. One of the gears has a kind of lid that slides in the gap, unblocking the IR-light, and generating a signal pulse.
eos1100d_opto1

Mirror lock-up

The EOS1100d is an entry level DSLR. At the time of its introduction, it was the cheapest canon DSLR to buy. With decent resolution, cheap price, and ability to be controlled remotely by gPhoto2, it formed the ideal candidate for an automatic camera station.
A cost-cutting consequence in the EOS1100D when compared to its more expensive siblings, is that it has no dedicated mirror lock-up subsystem. Instead, the mirror lock-up mechanism is directly driven by a pin attached to the shutter assembly. This also explains why there is no mirror lock-up support in the firmware for this camera (or in Magic Latern, for that matter).

Consequently, for this particular mod for the EOS1100D, the MLU assembly must also be removed. The advantage is that there are no more mechanical parts left to fail. But it also means that we lose the ability for electronic metering, i.e., we have to try exposure times manually to find the correct shutter/aperature/ISO for the scene. For night time photography, this is not such a big deal, because using sun elevation and moon phase the exposure can be appropriately programmed. For daytime, its a different matter! Either gamble, or program some smart digital metering as a substitute. After all, exposures are now really free of charge!

Implementation

From reverse engineering point of view, we only need to identify a few properties of the FC pins. Is the pin used? Is it an input or output? If an output, what type? And finally, what is the trigger? At first, I attempted by treating the shutter as a black box, and reverse engineer by looking at the electrical properties of the signals alone. In this I eventually succeeded with the emulation, but at the cost of a great deal of time. After inspecting the actual shutter assembly, and the FC, it became instantly apparent what the FC pins are used for. So, if you attempt to repeat this exercise for another camera – don’t do as I did – just disassemble the thing immediately.

Approach

For the reverse engineering, we need to measure the FC pin signals. This can only be done if you can access the pins. Of course, the back panel of the camera must be removed. It is quite tiresome to remove the back panel, make some adjustment, and re-adjust the backpanel again. Luckily, we can leave the backpanel off, and control the camera by laptop using gPhoto2.

Results

The following is a list of flatcable pins as best as I could identify. I regard this list with a high degree of probability.

EOS1100D shutter flatcable pins

FC pinInput/OutputEmulatedDescription
P1InputYesOpto-feedback
P2GNDNoReturn GND for phototransistor/diode.
P5OutputTrigger!On/Off IR-LED
P6OutputNoCoil pin 1
P7OutputNoCoil pin 2 (67Ohm ESR w.r.t. P6)
P8InputYesRotary FB
P9InputYesRotary FB
P10InputYesRotary FB
P11GNDNoReturn GND for Rotary
P12InputYesRotary FB
P3UnknownUnknownNot used / model extension
P4UnknownUnknownNot used / model extension

Next in line are the signal timings. There are two distinct modes of shutter operation – a long exposure mode, and a short exposure mode. The long exposure mode starts for exposure times of 1/60s and longer. For 1/50s and lower, the shutter works in short exposure mode. The key difference is that in long exposure mode, there are two separate triggers, shifted in time depending on the actual exposure time, for shutter-open and shutter-close.

Shutter signal timing sequence for the long mode

 

The curvy blue lines indicate the offset of the various signals with respect to the start of the trigger (rising edge). The other lines show the duration of the various pulses. In between, the time is indeterminate and depends on the actual exposure time. That is why there are two separate trigger pulses in this mode, one for shutter-open, and one for shutter-close.

 

Shutter signal timing sequence for the short mode

 

 

 

 
 

 

 

 

 

 

In the short mode, there is only one trigger pulse, and all the signals can be related against the rising edge. In short mode, the trigger pulse varies between 130ms and 120ms, again depending on exposure time (120ms @ 1/2000s). In long mode, the first trigger pulse is always 110ms. That is how they can be told apart. Alternatively, the coil signal P7 can be monitored for de-activation (rising edge again).

The idea is now to hook the used signal wires off the FC (best to use the big circular test pads, see Figure1), monitor the trigger signal, and pump out the feedback signals with the proper timings. For the trigger, the coil signal is not used. It turns out that the IR-LED is activated a little bit before the coil is activated (which makes sense!), and we might need to change the P1 signal level even before the coil is energized. However, a small complication is that the trigger signal, P5, is not CMOS/TTL compatible. Idle it is 800mV, and triggered it is 1200mV. This is because the trigger signal is actually an output stage of the dual BJT package indicated with the arrow in figure 2. One solution is to catch this signal with a comparator, the other solution is to hook the TTL signal off the base of the BJT package, indicated as the middle pin by the arrow. The nice thing about the first solution, is that you can fully connect the emulation on the flatcable only. The connector pins are very small, and it takes quite some patience to solder wires with such small pitch.
shutter_pcb1Figure 2: Camera point of view, white shows FC receptacle. The indicated package is a dual BJT, likely a Toshiba RN4982FE or similar, and drives the IR-LED. The big SOT23 MOSFET in the bottom drives the coil.

The actual modification will continue here.