Advertisement

Hacking a Camera Shutter with Infineon TLE94112LE and Arduino – Part 2

Part 2 – Arduino Software

This is the second part of the “PONF” series. For those that are not familiar, I am the CTO on the PONF (Photography On Film) Project.  This project is the first dual back camera: digital and analog.  One of the most important aspect of this project is that it is a full open-source project.

 

With this article we will detail all the electronics required for the project.  For me, this is the most interesting aspect of the PONF project.  I hope that hardware and software solutions presented will be helpful and interesting to the readers. Most of the parts of the project we will present on electroschematics.com have been presented in a fashion to be easier to replicate in your home workshop.

 

If you would like to know more on the PONF project take a look at the links below: https://www.element14.com/community/search.jspa?q=PONF

https://www.facebook.com/ponfmultibackcamera/

Project updates on twitter: @ponfcamera

 

A special thank for the support to this series to Adam Carlson, Editor-in-Chief.

 

Refresher

In Part 1, we examined the steps that were followed to build the shutter prototype hardware and curcuit.  This hardware is controlled by an Arduino and the custom designed TLE94112LE DC motor controller shield. In this installment we will explore the software and the approach I followed to control the shutter.  The Arduino sketch is available on GitHub and is released under the GNU/GPL license.

 

Software design

The software controlling the shutter has been designed to emulate the natural function of the shutter in the camera, though a camera is controlled by the user settings.  In our case, these user settings are replaced by control commands.  The loop architecture of the main sketch, ShutterControl_I2C, is extremely simple.  It is limited in scope to process the command sent via the USB serial port.

 

The sketch also includes the motorcontrol.cpp class to control the TLE94112 Arduino Shield hardware and a parser which is discussed below.

 

 

Commands

There are two kind of commands:

  • Setting commands – initialize the shutter emulator
  • Control commands – 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 desired 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 timing for the shutter. This is the exact same behavior found in a typical camera.  In addition, to simplify the testing, I have also added the four commands shown below to simulate a continuous shooting mode with exposure time from 1/125 and 1/1000 sec. The number of cycles is defined in the MULTI_SHOOTING constant

 

#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

Note: in the “commands.h” file there are unused/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 main types of APIs:

  • Low level API that interact directly with the TLE04112LE IC
  • High level API used by the parser to execute the commands

 

In order to interface properly with the DC motor controller, the MotorControl class needs the TLE94112 Arduino library available on GitHub by Infineon.

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 micro controller or embedded platform through the I2C protocol.  It is important to note that the I2C protocol portion 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() {

    #ifdef _SERIALCONTROL
     // -------------------------------------------------------------
     // BLOCK 2 : SERIAL PARSING
     // -------------------------------------------------------------
     // Serial commands parser
     if(Serial.available() > 0){
         parseCommand(Serial.readString());
     } // serial available
     #endif

} // Main loop

 

As mentioned before, the loop() function is extremely simple and manages 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
     motor.setPWM(tle94112.TLE_NOPWM);
     // Passive freewheeling
     motor.setMotorFreeWheeling(MOTOR_FW_ACTIVE);
     // Disable acceleration
     motor.setPWMRamp(RAMP_OFF);
     // Clockwise direction
     motor.setMotorDirection(MOTOR_DIRECTION_CCW);

     // 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
     motor.startMotor(SH_MOTOR);
     delay(SH_MOTOR_MS);
     motor.stopMotor(SH_MOTOR);
 }

//! Lock/unlock the shutter top window
 void shutterTop(boolean s) {
     if(s)
         digitalWrite(SH_TOP, 1);
     else
         digitalWrite(SH_TOP, 0);
 }

//! Lock/unlock the shutter bottom window
 void shutterBottom(boolean s) {
     if(s)
         digitalWrite(SH_BOTTOM, 1);
     else
         digitalWrite(SH_BOTTOM, 0);
 }

 //! Shooting sequence
 //!
 //! \param t shooting ms
 void shot(int t) {
     // Lock bottom
     digitalWrite(SH_BOTTOM, 1);
     // Load load shutter
     cycleShutterMotorWithDelay();

     // Shot
     digitalWrite(SH_BOTTOM, 0);
     delay(1);
     digitalWrite(SH_TOP, 1);
     cycleShutterMotorWithDelay();
 #ifdef _SHOTMARK
     digitalWrite(SHOT_MARK, 1);
 #endif
     delay(t);
 #ifdef _SHOTMARK
     digitalWrite(SHOT_MARK, 0);
 #endif
     digitalWrite(SH_TOP, 0);
 }

 

The last important function of the sketch is ParseCommand.  This processes the command requests from the serial interface and executes the commanded 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;
     commandString.remove(cmdlen);

     parseNoCRLF(commandString);
 }

 

More to come!

No Comments

Join the conversation!

Error! Please fill all fields.
Looking for the latest from TI?