/* 45 iTTL_V1 *********************** created 2020 by Herve QUEVAL V0 - manage 45CL3 CL4 in TTL mode. V1.000 - Modify minor bugs when bad protocol synchronization or frame time out (led blink correctly). Enhancement of the detection of Sync condition on Frame (try to manage better init phase for GODOX V1R-N - check Handshake high ( OK with D7000 and X1 improve but stop after B0 frame...) Modify trace for debugging Report version 1.000 on DSLR Implement non blocking Analog read Implement Red eyes reduction (even if never use it) Implement power managment according ISO, extend power table to support low duration until 43µS Ajustement of Exposure and Preflash 1 and 2 ( Preflash2 is sligtly 30% more power than preflash1 to use small aperture lens or longer distance) Implement over heating security (in case of usage of Turbo and external power pack) only in TTL mode - max 10 shot at 1/1 in 20sec then wait. use only preflash2 to be run on Teensy 2.0 with no addon cards. In fact use a SCA3009 M1 interface with flash 45CL 3 or CL4. warning: with original 45CL3 or 4 flash gun, due to Thyristor circuit design, TTL is only usable with AEL (FL mode). - preflash to memorize - take the picture. Some residual problem identified: shot missing or over exposed: this is due to bad transmission (ISO too high..., cde not received). To avoid this kind of problem implement Error detection on B0 frame. and/or improve signal quality. Analog input as follow FLASH_Mode 21 A0 Digital /DSLR_Sync 0 in DSLR_DATA 1 in/out DSLR_CLK 2 out /DSLR_Hshake 3 in /LED_OUT 20 out /FLASH_Sync 19 out /FLASH_Ready 18 in /AF_Asyst 17 out FLASH_Stop 167 out FLASH_Expo_OK 15 in /Test button 14 in /SW1 23 in selection TTL ou TTL BL */ //*********************** Compatibility *************************************************************** //#define PREFLASH1 1 // to enable Preflash 1 //*********************** Debugging *************************************************************** //#define DEBUG 1 //#define DEBUG_ITTL 1 //#define DEBUG_ITTL1 1 // verbode mode of DEBUG_ITTL // #define DEBUG_ITTL2 1 // I-TTL Time out trace // #define DEBUG_DSLR_CMD 1 // #define DEBUG_FLASH 1 // #define DEBUG_FLASH_MODE 1 //#define DEBUG_POWER_LIMIT // ************ constants Used here to set pin numbers ******************************************** // DSLR interface const int DSLR_SYNC = 0; // in const int DSLR_DATA = 1; // in/out (out during frame transfer initiation or send capability or info ) const int DSLR_CLK = 2; // out const int DSLR_Hshake=3; // in const int DSLR_CLK2 = 5; // in (out during HW init phase) // Flash Interface const byte FLASH_MODE_ANALOG_ID = 0; // analog input ID 0.. 12 according HW definition (for Non blocking analogConversion ) const int FLASH_MODE_IN = A0; // analog input Teensy pin number const int LED_SCA = 20; // out const int FLASH_Sync = 19; // out const int FLASH_READY = 18; // in const int AF_ASSIST = 17; // out const int FLASH_Stop = 16; // out const int FLASH_Expo_OK=15; // in //SCA interface (Led and test button const int TEST_BUTTON = 14; // in const int SW1 = 23; // in // test - Debugging interface - activ low const int TP1 = 6; // out Preflash 1 const int TP2 = 7; // out Power cde const int TP3 = 8; // out Data aborted // Power conversion table // ---------------------- // Table to convert Nikon index 0x54.. 0XA8 to duration // Min and max Nikon index values obtained using Godox XA2/WA1 in manual 1/128.. 1/1 and SB900 Flash // in real life could receive smaller values than 0x54 // 0 if manual or A mode int Flash_Duration_Long[90] = { // 89 elements - Offset 0x50 ( 0x54 minus 4 additional bytes) // 1/256+0,7 ... 1/1 - 1/12 IL increment // Index 0.. 88 43, 45, 47, 48, 50, 52, 54, 55, 57, 59, 61, 62, 64, 66, 68, 69, 71, 73, 76, 78, 80, 83, 85, 88, 90, 93, 95, 98, 100, 106, 111, 117, 122, 126, 131, 138, 144, 150, 155, 161, 169, 174, 180, 187, 194, 201, 208, 215, 222, 229, 236, 243, 250, 265, 277, 288, 300, 313, 320, 335, 345, 360, 370, 388, 405, 425, 450, 483, 510, 558, 600, 653, 710, 770, 835, 915, 1000, 1100, 1225, 1350, 1510, 1708, 1905, 2103, 2325, 2550, 2800, 3050, 3300 }; #define POWER_MINVALUE 0x50 int ISO_adjustment[29] = { // 28 elements - ISO100 min for Nikon D7000 et D7100 // 50 IS0 à H2 24, 20, 16, 12, 8, 4, 0, -4, -8, -12, -16, -20, -24, -28, -32, -36, -40, -44, -48, -52, -56, -60,-64,-68,-72,-76, -80,-84 }; int ISO_adjustment2[29] = { // same in case prefalsh2 is used // 50 IS0 à H2 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, -4, -8, -12, -16, -20, -24, -28, -32, -36,-40,-44,-48,-52, -56,-60 }; #define ISO_MinValue 0x18 // Power limit table // ---------------------- // Table to convert strobe duration to an index to calculate power limit and delay flash ready signel // Use Power index / 4 // int Flash_PowerLimit[23] = { // 22 elements 0, 0, 1, 2, 3, 4, 3, 4, 5, 6, 8, 10, 12, 16, 20, 23, 31, 39, 45, 60, 75, 90 }; //ITTL answer message definition //---------------------------------------------------------------------------------------------- // use to SB900 message // A0 first and second byte and CRC are recalculated to report flash ready and selected Flash mode ( A, M, TTL) #define A0_LEN 22 // message len in byte minus commande byte and includes CRC #define A1_LEN 18 #define A2_LEN 46 byte MessageA0[A0_LEN+1] = { 3,1,0xC0,4,0,0,0x92,0x5E,0x30,0x4B,0,0xFF,0xFF,0,0,0,0,0,0,0,0,0x32}; //byte MessageA1[A1_LEN+1] = { 1,1,5,2,8,7,0x81,0x78,0xB4,0x64,0x0A,0x4E,0xFF,0x3E,0x90,0x3E,0x90,0x1D}; // version 5.2 of SB-900 byte MessageA1[A1_LEN+1] = { 1,1,1,0,8,7,0x81,0x78,0xB4,0x64,0x0A,0x4E,0xFF,0x3E,0x90,0x3E,0x90,0x1D}; // version 1.000 of SCA ITLL adaptor byte MessageA2[A2_LEN+1] = { 3,5,0x6D,0x9B,0x90,0x86,0x80,0x7A,0x72,0x6A,0x65,0x5E,6,0x75,0x9E,0x94,0x8A,0x80, 0x77,0x6F,0x66,0x60,0x58,6,0x74,0x9E,0x95,0x8B,0x80,0x76,0x6F,0x66,0x60,0x59,4,0x5F, 0x96,0x8A,0x82,0x80,0x7E,0x79,0x71,0x6E,0x6A,0xFC }; //Nikon Flash ready code for A0 frame // bit 0 0 not ready 1 ready // bit 1 0 ack flash 1 normal no acl #define BIT_NIK_READY B00000001 #define BIT_NIK_NOACK B00000010 //Constantes ---------------- Protocole et Flash -------------------------------------------------------- #define TIME_OUT_DURATION 10 // Time Out protocol - duration in 0,1 sec #define TIME_OUT1_DURATION 400 // Time Out handshake - duration in 1 µSec Test give 200 µS limit... #define TEST_FLASH_DURATION 40 // Test flash duration in µS #define PRE_FLASH_DURATION 67 // Pre flash duration in µS #define PRE_FLASH2_DURATION 90 // Pre flash2 duration in µS #define EXPO_COMPENSATION 3 // value in 1/3IL to compensate expo difference between two preFlash method. #define EYES_REDUCTION_INTERVAL 300 // interval between eyes reduction strobe #define EYES_REDUCTION_STROBE_DURATION 40 // flash strobe duration in µS #define TEMP_LIMIT_HIGH 700 // temp managment - High water mark to delay ready signal to DSLR #define TEMP_LIMIT_LOW 0 //DEFINE section for non blocking ANALOG READ----------------------- #define ADC_REF_POWER (1< #include void setup() { // ******************************************************** initialisation ************************************** // setup DSLR Interface pin pinMode(DSLR_SYNC, INPUT_PULLUP); // in - internal + 220pF to GND pinMode(DSLR_DATA, INPUT_PULLUP); // in/out; PULLUP to avoid noise; at power up IN, always IN ; only out during Device identification and answer to DSLR request. pinMode(DSLR_CLK, INPUT); // output except during init. pinMode(DSLR_Hshake,INPUT); // in - external pull-down 10K pinMode(DSLR_CLK2, INPUT); // output during init. Data_Direction = IN; // setup Flash Interface pin pinMode(LED_SCA, OUTPUT); pinMode(FLASH_Sync, OUTPUT); pinMode(FLASH_READY, INPUT_PULLUP); pinMode(AF_ASSIST, OUTPUT); pinMode(FLASH_Stop, OUTPUT); pinMode(FLASH_Expo_OK, INPUT_PULLUP); pinMode(TEST_BUTTON, INPUT_PULLUP); // in with 0,1µF in parallel on contact. pinMode(SW1, INPUT_PULLUP); // in - external pull-up needed?? // init flash output interface digitalWrite(LED_SCA, LOW); // turn the SCA LED on during INIT digitalWrite(FLASH_Sync, HIGH); // Active low digitalWrite(AF_ASSIST, HIGH); // Active low digitalWrite(FLASH_Stop, LOW); // Active high // init and set Test pin pinMode(TP1, OUTPUT); digitalWrite(TP1, HIGH); pinMode(TP2, OUTPUT); digitalWrite(TP2, HIGH); pinMode(TP3, OUTPUT); digitalWrite(TP3, HIGH); // init Timer 3 use timer 3 to detect i-TTL protocol time-out Timer3.initialize(100000); // interrupt each 100ms Timer3.attachInterrupt(Time3Event); // init Timer 1 use timer 1 to detect i-TTL handshake time-out TimeOut1=0; Timer1.initialize(TIME_OUT1_DURATION); Timer1.attachInterrupt(Time1Event); Timer1.stop(); // will be started waiting Handshake // init context global variable ITTL_FrameState = DISABLE; ITTL_State = INACTIV; Flash_Duration = 50; RedEyes_Action=STOP; RedEyes_Sequence = INACTIV; Flash_TooHot = 0; // contexte Flash Mode Flash_Mode = UNDEFINED; Analog_Mode = analogRead(FLASH_MODE_IN); // contexte Test button Flash_TestRequest =0; Ack_requested=0; FlashActivityIndex=0; FlashActivityLevel=0; //flash fully available. #ifdef DEBUG delay(1000); // wait for serial USB initialized ....... Serial.println("DEBUG ON"); #endif #ifdef DEBUG_FLASH Serial.println("DEBUG FLASH interface ON"); #endif #ifdef DEBUG_ITTL Serial.println("DEBUG I-TTL ON"); #endif delay(100); // sense clock line (like X2T GODOX) -------------Experimental - not needed --------------------- pinMode(DSLR_CLK2, OUTPUT); digitalWrite (DSLR_CLK2, HIGH); // obtain CLK +5V if not connected, +1,4V if connected to body delay(48); delayMicroseconds(500); if (digitalRead(DSLR_CLK) == LOW) { // sens CLK line #ifdef DEBUG_ITTL Serial.println("INIT - SCA connected"); #endif } else { #ifdef DEBUG_ITTL Serial.println("INIT - SCA not connected"); #endif pinMode(DSLR_CLK, OUTPUT); digitalWrite (DSLR_CLK, HIGH); pinMode(DSLR_CLK2, INPUT); // high Z delayMicroseconds(1500); digitalWrite (DSLR_CLK, LOW); } digitalWrite(LED_SCA, HIGH); // turn the SCA LED off if (digitalRead(FLASH_READY) == LOW) { Flash_Recycling=0; } else { Flash_Recycling=1; SyncX_Time=millis(); } Flash_Battery = TURBO_BATTERY; // init led params T1=1600; T2=10; } //***************************************************************************************************** end Init ****************** // interupt 3 TimeOutEvent ---------------------------------- volatile byte TimeOut=0; // set to 1 if time out volatile byte TicCount=TIME_OUT_DURATION; //time ou in 0,1 sec volatile byte TimeOut_Stopped=0; // set to 1 to stop void Time3Event(void){ if (TimeOut_Stopped==0) { if (TicCount==0) {TimeOut = 1;} else {TicCount--;} } if (FlashActivityIndex != 0) { FlashActivityIndex--; if (FlashActivityIndex == TEMP_LIMIT_LOW) { Flash_TooHot = 0; } } } void ArmTimeOut(void){ noInterrupts(); TicCount=TIME_OUT_DURATION; TimeOut=0; TimeOut_Stopped=0; interrupts(); } void StopTimeOut(void){ TimeOut_Stopped=1; } // interupt 1 TimeOutEvent -----Hanshake time out --------------------- void Time1Event(void){ TimeOut1++; } void ArmTimeOut_1(void){ noInterrupts(); TimeOut1=0; Timer1.start(); interrupts(); } byte DSLR_ReadByte() { // Generate clock and deserialize data from DSLR; byte val = 0; for (byte offset = 0; offset < 8; offset++) { // loop to read the 8 bits val = val >> 1 ; digitalWrite(DSLR_CLK, LOW); delayMicroseconds(16); digitalWrite(DSLR_CLK, HIGH); if (digitalRead(DSLR_DATA) == HIGH ) { val |= 0x80; } delayMicroseconds(16); } return val; } void DSLR_OpenDataOutput() { // activate Serial Data Out pinMode(DSLR_DATA, OUTPUT); digitalWrite(DSLR_DATA,LOW); } void DSLR_CloseDataOutput() { // Close serial Data Out pinMode(DSLR_DATA, INPUT_PULLUP); } void DSLR_WriteByte(byte data) { // Wait Handshake low; Generate clock and serialize data from DSLR byte mask; delayMicroseconds(15); for (mask = 0x01; mask>0; mask <<= 1) { digitalWrite(DSLR_CLK, LOW); if (data & mask){ // choose bit digitalWrite(DSLR_DATA,HIGH); // send 1 } else{ digitalWrite(DSLR_DATA,LOW); // send 0 } delayMicroseconds(16); digitalWrite(DSLR_CLK, HIGH); delayMicroseconds(16); } } /* ************************************************************************************************************************************ * Main loop * process event: * - DSLR input according i-TTL state * - Test Button * - Test requested * - Time Out (long time out) * * Short time out on HandShake is a detection of aborted frame according protocol. ************************************************************************************************************************************ */ void loop() { // i-TTL Frame state decoder ------------------------------------ // DISABLE // DSLR OFF, STANDBY or SCA not connected. // WAIT // DSLR ON start nego begin frame // STANDBY // DSLR standby (protocole standby - already negotiated/sync) // READY // 1st pulse Handshake received - interface synchronized, read cde and decode // RECEIVED // Frame received, process frame - During process, manage i-TTL Prococol state switch(ITTL_FrameState) { // *********************************** Process DSLR input according i-TTL protocol state **************** case DISABLE: if (digitalRead(DSLR_Hshake) == HIGH) { // test cas flash ON; boitier off et s'active. delayMicroseconds(1300); digitalWrite(DSLR_CLK, HIGH); ITTL_FrameState = WAIT; #ifdef DEBUG_ITTL1 Serial.print("detect Hanshake HIGH - Frame state=");Serial.print(ITTL_FrameState);Serial.print(" Protocol state=");Serial.println(ITTL_State); #endif } break; case WAIT: if (digitalRead(DSLR_DATA) == LOW && digitalRead(DSLR_Hshake)==HIGH) { // Body is on - send recurrent DATA pulse, will sync on this pulse // if (digitalRead(DSLR_DATA) == LOW ) { // Body is on - send recurrent DATA pulse, will sync on this pulse ArmTimeOut(); #ifdef DEBUG_ITTL1 Serial.println();Serial.print("detect 1 of recurrent data pulse - Frame state=");Serial.print(ITTL_FrameState);Serial.print(" Protocol state=");Serial.println(ITTL_State); #endif pinMode(DSLR_DATA,OUTPUT); digitalWrite(DSLR_DATA,LOW); while (digitalRead(DSLR_Hshake)==HIGH && TimeOut==0 ) { } // wait Handshake // release data pinMode(DSLR_DATA,INPUT_PULLUP); if (TimeOut==0){ ITTL_FrameState = READY; #ifdef DEBUG_ITTL1 Serial.println();Serial.print("sync on frame start Frame state ");Serial.println(ITTL_FrameState); #endif } #ifdef DEBUG_ITTL1 else { Serial.println();Serial.println("Wait fail - Time out"); } #endif } break; case STANDBY: if (digitalRead(DSLR_DATA) == LOW) { ITTL_FrameState = WAIT; #ifdef DEBUG_ITTL1 Serial.print("detect standby - Frame state=");Serial.print(ITTL_FrameState);Serial.print(" Protocol state=");Serial.println(ITTL_State); #endif } break; case READY: // receive 1st Byte of a Frame -- Ready to decode Cde and read or send remaining part of the frame ++++ if (digitalRead(DSLR_Hshake)==LOW ) { ArmTimeOut(); delayMicroseconds(15); // initialement 15 Cde=DSLR_ReadByte(); while (digitalRead(DSLR_Hshake) == LOW && TimeOut==0) { } // attend fin Handshake #ifdef DEBUG_ITTL1 Serial.println(); Serial.print("cde=");Serial.print(Cde,HEX); #endif // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++decode first byte to identify cde ++++++++++++++ Data_Direction = IN; // default value; overwriten when needed switch (Cde) { case 0xA1: n=A1_LEN; Data_Direction = OUT; break; case 0xB1: n=10; break; case 0xA2: n=A2_LEN; Data_Direction = OUT; break; case 0xB0: n=15; break; case 0xA0: n=A0_LEN; Data_Direction = OUT; break; case 0xD7: // pre flash n=0; digitalWrite(TP1,LOW); break; case 0xD8: n=1; break; case 0xD3: // power cde n=3; digitalWrite(TP2,LOW); break; case 0xD5: // Modeling light start (stop after 1sec.) n=0; break; case 0xD0: // AF assist 01 (F0) on 00 (00) off n=2; break; case 0xD1: // pulse anti-yeux rouge 1 pulse 1/64 toutes les 0,25ms jusqu,à cde stop. n=1; break; case 0xC0: // main flash strobe confirmation ( byte signification unkown) n=5; break; case 0xE0: // standby n=2; #ifdef DEBUG_ITTL Serial.println(" E0..."); #endif break; default: n=0; #ifdef DEBUG_ITTL Serial.println(" Other..."); #endif break; } if (Data_Direction == OUT) { // ++++++++++++++++++++++++++++++++++++++++ Send byte Capability or Info +++++++++++++ // send answer to DSLR p=0; Crc=1; DSLR_OpenDataOutput(); while (n !=0) { // loop to write the answer of the cde. ArmTimeOut_1(); while (digitalRead(DSLR_Hshake) == HIGH && TimeOut1 == 1) { } // attend Handshake if(TimeOut1 > 1 ) {break;} Timer1.stop(); delayMicroseconds(20); // initalement 26 20 à 40 fonctionne avec D7000 if (Cde==0xA0) { b = MessageA0[p]; if (p==0) { // send flash status and ack b=0x00; if (Ack_requested==0) { b=b | BIT_NIK_NOACK;} // Ack: bit = 0 if no ACK Bit=1 if (Flash_Recycling == 0 && Flash_TooHot == 0 ) {b=b | BIT_NIK_READY;} // report flash ready in the viewfinder } if (p==1) {b=Flash_NikMode;} //send selected mode if (p==14) { if (FlashActivityLevel < 512) { FlashActivityLevel = FlashActivityIndex>>1;} else {FlashActivityLevel = 0xFF;} // if (FlashActivityLevel < 512) { FlashActivityLevel = FlashActivityIndex<<1;} else {FlashActivityLevel = 0xFF;} // for test only with low threshold if (Flash_Recycling == 0 && Flash_TooHot == 0) { b=FlashActivityLevel; } else { b=0xFF; } } // Power capacity 00 full - >0 lower - FF recycling } else if (Cde==0xA1) { b = MessageA1[p]; } else if (Cde==0xA2) { b = MessageA2[p]; } if (n==1) { // recalculate CRC //Serial.print("CRC=");Serial.print(Crc,HEX);Serial.print(" b=");Serial.println(b,HEX); b=Crc; // will send calculated Crc } else { Crc = Crc + b; } DSLR_WriteByte(b); n--; p++; #ifdef DEBUG_ITTL1 Serial.print(",");Serial.print(b,HEX); #endif while (digitalRead(DSLR_Hshake) == LOW && TimeOut==0) { } // attend fin Handshake if(TimeOut==1 ) {break;} } Timer1.stop(); DSLR_CloseDataOutput(); #ifdef DEBUG_ITTL2 if (TimeOut== 1){ Serial.println("data send time-out"); } if (TimeOut1 > 1){ Serial.println("data send aborted"); } #endif } else { //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Read byte to complete cde ++++++++++++++ while (n !=0) { // loop to read the data byte of the cde. n--; ArmTimeOut_1(); while (digitalRead(DSLR_Hshake) == HIGH && TimeOut1==1) { } // attend Handshake if(TimeOut1 > 1 ) {break;} Timer1.stop(); delayMicroseconds(15); // initialement 26, 15 OK avec D7000; if (Cde==0xD3 && n==0) { d=0xD3; DSLR_OpenDataOutput(); DSLR_WriteByte(d); // send ack to DSLR DSLR_CloseDataOutput(); } else { d = DSLR_ReadByte(); } #ifdef DEBUG_ITTL1 Serial.print(",");Serial.print(d,HEX); #endif // Here read command parameters - only few one are manage by the programm and by flash if (Cde==0xD3) { if(n==1) { Flash_Power_Index=d; } } else if (Cde==0xB0) { if(n==11) { Iso_Index = (d-ISO_MinValue)>>1;} else if(n==7) { Exposure_Correction = d; } else if(n==13) {d=d&4; if(d==0){ Ack_requested=1; } else { Ack_requested=0; }} } else if (Cde==0xD1) { if(n==0) { RedEyes_Action = d; } } while (digitalRead(DSLR_Hshake) == LOW && TimeOut==0) { } // attend fin Handshake if(TimeOut==1 ) {break;} } Timer1.stop(); #ifdef DEBUG_ITTL2 if (TimeOut== 1){ Serial.println("data read time-out"); } if (TimeOut1 > 1){ Serial.println("data read aborted"); } #endif } if ( TimeOut==1 || TimeOut1 > 1 ) { if (TimeOut1 > 1){ digitalWrite(TP3,LOW);} ITTL_FrameState = WAIT; #ifdef DEBUG_ITTL2 Serial.println();Serial.print(" Time Out WAIT frame T3 T1 ");Serial.print(TimeOut);Serial.print(" ");Serial.print(TimeOut1); #endif } else { ITTL_FrameState = RECEIVED; } } digitalWrite(TP1,HIGH); digitalWrite(TP2,HIGH); digitalWrite(TP3,HIGH); break; case RECEIVED : // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Execute cde ++++++++++++++++++++++++++++ ITTL_FrameState = WAIT; // default value for all cmd except special cases switch (Cde) { case 0xD7: // preflash for prime lens - short distance #ifdef DEBUG_ITTL Serial.println();Serial.print("pre-flash 1"); #endif delayMicroseconds(40); DSLR_OpenDataOutput(); delayMicroseconds(408); // + 4µs de traitement DoPreFlash(); Expo_IndexCompensation = 1; delayMicroseconds(5800); // + 4µS traitement + Preflash duration 6,1ms after flash start. DSLR_CloseDataOutput(); break; case 0xD8: // preflash 2 for small aperture lens and/or long distance #ifdef DEBUG_ITTL Serial.print(" pre-flash 2"); #endif delayMicroseconds(40); DSLR_OpenDataOutput(); delayMicroseconds(408); // + 4µs de traitement DoPreFlash2(); Expo_IndexCompensation = 0; delayMicroseconds(5800); // + 4µS traitement + Preflash duration 6,1ms after flash start. DSLR_CloseDataOutput(); break; case 0xD3: DSLR_OpenDataOutput(); if (Exposure_Correction >0x80) {temp = (~(Exposure_Correction-1))<<1; } else {temp = (~(Exposure_Correction<<1))+1; } if (Expo_IndexCompensation == 1) { temp=temp+Flash_Power_Index+ISO_adjustment[Iso_Index]; // calculation of the exact power needed preflash1 } else { temp=temp+Flash_Power_Index+ISO_adjustment2[Iso_Index]; // calculation of the exact power needed preflash2 } if (temp < POWER_MINVALUE) { // Check power index range and normalize Normalized_Power=0; } else if (temp > 0xA8) { Normalized_Power=88; } else { Normalized_Power=temp-POWER_MINVALUE; // minus Power min value is also the offset in the table. } Flash_Duration = Flash_Duration_Long[Normalized_Power]; #ifdef DEBUG_ITTL Serial.println(); Serial.print("ISO ");Serial.print(Iso_Index);Serial.print(" ISO adjustment ");Serial.println(ISO_adjustment[Iso_Index]); Serial.print("Power level:");Serial.print(Flash_Power_Index,HEX);Serial.print(" Duration:");Serial.print(Flash_Duration);Serial.print(" Expo Comp:");Serial.print(Exposure_Correction);Serial.print(" Index:");Serial.println(temp,HEX); #endif delayMicroseconds(610); // + 8µS traitement 618µS d'activation. DSLR_CloseDataOutput(); break; case 0xD5: #ifdef DEBUG_ITTL Serial.print(" D5...."); #endif DoPilot(); break; case 0xA0: if (ITTL_State == INACTIV) { ITTL_State = STARTED; } // reprise dialog sur time out flash mais pas coté boitier. if (ITTL_State == STARTED) { ITTL_State = ACTIV; #ifdef DEBUG_ITTL Serial.println();Serial.print("ITTL ACTIV"); #endif } break; case 0xA1: ITTL_State = INIT; #ifdef DEBUG_ITTL Serial.println();Serial.println("ITTL INIT"); #endif break; case 0xA2: ITTL_State = STARTED; #ifdef DEBUG_ITTL Serial.println();Serial.println("ITTL STARTED"); #endif break; case 0xD0: #ifdef DEBUG_ITTL Serial.println("ITTL AF Assist cde"); #endif AF_Assist=2; digitalWrite(AF_ASSIST, LOW); break; case 0xB0: if (AF_Assist > 0) { AF_Assist--; if (AF_Assist == 0) { digitalWrite(AF_ASSIST, HIGH); } } break; case 0xE0: StopTimeOut(); ITTL_FrameState = STANDBY; break; case 0xD1: if (RedEyes_Action == START){ RedEyes_Time = millis()+ 100; RedEyes_Sequence = ACTIV; #ifdef DEBUG_ITTL Serial.println(" Start"); #endif } else { RedEyes_Sequence = INACTIV; #ifdef DEBUG_ITTL Serial.println("Red Eyes reduction Stop"); #endif } break; } break; } if (TimeOut == 1) { // Event Time Out ------------------------------------------------------------- #ifdef DEBUG_ITTL Serial.println();Serial.print("ITTL - Time Out - Frame State=");Serial.print(ITTL_FrameState);Serial.print(" Protocol state=");Serial.println(ITTL_State); #endif ArmTimeOut(); StopTimeOut(); // sync process will restart the TimeOut soft counter ITTL_FrameState = DISABLE; ITTL_State = INACTIV; pinMode(DSLR_DATA, INPUT_PULLUP); digitalWrite(DSLR_CLK, LOW); delay(10); } if (digitalRead(DSLR_SYNC) == LOW) { //Event DSLR Sync X activ ----------------------------------------- switch (ITTL_State) { case ACTIV: if (Flash_TooHot == 1) { break; } pinMode(DSLR_SYNC,OUTPUT); digitalWrite(DSLR_SYNC,LOW); if (Flash_Mode == TTL) { DoFlash(); #ifdef DEBUG_ITTL Serial.println("X TTL main flash done"); #endif FlashActivityIndex = FlashActivityIndex + Flash_PowerLimit[Normalized_Power>>2]; if (FlashActivityIndex > TEMP_LIMIT_HIGH) { Flash_TooHot = 1; #ifdef DEBUG_POWER_LIMIT Serial.println("Flash too Hot !!!"); #endif } } else { StartFlash(); #ifdef DEBUG_ITTL Serial.println("X A ou M main flash done"); #endif } SyncX_Time=millis(); // to calculate recycling time delayMicroseconds(2760); // 2800 minus process time pinMode(DSLR_SYNC,INPUT_PULLUP); if (digitalRead(FLASH_READY) == HIGH ) { Flash_Recycling = 1; } // detect if flash recycling. while (digitalRead(DSLR_DATA)==HIGH && TimeOut==0) { } // skip 1st Data low pulse following main flash. while (digitalRead(DSLR_DATA)==LOW) { } break; default: pinMode(DSLR_SYNC,OUTPUT); digitalWrite(DSLR_SYNC,LOW); if (Flash_Mode == TTL) { #ifdef DEBUG_ITTL Serial.println("X TTL - NO flash possible"); #endif } else { StartFlash(); #ifdef DEBUG_ITTL Serial.println("X A ou M - ITTL NOT ACTIV"); #endif } delayMicroseconds(2800); pinMode(DSLR_SYNC,INPUT_PULLUP); while (digitalRead(DSLR_SYNC)==LOW) { } break; } } if (Flash_Recycling == 1 && digitalRead(FLASH_READY) == LOW ) { // flash ready event ------------------ Flash_Recycling=0; Flash_RecyclingDuration = millis()- SyncX_Time; if (Flash_RecyclingDuration > 5000) { Flash_Battery = INTERNAL_PACK; } // detect battery type based on Recycling duration. else if (Flash_RecyclingDuration > 2300) { Flash_Battery = EXTERNAL_PACK; } else { Flash_Battery = TURBO_BATTERY; } #ifdef DEBUG_POWER_LIMIT Serial.print(Flash_RecyclingDuration);Serial.print(" Battery type=");Serial.println(Flash_Battery); #endif } if (Flash_TestRequest == 1 ) { // Event Flash Test ------------------------------------------------ if (Flash_TestBlocked == 0) { // remise à 0 gérée dans boucle timer du controle led DoFlashTest(); Flash_TestBlocked = TEST_BLOCK_DURATION; } } if (digitalRead(TEST_BUTTON) == LOW ) { // Event Button Test ----------------------------------------- Flash_TestRequest = 1; } if (RedEyes_Sequence == ACTIV) { // Event Red eyes reduction ----------------------------------- if (RedEyes_Time < millis()) { RedEyes_Time = RedEyes_Time + EYES_REDUCTION_INTERVAL; #ifdef DEBUG_ITTL Serial.print("RedEyes reduction"); Serial.println(RedEyes_Time); #endif DoFlash2(EYES_REDUCTION_STROBE_DURATION); } } if (ITTL_State == INACTIV) { // Control LED depending of the protocol activation -------------------- // cde LED - Flash blink 1 sec T1--; if (T1 == 0) { ReleaseTestButton(); ReadMode(); T1= 20000; T2--; if (T2==1) { digitalWrite(LED_SCA, LOW); #ifdef DEBUG_FLASH Serial.print("Flash Mode = ");Serial.println(Flash_Mode); #endif } if (T2==0) { digitalWrite(LED_SCA, HIGH); T2=11; } } } else { // protocol i-TTL actif // cde LED - Flash blink 1 sec T1--; if (T1 == 0) { ReleaseTestButton(); ReadMode(); // refresh rate is sufficient. T1= 30400; T2--; if (T2==5) { digitalWrite(LED_SCA, LOW); #ifdef DEBUG_FLASH Serial.print("Flash Mode=");Serial.print(Flash_Mode);Serial.print(" Nikon Mode=");Serial.println(Flash_NikMode); #endif } if (T2==0) { digitalWrite(LED_SCA, HIGH); T2=10; } } } } // ***************** end main loop ************************************************************************************************************ void ReleaseTestButton() { if (Flash_TestBlocked > 0) { Flash_TestBlocked--; if (Flash_TestBlocked == 0) { Flash_TestRequest = 0; } } } void ReadMode() { // Analog_Mode = analogRead(FLASH_MODE_IN); Analog_Mode= analogGetResult(); // get result of previous demand analogConversionRequest(FLASH_MODE_ANALOG_ID); //start conversion for next loop if (Analog_Mode > Seuil_TTL) { if (Analog_Mode < Seuil_A) { Flash_Mode = TTL; if (digitalRead(SW1) == HIGH) { Flash_NikMode = NIK_TTLBL; } else { Flash_NikMode = NIK_TTL; } } else if (Analog_Mode < Seuil_M) { Flash_Mode = A; Flash_NikMode = NIK_A; } else { Flash_Mode = M ; Flash_NikMode = NIK_M; } } else { Flash_Mode = UNDEFINED; Flash_NikMode = UNDEFINED; } #ifdef DEBUG_FLASH_MODE Serial.print("Flash Mode =");Serial.print(Analog_Mode);Serial.print(" LSB");Serial.print(" Mode="),Serial.println(Flash_Mode); #endif } void DoPilot() { // for test purpose - cannot work at 70Hz like SB-900 for (byte z=0 ; z<=9; z++) { DoFlash2(40); delay(120); Serial.print("."); } } void DoFlashTest() { // used when TTL, otherwise strobe duration manage by flashgun if (Flash_Mode == TTL) { #ifdef DEBUG_FLASH Serial.println("Flash Test TTL (1/64)"); #endif DoFlash2(TEST_FLASH_DURATION); // duration µS } if (Flash_Mode == A || Flash_Mode == M) { #ifdef DEBUG_FLASH Serial.println("Flash Test"); #endif StartFlash(); } } void DoPreFlash() { // Do pre flash if (Flash_Mode==TTL) { digitalWrite(DSLR_CLK, LOW); #ifdef PREFLASH1 DoFlash2(PRE_FLASH_DURATION); #endif delayMicroseconds(94); // Increase to emulate optic detection 28 µS + 76 µS digitalWrite(DSLR_CLK, HIGH); } else { // if AA mode selected could receive preflash cde and do nothing. digitalWrite(DSLR_CLK, LOW); delayMicroseconds(146); digitalWrite(DSLR_CLK, HIGH); } } void DoPreFlash2() { // Do pre flash 2 slghtly more power for small aperture lens or long distance. digitalWrite(DSLR_CLK, LOW); DoFlash2(PRE_FLASH2_DURATION); delayMicroseconds(94); // Increase to emulate optic detection digitalWrite(DSLR_CLK, HIGH); } void DoFlash() { // using Flash power received from DSLR. - TTL only StartFlash2(); delayMicroseconds(Flash_Duration); StopFlash(); } void DoFlash2 (int T) { // same as DoFlash but T Flash duration µS as parameter T = (T-2); //remove duration code execution before delay StartFlash2(); delayMicroseconds(T); // replace by duration, minus 20µS (duration of start pulse) StopFlash(); } void StartFlash() { // to call in case A or M mode... digitalWrite(FLASH_Sync, LOW); delayMicroseconds(2); // initialement 10, 1 ratés en A; pas de départ en M; 2 OK digitalWrite(FLASH_Sync, HIGH); } void StartFlash2() { digitalWrite(FLASH_Sync, LOW); } void StopFlash() { digitalWrite(FLASH_Sync, HIGH); digitalWrite(FLASH_Stop, HIGH); delayMicroseconds(2); // initialement 30, digitalWrite(FLASH_Stop, LOW); } //++++++++++++++++++++++++++++++ Non blocking analogConversion ++++++++++++++++++++++++++++ void analogReference2(uint8_t mode) { aref = mode & 0xC0; } // Arduino compatible pin input void analogConversionRequest(uint8_t pin) // conversion request; read later using analogGetResult() { #if defined(__AVR_ATmega32U4__) static const uint8_t PROGMEM pin_to_mux[] = { 0x00, 0x01, 0x04, 0x05, 0x06, 0x07, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20}; if (pin >= 12) return; adc_req(pgm_read_byte(pin_to_mux + pin)); return; #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) if (pin >= 8) return; adc_req(pin); return; #else return; #endif } int16_t analogGetResult() { uint8_t low; low = ADCL; // must read LSB first return (ADCH << 8) | low; // must read MSB only once! } // Mux input void adc_req(uint8_t mux) { #if defined(__AVR_AT90USB162__) return 0; #else // uint8_t low; ADCSRA = (1<