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)

4 thoughts on “Shutter emulation EOS1100D, part 2

  1. Pingback: Shutter emulation on Canon EOS1100D DSLR | phym

  2. Erwin Lotter

    Hi Hendrik,

    absolutely great!
    I just googled your site when I was looking for infos on how to disassemble a 1100D shutter, since I actually have a broken one.
    I have modified 1100Ds for astro imaging (filter removal, cooling) and did already remove the mirror for that purpose. And I was thinking about a way to make the camera work shutterless, but didn’t start research on this yet.
    But now, the way seems clear. I’m however not sure whether I will be able to really conduct the whole mod. Soldering should be feasible, but programming a microcontroller is a bit outside of my actual skills. I didn’t look at the signal timing you presented in detail, but it seems to be relatively straightforward. Do you think there might be a way to do the special job of long time exposure with a more simple logic not using a microcontroller?

    Greetings,
    Erwin

    Reply
    1. Hendrik B. Post author

      It might be possible to do away with the shutter without emulating it at all. But you’d need to “fix” the firmware of the canon camera to not check for proper shutter operation. Clearly a job for Magic Lantern!

      In the meantime, while this is still not there, emulating the mechanical cascade of the shutter is (I think) most easily done with a microcontroller. As you can see from the timing diagrams, the “short mode” vs. “long mode” do not differ so much, so either is equally difficult (or easy).

      I contacted some companies and offered them an easy, commericalized version of this mod – but none showed any interest. Hence, you’d have to attempt it yourself 😉

      Reply
  3. Michael Hirmer

    Dear Hendrik,
    I am working on the 450D modification, but struggling at the moment.
    Compareted to the 1100mod the 450mod seems to be more complicated since all pins are functioning.
    I managed to emulate the phototransistor signals just using the LED as trigger and a small Arduino. I am also able to emulate Pin12 (feedback) and in 95% of the cases the mod is working. At the moment I am struggling with the rest of the 3 FB pins. Dependent on the mode (LiveView/ON switch/ long exposure) the FB sequence is different. And what is also interesting, that the FB sequence changes also sometimes in the same mode, which is pretty unclear for me.
    I will also take into account the motor pins, maybe I can get more info.
    Maybe you can support with some tips?Thanks a lot.

    Best regards,
    Michael

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *