According to the PONF Project design, the digital camera back will use a digital shutter controlled independently by an Infineon microcontroller - at the date, our ideas are focused on the XMC1100XMC1100 IC - hosting an Infineon TLE94112LETLE94112LE DC motor controller. These two components and the shutter itself will be controlled by the main processing unit (the Raspberry PI Compute Module 3Raspberry PI Compute Module 3) via the I2C protocol. As a matter of fact, the PONF electronic architecture is designed following a modular approach to optimising the single components performances controlled by the main processing unit.


Shutter Controller for Testing

This experience started disassembling a Canon 60D electro-mechanic shutter.


The first step was isolating the test points on the flat connector of the shutter; checking the signal paths I found the exact correspondence between every test point and the respective pin on of the pins of the shutter connector.

It is expected that the timings and the opening and closing sequences will be operated externally by the camera board; there is no intelligence on the shutter module. It is generically built in three parts: a geared DC motor of about 800-900 mA that can initialize the shutter curtains and two solenoids keeping them in place.

Based on what discussed above, I have connected the shutter through the test points to the Infineon TLC94112LE Arduino Shield; referring to the IC data-sheet this component will provide the features we need to control this component:


  • Twelve half-bridge power outputs
  • Very low power consumption in sleep mode
  • 3.3V / 5V compatible inputs with hysteresis
  • All outputs with overload and short circuit protection
  • Independently diagnosable outputs (over-current, open load)
  • Open load diagnostics in ON-state for all high-side and low-side
  • Outputs with selectable open load thresholds (HS1, HS2)
  • 16-bit Standard SPI interface with daisy-chain and in-frame response capability for control and diagnosis
  • Fast diagnosis of the global error flag
  • PWM capable outputs for frequencies 80Hz, 100Hz and 200Hz
  • PWM 8-bit duty cycle resolution
  • Over-temperature pre-warning and protection
  • Over and Under-voltage lockout
  • Cross-current protection


The TLC94112LE is conceived to manage both DC motors and solenoids, so I supposed possible to control the two solenoids with the same IC but it did not work. After further tests, I discovered that the solenoids, when the shutter is in use, are triggered sending the control signals to ground. This behavior is incompatible with a direct output logic from the Arduino GPIO so I added a small circuit and changed the wiring design; in addition, I also added a couple of LEDs to see when the two solenoids receive the signal to release the curtains.



The TLE94112LE Arduino Shield is connected to the shutter motor through the TLE94112 pin header; Nets OUT1 and OUT2 connect two of the twelve half bridges of the IC to the shutter DC motor.

The power line on the pin header P2 is connected to the shield motor power line; testing the circuit I found empirically that the optimal power supply for the motor should be 7.5 V. Modifying the Arduino software, I have progressively increased the power line with a cheap DC/DC voltage regulator until the TLE94112LE stopped sending an under-voltage error condition.

The two solenoid signals are sent directly by the Arduino to a couple of NPN transistors. To monitor the solenoids status changes I have also added a couple of LEDs.

Based on the above schematics, After a breadboarding test, I have created the PCB layout. It is a preliminary test architecture that obviously will be re-engineered to fit inside the PONF camera final design.


Prototype Assembly

The PCB has been engraved with a CNC as shown in the images below. I have also designed a support simulating the optical path of the camera from the lens ring up to the shutter blades plane.

Now the new shutter prototype can be finally tested. After the software development, obviously!


Software Design

The software controlling the shutter has been designed to emulate what is expected to happen when it is used by a camera; but a camera is controlled by the user settings, that in our case are replaced by control commands. As you can see in the main sketch ShutterControl_I2C the loop() architecture is extremely simple, limited to process the command sent via the USB serial port.

The sketch includes the motorcontrol.cpp class to control the TLE94112Arduino ShieldTLE94112Arduino Shield hardware and includes a parser we will discuss below.

The last updates of this sources are available on GitHub PONF/ShutterControl_I2C



There is two kind of commands: setting commands to initialize the shutter emulator and control commands to emulate the shutter features.


// Shutter commands (all prefixed with 'sh')
#define SH_MOTOR_INIT "shInit" ///< Initialise the shutter motor
#define SH_MOTOR_CYCLE "shMotor" ///< Exectue a shutter motor cycle
#define SH_TOP_LOCK "shToplock" ///< Lock the top shutter frame
#define SH_TOP_UNLOCK "shTopunlock" ///< Unlock the top shutter frame
#define SH_BOTTOM_LOCK "shBottomlock" ///< Lock the bottom shutter frame
#define SH_BOTTOM_UNLOCK "shBottomunlock" ///< Unlock the bottom shutter frame


The setting commands defined below are used by the control commands to generate the correct shutter behavior.


// Shooting
#define SHOT_8S "8s" ///< 8000 ms = 8 sec
#define SHOT_4S "4s" ///< 4000 ms = 4 sec
#define SHOT_2S "2s" ///< 2000 ms = 2 sec
#define SHOT_1S "1s" ///< 1000 ms = 1 sec
#define SHOT_2 "2" ///< 500 ms = 1/2 sec
#define SHOT_4 "4" ///< 250 ms = 1/4 sec
#define SHOT_8 "8" ///< 125 ms = 1/8 sec
#define SHOT_15 "15" ///< 66 ms = 1/15 sec
#define SHOT_30 "30" ///< 33 ms = 1/30 sec
#define SHOT_60 "60" ///< 16 ms = 1/60 sec
#define SHOT_125 "125" ///< 6 ms = 1/125 sec
#define SHOT_250 "250" ///< 4 ms = 1/250 sec
#define SHOT_400 "400" ///< 2 ms = 1/400 sec
#define SHOT_1000 "1000" ///< 1 ms = 1/1000 sec


The control commands set and execute the shutter opening for the desired timing as the camera will do under normal conditions. In addition, to simplify the testing I have also added the four commands


#define SHOT_MULTI125 "m125" ///< sequential shots 1/125 sec
#define SHOT_MULTI250 "m250" ///< sequential shots 1/250 sec
#define SHOT_MULTI400 "m400" ///< sequential shots 1/400 sec
#define SHOT_MULTI1000 "m1000" ///< sequential shots 1/1000 sec


to simulate continuous shooting with exposure time from 1/125 and 1/1000 sec. The number of cycles is defined in the MULTI_SHOOTING constant

In the preprocessor commands.h file there are commented definitions that are left for future usage and tests.

The MotorControl Class

The MotorControl class is the core of the shutter control; the class contains two kind of API: low-level API that interacts directly with the TLE04112LE IC, and high-level API used by the parser to execute the commands. To work with the DC motor controller the MotorControl class need the TLE94112 Arduino library available on GitHub by Infineon at the following address:


The Arduino Sketch

The ShutterControl_I2C.ino sketch is the main program of the application. There are two important constants that can be enabled or disabled to change the communication interface.

Defining _SERIALCONTROL constant Arduino will accept control commands from the USB serial while defining _I2CCONTROL constant Arduino will accept commands from another microcontroller or embedded platform through the I2C protocol; this last part is not yet completely working.


// ==============================================
 // Main loop
 // ==============================================
 * The main loop role is executing the service functions; display update,  
 * checking.
 * \note tHE i2c Data availability and reading from master is implemented in a
 * callback function. Data reading enable the command parsing immediately then
 * the function come back to the main loop cycle processing the other statuses
 * \warning The diagnostic check based on the status of the motors running has been
 * removed from the loop as the motors control methods check by themselves the
 * diagnostic status of the TLE when a command involving a motor is executed.
 void loop() {
  // -------------------------------------------------------------
  // -------------------------------------------------------------
  // Serial commands parser
  if(Serial.available() > 0){
  } // serial available
} // Main loop


As mentioned before, the loop() function is extremely simple and manage only the command parser. The sketch includes a series of functions: macros organizing together the MotorControl class APIs


//! Initialize the shutter motor
 void initShutterMotor(void) {
  // Enable shutter motor
  motor.currentMotor = SH_MOTOR;
 motor.internalStatus[SH_MOTOR-1].isEnabled = true;
  // Set shutter motor
  motor.currentMotor = SH_MOTOR;
  // PWM Disabled
  // Passive freewheeling
  // Disable acceleration
  // Clockwise direction
  // Initializes the shutter windows Both solenoids released
  digitalWrite(SH_TOP, 0);
  digitalWrite(SH_BOTTOM, 0);
 //! Executes a single shutter motor cycle with delay
 void cycleShutterMotorWithDelay(void) {
  // Start-stop 100 ms test
 //! Lock/unlock the shutter top window
 void shutterTop(boolean s) {
   digitalWrite(SH_TOP, 1);
   digitalWrite(SH_TOP, 0);
 //! Lock/unlock the shutter bottom window
 void shutterBottom(boolean s) {
 digitalWrite(SH_BOTTOM, 1);
 digitalWrite(SH_BOTTOM, 0);
 //! Shooting sequence
 //! \param t shooting ms
 void shot(int t) {
  // Lock bottom
  digitalWrite(SH_BOTTOM, 1);
  // Load load shutter
  // Shot
  digitalWrite(SH_BOTTOM, 0);
  digitalWrite(SH_TOP, 1);
 #ifdef _SHOTMARK
  digitalWrite(SHOT_MARK, 1);
 #ifdef _SHOTMARK
  digitalWrite(SHOT_MARK, 0);
  digitalWrite(SH_TOP, 0);


The last important function of the sketch is ParseCommand that process the command requests from the serial and executes the corresponding tasks.


/** ***********************************************************
 * Parse the command string and echo the executing message or  
 * command unknown error.
 * The command is removed from the last two characters before
 * effective parsing. Use this function when the command comes
 * from a serial terminal
 * \param commandString the string coming from the serial+CRLF
 * ***********************************************************
 void parseCommand(String cmdString) {
  int cmdlen;
  String commandString;
  commandString = cmdString;
  cmdlen = cmdString.length() - 2;


Previous article

PONF Project: Sony 24Mp Sensor Vs Raspberry PI Compute Module 3


Next article

to be continued...