Software apps and online services

Hand tools and fabrication machines

Soldering iron (generic)

Story

I was about to digitize a large collection of Hi8/Video8 tapes with my Sony TRV-120E camera. Some of the tapes were recorded in LP and had to be played in its original camcorder. I knew that the TRV-120E had surpassing capabilities and could digitize analog video input on the fly. However, on many European camcorders this functionality is locked due to tax reasons. After some research, I found old methods to fix it with LPT ports and DOS software by going into service mode. Since LPT ports are more rare than Pandas, I decide to renew the methods with an Arduino Mini Pro 16Mhz/5V.

All the hardware you need is two resistors, a NPN transistor, 5.1V Zener diode and a 2.5mm stereo plug. The code communicates with the camera over the LANC protocol which is common for many Sony cameras. The code can also be used to remotely control the camera over a serial interface. You can find LANC codes for different cameras/camcorders online.

Schematics

Arduino-LANC HW interface

Code

Arduino_LANC.ino

Arduino

Arduino LANC to Serial interface I used to enable Analog A/V -> Digital pass through on my Sony TRV-120E by modifying the camcorder EEPROM (see comments in the code). The interface can also be used to remote control a camera/camcorder over a serial bus. LANC commands for different cameras/camcorders can be found online. The code is written and timing checked for Arduino Mini Pro 16MHz/5V, if you want to use it on an other Arduino device check the I/O registers in the code because it is using fastWrite/Read which controls the registers directly.

/*Arduino LANC<->RS232 interfaceVersion 1.0For communicating with cameras via LANCFor the interface circuit interface see http://controlyourcamera.blogspot.com/2011/02/arduino-controlled-video-recording-over.html"LANC" is a registered trademark of SONY.CANON calls their LANC compatible port "REMOTE".Written by L.Rosén------------------------------------------------------------------------------------------Comments regarding service mode for Sony second generation D8 camcorders:DCR-TRV8000E, DCR-TRV8100E, DCR-TRV120E, DCR-TRV125E, DCR-TRV320E, DCR-TRV325EDCR-TRV420E, DCR-TRV520E, DCR-TRV620E, DCR-TRV725ELANC message layout when reading/writing EEPROM(8 bytes each sent with LSB first)B0 B1 B2 B3 B4 B5 B6 B7B0 = First sent byte from our adapterB1 = Second sent byte from our adapterB2B3B4 = The 4 highest bits b7..b4 tells which page in the EEPROM you are atB5 = Confirmation that the command has been received, read command confirmed with F0h, write commands confirmed with F1hB6 = Tells which address in the EEPROM you are atB7 = Data at addressThe following commands is used to navigate the EEPROM and change dataB1 B2FFh 00h = Read command, tells you current page:address:data without changing anythingFFh 67h = Increase page by 1FFh 65h = Decrase page by 1FFh 38h = Increase address by 1FFh 36h = Decrase address by 1FFh 34h = Increase data by 1FFh 30h = Decrase data by 1FFh 32h = STORE commandMetod for checksums (PAGE:ADDRESS:DATA):1) enable changes in memory: 00:01:00 to 00:01:01 (Store)2) change data on page D, how You need (all with STORE).3) read new value: "xx" from 02:F0"yy" from 02:F14) enable update and visibility of checksums on (0F:FE and 0F:FF):00:FF:00 -> 00:FF:02 (STORE)00:01:01 -> 00:01:80 (STORE)5) update new checksums:write to address:0F:FF data "xx" ( from 02:F0 ) (STORE)0F:FE data "yy" ( from 02:F1 ) (STORE)6) disable changes:00:FF:02 -> 00:FF:00 (STORE)00:01:80 -> 00:01:00 (STORE)Links to more information:http://lea.hamradio.si/~s51kq/DV-IN.HTMhttp://www.sps.volyne.cz/set1394/anin/code20.html------------------------------------------------------------------------------------------*/// The code uses fast I/O write because its time critical,// therefore setting pins are done by writing directly to the registers:#define cmdPinON (PORTD = B10000000) // Set digtal pin 7 (PD7)#define cmdPinOFF (PORTD = B00000000) // Reset digtal pin 7 (PD7)#define ledON (PORTB = B00100000) // Set LED pin 13 (PB5)#define ledOFF (PORTB = B00000000) // Reset LED pin 13 (PB5)#define lancPinREAD (PINB & B00001000) // Reads pin 11 (PB3)#define lancPin 11intbitDura=104;// Duration of one LANC bit in microseconds, orginal 104inthalfbitDura=52;// Half of bitDurabytestrPointer=0;// Index when receiving charscharinString[5];// A string to hold incoming datacharoutString[25];// A string to hold outgoing databooleanstrComplete=false;// Indicator to see if the string is completebooleanlancCmd[16];// Array for the lancCmd in bitsbooleanlancMessage[64];// Array for the complete LANC message in bitsvoidsetup(){DDRD=DDRD|B10000000;// Config cmdPin as outputDDRB=DDRB&B11110111;// Config lancPin as inputDDRB=DDRB|B00100000;// Config ledPin as outputpinMode(lancPin,INPUT);// Listens to the LANC line, used for pulseIn function cmdPinOFF;// Reset LANC control pin so that the LANC line is unaffected(HIGH)Serial.begin(57600);// Start serial port Serial.println("Welcome to the Arduino LANC-RS232 interface");Serial.println("Send two bytes in hex form etc. 02AF and wait for reply from camera");}voidloop(){if(strComplete){// inString has arrivedif(hexchartobitarray()){// Convert hex chars to bitarraysendLanc(4);// The LANC command needs to be repeated 4 timesbitarraytohexchar();// Convert received bitarray to hex charsfor(inti=0;i<24;i++){// Write back LANC message over serialSerial.print(outString[i]);}Serial.print('\n');}else{Serial.println("Faulty input!");}for(inti=0;i<5;i++){// Clear input arrayinString[i]=0;}strComplete=false;// Reset data received flag}}voidbitarraytohexchar(){// The bit array lancMessage contains the whole LANC message (8 bytes) with LSB first// This function converts them to hex chars and stores them in outString (16 chars)bytetemp=0;for(inti=0;i<8;i++){// Byte loopfor(intj=0;j<4;j++){// Bit looptemp+=(pow2(j)*lancMessage[(j+4)+i*8]);}outString[i*3]=bytetohexchar(temp);temp=0;for(intj=0;j<4;j++){// Bit looptemp+=(pow2(j)*lancMessage[j+i*8]);}outString[i*3+1]=bytetohexchar(temp);outString[i*3+2]=' ';temp=0;}outString[24]='\n';}booleanhexchartobitarray(){// The hex code in char (4 chars) is located in inString// This function fills the lancCmd array with the bits in the order they should be sent// First byte 1 then byte 2 but with LSB first for both bytesintbyte1,byte2;for(inti=0;i<4;i++){if(!(isHexadecimalDigit(inString[i]))){return0;}}byte1=(hexchartoint(inString[0])<<4)+hexchartoint(inString[1]);byte2=(hexchartoint(inString[2])<<4)+hexchartoint(inString[3]);for(inti=0;i<8;i++){lancCmd[i]=bitRead(byte1,i);// Reads one bit from a number, x is number, n is position (0 is LSB)}for(inti=0;i<8;i++){lancCmd[i+8]=bitRead(byte2,i);// Reads one bit from a number, x is number, n is position (0 is LSB)}return1;}voidsendLanc(byterepeats){// This function is time critical and optimized for Arduino Pro Mini// It takes ~3.2us for the arduino to set a pin state with the digitalWrite command// It takes ~80ns for the arduino to set pin state using the direct register method// delayMicroseconds(50) ~ 49us, delayMicroseconds(100) ~ 99usinti=0;intbytenr=0;while(pulseIn(lancPin,HIGH)<5000){// Sync to next LANC message// "pulseIn, HIGH" catches any 0V TO +5V TRANSITION and waits until the LANC line goes back to 0V // "pulseIn" also returns the pulse duration so we can check if the previous +5V duration was long enough (>5ms) to be the pause before a new 8 byte data packet}while(repeats){i=0;bytenr=0;ledON;// LANC message LED indicator onfor(;bytenr<8;bytenr++){delayMicroseconds(bitDura-7);// LOW after long pause means the START bit of Byte 0 is here, wait START bit durationfor(;i<(8*(bytenr+1));i++){if(bytenr<2){if(lancCmd[i]){// During the first two bytes the adapter controls the line and puts out datacmdPinON;}else{cmdPinOFF;}}delayMicroseconds(halfbitDura);lancMessage[i]=!lancPinREAD;// Read data line during middle of bitdelayMicroseconds(halfbitDura);}cmdPinOFF;if(bytenr==7){ledOFF;}delayMicroseconds(halfbitDura);// Make sure to be in the stop bit before waiting for next bytewhile(lancPinREAD){// Loop as long as the LANC line is +5V during the stop bit or between messages}}repeats--;}}/* SerialEvent occurs whenever a new data comes in the hardware serial RX. This routine is run between each time loop() runs, so using delay inside loop can delay response. Multiple bytes of data may be available. */voidserialEvent(){while(Serial.available()){charinChar=(char)Serial.read();// Get the new byteinString[strPointer++]=inChar;// Add it to the input stringif((inChar=='\n')||(inChar=='\r')||(strPointer>4)){// If the incoming character is a newline, carriage return or 4 bytes has been received flag so the main loop can actstrComplete=true;strPointer=0;}}}intpow2(intx){switch(x){case0:return1;break;case1:return2;break;case2:return4;break;case3:return8;break;case4:return16;break;case5:return32;break;case6:return64;break;case7:return128;break;default:return0;break;}}charbytetohexchar(bytehexbyte){switch(hexbyte){case15:return'F';break;case14:return'E';break;case13:return'D';break;case12:return'C';break;case11:return'B';break;case10:return'A';break;default:return(hexbyte+48);break;}}inthexchartoint(charhexchar){switch(hexchar){case'F':return15;break;case'f':return15;break;case'E':return14;break;case'e':return14;break;case'D':return13;break;case'd':return13;break;case'C':return12;break;case'c':return12;break;case'B':return11;break;case'b':return11;break;case'A':return10;break;case'a':return10;break;default:return(int)(hexchar-48);break;}}